| stfufs-1.1/README.brief | | stfufs-1.2/README.brief |
| 3 | =========================== | 3 | =========================== |
| 4 | | 4 | |
| 5 | --- | 5 | --- |
| 6 | 1.1 | 6 | 1.2 |
| 7 | --- | 7 | --- |
| 8 | | 8 | |
| 9 | Very brief for now, more to come if there is enough interest. | 9 | Very brief for now, more to come if there is enough interest. |
| 10 | | 10 | |
| 11 | **Note: Communication protocol in 1.1 is incompatible with 1.0 versions.** | 11 | **Note: Communication protocol in 1.2 is incompatible with older verions.** |
| 12 | Connection attempt will fail if using mixed versions. | 12 | Connection attempt will fail if using mixed versions. |
| | 13 | |
| | 14 | Server end may have versions 1.1 and 1.2 installed at the same time if 1.1 |
| | 15 | is installed when 1.2 is being installed. If this is the case, both 1.1 client |
| | 16 | and 1.2 client can connect to stfufs server. |
| | 17 | |
| 13 | | 18 | |
| 14 | Brief Intro | 19 | Brief Intro |
| 15 | =========== | 20 | =========== |
| 27 | 2) The machines has important high-load application(s) running. | 32 | 2) The machines has important high-load application(s) running. |
| 28 | 3) One wants to see real statvfs values ;) | 33 | 3) One wants to see real statvfs values ;) |
| 29 | | 34 | |
| 30 | This is first version. There is lot to improve. New versions may come. | 35 | This is one of the first versions. There is lot to improve. |
| | 36 | New versions may come. |
| 31 | | 37 | |
| 32 | | 38 | |
| 33 | License | 39 | License |
| 52 | | 58 | |
| 53 | After client compilation on "local" machine (where directory is to be mounted) | 59 | After client compilation on "local" machine (where directory is to be mounted) |
| 54 | and server compilation on "remote" machine (from where directory is mounted), | 60 | and server compilation on "remote" machine (from where directory is mounted), |
| 55 | move server component to a location that is on your PATH. In many cases | 61 | install client and server by using command ``make install PREFIX=<prefix>``. |
| 56 | entering command ``cp stfufs-server $HOME/bin/stfufs-server`` does the job. | 62 | Components will be installed in directories ``PREFIX/bin`` and |
| 57 | During initial testing, client does not need to be copied anywhere, but for | 63 | ``PREFIX/lib/stfufs``. Make sure ``PREFIX/bin`` is in your PATH. |
| 58 | permanent use it is good to be get somewhere in your PATH. | | |
| 59 | | | |
| 60 | | 64 | |
| 61 | Use | 65 | Use |
| 62 | === | 66 | === |
| 63 | | | |
| 64 | These examples expect stfufs (client) is found in your PATH. During | | |
| 65 | initial testing on stfufs source directory, use ``./stfufs ...`` | | |
| 66 | | 67 | |
| 67 | In it's basic form, the usage is pretty same as with sshfs_: | 68 | In it's basic form, the usage is pretty same as with sshfs_: |
| 68 | | 69 | |
| 145 | more docs in general | 146 | more docs in general |
| 146 | protocol updates for smarter stuff | 147 | protocol updates for smarter stuff |
| 147 | pretocol using stfufs-buffer code (maybe) | 148 | pretocol using stfufs-buffer code (maybe) |
| | 149 | split client code out of stfufs binary, to make "reverse" mount possible. |
| 148 | more | 150 | more |
| 149 | | 151 | |
| 150 | Thanks | 152 | Thanks |
| stfufs-1.1/pretocol.c | | stfufs-1.2/pretocol.c |
| 7 | * All rights reserved | 7 | * All rights reserved |
| 8 | * | 8 | * |
| 9 | * Created: Sun Aug 26 19:08:59 EEST 2007 too | 9 | * Created: Sun Aug 26 19:08:59 EEST 2007 too |
| 10 | * Last modified: Sun Jan 20 22:10:59 EET 2008 too | 10 | * Last modified: Fri Feb 01 16:40:20 EET 2008 too |
| 11 | */ | 11 | */ |
| 12 | | 12 | |
| 13 | #include <unistd.h> | 13 | #include <unistd.h> |
| 35 | | 35 | |
| 36 | switch (poll(&pfd, 1, timeout)) { | 36 | switch (poll(&pfd, 1, timeout)) { |
| 37 | case -1: | 37 | case -1: |
| 38 | die("poll failed:"); | 38 | die("%C: poll failed:"); |
| 39 | case 0: | 39 | case 0: |
| 40 | die("timeout"); | 40 | die("%C: timeout"); |
| 41 | } | 41 | } |
| 42 | i = read(fd, buf, len); | 42 | i = read(fd, buf, len); |
| 43 | if (i <= 0) | 43 | if (i <= 0) |
| 44 | die("eof or read error"); | 44 | die("%C: eof or read error"); |
| 45 | | 45 | |
| 46 | #if 0 /* d1(()) */ | 46 | #if 0 /* d1(()) */ |
| 47 | {int j; for (j = 0; j < i; j++) printf("%02x ", buf[j]); puts("");} | 47 | {int j; for (j = 0; j < i; j++) printf("%02x ", buf[j]); puts("");} |
| 51 | } | 51 | } |
| 52 | | 52 | |
| 53 | /* 123456789012345678901234567 */ | 53 | /* 123456789012345678901234567 */ |
| 54 | const char ident[] = "Simple TCP FUSE filesystem " VERSION " protocol version 2\ | 54 | const char ident[] = "Simple TCP FUSE filesystem " VERSION |
| n"; | | |
| | 55 | " protocol version " PROTVER "\n"; |
| 55 | | 56 | |
| 56 | void sendident(int fd) | 57 | void sendident(int fd) |
| 57 | { | 58 | { |
| 75 | out: | 76 | out: |
| 76 | d0(("%d %s -%c %c-", l, buf, p[-3], p[-2])); | 77 | d0(("%d %s -%c %c-", l, buf, p[-3], p[-2])); |
| 77 | | 78 | |
| 78 | if (l == 0 || memcmp(buf, ident, 27) != 0 | 79 | if (l == 0 || memcmp(buf, ident, 27) != 0) |
| 79 | || p[-3] != ' ' || p[-2] != '2') | 80 | die("%C: ident mismatch"); |
| 80 | die("Received ident mismatch"); /* XXX show ident. */ | 81 | if (p[-3] != ' ' || p[-2] != PROTVER[0]) |
| | 82 | die("%C: protocol mismatch. Got %c%c, expected %s", |
| | 83 | p[-3], p[-2], PROTVER); |
| 81 | | 84 | |
| 82 | if (i > 0) /* ack already in buffer */ | 85 | if (i > 0) /* ack already in buffer */ |
| 83 | return p[0]; | 86 | return p[0]; |
| 92 | unsigned char * p; | 95 | unsigned char * p; |
| 93 | | 96 | |
| 94 | if (read(fd, &c, 1) <= 0) | 97 | if (read(fd, &c, 1) <= 0) |
| 95 | die("Disconnect:"); | 98 | die("%C: Disconnect:"); |
| 96 | if (c == 0) | 99 | if (c == 0) |
| 97 | die("0-sized message"); | 100 | die("%C: 0-sized message"); |
| 98 | | 101 | |
| 99 | for (p = buf, i = c; i; p += l, i -= l) | 102 | for (p = buf, i = c; i; p += l, i -= l) |
| 100 | l = readwt(fd, p, i, 10 * 1000); | 103 | l = readwt(fd, p, i, 10 * 1000); |
| 121 | int sd = socket(AF_INET, SOCK_STREAM, 0); | 124 | int sd = socket(AF_INET, SOCK_STREAM, 0); |
| 122 | | 125 | |
| 123 | if (sd < 0) | 126 | if (sd < 0) |
| 124 | die("socket failed:"); | 127 | die("%C: socket failed:"); |
| 125 | | 128 | |
| 126 | setsockopt(sd, SOL_SOCKET, | 129 | setsockopt(sd, SOL_SOCKET, |
| 127 | dobind? SO_REUSEADDR: SO_KEEPALIVE, &one, sizeof one); | 130 | dobind? SO_REUSEADDR: SO_KEEPALIVE, &one, sizeof one); |
| 147 | l = readwt(sd, p, i, 10 * 1000); | 150 | l = readwt(sd, p, i, 10 * 1000); |
| 148 | | 151 | |
| 149 | if (memcmp(buf, secrets, 4) != 0) | 152 | if (memcmp(buf, secrets, 4) != 0) |
| 150 | die("Secret mismatch"); | 153 | die("%C: Secret mismatch"); |
| 151 | | 154 | |
| 152 | write(sd, "", 1); | 155 | write(sd, "", 1); |
| 153 | readwt(sd, buf, 1, 10 * 1000); | 156 | readwt(sd, buf, 1, 10 * 1000); |
| 154 | if (buf[0] != 0) | 157 | if (buf[0] != 0) |
| 155 | die("Peer did not accept our secret -- actually junk in stream"); | 158 | die("%C: Peer did not accept our secret -- actually junk in stream"); |
| 156 | | 159 | |
| 157 | return sd; | 160 | return sd; |
| 158 | } | 161 | } |
| 167 | | 170 | |
| 168 | remote = gethostbyname(host); | 171 | remote = gethostbyname(host); |
| 169 | if (remote == null) | 172 | if (remote == null) |
| 170 | die("gethostbyname on '%s' returned no value", host); | 173 | die("%C: gethostbyname on '%s' returned no value", host); |
| 171 | | 174 | |
| 172 | memcpy(&addr.sin_addr, remote->h_addr, sizeof addr.sin_addr); | 175 | memcpy(&addr.sin_addr, remote->h_addr, sizeof addr.sin_addr); |
| 173 | | 176 | |
| 174 | if (connect(sd, (struct sockaddr *)&addr, sizeof addr) < 0) | 177 | if (connect(sd, (struct sockaddr *)&addr, sizeof addr) < 0) |
| 175 | die("connect failed:"); | 178 | die("%C: connect failed:"); |
| 176 | | 179 | |
| 177 | return doweaksecretexchange(sd, secrets); | 180 | return doweaksecretexchange(sd, secrets); |
| 178 | } | 181 | } |
| 184 | | 187 | |
| 185 | if (bind(ssd, (struct sockaddr *)&addr, sizeof addr) < 0) { | 188 | if (bind(ssd, (struct sockaddr *)&addr, sizeof addr) < 0) { |
| 186 | if (fatal) | 189 | if (fatal) |
| 187 | die("bind failed:"); | 190 | die("%C: bind failed:"); |
| 188 | else | 191 | else |
| 189 | return -1; | 192 | return -1; |
| 190 | } | 193 | } |
| 202 | memset(&addr, 0, sizeof addr); | 205 | memset(&addr, 0, sizeof addr); |
| 203 | sd = accept(ssd, (struct sockaddr *)&addr, &addrlen); | 206 | sd = accept(ssd, (struct sockaddr *)&addr, &addrlen); |
| 204 | if (sd < 0) | 207 | if (sd < 0) |
| 205 | die("accept failed:"); | 208 | die("%C: accept failed:"); |
| 206 | | 209 | |
| 207 | close(ssd); | 210 | close(ssd); |
| 208 | return doweaksecretexchange(sd, secrets); | 211 | return doweaksecretexchange(sd, secrets); |
| stfufs-1.1/stfufs-client-fuse.c | | stfufs-1.2/stfufs-client-fuse.c |
| 7 | * All rights reserved | 7 | * All rights reserved |
| 8 | * | 8 | * |
| 9 | * Created: Tue Aug 28 21:47:30 EEST 2007 too | 9 | * Created: Tue Aug 28 21:47:30 EEST 2007 too |
| 10 | * Last modified: Sun Jan 20 22:05:37 EET 2008 too | 10 | * Last modified: Tue Jan 29 19:17:06 EET 2008 too |
| 11 | */ | 11 | */ |
| 12 | | 12 | |
| 13 | #include <unistd.h> | 13 | #include <unistd.h> |
| 782 | stfufs_ok_cb, null); | 782 | stfufs_ok_cb, null); |
| 783 | } | 783 | } |
| 784 | | 784 | |
| | 785 | static uint8_t * stfufs_retval_cb(void * cbdata, uint32_t rlen, uint8_t * p) |
| | 786 | { |
| | 787 | uint32_t * rv32p = (uint32_t *)cbdata; |
| | 788 | (void)rlen; |
| | 789 | |
| | 790 | d1(("--- %s(%p, %d, %p)", __func__, cbdata, rlen, p)); |
| | 791 | |
| | 792 | if ((p = stfufs_buffer_reserve(p, 4)) == null) |
| | 793 | return null; |
| | 794 | |
| | 795 | *rv32p = xdecode_uint32(&p); |
| | 796 | return p; |
| | 797 | } |
| 785 | | 798 | |
| 786 | static int stfufs_open(const char * path, struct fuse_file_info * fi) | 799 | static int stfufs_open(const char * path, struct fuse_file_info * fi) |
| 787 | { | 800 | { |
| 788 | uint8_t buf[32]; | 801 | uint8_t buf[32]; |
| 789 | struct iovec iov[3]; | 802 | struct iovec iov[3]; |
| 790 | int iovlen; | 803 | int iovlen, error; |
| 791 | int plen = strlen(path) + 1; | 804 | int plen = strlen(path) + 1; |
| 792 | int alen = (plen + 3) & ~3; | 805 | int alen = (plen + 3) & ~3; |
| | 806 | uint32_t fd; |
| 793 | | 807 | |
| 794 | d1(("--- %s(\"%s\", %p) %d", __func__, path, fi, fi->flags)); | 808 | d1(("--- %s(\"%s\", %p) %d", __func__, path, fi, fi->flags)); |
| 795 | | 809 | |
| 809 | | 823 | |
| 810 | alen += 4; | 824 | alen += 4; |
| 811 | | 825 | |
| 812 | return stfufs_client_request_handle(STFUFS__OPEN, iov, iovlen, alen, | 826 | error = stfufs_client_request_handle(STFUFS__OPEN, iov, iovlen, alen, |
| 813 | stfufs_ok_cb, null); | 827 | stfufs_retval_cb, (void *)&fd); |
| | 828 | if (error < 0) |
| | 829 | return error; |
| | 830 | fi->fh = fd; |
| | 831 | return 0; |
| 814 | } | 832 | } |
| 815 | | 833 | |
| 816 | | 834 | |
| 848 | off_t offset, struct fuse_file_info * fi) | 866 | off_t offset, struct fuse_file_info * fi) |
| 849 | { | 867 | { |
| 850 | uint8_t buf[32], *p; | 868 | uint8_t buf[32], *p; |
| 851 | struct iovec iov[3]; | 869 | struct iovec iov[1]; |
| 852 | int iovlen; | | |
| 853 | int plen = strlen(path) + 1; | | |
| 854 | int alen = (plen + 3) & ~3; | | |
| 855 | struct iovec readdata; | 870 | struct iovec readdata; |
| 856 | int error; | 871 | int error; |
| 857 | | 872 | |
| 858 | (void)fi; | 873 | (void)path; |
| 859 | d1(("--- %s(\"%s\", %d, %lld)", __func__, path, size, offset)); | 874 | d1(("--- %s(\"%s\", %d, %lld)", __func__, path, size, offset)); |
| 860 | | 875 | |
| 861 | p = xencode_uint32(buf + REQUEST_HEADER_LEN, size); | 876 | p = xencode_uint32(buf + REQUEST_HEADER_LEN, (uint32_t)fi->fh); |
| | 877 | p = xencode_uint32(p, size); |
| 862 | (void)xencode_uint64(p, offset); | 878 | (void)xencode_uint64(p, offset); |
| 863 | | 879 | |
| 864 | iov[0].iov_base = buf; /* stfufs_client_request_handle() will fill this */ | 880 | iov[0].iov_base = buf; /* stfufs_client_request_handle() will fill this */ |
| 865 | iov[0].iov_len = REQUEST_HEADER_LEN + 4 + 8; | 881 | iov[0].iov_len = REQUEST_HEADER_LEN + 4 + 4 + 8; |
| 866 | iov[1].iov_base = str_unconst(path); /* const void * when writing... */ | | |
| 867 | iov[1].iov_len = plen; | | |
| 868 | | | |
| 869 | if (plen != alen) { | | |
| 870 | iov[2].iov_base = str_unconst(G_pad000); /*const void * when writing */ | | |
| 871 | iov[2].iov_len = alen - plen; | | |
| 872 | iovlen = 3; | | |
| 873 | } | | |
| 874 | else iovlen = 2; | | |
| 875 | | | |
| 876 | alen += 4 + 8; | | |
| 877 | | 882 | |
| 878 | readdata.iov_base = data; | 883 | readdata.iov_base = data; |
| 879 | readdata.iov_len = size; | 884 | readdata.iov_len = size; |
| 880 | | 885 | |
| 881 | error = stfufs_client_request_handle(STFUFS__READ, iov, iovlen, alen, | 886 | error = stfufs_client_request_handle(STFUFS__READ, iov, 1, 4 + 4 + 8, |
| 882 | stfufs_read_cb, &readdata); | 887 | stfufs_read_cb, &readdata); |
| 883 | if (error < 0) | 888 | if (error < 0) |
| 884 | return error; | 889 | return error; |
| 886 | } | 891 | } |
| 887 | | 892 | |
| 888 | | 893 | |
| 889 | static uint8_t * stfufs_write_cb(void * cbdata, uint32_t rlen, uint8_t * p) | | |
| 890 | { | | |
| 891 | uint32_t * lenp = (uint32_t *)cbdata; | | |
| 892 | | | |
| 893 | d1(("--- %s(%p, %d, %p)", __func__, cbdata, rlen, p)); | | |
| 894 | | | |
| 895 | if ((p = stfufs_buffer_reserve(p, 4)) == null) | | |
| 896 | return null; | | |
| 897 | | | |
| 898 | *lenp = xdecode_uint32(&p); | | |
| 899 | return p; | | |
| 900 | } | | |
| 901 | | | |
| 902 | static int stfufs_write(const char * path, const char * data, size_t size, | 894 | static int stfufs_write(const char * path, const char * data, size_t size, |
| 903 | off_t offset, struct fuse_file_info * fi) | 895 | off_t offset, struct fuse_file_info * fi) |
| 904 | { | 896 | { |
| 905 | uint8_t buf[32], *p; | 897 | uint8_t buf[32], *p; |
| 906 | struct iovec iov[5]; | 898 | struct iovec iov[3]; |
| 907 | int iovlen; | | |
| 908 | int plen = strlen(path) + 1; | | |
| 909 | int alen = (plen + 3) & ~3; | | |
| 910 | int rlen, error; | 899 | int iovlen, error, alen; |
| | 900 | uint32_t rlen; |
| 911 | | 901 | |
| 912 | (void)fi; | 902 | (void)path; |
| 913 | d1(("--- %s(\"%s\", %d, %lld)", __func__, path, size, offset)); | 903 | d1(("--- %s(\"%s\", %d, %lld)", __func__, path, size, offset)); |
| 914 | | 904 | |
| 915 | p = xencode_uint32(buf + REQUEST_HEADER_LEN, size); | 905 | p = xencode_uint32(buf + REQUEST_HEADER_LEN, (uint32_t)fi->fh); |
| | 906 | p = xencode_uint32(p, size); |
| 916 | p = xencode_uint64(p, offset); | 907 | p = xencode_uint64(p, offset); |
| 917 | p = xencode_uint32(p, alen); | | |
| 918 | | 908 | |
| 919 | iov[0].iov_base = buf; /* stfufs_client_request_handle() will fill this */ | 909 | iov[0].iov_base = buf; /* stfufs_client_request_handle() will fill this */ |
| 920 | iov[0].iov_len = REQUEST_HEADER_LEN + 4 + 8 + 4; | 910 | iov[0].iov_len = REQUEST_HEADER_LEN + 4 + 4 + 8; |
| 921 | iov[1].iov_base = str_unconst(path); /* const void * when writing... */ | 911 | iov[1].iov_base = str_unconst(data); /* const void * when writing... */ |
| 922 | iov[1].iov_len = plen; | 912 | iov[1].iov_len = size; |
| 923 | | | |
| 924 | if (plen != alen) { | | |
| 925 | iov[2].iov_base = str_unconst(G_pad000); /*const void * when writing */ | | |
| 926 | iov[2].iov_len = alen - plen; | | |
| 927 | iovlen = 3; | | |
| 928 | } | | |
| 929 | else iovlen = 2; | | |
| 930 | | | |
| 931 | iov[iovlen].iov_base = str_unconst(data); /* const void * when writing...*/ | | |
| 932 | iov[iovlen++].iov_len = size; | | |
| 933 | | 913 | |
| 934 | if ((size & 3) != 0) { | 914 | if ((size & 3) != 0) { |
| 935 | int pad = 4 - (size & 3); | 915 | int pad = 4 - (size & 3); |
| 936 | iov[iovlen].iov_base = str_unconst(G_pad000); | 916 | iov[2].iov_base = str_unconst(G_pad000); |
| 937 | iov[iovlen++].iov_len = pad; | 917 | iov[2].iov_len = pad; |
| 938 | size += pad; | 918 | size += pad; |
| | 919 | iovlen = 3; |
| 939 | } | 920 | } |
| | 921 | else iovlen = 2; |
| 940 | | 922 | |
| 941 | alen += 4 + 8 + 4 + size; | 923 | alen = 4 + 8 + 4 + size; |
| 942 | | 924 | |
| 943 | error = stfufs_client_request_handle(STFUFS__WRITE, iov, iovlen, alen, | 925 | error = stfufs_client_request_handle(STFUFS__WRITE, iov, iovlen, alen, |
| 944 | stfufs_write_cb, (void *)&rlen); | 926 | stfufs_retval_cb, (void *)&rlen); |
| 945 | if (error < 0) | 927 | if (error < 0) |
| 946 | return error; | 928 | return error; |
| 947 | return rlen; | 929 | return (int)rlen; /* XXX */ |
| 948 | } | 930 | } |
| 949 | | 931 | |
| 950 | | 932 | |
| 1002 | } | 984 | } |
| 1003 | | 985 | |
| 1004 | | 986 | |
| 1005 | /* like mkdir. refactor */ | | |
| 1006 | static int stfufs_release(const char * path, struct fuse_file_info * fi) | 987 | static int stfufs_release(const char * path, struct fuse_file_info * fi) |
| 1007 | { | 988 | { |
| 1008 | uint8_t buf[32]; | 989 | uint8_t buf[32], *p; |
| 1009 | struct iovec iov[3]; | 990 | struct iovec iov[1]; |
| 1010 | int iovlen; | | |
| 1011 | int plen = strlen(path) + 1; | | |
| 1012 | int alen = (plen + 3) & ~3; | | |
| 1013 | | 991 | |
| | 992 | (void)path; |
| 1014 | d1(("--- %s(\"%s\", %p)", __func__, path, fi)); | 993 | d1(("--- %s(\"%s\", %lld)", __func__, path, fi->fh)); |
| 1015 | | 994 | |
| | 995 | p = xencode_uint32(buf + REQUEST_HEADER_LEN, (uint32_t)fi->fh); |
| 1016 | iov[0].iov_base = buf; /* stfufs_client_request_handle() will fill this */ | 996 | iov[0].iov_base = buf; /* stfufs_client_request_handle() will fill this */ |
| 1017 | iov[0].iov_len = REQUEST_HEADER_LEN; | 997 | iov[0].iov_len = REQUEST_HEADER_LEN + 4; |
| 1018 | iov[1].iov_base = str_unconst(path); /* const void * when writing... */ | | |
| 1019 | iov[1].iov_len = plen; | | |
| 1020 | | 998 | |
| 1021 | if (plen != alen) { | | |
| 1022 | iov[2].iov_base = str_unconst(G_pad000); /*const void * when writing */ | | |
| 1023 | iov[2].iov_len = alen - plen; | | |
| 1024 | iovlen = 3; | | |
| 1025 | } | | |
| 1026 | else iovlen = 2; | | |
| 1027 | | | |
| 1028 | return stfufs_client_request_handle(STFUFS__RELEASE, iov, iovlen, alen, | 999 | return stfufs_client_request_handle(STFUFS__RELEASE, iov, 1, 4, |
| 1029 | stfufs_ok_cb, null); | 1000 | stfufs_ok_cb, null); |
| 1030 | } | 1001 | } |
| 1031 | | 1002 | |
| stfufs-1.1/stfufs-server-fs.c | | stfufs-1.2/stfufs-server-fs.c |
| 7 | * All rights reserved | 7 | * All rights reserved |
| 8 | * | 8 | * |
| 9 | * Created: Tue Aug 28 21:47:42 EEST 2007 too | 9 | * Created: Tue Aug 28 21:47:42 EEST 2007 too |
| 10 | * Last modified: Sun Jan 20 19:59:47 EET 2008 too | 10 | * Last modified: Tue Jan 29 17:31:00 EET 2008 too |
| 11 | */ | 11 | */ |
| 12 | | 12 | |
| 13 | #include <unistd.h> | 13 | #include <unistd.h> |
| 35 | #include "simplexdr.h" | 35 | #include "simplexdr.h" |
| 36 | | 36 | |
| 37 | | 37 | |
| | 38 | static struct { |
| | 39 | #define FDOFFSETS 1024 |
| | 40 | int64_t fdoffsets[FDOFFSETS]; |
| | 41 | } S; |
| | 42 | |
| | 43 | |
| | 44 | static void init_S(void) |
| | 45 | { |
| | 46 | int i; |
| | 47 | |
| | 48 | for (i = 0; i < FDOFFSETS; i++) |
| | 49 | S.fdoffsets[i] = -1; |
| | 50 | } |
| | 51 | |
| 38 | static void _write_simple(uint8_t * s, uint8_t * e) | 52 | static void _write_simple(uint8_t * s, uint8_t * e) |
| 39 | { | 53 | { |
| 40 | int len = write(0, s, e - s); | 54 | int len = write(0, s, e - s); |
| 57 | p = xencode_uint32(p, 0); /* length */ | 71 | p = xencode_uint32(p, 0); /* length */ |
| 58 | _write_simple(buf, p); | 72 | _write_simple(buf, p); |
| 59 | } | 73 | } |
| | 74 | |
| | 75 | /* retvall for 64bits ;) if ever needed ? */ |
| | 76 | static void _write_retval(uint32_t type, uint32_t id, uint32_t value) |
| | 77 | { |
| | 78 | uint8_t buf[32]; |
| | 79 | uint8_t * p = buf; |
| | 80 | |
| | 81 | p = xencode_uint32(p, type); |
| | 82 | p = xencode_uint32(p, id); |
| | 83 | p = xencode_uint32(p, 0); /* no error */ |
| | 84 | p = xencode_uint32(p, 4); /* response length */ |
| | 85 | p = xencode_uint32(p, value); |
| | 86 | |
| | 87 | _write_simple(buf, p); |
| | 88 | } |
| | 89 | |
| 60 | | 90 | |
| 61 | static uint8_t * unsupported(uint8_t * p, uint32_t type, uint32_t id, int clen) | 91 | static uint8_t * unsupported(uint8_t * p, uint32_t type, uint32_t id, int clen) |
| 62 | { | 92 | { |
| 430 | flags = xdecode_uint32(&p); | 460 | flags = xdecode_uint32(&p); |
| 431 | | 461 | |
| 432 | if ((fd = open(_mypath(p), flags)) >= 0) { | 462 | if ((fd = open(_mypath(p), flags)) >= 0) { |
| | 463 | if (fd < FDOFFSETS) { |
| | 464 | S.fdoffsets[fd] = 0; |
| | 465 | _write_retval(type, id, (uint32_t)fd); |
| | 466 | return r; |
| | 467 | } |
| | 468 | /* else */ |
| 433 | close(fd); | 469 | close(fd); |
| 434 | errno = 0; | 470 | errno = ENFILE; |
| 435 | } | 471 | } |
| 436 | _write_status(type, id, errno); | 472 | _write_status(type, id, errno); |
| 437 | return r; | 473 | return r; |
| 459 | return ll; | 495 | return ll; |
| 460 | } | 496 | } |
| 461 | | 497 | |
| 462 | struct SEC4RW /* single element cache for read/write */ | | |
| 463 | { | | |
| 464 | uint32_t path[4100]; | | |
| 465 | int fd; | | |
| 466 | off_t offset; | | |
| 467 | }; | | |
| 468 | | | |
| 469 | struct SEC4RW readsec; | | |
| 470 | | 498 | |
| 471 | static uint8_t * stfufs_server_read(uint8_t * p, | 499 | static uint8_t * stfufs_server_read(uint8_t * p, |
| 472 | uint32_t type, uint32_t id, int clen) | 500 | uint32_t type, uint32_t id, int clen) |
| 473 | { | 501 | { |
| 474 | uint8_t * r; | 502 | uint8_t * r; |
| 475 | int fd, len; | 503 | int32_t fd, len; |
| 476 | uint32_t size; | 504 | uint32_t size; |
| 477 | off_t offset; | 505 | off_t offset; |
| 478 | uint8_t buf[32768 + 16]; | 506 | uint8_t buf[32768 + 16]; |
| 479 | uint8_t * filename; | | |
| 480 | off_t cacheoffset; | | |
| 481 | | 507 | |
| 482 | d1(("--- stfufs_server_read(%p, %x, %d, %d)", p, type, id, clen)); | 508 | d1(("--- stfufs_server_read(%p, %x, %d, %d)", p, type, id, clen)); |
| 483 | | 509 | |
| 486 | | 512 | |
| 487 | r = p + clen; | 513 | r = p + clen; |
| 488 | | 514 | |
| | 515 | fd = (int32_t)xdecode_uint32(&p); |
| 489 | size = xdecode_uint32(&p); | 516 | size = xdecode_uint32(&p); |
| 490 | offset = xdecode_uint64(&p); | 517 | offset = xdecode_uint64(&p); |
| 491 | | 518 | |
| 492 | if (memcmp(readsec.path, p, clen - 12) == 0) { | 519 | if ((uint32_t)fd >= FDOFFSETS || S.fdoffsets[fd] < 0) { |
| 493 | fd = readsec.fd; | 520 | _write_status(type, id, EBADF); |
| 494 | cacheoffset = readsec.offset; | 521 | return r; |
| 495 | } | 522 | } |
| 496 | else { | 523 | if (S.fdoffsets[fd] == offset) |
| 497 | if ((fd = open(_mypath(p), O_RDONLY, 0)) < 0) { | 524 | d1(("Optimal offset hit at offset %lld", offset)); |
| | 525 | else if (lseek(fd, offset, SEEK_SET) < 0) { |
| 498 | _write_status(type, id, errno); | 526 | _write_status(type, id, errno); |
| 499 | return r; | 527 | return r; |
| 500 | } | | |
| 501 | cacheoffset = -1; | | |
| 502 | } | 528 | } |
| 503 | if (cacheoffset == offset) | | |
| 504 | d1(("Optimal cache hit at offset %lld", offset)); | | |
| 505 | else { | | |
| 506 | if (lseek(fd, offset, SEEK_SET) < 0) { | | |
| 507 | _write_status(type, id, errno); | | |
| 508 | if (cacheoffset < 0) | | |
| 509 | close(fd); | | |
| 510 | return r; | | |
| 511 | }} | | |
| 512 | filename = p; | | |
| 513 | | 529 | |
| 514 | if (size > 32768) | 530 | if (size > 32768) |
| 515 | size = 32768; | 531 | size = 32768; |
| 519 | | 535 | |
| 520 | if (len < 0) { | 536 | if (len < 0) { |
| 521 | _write_status(type, id, errno); | 537 | _write_status(type, id, errno); |
| 522 | if (cacheoffset < 0) | | |
| 523 | close(fd); | | |
| 524 | return r; | 538 | return r; |
| 525 | } | 539 | } |
| 526 | | 540 | |
| 527 | if (cacheoffset < 0) { | | |
| 528 | if (clen - 12 > sizeof readsec.path) | | |
| 529 | close(fd); | | |
| 530 | else { | | |
| 531 | if (readsec.fd >= 0) | | |
| 532 | close(readsec.fd); | | |
| 533 | memcpy(readsec.path, filename, clen - 12); | | |
| 534 | readsec.fd = fd; | | |
| 535 | d1(("--- read path '%s'", p)); | | |
| 536 | }} | | |
| 537 | readsec.offset = offset + len; | 541 | S.fdoffsets[fd] = offset + len; |
| 538 | | 542 | |
| 539 | p = buf; | 543 | p = buf; |
| 540 | p = xencode_uint32(p, type); | 544 | p = xencode_uint32(p, type); |
| 547 | return r; | 551 | return r; |
| 548 | } | 552 | } |
| 549 | | 553 | |
| 550 | struct SEC4RW writesec; | | |
| 551 | | | |
| 552 | static uint8_t * stfufs_server_write(uint8_t * p, | 554 | static uint8_t * stfufs_server_write(uint8_t * p, |
| 553 | uint32_t type, uint32_t id, int clen) | 555 | uint32_t type, uint32_t id, int clen) |
| 554 | { | 556 | { |
| 555 | uint8_t buf[32]; | | |
| 556 | uint8_t * r; | 557 | uint8_t * r; |
| 557 | int fd; | 558 | int32_t fd; |
| 558 | uint32_t size, palen, len; | 559 | uint32_t size, len; |
| 559 | off_t offset; | 560 | off_t offset; |
| 560 | uint8_t * filename; | | |
| 561 | off_t cacheoffset; | | |
| 562 | | 561 | |
| 563 | d1(("stfufs_server_write(%p, %x, %d, %d)", p, type, id, clen)); | 562 | d1(("stfufs_server_write(%p, %x, %d, %d)", p, type, id, clen)); |
| 564 | | 563 | |
| 565 | if ((p = stfufs_buffer_reserve(p, 4 + 8 + 4)) == null) | 564 | if ((p = stfufs_buffer_reserve(p, 4 + 4 + 8)) == null) |
| 566 | return null; | 565 | return null; |
| 567 | | 566 | |
| | 567 | fd = (int32_t)xdecode_uint32(&p); |
| 568 | size = xdecode_uint32(&p); | 568 | size = xdecode_uint32(&p); |
| 569 | offset = xdecode_uint64(&p); | 569 | offset = xdecode_uint64(&p); |
| 570 | palen = xdecode_uint32(&p); | | |
| 571 | | 570 | |
| 572 | r = p; | 571 | r = p; |
| 573 | clen -= (4 + 8 + 4); | 572 | clen -= (4 + 8 + 4); |
| 574 | | 573 | |
| 575 | if ((p = stfufs_buffer_reserve(p, palen)) == null) | 574 | if ((uint32_t)fd >= FDOFFSETS || S.fdoffsets[fd] < 0) { |
| | 575 | _write_status(type, id, EBADF); |
| 576 | return null; | 576 | return r; |
| 577 | | | |
| 578 | if (memcmp(writesec.path, p, palen) == 0) { | | |
| 579 | fd = writesec.fd; | | |
| 580 | cacheoffset = writesec.offset; | | |
| 581 | } | 577 | } |
| 582 | else { | 578 | if (S.fdoffsets[fd] == offset) |
| 583 | if ((fd = open(_mypath(p), O_WRONLY, 0500)) < 0) { | 579 | d1(("Optimal offset hit at offset %lld", offset)); |
| | 580 | else if (lseek(fd, offset, SEEK_SET) < 0) { |
| 584 | _write_status(type, id, errno); | 581 | _write_status(type, id, errno); |
| 585 | return stfufs_buffer_discard(r, clen); | 582 | return stfufs_buffer_discard(r, clen); |
| 586 | } | | |
| 587 | cacheoffset = -1; | | |
| 588 | } | 583 | } |
| 589 | if (cacheoffset == offset) | | |
| 590 | d1(("Optimal cache hit at offset %lld", offset)); | | |
| 591 | else { | | |
| 592 | if (lseek(fd, offset, SEEK_SET) < 0) { | | |
| 593 | _write_status(type, id, errno); | | |
| 594 | if (cacheoffset < 0) | | |
| 595 | close(fd); | | |
| 596 | return stfufs_buffer_discard(r, clen); | | |
| 597 | }} | | |
| 598 | filename = p; | | |
| 599 | | 584 | |
| 600 | p += palen; | | |
| 601 | len = stfufs_buffer_rest(p); | 585 | len = stfufs_buffer_rest(p); |
| 602 | | 586 | |
| 603 | if ((int32_t)(len = write(fd, p, len < size? len: size)) < 0) { | 587 | if ((int32_t)(len = write(fd, p, len < size? len: size)) < 0) { |
| 604 | _write_status(type, id, errno); | 588 | _write_status(type, id, errno); |
| 605 | if (cacheoffset < 0) | | |
| 606 | close(fd); | | |
| 607 | return stfufs_buffer_discard(r, clen); | 589 | return stfufs_buffer_discard(r, clen); |
| 608 | } | 590 | } |
| 609 | /* XXX partial write above is a problem ! need a wrapper or something */ | 591 | /* XXX partial write above is a problem ! need a wrapper or something */ |
| 619 | r = p + needreserve; | 601 | r = p + needreserve; |
| 620 | if ((len2 = write(fd, p, missing)) < 0) { | 602 | if ((len2 = write(fd, p, missing)) < 0) { |
| 621 | _write_status(type, id, errno); | 603 | _write_status(type, id, errno); |
| 622 | if (cacheoffset < 0) | | |
| 623 | close(fd); | | |
| 624 | return r; | 604 | return r; |
| 625 | } | 605 | } |
| 626 | len += len2; | 606 | len += len2; |
| 627 | } | 607 | } |
| 628 | | 608 | |
| 629 | if (cacheoffset < 0) { | | |
| 630 | if (palen > sizeof writesec.path) | | |
| 631 | close(fd); | | |
| 632 | else { | | |
| 633 | if (writesec.fd >= 0) | | |
| 634 | close(writesec.fd); | | |
| 635 | memcpy(writesec.path, filename, palen); | | |
| 636 | writesec.fd = fd; | | |
| 637 | d1(("--- write path '%s'", p)); | | |
| 638 | }} | | |
| 639 | writesec.offset = offset + len; | 609 | S.fdoffsets[fd] = offset + len; |
| 640 | | 610 | |
| 641 | p = buf; | 611 | _write_retval(type, id, len); |
| 642 | p = xencode_uint32(p, type); | | |
| 643 | p = xencode_uint32(p, id); | | |
| 644 | p = xencode_uint32(p, 0); /* no error */ | | |
| 645 | p = xencode_uint32(p, 4); /* response length */ | | |
| 646 | p = xencode_uint32(p, len); /* written data */ | | |
| 647 | | | |
| 648 | _write_simple(buf, p); | | |
| 649 | | | |
| 650 | return r; | 612 | return r; |
| 651 | } | 613 | } |
| 652 | | 614 | |
| 703 | uint32_t type, uint32_t id, int clen) | 665 | uint32_t type, uint32_t id, int clen) |
| 704 | { | 666 | { |
| 705 | uint8_t * r; | 667 | uint8_t * r; |
| | 668 | int32_t fd; |
| 706 | | 669 | |
| 707 | d1(("--- stfufs_server_release(%p, %x, %d, %d)", p, type, id, clen)); | 670 | d1(("--- stfufs_server_release(%p, %x, %d, %d)", p, type, id, clen)); |
| 708 | | 671 | |
| 709 | if ((p = stfufs_buffer_reserve(p, clen)) == null) | 672 | if ((p = stfufs_buffer_reserve(p, clen)) == null) |
| 710 | return null; | 673 | return null; |
| 711 | | 674 | |
| 712 | if (memcmp(p, readsec.path, clen) == 0) { | | |
| 713 | d1(("read release: '%s'", p)); | | |
| 714 | readsec.path[0] = 0; | | |
| 715 | close(readsec.fd); | | |
| 716 | readsec.fd = -1; | | |
| 717 | } | | |
| 718 | if (memcmp(p, writesec.path, clen) == 0) { | | |
| 719 | d1(("write release: '%s'", p)); | | |
| 720 | writesec.path[0] = 0; | | |
| 721 | close(writesec.fd); | | |
| 722 | writesec.fd = -1; | | |
| 723 | } | | |
| 724 | | | |
| 725 | r = p + clen; | 675 | r = p + clen; |
| 726 | | 676 | |
| 727 | /* do release on _mypath(p) */ | 677 | fd = (int32_t)xdecode_uint32(&p); |
| | 678 | |
| | 679 | if ((uint32_t)fd >= FDOFFSETS || S.fdoffsets[fd] < 0) |
| | 680 | errno = EBADF; |
| | 681 | else { |
| | 682 | S.fdoffsets[fd] = -1; |
| 728 | errno = 0; | 683 | errno = 0; |
| 729 | | 684 | close(fd); |
| | 685 | } |
| 730 | _write_status(type, id, errno); | 686 | _write_status(type, id, errno); |
| 731 | return r; | 687 | return r; |
| 732 | } | 688 | } |
| | 689 | |
| 733 | | 690 | |
| 734 | static uint8_t * stfufs_server_readdir(uint8_t * p, | 691 | static uint8_t * stfufs_server_readdir(uint8_t * p, |
| 735 | uint32_t type, uint32_t id, int clen) | 692 | uint32_t type, uint32_t id, int clen) |
| 842 | { | 799 | { |
| 843 | uint8_t * p = stfufs_buffer_init(0); | 800 | uint8_t * p = stfufs_buffer_init(0); |
| 844 | | 801 | |
| 845 | readsec.path[0] = writesec.path[0] = 0; | 802 | init_S(); |
| 846 | readsec.fd = writesec.fd = -1; | | |
| 847 | | 803 | |
| 848 | while (1) | 804 | while (1) |
| 849 | { | 805 | { |