Changes in / [5b46ec8:1dff985] in mainline
- Location:
- uspace
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/trace/trace.c
r5b46ec8 r1dff985 696 696 697 697 p = proto_new("vfs"); 698 o = oper_new("open", 2, arg_def, V_INT_ERRNO, 0, resp_def);699 proto_add_oper(p, VFS_IN_OPEN, o);700 698 o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def); 701 699 proto_add_oper(p, VFS_IN_READ, o); … … 716 714 o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def); 717 715 proto_add_oper(p, VFS_IN_SYNC, o); 718 o = oper_new("mkdir", 1, arg_def, V_ERRNO, 0, resp_def);719 proto_add_oper(p, VFS_IN_MKDIR, o);720 o = oper_new("unlink", 0, arg_def, V_ERRNO, 0, resp_def);721 proto_add_oper(p, VFS_IN_UNLINK, o);722 716 o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def); 723 717 proto_add_oper(p, VFS_IN_RENAME, o); 724 o = oper_new("stat", 0, arg_def, V_ERRNO, 0, resp_def);725 proto_add_oper(p, VFS_IN_STAT, o);726 718 o = oper_new("statfs", 0, arg_def, V_ERRNO, 0, resp_def); 727 719 proto_add_oper(p, VFS_IN_STATFS, o); 720 o = oper_new("walk", 2, arg_def, V_INT_ERRNO, 0, resp_def); 721 proto_add_oper(p, VFS_IN_WALK, o); 722 o = oper_new("open2", 2, arg_def, V_ERRNO, 0, resp_def); 723 proto_add_oper(p, VFS_IN_OPEN2, o); 724 o = oper_new("unlink2", 3, arg_def, V_ERRNO, 0, resp_def); 725 proto_add_oper(p, VFS_IN_UNLINK2, o); 728 726 729 727 proto_register(SERVICE_VFS, p); -
uspace/lib/c/generic/vfs/vfs.c
r5b46ec8 r1dff985 93 93 } 94 94 95 int _vfs_walk(int parent, const char *path, int flags) 96 { 97 async_exch_t *exch = vfs_exchange_begin(); 98 99 ipc_call_t answer; 100 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer); 101 sysarg_t rc = async_data_write_start(exch, path, str_size(path)); 102 vfs_exchange_end(exch); 103 104 sysarg_t rc_orig; 105 async_wait_for(req, &rc_orig); 106 107 if (rc_orig != EOK) { 108 return (int) rc_orig; 109 } 110 111 if (rc != EOK) { 112 return (int) rc; 113 } 114 115 return (int) IPC_GET_ARG1(answer); 116 } 117 118 int _vfs_open(int fildes, int mode) 119 { 120 async_exch_t *exch = vfs_exchange_begin(); 121 sysarg_t rc = async_req_2_0(exch, VFS_IN_OPEN2, fildes, mode); 122 vfs_exchange_end(exch); 123 124 return (int) rc; 125 } 126 95 127 char *vfs_absolutize(const char *path, size_t *retlen) 96 128 { … … 229 261 } 230 262 231 /* Ask VFS whether it likes fs_name. */232 rc = async_req_0_0(exch, VFS_IN_PING);233 if (rc != EOK) {234 vfs_exchange_end(exch);235 free(mpa);236 async_wait_for(req, &rc_orig);237 238 if (null_id != -1)239 loc_null_destroy(null_id);240 241 if (rc_orig == EOK)242 return (int) rc;243 else244 return (int) rc_orig;245 }246 247 263 vfs_exchange_end(exch); 248 264 free(mpa); … … 289 305 } 290 306 291 /** Open file (internal). 292 * 293 * @param abs Absolute path to file 294 * @param abs_size Size of @a abs string 295 * @param lflag L_xxx flags 296 * @param oflag O_xxx flags 297 * @param fd Place to store new file descriptor 298 * 299 * @return EOK on success, non-zero error code on error 300 */ 301 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag, 302 int *fd) 303 { 304 async_exch_t *exch = vfs_exchange_begin(); 305 306 ipc_call_t answer; 307 aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer); 308 sysarg_t rc = async_data_write_start(exch, abs, abs_size); 309 310 if (rc != EOK) { 311 vfs_exchange_end(exch); 312 313 sysarg_t rc_orig; 314 async_wait_for(req, &rc_orig); 315 316 if (rc_orig == EOK) 317 return (int) rc; 318 else 319 return (int) rc_orig; 320 } 321 322 vfs_exchange_end(exch); 323 async_wait_for(req, &rc); 324 325 if (rc != EOK) 326 return (int) rc; 327 328 *fd = (int) IPC_GET_ARG1(answer); 329 return EOK; 307 static int walk_flags(int oflags) 308 { 309 int flags = 0; 310 if (oflags & O_CREAT) { 311 if (oflags & O_EXCL) { 312 flags |= WALK_MUST_CREATE; 313 } else { 314 flags |= WALK_MAY_CREATE; 315 } 316 } 317 return flags; 330 318 } 331 319 … … 341 329 int open(const char *path, int oflag, ...) 342 330 { 331 // FIXME: Some applications call this incorrectly. 332 if ((oflag & (O_RDONLY|O_WRONLY|O_RDWR)) == 0) { 333 oflag |= O_RDWR; 334 } 335 336 assert((((oflag & O_RDONLY) != 0) + ((oflag & O_WRONLY) != 0) + ((oflag & O_RDWR) != 0)) == 1); 337 343 338 size_t abs_size; 344 339 char *abs = vfs_absolutize(path, &abs_size); 345 int fd = -1; 346 347 if (abs == NULL) { 348 errno = ENOMEM; 349 return -1; 350 } 351 352 int rc = open_internal(abs, abs_size, L_FILE, oflag, &fd); 353 free(abs); 354 355 if (rc != EOK) { 356 errno = rc; 357 return -1; 358 } 359 360 return fd; 340 if (!abs) { 341 return ENOMEM; 342 } 343 344 int ret = _vfs_walk(-1, abs, walk_flags(oflag) | WALK_REGULAR); 345 if (ret < 0) { 346 return ret; 347 } 348 349 int mode = 350 ((oflag & O_RDWR) ? MODE_READ|MODE_WRITE : 0) | 351 ((oflag & O_RDONLY) ? MODE_READ : 0) | 352 ((oflag & O_WRONLY) ? MODE_WRITE : 0) | 353 ((oflag & O_APPEND) ? MODE_APPEND : 0); 354 355 int rc = _vfs_open(ret, mode); 356 if (rc < 0) { 357 // _vfs_put(ret); 358 close(ret); 359 return rc; 360 } 361 362 if (oflag & O_TRUNC) { 363 assert(oflag & O_WRONLY || oflag & O_RDWR); 364 assert(!(oflag & O_APPEND)); 365 366 // _vfs_resize 367 (void) ftruncate(ret, 0); 368 } 369 370 return ret; 361 371 } 362 372 … … 670 680 int stat(const char *path, struct stat *stat) 671 681 { 672 sysarg_t rc;673 sysarg_t rc_orig;674 aid_t req;675 676 682 size_t pa_size; 677 683 char *pa = vfs_absolutize(path, &pa_size); 678 if (pa == NULL) { 679 errno = ENOMEM; 680 return -1; 681 } 682 683 async_exch_t *exch = vfs_exchange_begin(); 684 685 req = async_send_0(exch, VFS_IN_STAT, NULL); 686 rc = async_data_write_start(exch, pa, pa_size); 687 if (rc != EOK) { 688 vfs_exchange_end(exch); 689 free(pa); 690 async_wait_for(req, &rc_orig); 691 if (rc_orig != EOK) 692 rc = rc_orig; 693 if (rc != EOK) { 694 errno = rc; 695 return -1; 696 } 697 } 698 rc = async_data_read_start(exch, stat, sizeof(struct stat)); 699 if (rc != EOK) { 700 vfs_exchange_end(exch); 701 free(pa); 702 async_wait_for(req, &rc_orig); 703 if (rc_orig != EOK) 704 rc = rc_orig; 705 if (rc != EOK) { 706 errno = rc; 707 return -1; 708 } 709 } 710 vfs_exchange_end(exch); 711 free(pa); 712 async_wait_for(req, &rc); 713 if (rc != EOK) { 714 errno = rc; 715 return -1; 716 } 717 return 0; 684 if (!pa) { 685 return ENOMEM; 686 } 687 688 int fd = _vfs_walk(-1, pa, 0); 689 if (fd < 0) { 690 return fd; 691 } 692 693 int rc = fstat(fd, stat); 694 close(fd); 695 return rc; 718 696 } 719 697 … … 727 705 { 728 706 DIR *dirp = malloc(sizeof(DIR)); 729 int fd = -1; 730 731 if (dirp == NULL) { 707 if (!dirp) { 732 708 errno = ENOMEM; 733 709 return NULL; … … 742 718 } 743 719 744 int r c = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd);720 int ret = _vfs_walk(-1, abs, WALK_DIRECTORY); 745 721 free(abs); 746 722 747 if (r c !=EOK) {723 if (ret < EOK) { 748 724 free(dirp); 725 errno = ret; 726 return NULL; 727 } 728 729 int rc = _vfs_open(ret, MODE_READ); 730 if (rc < 0) { 731 free(dirp); 732 close(ret); 749 733 errno = rc; 750 734 return NULL; 751 735 } 752 736 753 dirp->fd = fd;737 dirp->fd = ret; 754 738 return dirp; 755 739 } … … 809 793 int mkdir(const char *path, mode_t mode) 810 794 { 795 size_t pa_size; 796 char *pa = vfs_absolutize(path, &pa_size); 797 if (!pa) { 798 return ENOMEM; 799 } 800 801 int ret = _vfs_walk(-1, pa, WALK_MUST_CREATE | WALK_DIRECTORY); 802 if (ret < 0) { 803 return ret; 804 } 805 806 close(ret); 807 return EOK; 808 } 809 810 static int _vfs_unlink2(int parent, const char *path, int expect, int wflag) 811 { 811 812 sysarg_t rc; 812 813 aid_t req; 813 814 815 async_exch_t *exch = vfs_exchange_begin(); 816 817 req = async_send_3(exch, VFS_IN_UNLINK2, parent, expect, wflag, NULL); 818 rc = async_data_write_start(exch, path, str_size(path)); 819 820 vfs_exchange_end(exch); 821 822 sysarg_t rc_orig; 823 async_wait_for(req, &rc_orig); 824 825 if (rc_orig != EOK) { 826 return (int) rc_orig; 827 } 828 return rc; 829 } 830 831 /** Unlink file or directory. 832 * 833 * @param path Path 834 * @return EOk on success, error code on error 835 */ 836 int unlink(const char *path) 837 { 814 838 size_t pa_size; 815 839 char *pa = vfs_absolutize(path, &pa_size); 816 if (pa == NULL) { 817 errno = ENOMEM; 818 return -1; 819 } 820 821 async_exch_t *exch = vfs_exchange_begin(); 822 823 req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL); 824 rc = async_data_write_start(exch, pa, pa_size); 825 if (rc != EOK) { 826 vfs_exchange_end(exch); 827 free(pa); 828 829 sysarg_t rc_orig; 830 async_wait_for(req, &rc_orig); 831 832 if (rc_orig != EOK) 833 rc = rc_orig; 834 835 if (rc != EOK) { 836 errno = rc; 837 return -1; 838 } 839 840 return 0; 841 } 842 843 vfs_exchange_end(exch); 844 free(pa); 845 async_wait_for(req, &rc); 846 847 if (rc != EOK) { 848 errno = rc; 849 return -1; 850 } 851 852 return 0; 853 } 854 855 /** Unlink a file or directory. 856 * 857 * @param path Path to file or empty directory 858 * @param lflag L_xxx flag (L_NONE, L_FILE or L_DIRECTORY) 859 * @return EOK on success, non-zero error code on error 860 */ 861 static int _unlink(const char *path, int lflag) 862 { 863 sysarg_t rc; 864 aid_t req; 865 840 if (!pa) { 841 return ENOMEM; 842 } 843 844 return _vfs_unlink2(-1, pa, -1, 0); 845 } 846 847 /** Remove empty directory. 848 * 849 * @param path Path 850 * @return 0 on success. On error returns -1 and sets errno. 851 */ 852 int rmdir(const char *path) 853 { 866 854 size_t pa_size; 867 855 char *pa = vfs_absolutize(path, &pa_size); 868 if ( pa == NULL)856 if (!pa) { 869 857 return ENOMEM; 870 871 async_exch_t *exch = vfs_exchange_begin(); 872 873 req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL); 874 rc = async_data_write_start(exch, pa, pa_size); 875 if (rc != EOK) { 876 vfs_exchange_end(exch); 877 free(pa); 878 879 sysarg_t rc_orig; 880 async_wait_for(req, &rc_orig); 881 882 if (rc_orig == EOK) 883 return (int) rc; 884 else 885 return (int) rc_orig; 886 } 887 vfs_exchange_end(exch); 888 free(pa); 889 async_wait_for(req, &rc); 890 return rc; 891 } 892 893 /** Unlink file or directory. 894 * 895 * @param path Path 896 * @return EOk on success, error code on error 897 */ 898 int unlink(const char *path) 899 { 900 int rc; 901 902 rc = _unlink(path, L_NONE); 903 if (rc != EOK) { 904 errno = rc; 905 return -1; 906 } 907 908 return 0; 909 } 910 911 /** Remove empty directory. 912 * 913 * @param path Path 914 * @return 0 on success. On error returns -1 and sets errno. 915 */ 916 int rmdir(const char *path) 917 { 918 int rc; 919 920 rc = _unlink(path, L_DIRECTORY); 921 if (rc != EOK) { 922 errno = rc; 923 return -1; 924 } 925 926 return 0; 858 } 859 860 return _vfs_unlink2(-1, pa, -1, WALK_DIRECTORY); 927 861 } 928 862 … … 957 891 async_exch_t *exch = vfs_exchange_begin(); 958 892 959 req = async_send_ 0(exch, VFS_IN_RENAME, NULL);893 req = async_send_1(exch, VFS_IN_RENAME, -1, NULL); 960 894 rc = async_data_write_start(exch, olda, olda_size); 961 895 if (rc != EOK) { … … 1018 952 size_t abs_size; 1019 953 char *abs = vfs_absolutize(path, &abs_size); 1020 int fd = -1; 1021 1022 if (abs == NULL) { 1023 errno = ENOMEM; 1024 return -1; 1025 } 1026 1027 int rc = open_internal(abs, abs_size, L_DIRECTORY, O_DESC, &fd); 1028 1029 if (rc != EOK) { 954 if (!abs) 955 return ENOMEM; 956 957 int fd = _vfs_walk(-1, abs, WALK_DIRECTORY); 958 if (fd < 0) { 1030 959 free(abs); 1031 errno = rc;960 errno = fd; 1032 961 return -1; 1033 962 } -
uspace/lib/c/include/ipc/vfs.h
r5b46ec8 r1dff985 63 63 64 64 typedef enum { 65 VFS_IN_OPEN = IPC_FIRST_USER_METHOD, 66 VFS_IN_READ, 65 VFS_IN_READ = IPC_FIRST_USER_METHOD, 67 66 VFS_IN_WRITE, 68 67 VFS_IN_SEEK, … … 75 74 VFS_IN_SYNC, 76 75 VFS_IN_REGISTER, 77 VFS_IN_MKDIR,78 76 VFS_IN_UNLINK, 79 77 VFS_IN_RENAME, 80 VFS_IN_STAT,81 78 VFS_IN_DUP, 82 79 VFS_IN_WAIT_HANDLE, 83 80 VFS_IN_MTAB_GET, 84 VFS_IN_STATFS 81 VFS_IN_STATFS, 82 VFS_IN_WALK, 83 VFS_IN_OPEN2, 84 VFS_IN_UNLINK2, 85 85 } vfs_in_request_t; 86 86 … … 91 91 VFS_OUT_TRUNCATE, 92 92 VFS_OUT_CLOSE, 93 VFS_OUT_MOUNT,94 93 VFS_OUT_MOUNTED, 95 VFS_OUT_UNMOUNT,96 94 VFS_OUT_UNMOUNTED, 95 VFS_OUT_GET_SIZE, 96 VFS_OUT_IS_EMPTY, 97 97 VFS_OUT_SYNC, 98 98 VFS_OUT_STAT, 99 99 VFS_OUT_LOOKUP, 100 VFS_OUT_LINK, 100 101 VFS_OUT_DESTROY, 101 102 VFS_OUT_STATFS, … … 127 128 128 129 /** 129 * Lookup will succeed only if the object is a root directory. The flag is130 * mutually exclusive with L_FILE and L_MP.130 * Lookup will not cross any mount points. 131 * If the lookup would have to cross a mount point, it returns EXDEV instead. 131 132 */ 132 #define L_ ROOT4133 #define L_DISABLE_MOUNTS 4 133 134 134 135 /** … … 151 152 152 153 /** 153 * L_LINK is used for linking to an already existing nodes.154 */155 #define L_LINK 64156 157 /**158 154 * L_UNLINK is used to remove leaves from the file system namespace. This flag 159 155 * cannot be passed directly by the client, but will be set by VFS during … … 170 166 #define L_OPEN 256 171 167 168 /* 169 * Walk flags. 170 */ 171 enum { 172 /** 173 * WALK_PARTIAL requests that if the whole path cannot be traversed, 174 * the walk() operation should return the last visited file, along 175 * with an indication of how many directories have been traversed. 176 */ 177 //WALK_PARTIAL = (1 << 0), 178 179 WALK_MAY_CREATE = (1 << 1), 180 WALK_MUST_CREATE = (1 << 2), 181 182 WALK_REGULAR = (1 << 3), 183 WALK_DIRECTORY = (1 << 4), 184 185 WALK_ALL_FLAGS = WALK_MAY_CREATE | WALK_MUST_CREATE | WALK_REGULAR | WALK_DIRECTORY, 186 }; 187 188 enum { 189 MODE_READ = 1, 190 MODE_WRITE = 2, 191 MODE_APPEND = 4, 192 }; 193 172 194 #endif 173 195 -
uspace/lib/c/include/vfs/vfs.h
r5b46ec8 r1dff985 64 64 extern void vfs_exchange_end(async_exch_t *); 65 65 66 extern int _vfs_walk(int parent, const char *path, int flags); 67 extern int _vfs_open(int file, int mode); 68 66 69 #endif 67 70 -
uspace/lib/fs/libfs.c
r5b46ec8 r1dff985 36 36 37 37 #include "libfs.h" 38 #include "../../srv/vfs/vfs.h"39 38 #include <macros.h> 40 39 #include <errno.h> … … 47 46 #include <sys/statfs.h> 48 47 #include <stdlib.h> 48 #include <fibril_synch.h> 49 49 50 50 #define on_error(rc, action) \ … … 63 63 } while (0) 64 64 65 #define DPRINTF(...) 66 67 #define LOG_EXIT(rc) \ 68 DPRINTF("Exiting %s() with rc = %d at line %d\n", __FUNC__, rc, __LINE__); 69 65 70 static fs_reg_t reg; 66 71 … … 68 73 static libfs_ops_t *libfs_ops = NULL; 69 74 70 static void libfs_ mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);71 static void libfs_unmount(libfs_ops_t *, ipc_callid_t,ipc_call_t *);75 static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t, 76 ipc_call_t *); 72 77 static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t, 73 78 ipc_call_t *); … … 104 109 } 105 110 106 static void vfs_out_mount(ipc_callid_t rid, ipc_call_t *req)107 {108 libfs_mount(libfs_ops, reg.fs_handle, rid, req);109 }110 111 111 static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req) 112 112 { … … 119 119 } 120 120 121 static void vfs_out_unmount(ipc_callid_t rid, ipc_call_t *req) 122 { 123 124 libfs_unmount(libfs_ops, rid, req); 121 static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req) 122 { 123 libfs_link(libfs_ops, reg.fs_handle, rid, req); 125 124 } 126 125 … … 193 192 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req); 194 193 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req); 194 195 195 int rc; 196 197 rc = vfs_out_ops->destroy(service_id, index); 198 196 fs_node_t *node = NULL; 197 rc = libfs_ops->node_get(&node, service_id, index); 198 if (rc == EOK && node != NULL) { 199 bool destroy = (libfs_ops->lnkcnt_get(node) == 0); 200 libfs_ops->node_put(node); 201 if (destroy) { 202 rc = vfs_out_ops->destroy(service_id, index); 203 } 204 } 199 205 async_answer_0(rid, rc); 200 206 } … … 225 231 libfs_statfs(libfs_ops, reg.fs_handle, rid, req); 226 232 } 233 234 static void vfs_out_get_size(ipc_callid_t rid, ipc_call_t *req) 235 { 236 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req); 237 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req); 238 int rc; 239 240 fs_node_t *node = NULL; 241 rc = libfs_ops->node_get(&node, service_id, index); 242 if (rc != EOK) { 243 async_answer_0(rid, rc); 244 } 245 if (node == NULL) { 246 async_answer_0(rid, EINVAL); 247 } 248 249 uint64_t size = libfs_ops->size_get(node); 250 libfs_ops->node_put(node); 251 252 async_answer_2(rid, EOK, LOWER32(size), UPPER32(size)); 253 } 254 255 static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req) 256 { 257 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req); 258 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req); 259 int rc; 260 261 fs_node_t *node = NULL; 262 rc = libfs_ops->node_get(&node, service_id, index); 263 if (rc != EOK) { 264 async_answer_0(rid, rc); 265 } 266 if (node == NULL) { 267 async_answer_0(rid, EINVAL); 268 } 269 270 bool children = false; 271 rc = libfs_ops->has_children(&children, node); 272 libfs_ops->node_put(node); 273 274 if (rc != EOK) { 275 async_answer_0(rid, rc); 276 } 277 async_answer_0(rid, children ? ENOTEMPTY : EOK); 278 } 279 227 280 static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 228 281 { … … 247 300 vfs_out_mounted(callid, &call); 248 301 break; 249 case VFS_OUT_MOUNT:250 vfs_out_mount(callid, &call);251 break;252 302 case VFS_OUT_UNMOUNTED: 253 303 vfs_out_unmounted(callid, &call); 254 304 break; 255 case VFS_OUT_ UNMOUNT:256 vfs_out_ unmount(callid, &call);305 case VFS_OUT_LINK: 306 vfs_out_link(callid, &call); 257 307 break; 258 308 case VFS_OUT_LOOKUP: … … 285 335 case VFS_OUT_STATFS: 286 336 vfs_out_statfs(callid, &call); 337 break; 338 case VFS_OUT_GET_SIZE: 339 vfs_out_get_size(callid, &call); 340 break; 341 case VFS_OUT_IS_EMPTY: 342 vfs_out_is_empty(callid, &call); 287 343 break; 288 344 default: … … 383 439 } 384 440 385 void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, 386 ipc_call_t *req) 387 { 388 service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req); 389 fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req); 390 fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*req); 391 service_id_t mr_service_id = (service_id_t) IPC_GET_ARG4(*req); 392 393 async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL); 394 if (mountee_sess == NULL) { 395 async_answer_0(rid, EINVAL); 441 static char plb_get_char(unsigned pos) 442 { 443 return reg.plb_ro[pos % PLB_SIZE]; 444 } 445 446 static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos, unsigned last) 447 { 448 unsigned pos = *ppos; 449 unsigned size = 0; 450 451 if (pos == last) { 452 *sz = 0; 453 return ERANGE; 454 } 455 456 char c = plb_get_char(pos); 457 if (c == '/') { 458 pos++; 459 } 460 461 for (int i = 0; i <= NAME_MAX; i++) { 462 c = plb_get_char(pos); 463 if (pos == last || c == '/') { 464 dest[i] = 0; 465 *ppos = pos; 466 *sz = size; 467 return EOK; 468 } 469 dest[i] = c; 470 pos++; 471 size++; 472 } 473 return ENAMETOOLONG; 474 } 475 476 static int receive_fname(char *buffer) 477 { 478 size_t size; 479 ipc_callid_t wcall; 480 481 if (!async_data_write_receive(&wcall, &size)) { 482 return ENOENT; 483 } 484 if (size > NAME_MAX + 1) { 485 async_answer_0(wcall, ERANGE); 486 return ERANGE; 487 } 488 return async_data_write_finalize(wcall, buffer, size); 489 } 490 491 /** Link a file at a path. 492 */ 493 void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, ipc_call_t *req) 494 { 495 service_id_t parent_sid = IPC_GET_ARG1(*req); 496 fs_index_t parent_index = IPC_GET_ARG2(*req); 497 fs_index_t child_index = IPC_GET_ARG3(*req); 498 499 char component[NAME_MAX + 1]; 500 int rc = receive_fname(component); 501 if (rc != EOK) { 502 async_answer_0(rid, rc); 396 503 return; 397 504 } 398 399 fs_node_t *fn; 400 int res = ops->node_get(&fn, mp_service_id, mp_fs_index); 401 if ((res != EOK) || (!fn)) { 402 async_hangup(mountee_sess); 403 async_data_write_void(combine_rc(res, ENOENT)); 404 async_answer_0(rid, combine_rc(res, ENOENT)); 505 506 fs_node_t *parent = NULL; 507 rc = ops->node_get(&parent, parent_sid, parent_index); 508 if (parent == NULL) { 509 async_answer_0(rid, rc == EOK ? EBADF : rc); 405 510 return; 406 511 } 407 512 408 if (fn->mp_data.mp_active) {409 async_hangup(mountee_sess);410 (void) ops->node_put(fn);411 async_ data_write_void(EBUSY);412 async_answer_0(rid, EBUSY);513 fs_node_t *child = NULL; 514 rc = ops->node_get(&child, parent_sid, child_index); 515 if (child == NULL) { 516 async_answer_0(rid, rc == EOK ? EBADF : rc); 517 ops->node_put(parent); 413 518 return; 414 519 } 415 520 416 async_exch_t *exch = async_exchange_begin(mountee_sess); 417 async_sess_t *sess = async_clone_establish(EXCHANGE_PARALLEL, exch); 418 419 if (!sess) { 420 async_exchange_end(exch); 421 async_hangup(mountee_sess); 422 (void) ops->node_put(fn); 423 async_data_write_void(errno); 424 async_answer_0(rid, errno); 425 return; 426 } 427 428 ipc_call_t answer; 429 int rc = async_data_write_forward_1_1(exch, VFS_OUT_MOUNTED, 430 mr_service_id, &answer); 431 async_exchange_end(exch); 432 433 if (rc == EOK) { 434 fn->mp_data.mp_active = true; 435 fn->mp_data.fs_handle = mr_fs_handle; 436 fn->mp_data.service_id = mr_service_id; 437 fn->mp_data.sess = mountee_sess; 438 } 439 440 /* 441 * Do not release the FS node so that it stays in memory. 442 */ 443 async_answer_4(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer), 444 IPC_GET_ARG3(answer), IPC_GET_ARG4(answer)); 445 } 446 447 void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *req) 448 { 449 service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req); 450 fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req); 451 fs_node_t *fn; 452 int res; 453 454 res = ops->node_get(&fn, mp_service_id, mp_fs_index); 455 if ((res != EOK) || (!fn)) { 456 async_answer_0(rid, combine_rc(res, ENOENT)); 457 return; 458 } 459 460 /* 461 * We are clearly expecting to find the mount point active. 462 */ 463 if (!fn->mp_data.mp_active) { 464 (void) ops->node_put(fn); 465 async_answer_0(rid, EINVAL); 466 return; 467 } 468 469 /* 470 * Tell the mounted file system to unmount. 471 */ 472 async_exch_t *exch = async_exchange_begin(fn->mp_data.sess); 473 res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.service_id); 474 async_exchange_end(exch); 475 476 /* 477 * If everything went well, perform the clean-up on our side. 478 */ 479 if (res == EOK) { 480 async_hangup(fn->mp_data.sess); 481 fn->mp_data.mp_active = false; 482 fn->mp_data.fs_handle = 0; 483 fn->mp_data.service_id = 0; 484 fn->mp_data.sess = NULL; 485 486 /* Drop the reference created in libfs_mount(). */ 487 (void) ops->node_put(fn); 488 } 489 490 (void) ops->node_put(fn); 491 async_answer_0(rid, res); 492 } 493 494 static char plb_get_char(unsigned pos) 495 { 496 return reg.plb_ro[pos % PLB_SIZE]; 521 rc = ops->link(parent, child, component); 522 ops->node_put(parent); 523 ops->node_put(child); 524 async_answer_0(rid, rc); 497 525 } 498 526 … … 513 541 ipc_call_t *req) 514 542 { 515 unsigned int first = IPC_GET_ARG1(*req); 516 unsigned int last = IPC_GET_ARG2(*req); 517 unsigned int next = first; 543 unsigned first = IPC_GET_ARG1(*req); 544 unsigned len = IPC_GET_ARG2(*req); 518 545 service_id_t service_id = IPC_GET_ARG3(*req); 519 int lflag = IPC_GET_ARG4(*req); 520 fs_index_t index = IPC_GET_ARG5(*req); 546 fs_index_t index = IPC_GET_ARG4(*req); 547 int lflag = IPC_GET_ARG5(*req); 548 549 assert((int) index != -1); 550 551 DPRINTF("Entered libfs_lookup()\n"); 552 553 // TODO: Validate flags. 554 555 unsigned next = first; 556 unsigned last = first + len; 557 521 558 char component[NAME_MAX + 1]; 522 int len;523 559 int rc; 524 525 if (last < next)526 last += PLB_SIZE;527 560 528 561 fs_node_t *par = NULL; 529 562 fs_node_t *cur = NULL; 530 563 fs_node_t *tmp = NULL; 531 532 rc = ops->root_get(&cur, service_id); 533 on_error(rc, goto out_with_answer); 534 535 if (cur->mp_data.mp_active) { 536 async_exch_t *exch = async_exchange_begin(cur->mp_data.sess); 537 async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last, 538 cur->mp_data.service_id, lflag, index, 539 IPC_FF_ROUTE_FROM_ME); 540 async_exchange_end(exch); 564 unsigned clen = 0; 565 566 rc = ops->node_get(&cur, service_id, index); 567 if (rc != EOK) { 568 async_answer_0(rid, rc); 569 LOG_EXIT(rc); 570 goto out; 571 } 572 573 assert(cur != NULL); 574 575 /* Find the file and its parent. */ 576 577 unsigned last_next = 0; 578 579 while (next != last) { 580 if (cur == NULL) { 581 assert(par != NULL); 582 goto out1; 583 } 584 585 if (!ops->is_directory(cur)) { 586 async_answer_0(rid, ENOTDIR); 587 LOG_EXIT(ENOTDIR); 588 goto out; 589 } 541 590 542 (void) ops->node_put(cur); 543 return; 544 } 545 546 /* Eat slash */ 547 if (plb_get_char(next) == '/') 548 next++; 549 550 while (next <= last) { 551 bool has_children; 591 last_next = next; 592 /* Collect the component */ 593 rc = plb_get_component(component, &clen, &next, last); 594 assert(rc != ERANGE); 595 if (rc != EOK) { 596 async_answer_0(rid, rc); 597 LOG_EXIT(rc); 598 goto out; 599 } 552 600 553 rc = ops->has_children(&has_children, cur);554 on_error(rc, goto out_with_answer);555 if (!has_children)556 break;601 if (clen == 0) { 602 /* The path is just "/". */ 603 break; 604 } 557 605 558 /* Collect the component */ 559 len = 0; 560 while ((next <= last) && (plb_get_char(next) != '/')) { 561 if (len + 1 == NAME_MAX) { 562 /* Component length overflow */ 563 async_answer_0(rid, ENAMETOOLONG); 564 goto out; 565 } 566 component[len++] = plb_get_char(next); 567 /* Process next character */ 568 next++; 569 } 570 571 assert(len); 572 component[len] = '\0'; 573 /* Eat slash */ 574 next++; 606 assert(component[clen] == 0); 575 607 576 608 /* Match the component */ 577 609 rc = ops->match(&tmp, cur, component); 578 on_error(rc, goto out_with_answer); 610 if (rc != EOK) { 611 async_answer_0(rid, rc); 612 LOG_EXIT(rc); 613 goto out; 614 } 579 615 580 /* 581 * If the matching component is a mount point, there are two 582 * legitimate semantics of the lookup operation. The first is 583 * the commonly used one in which the lookup crosses each mount 584 * point into the mounted file system. The second semantics is 585 * used mostly during unmount() and differs from the first one 586 * only in that the last mount point in the looked up path, 587 * which is also its last component, is not crossed. 588 */ 589 590 if ((tmp) && (tmp->mp_data.mp_active) && 591 (!(lflag & L_MP) || (next <= last))) { 592 if (next > last) 593 next = last = first; 594 else 595 next--; 616 /* Descend one level */ 617 if (par) { 618 rc = ops->node_put(par); 619 if (rc != EOK) { 620 async_answer_0(rid, rc); 621 LOG_EXIT(rc); 622 goto out; 623 } 624 } 625 626 par = cur; 627 cur = tmp; 628 tmp = NULL; 629 } 630 631 /* At this point, par is either NULL or a directory. 632 * If cur is NULL, the looked up file does not exist yet. 633 */ 634 635 assert(par == NULL || ops->is_directory(par)); 636 assert(par != NULL || cur != NULL); 637 638 /* Check for some error conditions. */ 639 640 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) { 641 async_answer_0(rid, EISDIR); 642 LOG_EXIT(EISDIR); 643 goto out; 644 } 645 646 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) { 647 async_answer_0(rid, ENOTDIR); 648 LOG_EXIT(ENOTDIR); 649 goto out; 650 } 651 652 /* Unlink. */ 653 654 if (lflag & L_UNLINK) { 655 if (!cur) { 656 async_answer_0(rid, ENOENT); 657 LOG_EXIT(ENOENT); 658 goto out; 659 } 660 if (!par) { 661 async_answer_0(rid, EINVAL); 662 LOG_EXIT(EINVAL); 663 goto out; 664 } 665 666 rc = ops->unlink(par, cur, component); 667 if (rc == EOK) { 668 int64_t size = ops->size_get(cur); 669 int32_t lsize = LOWER32(size); 670 if (lsize != size) { 671 lsize = -1; 672 } 596 673 597 async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess); 598 async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, 599 last, tmp->mp_data.service_id, lflag, index, 600 IPC_FF_ROUTE_FROM_ME); 601 async_exchange_end(exch); 602 603 (void) ops->node_put(cur); 604 (void) ops->node_put(tmp); 605 if (par) 606 (void) ops->node_put(par); 607 return; 608 } 609 610 /* Handle miss: match amongst siblings */ 611 if (!tmp) { 612 if (next <= last) { 613 /* There are unprocessed components */ 614 async_answer_0(rid, ENOENT); 674 async_answer_5(rid, fs_handle, service_id, 675 ops->index_get(cur), last, lsize, 676 ops->is_directory(cur)); 677 LOG_EXIT(EOK); 678 } else { 679 async_answer_0(rid, rc); 680 LOG_EXIT(rc); 681 } 682 goto out; 683 } 684 685 /* Create. */ 686 687 if (lflag & L_CREATE) { 688 if (cur && (lflag & L_EXCLUSIVE)) { 689 async_answer_0(rid, EEXIST); 690 LOG_EXIT(EEXIST); 691 goto out; 692 } 693 694 if (!cur) { 695 rc = ops->create(&cur, service_id, lflag & (L_FILE|L_DIRECTORY)); 696 if (rc != EOK) { 697 async_answer_0(rid, rc); 698 LOG_EXIT(rc); 699 goto out; 700 } 701 if (!cur) { 702 async_answer_0(rid, ENOSPC); 703 LOG_EXIT(ENOSPC); 615 704 goto out; 616 705 } 617 706 618 /* Miss in the last component */ 619 if (lflag & (L_CREATE | L_LINK)) { 620 /* Request to create a new link */ 621 if (!ops->is_directory(cur)) { 622 async_answer_0(rid, ENOTDIR); 623 goto out; 624 } 625 626 fs_node_t *fn; 627 if (lflag & L_CREATE) 628 rc = ops->create(&fn, service_id, 629 lflag); 630 else 631 rc = ops->node_get(&fn, service_id, 632 index); 633 on_error(rc, goto out_with_answer); 634 635 if (fn) { 636 rc = ops->link(cur, fn, component); 637 if (rc != EOK) { 638 if (lflag & L_CREATE) 639 (void) ops->destroy(fn); 640 else 641 (void) ops->node_put(fn); 642 async_answer_0(rid, rc); 643 } else { 644 (void) ops->node_put(cur); 645 cur = fn; 646 goto out_with_answer; 647 } 648 } else 649 async_answer_0(rid, ENOSPC); 650 707 rc = ops->link(par, cur, component); 708 if (rc != EOK) { 709 (void) ops->destroy(cur); 710 cur = NULL; 711 async_answer_0(rid, rc); 712 LOG_EXIT(rc); 651 713 goto out; 652 714 } 653 654 async_answer_0(rid, ENOENT); 715 } 716 } 717 718 /* Return. */ 719 out1: 720 if (!cur) { 721 async_answer_5(rid, fs_handle, service_id, 722 ops->index_get(par), last_next, -1, true); 723 LOG_EXIT(EOK); 724 goto out; 725 } 726 727 if (lflag & L_OPEN) { 728 rc = ops->node_open(cur); 729 if (rc != EOK) { 730 async_answer_0(rid, rc); 731 LOG_EXIT(rc); 655 732 goto out; 656 733 } 657 658 if (par) { 659 rc = ops->node_put(par); 660 on_error(rc, goto out_with_answer); 661 } 662 663 /* Descend one level */ 664 par = cur; 665 cur = tmp; 666 tmp = NULL; 667 } 668 669 /* Handle miss: excessive components */ 670 if (next <= last) { 671 bool has_children; 672 rc = ops->has_children(&has_children, cur); 673 on_error(rc, goto out_with_answer); 674 675 if (has_children) 676 goto skip_miss; 677 678 if (lflag & (L_CREATE | L_LINK)) { 679 if (!ops->is_directory(cur)) { 680 async_answer_0(rid, ENOTDIR); 681 goto out; 682 } 683 684 /* Collect next component */ 685 len = 0; 686 while (next <= last) { 687 if (plb_get_char(next) == '/') { 688 /* More than one component */ 689 async_answer_0(rid, ENOENT); 690 goto out; 691 } 692 693 if (len + 1 == NAME_MAX) { 694 /* Component length overflow */ 695 async_answer_0(rid, ENAMETOOLONG); 696 goto out; 697 } 698 699 component[len++] = plb_get_char(next); 700 /* Process next character */ 701 next++; 702 } 703 704 assert(len); 705 component[len] = '\0'; 706 707 fs_node_t *fn; 708 if (lflag & L_CREATE) 709 rc = ops->create(&fn, service_id, lflag); 710 else 711 rc = ops->node_get(&fn, service_id, index); 712 on_error(rc, goto out_with_answer); 713 714 if (fn) { 715 rc = ops->link(cur, fn, component); 716 if (rc != EOK) { 717 if (lflag & L_CREATE) 718 (void) ops->destroy(fn); 719 else 720 (void) ops->node_put(fn); 721 async_answer_0(rid, rc); 722 } else { 723 (void) ops->node_put(cur); 724 cur = fn; 725 goto out_with_answer; 726 } 727 } else 728 async_answer_0(rid, ENOSPC); 729 730 goto out; 731 } 732 733 async_answer_0(rid, ENOENT); 734 goto out; 735 } 736 737 skip_miss: 738 739 /* Handle hit */ 740 if (lflag & L_UNLINK) { 741 unsigned int old_lnkcnt = ops->lnkcnt_get(cur); 742 rc = ops->unlink(par, cur, component); 743 744 if (rc == EOK) { 745 aoff64_t size = ops->size_get(cur); 746 async_answer_5(rid, fs_handle, service_id, 747 ops->index_get(cur), LOWER32(size), UPPER32(size), 748 old_lnkcnt); 749 } else 750 async_answer_0(rid, rc); 751 752 goto out; 753 } 754 755 if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) || 756 (lflag & L_LINK)) { 757 async_answer_0(rid, EEXIST); 758 goto out; 759 } 760 761 if ((lflag & L_FILE) && (ops->is_directory(cur))) { 762 async_answer_0(rid, EISDIR); 763 goto out; 764 } 765 766 if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) { 767 async_answer_0(rid, ENOTDIR); 768 goto out; 769 } 770 771 if ((lflag & L_ROOT) && par) { 772 async_answer_0(rid, EINVAL); 773 goto out; 774 } 775 776 out_with_answer: 777 778 if (rc == EOK) { 779 if (lflag & L_OPEN) 780 rc = ops->node_open(cur); 781 782 if (rc == EOK) { 783 aoff64_t size = ops->size_get(cur); 784 async_answer_5(rid, fs_handle, service_id, 785 ops->index_get(cur), LOWER32(size), UPPER32(size), 786 ops->lnkcnt_get(cur)); 787 } else 788 async_answer_0(rid, rc); 789 790 } else 791 async_answer_0(rid, rc); 792 734 } 735 736 int64_t size = ops->size_get(cur); 737 int32_t lsize = LOWER32(size); 738 if (lsize != size) { 739 lsize = -1; 740 } 741 742 async_answer_5(rid, fs_handle, service_id, ops->index_get(cur), last, 743 lsize, ops->is_directory(cur)); 744 745 LOG_EXIT(EOK); 793 746 out: 794 795 if (par) 747 if (par) { 796 748 (void) ops->node_put(par); 797 798 if (cur) 749 } 750 751 if (cur) { 799 752 (void) ops->node_put(cur); 800 801 if (tmp) 753 } 754 755 if (tmp) { 802 756 (void) ops->node_put(tmp); 757 } 803 758 } 804 759 -
uspace/lib/fs/libfs.h
r5b46ec8 r1dff985 56 56 57 57 typedef struct { 58 bool mp_active;59 async_sess_t *sess;60 fs_handle_t fs_handle;61 service_id_t service_id;62 } mp_data_t;63 64 typedef struct {65 mp_data_t mp_data; /**< Mount point info. */66 58 void *data; /**< Data of the file system implementation. */ 67 59 } fs_node_t; -
uspace/srv/vfs/vfs.c
r5b46ec8 r1dff985 104 104 vfs_unmount_srv(callid, &call); 105 105 break; 106 case VFS_IN_OPEN: 107 vfs_open(callid, &call); 106 case VFS_IN_WALK: 107 vfs_walk(callid, &call); 108 break; 109 case VFS_IN_OPEN2: 110 vfs_open2(callid, &call); 108 111 break; 109 112 case VFS_IN_CLOSE: … … 125 128 vfs_fstat(callid, &call); 126 129 break; 127 case VFS_IN_STAT: 128 vfs_stat(callid, &call); 129 break; 130 case VFS_IN_MKDIR: 131 vfs_mkdir(callid, &call); 132 break; 133 case VFS_IN_UNLINK: 134 vfs_unlink(callid, &call); 130 case VFS_IN_UNLINK2: 131 vfs_unlink2(callid, &call); 135 132 break; 136 133 case VFS_IN_RENAME: -
uspace/srv/vfs/vfs.h
r5b46ec8 r1dff985 94 94 vfs_node_type_t type; 95 95 aoff64_t size; 96 unsigned int lnkcnt;97 96 } vfs_lookup_res_t; 98 97 … … 101 100 * which may be associated with it. 102 101 */ 103 typedef struct {102 typedef struct _vfs_node { 104 103 VFS_TRIPLET; /**< Identity of the node. */ 105 104 … … 110 109 unsigned refcnt; 111 110 112 /** Number of names this node has in the file system namespace. */113 unsigned lnkcnt;114 115 111 ht_link_t nh_link; /**< Node hash-table link. */ 116 112 117 113 vfs_node_type_t type; /**< Partial info about the node type. */ 118 114 119 aoff64_t size; /**< Cached size if the node is a file. */115 int64_t size; /**< Cached size if the node is a file. */ 120 116 121 117 /** … … 123 119 */ 124 120 fibril_rwlock_t contents_rwlock; 121 122 struct _vfs_node *mount; 125 123 } vfs_node_t; 126 124 … … 138 136 unsigned refcnt; 139 137 138 int permissions; 139 bool open_read; 140 bool open_write; 141 140 142 /** Append on write. */ 141 143 bool append; … … 176 178 extern vfs_info_t *fs_handle_to_info(fs_handle_t); 177 179 178 extern int vfs_lookup_internal( char *, int, vfs_lookup_res_t *,179 vfs_pair_t *, ...);180 extern int vfs_lookup_internal(vfs_node_t *, char *, int, vfs_lookup_res_t *); 181 extern int vfs_link_internal(vfs_node_t *, char *, vfs_triplet_t *); 180 182 181 183 extern bool vfs_nodes_init(void); 182 184 extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *); 185 extern vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result); 183 186 extern void vfs_node_put(vfs_node_t *); 184 187 extern void vfs_node_forget(vfs_node_t *); 185 188 extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t); 186 189 190 extern int64_t vfs_node_get_size(vfs_node_t *node); 191 extern bool vfs_node_has_children(vfs_node_t *node); 187 192 188 193 #define MAX_OPEN_FILES 128 … … 207 212 extern void vfs_mount_srv(ipc_callid_t, ipc_call_t *); 208 213 extern void vfs_unmount_srv(ipc_callid_t, ipc_call_t *); 209 extern void vfs_open(ipc_callid_t, ipc_call_t *);210 214 extern void vfs_sync(ipc_callid_t, ipc_call_t *); 211 215 extern void vfs_dup(ipc_callid_t, ipc_call_t *); … … 216 220 extern void vfs_truncate(ipc_callid_t, ipc_call_t *); 217 221 extern void vfs_fstat(ipc_callid_t, ipc_call_t *); 218 extern void vfs_stat(ipc_callid_t, ipc_call_t *);219 extern void vfs_mkdir(ipc_callid_t, ipc_call_t *);220 extern void vfs_unlink(ipc_callid_t, ipc_call_t *);221 222 extern void vfs_rename(ipc_callid_t, ipc_call_t *); 222 223 extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *); … … 233 234 extern int vfs_rdwr_internal(int, bool, rdwr_io_chunk_t *); 234 235 236 extern void vfs_walk(ipc_callid_t, ipc_call_t *); 237 extern void vfs_open2(ipc_callid_t, ipc_call_t *); 238 extern void vfs_unlink2(ipc_callid_t, ipc_call_t *); 239 235 240 #endif 236 241 -
uspace/srv/vfs/vfs_file.c
r5b46ec8 r1dff985 177 177 * endpoint FS and drop our reference to the underlying VFS node. 178 178 */ 179 rc = vfs_file_close_remote(file); 179 if (file->open_read || file->open_write) { 180 rc = vfs_file_close_remote(file); 181 } 180 182 vfs_node_delref(file->node); 181 183 free(file); … … 393 395 */ 394 396 acceptor_file->node = donor_file->node; 397 acceptor_file->permissions = donor_file->permissions; 398 399 // TODO: The file should not inherit its open status, but clients depend on this. 400 acceptor_file->pos = donor_file->pos; 395 401 acceptor_file->append = donor_file->append; 396 acceptor_file->pos = donor_file->pos; 402 acceptor_file->open_read = donor_file->open_read; 403 acceptor_file->open_write = donor_file->open_write; 397 404 398 405 out: -
uspace/srv/vfs/vfs_lookup.c
r5b46ec8 r1dff985 46 46 #include <adt/list.h> 47 47 #include <vfs/canonify.h> 48 #include <dirent.h> 49 #include <assert.h> 50 51 #define DPRINTF(...) 48 52 49 53 #define min(a, b) ((a) < (b) ? (a) : (b)) … … 53 57 uint8_t *plb = NULL; 54 58 55 /** Perform a path lookup. 56 * 57 * @param path Path to be resolved; it must be a NULL-terminated 58 * string. 59 * @param lflag Flags to be used during lookup. 60 * @param result Empty structure where the lookup result will be stored. 61 * Can be NULL. 62 * @param altroot If non-empty, will be used instead of rootfs as the root 63 * of the whole VFS tree. 64 * 65 * @return EOK on success or an error code from errno.h. 66 * 67 */ 68 int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result, 69 vfs_pair_t *altroot, ...) 70 { 71 vfs_pair_t *root; 72 73 if (altroot) 74 root = altroot; 75 else 76 root = &rootfs; 77 78 if (!root->fs_handle) 79 return ENOENT; 80 81 size_t len; 82 path = canonify(path, &len); 83 if (!path) 84 return EINVAL; 85 86 fs_index_t index = 0; 87 if (lflag & L_LINK) { 88 va_list ap; 89 90 va_start(ap, altroot); 91 index = va_arg(ap, fs_index_t); 92 va_end(ap); 93 } 94 59 static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start, size_t len) 60 { 95 61 fibril_mutex_lock(&plb_mutex); 96 62 97 plb_entry_t entry; 98 link_initialize(&entry.plb_link); 99 entry.len = len; 63 link_initialize(&entry->plb_link); 64 entry->len = len; 100 65 101 66 size_t first; /* the first free index */ … … 138 103 */ 139 104 140 entry .index = first;141 entry .len = len;105 entry->index = first; 106 entry->len = len; 142 107 143 108 /* … … 145 110 * buffer. 146 111 */ 147 list_append(&entry .plb_link, &plb_entries);112 list_append(&entry->plb_link, &plb_entries); 148 113 149 114 fibril_mutex_unlock(&plb_mutex); … … 158 123 memcpy(plb, &path[cnt1], cnt2); 159 124 160 ipc_call_t answer; 161 async_exch_t *exch = vfs_exchange_grab(root->fs_handle); 162 aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first, 163 (sysarg_t) (first + len - 1) % PLB_SIZE, 164 (sysarg_t) root->service_id, (sysarg_t) lflag, (sysarg_t) index, 165 &answer); 166 167 sysarg_t rc; 168 async_wait_for(req, &rc); 169 vfs_exchange_release(exch); 170 125 *start = first; 126 return EOK; 127 } 128 129 static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len) 130 { 171 131 fibril_mutex_lock(&plb_mutex); 172 list_remove(&entry .plb_link);132 list_remove(&entry->plb_link); 173 133 /* 174 134 * Erasing the path from PLB will come handy for debugging purposes. 175 135 */ 136 size_t cnt1 = min(len, (PLB_SIZE - first) + 1); 137 size_t cnt2 = len - cnt1; 176 138 memset(&plb[first], 0, cnt1); 177 139 memset(plb, 0, cnt2); 178 140 fibril_mutex_unlock(&plb_mutex); 179 180 if ((int) rc < EOK) 141 } 142 143 static char *_strrchr(char *path, int c) 144 { 145 char *res = NULL; 146 while (*path != 0) { 147 if (*path == c) { 148 res = path; 149 } 150 path++; 151 } 152 return res; 153 } 154 155 int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child) 156 { 157 assert(base != NULL); 158 assert(child != NULL); 159 assert(base->fs_handle); 160 assert(child->fs_handle); 161 assert(path != NULL); 162 163 vfs_lookup_res_t res; 164 char component[NAME_MAX + 1]; 165 int rc; 166 167 size_t len; 168 char *npath = canonify(path, &len); 169 if (!npath) { 170 rc = EINVAL; 171 goto out; 172 } 173 path = npath; 174 175 vfs_triplet_t *triplet; 176 177 char *slash = _strrchr(path, '/'); 178 if (slash && slash != path) { 179 if (slash[1] == 0) { 180 rc = EINVAL; 181 goto out; 182 } 183 184 memcpy(component, slash + 1, str_size(slash)); 185 *slash = 0; 186 187 rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res); 188 if (rc != EOK) { 189 goto out; 190 } 191 triplet = &res.triplet; 192 193 *slash = '/'; 194 } else { 195 if (base->mount != NULL) { 196 rc = EINVAL; 197 goto out; 198 } 199 200 memcpy(component, path + 1, str_size(path)); 201 triplet = (vfs_triplet_t *) base; 202 } 203 204 if (triplet->fs_handle != child->fs_handle || triplet->service_id != child->service_id) { 205 rc = EXDEV; 206 goto out; 207 } 208 209 async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle); 210 aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id, triplet->index, child->index, NULL); 211 212 rc = async_data_write_start(exch, component, str_size(component) + 1); 213 sysarg_t orig_rc; 214 async_wait_for(req, &orig_rc); 215 vfs_exchange_release(exch); 216 if (orig_rc != EOK) { 217 rc = orig_rc; 218 } 219 220 out: 221 DPRINTF("vfs_link_internal() with path '%s' returns %d\n", path, rc); 222 return rc; 223 } 224 225 static int out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen, 226 int lflag, vfs_lookup_res_t *result) 227 { 228 assert(base); 229 assert(result); 230 231 sysarg_t rc; 232 ipc_call_t answer; 233 async_exch_t *exch = vfs_exchange_grab(base->fs_handle); 234 aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst, (sysarg_t) *plen, 235 (sysarg_t) base->service_id, (sysarg_t) base->index, (sysarg_t) lflag, &answer); 236 async_wait_for(req, &rc); 237 vfs_exchange_release(exch); 238 239 if ((int) rc < 0) { 181 240 return (int) rc; 182 183 if (!result) 184 return EOK; 241 } 242 243 unsigned last = *pfirst + *plen; 244 *pfirst = IPC_GET_ARG3(answer); 245 *plen = last - *pfirst; 185 246 186 247 result->triplet.fs_handle = (fs_handle_t) rc; 187 248 result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer); 188 249 result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer); 189 result->size = 190 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer)); 191 result->lnkcnt = (unsigned int) IPC_GET_ARG5(answer); 192 193 if (lflag & L_FILE) 194 result->type = VFS_NODE_FILE; 195 else if (lflag & L_DIRECTORY) 196 result->type = VFS_NODE_DIRECTORY; 197 else 198 result->type = VFS_NODE_UNKNOWN; 199 250 result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer); 251 result->type = IPC_GET_ARG5(answer) ? VFS_NODE_DIRECTORY : VFS_NODE_FILE; 200 252 return EOK; 253 } 254 255 /** Perform a path lookup. 256 * 257 * @param base The file from which to perform the lookup. 258 * @param path Path to be resolved; it must be a NULL-terminated 259 * string. 260 * @param lflag Flags to be used during lookup. 261 * @param result Empty structure where the lookup result will be stored. 262 * Can be NULL. 263 * 264 * @return EOK on success or an error code from errno.h. 265 * 266 */ 267 int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag, vfs_lookup_res_t *result) 268 { 269 assert(base != NULL); 270 assert(path != NULL); 271 272 size_t len; 273 int rc; 274 char *npath = canonify(path, &len); 275 if (!npath) { 276 DPRINTF("vfs_lookup_internal() can't canonify path: %s\n", path); 277 rc = EINVAL; 278 return rc; 279 } 280 path = npath; 281 282 assert(path[0] == '/'); 283 284 size_t first; 285 286 plb_entry_t entry; 287 rc = plb_insert_entry(&entry, path, &first, len); 288 if (rc != EOK) { 289 DPRINTF("vfs_lookup_internal() can't insert entry into PLB: %d\n", rc); 290 return rc; 291 } 292 293 size_t next = first; 294 size_t nlen = len; 295 296 vfs_lookup_res_t res; 297 298 /* Resolve path as long as there are mount points to cross. */ 299 while (nlen > 0) { 300 while (base->mount != NULL) { 301 if (lflag & L_DISABLE_MOUNTS) { 302 rc = EXDEV; 303 goto out; 304 } 305 306 base = base->mount; 307 } 308 309 rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag, &res); 310 if (rc != EOK) { 311 goto out; 312 } 313 314 if (nlen > 0) { 315 base = vfs_node_peek(&res); 316 if (base == NULL || base->mount == NULL) { 317 rc = ENOENT; 318 goto out; 319 } 320 if (lflag & L_DISABLE_MOUNTS) { 321 rc = EXDEV; 322 goto out; 323 } 324 } 325 } 326 327 assert(nlen == 0); 328 rc = EOK; 329 330 if (result != NULL) { 331 /* The found file may be a mount point. Try to cross it. */ 332 if (!(lflag & L_MP)) { 333 base = vfs_node_peek(&res); 334 if (base != NULL && base->mount != NULL) { 335 while (base->mount != NULL) { 336 base = base->mount; 337 } 338 339 result->triplet = *(vfs_triplet_t *)base; 340 result->type = base->type; 341 result->size = base->size; 342 goto out; 343 } 344 } 345 346 memcpy(result, &res, sizeof(vfs_lookup_res_t)); 347 } 348 349 out: 350 plb_clear_entry(&entry, first, len); 351 DPRINTF("vfs_lookup_internal() with path '%s' returns %d\n", path, rc); 352 return rc; 201 353 } 202 354 -
uspace/srv/vfs/vfs_node.c
r5b46ec8 r1dff985 45 45 #include <async.h> 46 46 #include <errno.h> 47 #include <macros.h> 47 48 48 49 /** Mutex protecting the VFS node hash table. */ … … 106 107 void vfs_node_delref(vfs_node_t *node) 107 108 { 108 bool free_ vfs_node = false;109 bool free_fs_node = false;110 111 fibril_mutex_lock(&nodes_mutex);112 113 if (node->refcnt -- == 1) {109 bool free_node = false; 110 111 fibril_mutex_lock(&nodes_mutex); 112 113 node->refcnt--; 114 if (node->refcnt == 0) { 114 115 115 116 /* … … 119 120 120 121 hash_table_remove_item(&nodes, &node->nh_link); 121 free_vfs_node = true; 122 123 if (!node->lnkcnt) 124 free_fs_node = true; 125 } 126 127 fibril_mutex_unlock(&nodes_mutex); 128 129 if (free_fs_node) { 130 122 free_node = true; 123 } 124 125 fibril_mutex_unlock(&nodes_mutex); 126 127 if (free_node) { 131 128 /* 132 * The node is not visible in the file system namespace. 133 * Free up its resources. 129 * DESTROY will free up the file's resources if there are no more hard links. 134 130 */ 135 131 136 132 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 137 sysarg_t rc = async_req_2_0(exch, VFS_OUT_DESTROY, 138 (sysarg_t) node->service_id, (sysarg_t)node->index); 139 140 assert(rc == EOK); 133 async_msg_2(exch, VFS_OUT_DESTROY, 134 (sysarg_t) node->service_id, (sysarg_t)node->index); 141 135 vfs_exchange_release(exch); 142 } 143 144 if (free_vfs_node) 136 145 137 free(node); 138 } 146 139 } 147 140 … … 190 183 node->index = result->triplet.index; 191 184 node->size = result->size; 192 node->lnkcnt = result->lnkcnt;193 185 node->type = result->type; 194 186 fibril_rwlock_initialize(&node->contents_rwlock); … … 196 188 } else { 197 189 node = hash_table_get_inst(tmp, vfs_node_t, nh_link); 198 if (node->type == VFS_NODE_UNKNOWN && 199 result->type != VFS_NODE_UNKNOWN) { 200 /* Upgrade the node type. */ 201 node->type = result->type; 202 } 203 } 204 205 assert(node->size == result->size || node->type != VFS_NODE_FILE); 206 assert(node->lnkcnt == result->lnkcnt); 207 assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN); 190 } 208 191 209 192 _vfs_node_addref(node); 193 fibril_mutex_unlock(&nodes_mutex); 194 195 return node; 196 } 197 198 vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result) 199 { 200 vfs_node_t *node = NULL; 201 202 fibril_mutex_lock(&nodes_mutex); 203 ht_link_t *tmp = hash_table_find(&nodes, &result->triplet); 204 if (tmp) { 205 node = hash_table_get_inst(tmp, vfs_node_t, nh_link); 206 } 210 207 fibril_mutex_unlock(&nodes_mutex); 211 208 … … 318 315 } 319 316 317 int64_t vfs_node_get_size(vfs_node_t *node) 318 { 319 if (node->size == -1) { 320 sysarg_t sz1 = 0; 321 sysarg_t sz2 = 0; 322 323 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 324 (void) async_req_2_2(exch, VFS_OUT_GET_SIZE, 325 node->service_id, node->index, &sz1, &sz2); 326 vfs_exchange_release(exch); 327 328 node->size = MERGE_LOUP32(sz1, sz2); 329 } 330 return node->size; 331 } 332 333 bool vfs_node_has_children(vfs_node_t *node) 334 { 335 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 336 int rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id, node->index); 337 vfs_exchange_release(exch); 338 return rc == ENOTEMPTY; 339 } 340 320 341 /** 321 342 * @} -
uspace/srv/vfs/vfs_ops.c
r5b46ec8 r1dff985 68 68 FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock); 69 69 70 vfs_pair_t rootfs = { 71 .fs_handle = 0, 72 .service_id = 0 73 }; 74 75 static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id, 76 fs_handle_t fs_handle, char *mp, char *opts) 77 { 78 vfs_lookup_res_t mp_res; 79 vfs_lookup_res_t mr_res; 80 vfs_node_t *mp_node = NULL; 81 vfs_node_t *mr_node; 82 fs_index_t rindex; 83 aoff64_t rsize; 84 unsigned rlnkcnt; 85 async_exch_t *exch; 86 sysarg_t rc; 87 aid_t msg; 70 vfs_node_t *root = NULL; 71 72 static int vfs_connect_internal(service_id_t service_id, unsigned flags, unsigned instance, 73 char *options, char *fsname, vfs_node_t **root) 74 { 75 fs_handle_t fs_handle = 0; 76 77 fibril_mutex_lock(&fs_list_lock); 78 while (1) { 79 fs_handle = fs_name_to_handle(instance, fsname, false); 80 81 if (fs_handle != 0 || !(flags & IPC_FLAG_BLOCKING)) { 82 break; 83 } 84 85 fibril_condvar_wait(&fs_list_cv, &fs_list_lock); 86 } 87 fibril_mutex_unlock(&fs_list_lock); 88 89 if (fs_handle == 0) { 90 return ENOENT; 91 } 92 93 /* Tell the mountee that it is being mounted. */ 88 94 ipc_call_t answer; 89 95 async_exch_t *exch = vfs_exchange_grab(fs_handle); 96 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, &answer); 97 /* Send the mount options */ 98 sysarg_t rc = async_data_write_start(exch, options, str_size(options)); 99 if (rc != EOK) { 100 async_forget(msg); 101 vfs_exchange_release(exch); 102 return rc; 103 } 104 async_wait_for(msg, &rc); 105 vfs_exchange_release(exch); 106 107 if (rc != EOK) { 108 return rc; 109 } 110 111 vfs_lookup_res_t res; 112 res.triplet.fs_handle = fs_handle; 113 res.triplet.service_id = service_id; 114 res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer); 115 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer)); 116 res.type = VFS_NODE_DIRECTORY; 117 118 /* Add reference to the mounted root. */ 119 *root = vfs_node_get(&res); 120 assert(*root); 121 122 return EOK; 123 } 124 125 static int vfs_mount_internal(service_id_t service_id, unsigned flags, unsigned instance, 126 char *opts, char *fs_name, char *mp) 127 { 90 128 /* Resolve the path to the mountpoint. */ 91 fibril_rwlock_write_lock(&namespace_rwlock); 92 if (rootfs.fs_handle) { 93 /* We already have the root FS. */ 94 if (str_cmp(mp, "/") == 0) { 95 /* Trying to mount root FS over root FS */ 96 fibril_rwlock_write_unlock(&namespace_rwlock); 97 async_answer_0(rid, EBUSY); 98 return EBUSY; 99 } 100 101 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL); 102 if (rc != EOK) { 103 /* The lookup failed for some reason. */ 104 fibril_rwlock_write_unlock(&namespace_rwlock); 105 async_answer_0(rid, rc); 106 return rc; 107 } 108 109 mp_node = vfs_node_get(&mp_res); 110 if (!mp_node) { 111 fibril_rwlock_write_unlock(&namespace_rwlock); 112 async_answer_0(rid, ENOMEM); 113 return ENOMEM; 114 } 115 116 /* 117 * Now we hold a reference to mp_node. 118 * It will be dropped upon the corresponding VFS_IN_UNMOUNT. 119 * This prevents the mount point from being deleted. 120 */ 121 } else { 129 130 if (root == NULL) { 122 131 /* We still don't have the root file system mounted. */ 123 if (str_cmp(mp, "/") == 0) { 124 /* 125 * For this simple, but important case, 126 * we are almost done. 127 */ 128 129 /* Tell the mountee that it is being mounted. */ 130 exch = vfs_exchange_grab(fs_handle); 131 msg = async_send_1(exch, VFS_OUT_MOUNTED, 132 (sysarg_t) service_id, &answer); 133 /* Send the mount options */ 134 rc = async_data_write_start(exch, (void *)opts, 135 str_size(opts)); 136 vfs_exchange_release(exch); 137 138 if (rc != EOK) { 139 async_forget(msg); 140 fibril_rwlock_write_unlock(&namespace_rwlock); 141 async_answer_0(rid, rc); 142 return rc; 143 } 144 async_wait_for(msg, &rc); 145 146 if (rc != EOK) { 147 fibril_rwlock_write_unlock(&namespace_rwlock); 148 async_answer_0(rid, rc); 149 return rc; 150 } 151 152 rindex = (fs_index_t) IPC_GET_ARG1(answer); 153 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), 154 IPC_GET_ARG3(answer)); 155 rlnkcnt = (unsigned) IPC_GET_ARG4(answer); 156 157 mr_res.triplet.fs_handle = fs_handle; 158 mr_res.triplet.service_id = service_id; 159 mr_res.triplet.index = rindex; 160 mr_res.size = rsize; 161 mr_res.lnkcnt = rlnkcnt; 162 mr_res.type = VFS_NODE_DIRECTORY; 163 164 rootfs.fs_handle = fs_handle; 165 rootfs.service_id = service_id; 166 167 /* Add reference to the mounted root. */ 168 mr_node = vfs_node_get(&mr_res); 169 assert(mr_node); 170 171 fibril_rwlock_write_unlock(&namespace_rwlock); 172 async_answer_0(rid, rc); 173 return rc; 174 } else { 132 if (str_cmp(mp, "/") != 0) { 175 133 /* 176 134 * We can't resolve this without the root filesystem 177 135 * being mounted first. 178 136 */ 179 fibril_rwlock_write_unlock(&namespace_rwlock);180 async_answer_0(rid, ENOENT);181 137 return ENOENT; 182 138 } 183 } 184 185 /* 186 * At this point, we have all necessary pieces: file system handle 187 * and service ID, and we know the mount point VFS node. 188 */ 189 190 async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle); 191 assert(mountee_exch); 192 193 exch = vfs_exchange_grab(mp_res.triplet.fs_handle); 194 msg = async_send_4(exch, VFS_OUT_MOUNT, 195 (sysarg_t) mp_res.triplet.service_id, 196 (sysarg_t) mp_res.triplet.index, 197 (sysarg_t) fs_handle, 198 (sysarg_t) service_id, &answer); 199 200 /* Send connection */ 201 rc = async_exchange_clone(exch, mountee_exch); 202 vfs_exchange_release(mountee_exch); 203 204 if (rc != EOK) { 205 vfs_exchange_release(exch); 206 async_forget(msg); 207 208 /* Mount failed, drop reference to mp_node. */ 209 if (mp_node) 210 vfs_node_put(mp_node); 211 212 async_answer_0(rid, rc); 213 fibril_rwlock_write_unlock(&namespace_rwlock); 139 140 return vfs_connect_internal(service_id, flags, instance, opts, fs_name, &root); 141 } 142 143 /* We already have the root FS. */ 144 if (str_cmp(mp, "/") == 0) { 145 /* Trying to mount root FS over root FS */ 146 return EBUSY; 147 } 148 149 vfs_lookup_res_t mp_res; 150 int rc = vfs_lookup_internal(root, mp, L_DIRECTORY, &mp_res); 151 if (rc != EOK) { 152 /* The lookup failed. */ 214 153 return rc; 215 154 } 216 155 217 /* send the mount options */ 218 rc = async_data_write_start(exch, (void *) opts, str_size(opts)); 219 if (rc != EOK) { 220 vfs_exchange_release(exch); 221 async_forget(msg); 222 223 /* Mount failed, drop reference to mp_node. */ 224 if (mp_node) 225 vfs_node_put(mp_node); 226 227 fibril_rwlock_write_unlock(&namespace_rwlock); 228 async_answer_0(rid, rc); 229 return rc; 230 } 231 232 /* 233 * Wait for the answer before releasing the exchange to avoid deadlock 234 * in case the answer depends on further calls to the same file system. 235 * Think of a case when mounting a FS on a file_bd backed by a file on 236 * the same FS. 237 */ 238 async_wait_for(msg, &rc); 239 vfs_exchange_release(exch); 240 241 if (rc == EOK) { 242 rindex = (fs_index_t) IPC_GET_ARG1(answer); 243 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), 244 IPC_GET_ARG3(answer)); 245 rlnkcnt = (unsigned) IPC_GET_ARG4(answer); 246 247 mr_res.triplet.fs_handle = fs_handle; 248 mr_res.triplet.service_id = service_id; 249 mr_res.triplet.index = rindex; 250 mr_res.size = rsize; 251 mr_res.lnkcnt = rlnkcnt; 252 mr_res.type = VFS_NODE_DIRECTORY; 253 254 /* Add reference to the mounted root. */ 255 mr_node = vfs_node_get(&mr_res); 256 assert(mr_node); 257 } else { 258 /* Mount failed, drop reference to mp_node. */ 259 if (mp_node) 260 vfs_node_put(mp_node); 261 } 262 263 async_answer_0(rid, rc); 264 fibril_rwlock_write_unlock(&namespace_rwlock); 265 return rc; 156 vfs_node_t *mp_node; 157 mp_node = vfs_node_get(&mp_res); 158 if (!mp_node) { 159 return ENOMEM; 160 } 161 162 if (mp_node->mount != NULL) { 163 return EBUSY; 164 } 165 166 if (mp_node->type != VFS_NODE_DIRECTORY) { 167 printf("%s node not a directory, type=%d\n", mp, mp_node->type); 168 return ENOTDIR; 169 } 170 171 if (vfs_node_has_children(mp_node)) { 172 return ENOTEMPTY; 173 } 174 175 vfs_node_t *mountee; 176 177 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, &mountee); 178 if (rc != EOK) { 179 vfs_node_put(mp_node); 180 return ENOMEM; 181 } 182 183 mp_node->mount = mountee; 184 /* The two references to nodes are held by the mount so that they cannot be freed. 185 * They are removed in detach_internal(). 186 */ 187 return EOK; 266 188 } 267 189 268 190 void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request) 269 191 { 270 service_id_t service_id;271 272 192 /* 273 193 * We expect the library to do the device-name to device-handle … … 275 195 * in the request. 276 196 */ 277 service_id = (service_id_t) IPC_GET_ARG1(*request);197 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request); 278 198 279 199 /* … … 301 221 0, NULL); 302 222 if (rc != EOK) { 223 async_answer_0(rid, rc); 303 224 free(mp); 304 async_answer_0(rid, rc);305 225 return; 306 226 } … … 314 234 FS_NAME_MAXLEN, 0, NULL); 315 235 if (rc != EOK) { 236 async_answer_0(rid, rc); 316 237 free(mp); 317 238 free(opts); 318 async_answer_0(rid, rc); 319 return; 320 } 321 322 /* 323 * Wait for VFS_IN_PING so that we can return an error if we don't know 324 * fs_name. 325 */ 326 ipc_call_t data; 327 ipc_callid_t callid = async_get_call(&data); 328 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 329 async_answer_0(callid, ENOTSUP); 330 async_answer_0(rid, ENOTSUP); 331 free(mp); 332 free(opts); 333 free(fs_name); 334 return; 335 } 336 337 /* 338 * Check if we know a file system with the same name as is in fs_name. 339 * This will also give us its file system handle. 340 */ 341 fibril_mutex_lock(&fs_list_lock); 342 fs_handle_t fs_handle; 343 recheck: 344 fs_handle = fs_name_to_handle(instance, fs_name, false); 345 if (!fs_handle) { 346 if (flags & IPC_FLAG_BLOCKING) { 347 fibril_condvar_wait(&fs_list_cv, &fs_list_lock); 348 goto recheck; 349 } 350 351 fibril_mutex_unlock(&fs_list_lock); 352 async_answer_0(callid, ENOENT); 353 async_answer_0(rid, ENOENT); 354 free(mp); 355 free(fs_name); 356 free(opts); 357 return; 358 } 359 fibril_mutex_unlock(&fs_list_lock); 360 239 return; 240 } 241 361 242 /* Add the filesystem info to the list of mounted filesystems */ 362 243 mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t)); 363 244 if (!mtab_ent) { 364 async_answer_0(callid, ENOMEM);365 245 async_answer_0(rid, ENOMEM); 366 246 free(mp); … … 369 249 return; 370 250 } 371 372 /* Do the mount */ 373 rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts); 374 if (rc != EOK) { 375 async_answer_0(callid, ENOTSUP); 376 async_answer_0(rid, ENOTSUP); 377 free(mtab_ent); 378 free(mp); 379 free(opts); 380 free(fs_name); 381 return; 382 } 251 252 /* Mount the filesystem. */ 253 fibril_rwlock_write_lock(&namespace_rwlock); 254 rc = vfs_mount_internal(service_id, flags, instance, opts, fs_name, mp); 255 fibril_rwlock_write_unlock(&namespace_rwlock); 383 256 384 257 /* Add the filesystem info to the list of mounted filesystems */ 385 386 str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp); 387 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name); 388 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts); 389 mtab_ent->instance = instance; 390 mtab_ent->service_id = service_id; 391 392 link_initialize(&mtab_ent->link); 393 394 fibril_mutex_lock(&mtab_list_lock); 395 list_append(&mtab_ent->link, &mtab_list); 396 mtab_size++; 397 fibril_mutex_unlock(&mtab_list_lock); 258 if (rc == EOK) { 259 str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp); 260 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name); 261 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts); 262 mtab_ent->instance = instance; 263 mtab_ent->service_id = service_id; 264 265 link_initialize(&mtab_ent->link); 266 267 fibril_mutex_lock(&mtab_list_lock); 268 list_append(&mtab_ent->link, &mtab_list); 269 mtab_size++; 270 fibril_mutex_unlock(&mtab_list_lock); 271 } 272 273 async_answer_0(rid, rc); 398 274 399 275 free(mp); 400 276 free(fs_name); 401 277 free(opts); 402 403 /* Acknowledge that we know fs_name. */404 async_answer_0(callid, EOK);405 278 } 406 279 407 280 void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request) 408 281 { 409 int rc; 282 /* 283 * Receive the mount point path. 284 */ 410 285 char *mp; 411 vfs_lookup_res_t mp_res; 412 vfs_lookup_res_t mr_res; 413 vfs_node_t *mr_node; 414 async_exch_t *exch; 415 416 /* 417 * Receive the mount point path. 418 */ 419 rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN, 286 int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN, 420 287 0, NULL); 421 288 if (rc != EOK) … … 431 298 */ 432 299 fibril_rwlock_write_lock(&namespace_rwlock); 433 434 /* 435 * Lookup the mounted root and instantiate it. 436 */ 437 rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL); 438 if (rc != EOK) { 439 fibril_rwlock_write_unlock(&namespace_rwlock); 300 301 if (str_cmp(mp, "/") == 0) { 440 302 free(mp); 441 async_answer_0(rid, rc);442 return;443 }444 mr_node = vfs_node_get(&mr_res);445 if (!mr_node) {446 fibril_rwlock_write_unlock(&namespace_rwlock);447 free(mp);448 async_answer_0(rid, ENOMEM);449 return;450 }451 452 /*453 * Count the total number of references for the mounted file system. We454 * are expecting at least two. One which we got above and one which we455 * got when the file system was mounted. If we find more, it means that456 * the file system cannot be gracefully unmounted at the moment because457 * someone is working with it.458 */459 if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,460 mr_node->service_id) != 2) {461 fibril_rwlock_write_unlock(&namespace_rwlock);462 vfs_node_put(mr_node);463 free(mp);464 async_answer_0(rid, EBUSY);465 return;466 }467 468 if (str_cmp(mp, "/") == 0) {469 303 470 304 /* … … 475 309 */ 476 310 477 exch = vfs_exchange_grab(mr_node->fs_handle); 478 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, 479 mr_node->service_id); 311 if (!root) { 312 fibril_rwlock_write_unlock(&namespace_rwlock); 313 async_answer_0(rid, ENOENT); 314 return; 315 } 316 317 /* 318 * Count the total number of references for the mounted file system. We 319 * are expecting at least one, which we got when the file system was mounted. 320 * If we find more, it means that 321 * the file system cannot be gracefully unmounted at the moment because 322 * someone is working with it. 323 */ 324 if (vfs_nodes_refcount_sum_get(root->fs_handle, root->service_id) != 1) { 325 fibril_rwlock_write_unlock(&namespace_rwlock); 326 async_answer_0(rid, EBUSY); 327 return; 328 } 329 330 async_exch_t *exch = vfs_exchange_grab(root->fs_handle); 331 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, root->service_id); 480 332 vfs_exchange_release(exch); 481 333 482 if (rc != EOK) { 483 fibril_rwlock_write_unlock(&namespace_rwlock); 484 free(mp); 485 vfs_node_put(mr_node); 486 async_answer_0(rid, rc); 487 return; 488 } 489 490 rootfs.fs_handle = 0; 491 rootfs.service_id = 0; 492 } else { 493 494 /* 495 * Unmounting a non-root file system. 496 * 497 * We have a regular mount point node representing the parent 498 * file system, so we delegate the operation to it. 499 */ 500 501 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL); 502 if (rc != EOK) { 503 fibril_rwlock_write_unlock(&namespace_rwlock); 504 free(mp); 505 vfs_node_put(mr_node); 506 async_answer_0(rid, rc); 507 return; 508 } 509 510 vfs_node_t *mp_node = vfs_node_get(&mp_res); 511 if (!mp_node) { 512 fibril_rwlock_write_unlock(&namespace_rwlock); 513 free(mp); 514 vfs_node_put(mr_node); 515 async_answer_0(rid, ENOMEM); 516 return; 517 } 518 519 exch = vfs_exchange_grab(mp_node->fs_handle); 520 rc = async_req_2_0(exch, VFS_OUT_UNMOUNT, 521 mp_node->service_id, mp_node->index); 522 vfs_exchange_release(exch); 523 524 if (rc != EOK) { 525 fibril_rwlock_write_unlock(&namespace_rwlock); 526 free(mp); 527 vfs_node_put(mp_node); 528 vfs_node_put(mr_node); 529 async_answer_0(rid, rc); 530 return; 531 } 532 533 /* Drop the reference we got above. */ 334 fibril_rwlock_write_unlock(&namespace_rwlock); 335 if (rc == EOK) { 336 vfs_node_forget(root); 337 root = NULL; 338 } 339 async_answer_0(rid, rc); 340 return; 341 } 342 343 /* 344 * Lookup the mounted root and instantiate it. 345 */ 346 vfs_lookup_res_t mp_res; 347 rc = vfs_lookup_internal(root, mp, L_MP, &mp_res); 348 if (rc != EOK) { 349 fibril_rwlock_write_unlock(&namespace_rwlock); 350 free(mp); 351 async_answer_0(rid, rc); 352 return; 353 } 354 vfs_node_t *mp_node = vfs_node_get(&mp_res); 355 if (!mp_node) { 356 fibril_rwlock_write_unlock(&namespace_rwlock); 357 free(mp); 358 async_answer_0(rid, ENOMEM); 359 return; 360 } 361 362 if (mp_node->mount == NULL) { 363 fibril_rwlock_write_unlock(&namespace_rwlock); 534 364 vfs_node_put(mp_node); 535 /* Drop the reference from when the file system was mounted. */ 365 free(mp); 366 async_answer_0(rid, ENOENT); 367 return; 368 } 369 370 /* 371 * Count the total number of references for the mounted file system. We 372 * are expecting at least one, which we got when the file system was mounted. 373 * If we find more, it means that 374 * the file system cannot be gracefully unmounted at the moment because 375 * someone is working with it. 376 */ 377 if (vfs_nodes_refcount_sum_get(mp_node->mount->fs_handle, mp_node->mount->service_id) != 1) { 378 fibril_rwlock_write_unlock(&namespace_rwlock); 536 379 vfs_node_put(mp_node); 537 } 538 539 /* 540 * All went well, the mounted file system was successfully unmounted. 541 * The only thing left is to forget the unmounted root VFS node. 542 */ 543 vfs_node_forget(mr_node); 380 free(mp); 381 async_answer_0(rid, EBUSY); 382 return; 383 } 384 385 /* Unmount the filesystem. */ 386 async_exch_t *exch = vfs_exchange_grab(mp_node->mount->fs_handle); 387 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, mp_node->mount->service_id); 388 vfs_exchange_release(exch); 389 390 vfs_node_forget(mp_node->mount); 391 mp_node->mount = NULL; 392 393 vfs_node_put(mp_node); 544 394 fibril_rwlock_write_unlock(&namespace_rwlock); 545 395 546 396 fibril_mutex_lock(&mtab_list_lock); 547 548 397 int found = 0; 549 398 … … 560 409 fibril_mutex_unlock(&mtab_list_lock); 561 410 562 free(mp); 563 411 free(mp); 412 564 413 async_answer_0(rid, EOK); 565 } 566 567 void vfs_open(ipc_callid_t rid, ipc_call_t *request) 568 { 569 /* 570 * The POSIX interface is open(path, oflag, mode). 571 * We can receive oflags and mode along with the VFS_IN_OPEN call; 572 * the path will need to arrive in another call. 573 * 574 * We also receive one private, non-POSIX set of flags called lflag 575 * used to pass information to vfs_lookup_internal(). 576 */ 577 int lflag = IPC_GET_ARG1(*request); 578 int oflag = IPC_GET_ARG2(*request); 579 int mode = IPC_GET_ARG3(*request); 580 581 /* Ignore mode for now. */ 582 (void) mode; 583 584 /* 585 * Make sure that we are called with exactly one of L_FILE and 586 * L_DIRECTORY. Make sure that the user does not pass L_OPEN, 587 * L_ROOT or L_MP. 588 */ 589 if (((lflag & (L_FILE | L_DIRECTORY)) == 0) || 590 ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) || 591 (lflag & (L_OPEN | L_ROOT | L_MP))) { 414 return; 415 } 416 417 static inline bool walk_flags_valid(int flags) 418 { 419 if ((flags&~WALK_ALL_FLAGS) != 0) { 420 return false; 421 } 422 if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) { 423 return false; 424 } 425 if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) { 426 return false; 427 } 428 if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) { 429 if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) { 430 return false; 431 } 432 } 433 return true; 434 } 435 436 static inline int walk_lookup_flags(int flags) 437 { 438 int lflags = 0; 439 if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) { 440 lflags |= L_CREATE; 441 } 442 if (flags&WALK_MUST_CREATE) { 443 lflags |= L_EXCLUSIVE; 444 } 445 if (flags&WALK_REGULAR) { 446 lflags |= L_FILE; 447 } 448 if (flags&WALK_DIRECTORY) { 449 lflags |= L_DIRECTORY; 450 } 451 return lflags; 452 } 453 454 void vfs_walk(ipc_callid_t rid, ipc_call_t *request) 455 { 456 /* 457 * Parent is our relative root for file lookup. 458 * For defined flags, see <ipc/vfs.h>. 459 */ 460 int parentfd = IPC_GET_ARG1(*request); 461 int flags = IPC_GET_ARG2(*request); 462 463 if (!walk_flags_valid(flags)) { 592 464 async_answer_0(rid, EINVAL); 593 465 return; 594 466 } 595 467 596 if (oflag & O_CREAT)597 lflag |= L_CREATE;598 if (oflag & O_EXCL)599 lflag |= L_EXCLUSIVE;600 601 468 char *path; 602 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 603 if (rc != EOK) { 469 int rc = async_data_write_accept((void **)&path, true, 0, 0, 0, NULL); 470 471 /* Lookup the file structure corresponding to the file descriptor. */ 472 vfs_file_t *parent = NULL; 473 vfs_node_t *parent_node = root; 474 // TODO: Client-side root. 475 if (parentfd != -1) { 476 parent = vfs_file_get(parentfd); 477 if (!parent) { 478 free(path); 479 async_answer_0(rid, EBADF); 480 return; 481 } 482 parent_node = parent->node; 483 } 484 485 fibril_rwlock_read_lock(&namespace_rwlock); 486 487 vfs_lookup_res_t lr; 488 rc = vfs_lookup_internal(parent_node, path, walk_lookup_flags(flags), &lr); 489 free(path); 490 491 if (rc != EOK) { 492 fibril_rwlock_read_unlock(&namespace_rwlock); 493 if (parent) { 494 vfs_file_put(parent); 495 } 604 496 async_answer_0(rid, rc); 605 497 return; 606 498 } 607 499 608 /*609 * Avoid the race condition in which the file can be deleted before we610 * find/create-and-lock the VFS node corresponding to the looked-up611 * triplet.612 */613 if (lflag & L_CREATE)614 fibril_rwlock_write_lock(&namespace_rwlock);615 else616 fibril_rwlock_read_lock(&namespace_rwlock);617 618 /* The path is now populated and we can call vfs_lookup_internal(). */619 vfs_lookup_res_t lr;620 rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);621 if (rc != EOK) {622 if (lflag & L_CREATE)623 fibril_rwlock_write_unlock(&namespace_rwlock);624 else625 fibril_rwlock_read_unlock(&namespace_rwlock);626 async_answer_0(rid, rc);627 free(path);628 return;629 }630 631 /* Path is no longer needed. */632 free(path);633 634 500 vfs_node_t *node = vfs_node_get(&lr); 635 if (lflag & L_CREATE) 636 fibril_rwlock_write_unlock(&namespace_rwlock); 637 else 638 fibril_rwlock_read_unlock(&namespace_rwlock); 639 640 if (!node) { 641 async_answer_0(rid, ENOMEM); 642 return; 643 } 644 645 /* Truncate the file if requested and if necessary. */ 646 if (oflag & O_TRUNC) { 647 fibril_rwlock_write_lock(&node->contents_rwlock); 648 if (node->size) { 649 rc = vfs_truncate_internal(node->fs_handle, 650 node->service_id, node->index, 0); 651 if (rc) { 652 fibril_rwlock_write_unlock(&node->contents_rwlock); 653 vfs_node_put(node); 654 async_answer_0(rid, rc); 655 return; 656 } 657 node->size = 0; 658 } 659 fibril_rwlock_write_unlock(&node->contents_rwlock); 660 } 661 662 /* 663 * Get ourselves a file descriptor and the corresponding vfs_file_t 664 * structure. 665 */ 666 int fd = vfs_fd_alloc((oflag & O_DESC) != 0); 501 502 int fd = vfs_fd_alloc(false); 667 503 if (fd < 0) { 668 504 vfs_node_put(node); 505 if (parent) { 506 vfs_file_put(parent); 507 } 669 508 async_answer_0(rid, fd); 670 509 return; 671 510 } 511 672 512 vfs_file_t *file = vfs_file_get(fd); 673 assert(file); 513 assert(file != NULL); 514 674 515 file->node = node; 675 if (oflag & O_APPEND) 676 file->append = true; 677 678 /* 679 * The following increase in reference count is for the fact that the 680 * file is being opened and that a file structure is pointing to it. 681 * It is necessary so that the file will not disappear when 682 * vfs_node_put() is called. The reference will be dropped by the 683 * respective VFS_IN_CLOSE. 684 */ 685 vfs_node_addref(node); 686 vfs_node_put(node); 516 if (parent) { 517 file->permissions = parent->permissions; 518 } else { 519 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND; 520 } 521 file->open_read = false; 522 file->open_write = false; 523 687 524 vfs_file_put(file); 688 689 /* Success! Return the new file descriptor to the client. */ 525 if (parent) { 526 vfs_file_put(parent); 527 } 528 529 fibril_rwlock_read_unlock(&namespace_rwlock); 530 690 531 async_answer_1(rid, EOK, fd); 532 } 533 534 void vfs_open2(ipc_callid_t rid, ipc_call_t *request) 535 { 536 int fd = IPC_GET_ARG1(*request); 537 int flags = IPC_GET_ARG2(*request); 538 539 if (flags == 0) { 540 async_answer_0(rid, EINVAL); 541 return; 542 } 543 544 vfs_file_t *file = vfs_file_get(fd); 545 if (!file) { 546 async_answer_0(rid, EBADF); 547 return; 548 } 549 550 if ((flags & ~file->permissions) != 0) { 551 vfs_file_put(file); 552 async_answer_0(rid, EPERM); 553 return; 554 } 555 556 file->open_read = (flags & MODE_READ) != 0; 557 file->open_write = (flags & (MODE_WRITE | MODE_APPEND)) != 0; 558 file->append = (flags & MODE_APPEND) != 0; 559 560 if (!file->open_read && !file->open_write) { 561 vfs_file_put(file); 562 async_answer_0(rid, EINVAL); 563 return; 564 } 565 566 if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) { 567 file->open_read = file->open_write = false; 568 vfs_file_put(file); 569 async_answer_0(rid, EINVAL); 570 return; 571 } 572 573 int rc = vfs_open_node_remote(file->node); 574 if (rc != EOK) { 575 file->open_read = file->open_write = false; 576 vfs_file_put(file); 577 async_answer_0(rid, rc); 578 return; 579 } 580 581 vfs_file_put(file); 582 async_answer_0(rid, EOK); 691 583 } 692 584 … … 816 708 fibril_mutex_lock(&file->lock); 817 709 710 if ((read && !file->open_read) || (!read && !file->open_write)) { 711 fibril_mutex_unlock(&file->lock); 712 return EINVAL; 713 } 714 818 715 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle); 819 716 assert(fs_info); … … 854 751 size_t bytes = IPC_GET_ARG1(answer); 855 752 856 if (file->node->type == VFS_NODE_DIRECTORY) 753 if (file->node->type == VFS_NODE_DIRECTORY) { 857 754 fibril_rwlock_read_unlock(&namespace_rwlock); 755 } 858 756 859 757 /* Unlock the VFS node. */ … … 953 851 case SEEK_END: 954 852 fibril_rwlock_read_lock(&file->node->contents_rwlock); 955 aoff64_t size = file->node->size;853 aoff64_t size = vfs_node_get_size(file->node); 956 854 957 855 if ((off >= 0) && (size + off < size)) { … … 1061 959 } 1062 960 1063 void vfs_stat(ipc_callid_t rid, ipc_call_t *request) 1064 { 961 static void out_destroy(vfs_triplet_t *file) 962 { 963 async_exch_t *exch = vfs_exchange_grab(file->fs_handle); 964 async_msg_2(exch, VFS_OUT_DESTROY, 965 (sysarg_t) file->service_id, (sysarg_t) file->index); 966 vfs_exchange_release(exch); 967 } 968 969 void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request) 970 { 971 int rc; 1065 972 char *path; 1066 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 973 vfs_file_t *parent = NULL; 974 vfs_file_t *expect = NULL; 975 vfs_node_t *parent_node = root; 976 977 int parentfd = IPC_GET_ARG1(*request); 978 int expectfd = IPC_GET_ARG2(*request); 979 int wflag = IPC_GET_ARG3(*request); 980 981 rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1067 982 if (rc != EOK) { 1068 983 async_answer_0(rid, rc); … … 1070 985 } 1071 986 1072 ipc_callid_t callid; 1073 if (!async_data_read_receive(&callid, NULL)) { 987 fibril_rwlock_write_lock(&namespace_rwlock); 988 989 int lflag = (wflag&WALK_DIRECTORY) ? L_DIRECTORY: 0; 990 991 if (parentfd >= 0) { 992 parent = vfs_file_get(parentfd); 993 if (!parent) { 994 rc = ENOENT; 995 goto exit; 996 } 997 parent_node = parent->node; 998 } 999 1000 if (expectfd >= 0) { 1001 expect = vfs_file_get(expectfd); 1002 if (!expect) { 1003 rc = ENOENT; 1004 goto exit; 1005 } 1006 1007 vfs_lookup_res_t lr; 1008 rc = vfs_lookup_internal(parent_node, path, lflag, &lr); 1009 if (rc != EOK) { 1010 goto exit; 1011 } 1012 1013 if (__builtin_memcmp(&lr.triplet, expect->node, sizeof(vfs_triplet_t)) != 0) { 1014 rc = ENOENT; 1015 goto exit; 1016 } 1017 1018 vfs_file_put(expect); 1019 expect = NULL; 1020 } 1021 1022 vfs_lookup_res_t lr; 1023 rc = vfs_lookup_internal(parent_node, path, lflag | L_UNLINK, &lr); 1024 if (rc != EOK) { 1025 goto exit; 1026 } 1027 1028 /* If the node is not held by anyone, try to destroy it. */ 1029 if (vfs_node_peek(&lr) == NULL) { 1030 out_destroy(&lr.triplet); 1031 } 1032 1033 exit: 1034 if (path) { 1074 1035 free(path); 1075 async_answer_0(callid, EINVAL); 1076 async_answer_0(rid, EINVAL); 1077 return; 1078 } 1079 1080 vfs_lookup_res_t lr; 1081 fibril_rwlock_read_lock(&namespace_rwlock); 1082 rc = vfs_lookup_internal(path, L_NONE, &lr, NULL); 1083 free(path); 1084 if (rc != EOK) { 1085 fibril_rwlock_read_unlock(&namespace_rwlock); 1086 async_answer_0(callid, rc); 1087 async_answer_0(rid, rc); 1088 return; 1089 } 1090 vfs_node_t *node = vfs_node_get(&lr); 1091 if (!node) { 1092 fibril_rwlock_read_unlock(&namespace_rwlock); 1093 async_answer_0(callid, ENOMEM); 1094 async_answer_0(rid, ENOMEM); 1095 return; 1096 } 1097 1098 fibril_rwlock_read_unlock(&namespace_rwlock); 1099 1100 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 1101 1102 aid_t msg; 1103 msg = async_send_3(exch, VFS_OUT_STAT, node->service_id, 1104 node->index, false, NULL); 1105 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 1106 1107 vfs_exchange_release(exch); 1108 1109 sysarg_t rv; 1110 async_wait_for(msg, &rv); 1111 1112 async_answer_0(rid, rv); 1113 1114 vfs_node_put(node); 1115 } 1116 1117 void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request) 1118 { 1119 int mode = IPC_GET_ARG1(*request); 1120 1121 char *path; 1122 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1123 if (rc != EOK) { 1124 async_answer_0(rid, rc); 1125 return; 1126 } 1127 1128 /* Ignore mode for now. */ 1129 (void) mode; 1036 } 1037 if (parent) { 1038 vfs_file_put(parent); 1039 } 1040 if (expect) { 1041 vfs_file_put(expect); 1042 } 1043 fibril_rwlock_write_unlock(&namespace_rwlock); 1044 async_answer_0(rid, rc); 1045 } 1046 1047 static size_t shared_path(char *a, char *b) 1048 { 1049 size_t res = 0; 1050 1051 while (a[res] == b[res] && a[res] != 0) { 1052 res++; 1053 } 1054 1055 if (a[res] == b[res]) { 1056 return res; 1057 } 1058 1059 res--; 1060 while (a[res] != '/') { 1061 res--; 1062 } 1063 return res; 1064 } 1065 1066 static int vfs_rename_internal(vfs_node_t *base, char *old, char *new) 1067 { 1068 assert(base != NULL); 1069 assert(old != NULL); 1070 assert(new != NULL); 1071 1072 vfs_lookup_res_t base_lr; 1073 vfs_lookup_res_t old_lr; 1074 vfs_lookup_res_t new_lr_orig; 1075 bool orig_unlinked = false; 1076 1077 int rc; 1078 1079 size_t shared = shared_path(old, new); 1080 1081 /* Do not allow one path to be a prefix of the other. */ 1082 if (old[shared] == 0 || new[shared] == 0) { 1083 return EINVAL; 1084 } 1085 assert(old[shared] == '/'); 1086 assert(new[shared] == '/'); 1130 1087 1131 1088 fibril_rwlock_write_lock(&namespace_rwlock); 1132 int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE; 1133 rc = vfs_lookup_internal(path, lflag, NULL, NULL); 1089 1090 /* Resolve the shared portion of the path first. */ 1091 if (shared != 0) { 1092 old[shared] = 0; 1093 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr); 1094 if (rc != EOK) { 1095 fibril_rwlock_write_unlock(&namespace_rwlock); 1096 return rc; 1097 } 1098 1099 base = vfs_node_get(&base_lr); 1100 old[shared] = '/'; 1101 old += shared; 1102 new += shared; 1103 } else { 1104 vfs_node_addref(base); 1105 } 1106 1107 1108 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, &new_lr_orig); 1109 if (rc == EOK) { 1110 orig_unlinked = true; 1111 } else if (rc != ENOENT) { 1112 vfs_node_put(base); 1113 fibril_rwlock_write_unlock(&namespace_rwlock); 1114 return rc; 1115 } 1116 1117 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, &old_lr); 1118 if (rc != EOK) { 1119 if (orig_unlinked) { 1120 vfs_link_internal(base, new, &new_lr_orig.triplet); 1121 } 1122 vfs_node_put(base); 1123 fibril_rwlock_write_unlock(&namespace_rwlock); 1124 return rc; 1125 } 1126 1127 rc = vfs_link_internal(base, new, &old_lr.triplet); 1128 if (rc != EOK) { 1129 vfs_link_internal(base, old, &old_lr.triplet); 1130 if (orig_unlinked) { 1131 vfs_link_internal(base, new, &new_lr_orig.triplet); 1132 } 1133 vfs_node_put(base); 1134 fibril_rwlock_write_unlock(&namespace_rwlock); 1135 return rc; 1136 } 1137 1138 /* If the node is not held by anyone, try to destroy it. */ 1139 if (orig_unlinked && vfs_node_peek(&new_lr_orig) == NULL) { 1140 out_destroy(&new_lr_orig.triplet); 1141 } 1142 1143 vfs_node_put(base); 1134 1144 fibril_rwlock_write_unlock(&namespace_rwlock); 1135 free(path); 1136 async_answer_0(rid, rc); 1137 } 1138 1139 void vfs_unlink(ipc_callid_t rid, ipc_call_t *request) 1140 { 1141 int lflag = IPC_GET_ARG1(*request); 1142 1143 char *path; 1144 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1145 if (rc != EOK) { 1146 async_answer_0(rid, rc); 1147 return; 1148 } 1149 1150 fibril_rwlock_write_lock(&namespace_rwlock); 1151 lflag &= L_DIRECTORY; /* sanitize lflag */ 1152 vfs_lookup_res_t lr; 1153 rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL); 1154 free(path); 1155 if (rc != EOK) { 1156 fibril_rwlock_write_unlock(&namespace_rwlock); 1157 async_answer_0(rid, rc); 1158 return; 1159 } 1160 1161 /* 1162 * The name has already been unlinked by vfs_lookup_internal(). 1163 * We have to get and put the VFS node to ensure that it is 1164 * VFS_OUT_DESTROY'ed after the last reference to it is dropped. 1165 */ 1166 vfs_node_t *node = vfs_node_get(&lr); 1167 fibril_mutex_lock(&nodes_mutex); 1168 node->lnkcnt--; 1169 fibril_mutex_unlock(&nodes_mutex); 1170 fibril_rwlock_write_unlock(&namespace_rwlock); 1171 vfs_node_put(node); 1172 async_answer_0(rid, EOK); 1145 return EOK; 1173 1146 } 1174 1147 1175 1148 void vfs_rename(ipc_callid_t rid, ipc_call_t *request) 1176 1149 { 1150 /* The common base directory. */ 1151 int basefd; 1152 char *old = NULL; 1153 char *new = NULL; 1154 vfs_file_t *base = NULL; 1155 int rc; 1156 1157 basefd = IPC_GET_ARG1(*request); 1158 1177 1159 /* Retrieve the old path. */ 1178 char *old; 1179 int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1180 if (rc != EOK) { 1181 async_answer_0(rid, rc); 1182 return; 1160 rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1161 if (rc != EOK) { 1162 goto out; 1183 1163 } 1184 1164 1185 1165 /* Retrieve the new path. */ 1186 char *new;1187 1166 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL); 1188 1167 if (rc != EOK) { 1189 free(old); 1190 async_answer_0(rid, rc); 1191 return; 1168 goto out; 1192 1169 } 1193 1170 … … 1198 1175 1199 1176 if ((!oldc) || (!newc)) { 1200 async_answer_0(rid, EINVAL); 1177 rc = EINVAL; 1178 goto out; 1179 } 1180 1181 assert(oldc[olen] == '\0'); 1182 assert(newc[nlen] == '\0'); 1183 1184 /* Lookup the file structure corresponding to the file descriptor. */ 1185 vfs_node_t *base_node = root; 1186 // TODO: Client-side root. 1187 if (basefd != -1) { 1188 base = vfs_file_get(basefd); 1189 if (!base) { 1190 rc = EBADF; 1191 goto out; 1192 } 1193 base_node = base->node; 1194 } 1195 1196 rc = vfs_rename_internal(base_node, oldc, newc); 1197 1198 out: 1199 async_answer_0(rid, rc); 1200 1201 if (old) { 1201 1202 free(old); 1203 } 1204 if (new) { 1202 1205 free(new); 1203 return; 1204 } 1205 1206 oldc[olen] = '\0'; 1207 newc[nlen] = '\0'; 1208 1209 if ((!str_lcmp(newc, oldc, str_length(oldc))) && 1210 ((newc[str_length(oldc)] == '/') || 1211 (str_length(oldc) == 1) || 1212 (str_length(oldc) == str_length(newc)))) { 1213 /* 1214 * oldc is a prefix of newc and either 1215 * - newc continues with a / where oldc ends, or 1216 * - oldc was / itself, or 1217 * - oldc and newc are equal. 1218 */ 1219 async_answer_0(rid, EINVAL); 1220 free(old); 1221 free(new); 1222 return; 1223 } 1224 1225 vfs_lookup_res_t old_lr; 1226 vfs_lookup_res_t new_lr; 1227 vfs_lookup_res_t new_par_lr; 1228 fibril_rwlock_write_lock(&namespace_rwlock); 1229 1230 /* Lookup the node belonging to the old file name. */ 1231 rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL); 1232 if (rc != EOK) { 1233 fibril_rwlock_write_unlock(&namespace_rwlock); 1234 async_answer_0(rid, rc); 1235 free(old); 1236 free(new); 1237 return; 1238 } 1239 1240 vfs_node_t *old_node = vfs_node_get(&old_lr); 1241 if (!old_node) { 1242 fibril_rwlock_write_unlock(&namespace_rwlock); 1243 async_answer_0(rid, ENOMEM); 1244 free(old); 1245 free(new); 1246 return; 1247 } 1248 1249 /* Determine the path to the parent of the node with the new name. */ 1250 char *parentc = str_dup(newc); 1251 if (!parentc) { 1252 fibril_rwlock_write_unlock(&namespace_rwlock); 1253 vfs_node_put(old_node); 1254 async_answer_0(rid, rc); 1255 free(old); 1256 free(new); 1257 return; 1258 } 1259 1260 char *lastsl = str_rchr(parentc + 1, '/'); 1261 if (lastsl) 1262 *lastsl = '\0'; 1263 else 1264 parentc[1] = '\0'; 1265 1266 /* Lookup parent of the new file name. */ 1267 rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL); 1268 free(parentc); /* not needed anymore */ 1269 if (rc != EOK) { 1270 fibril_rwlock_write_unlock(&namespace_rwlock); 1271 vfs_node_put(old_node); 1272 async_answer_0(rid, rc); 1273 free(old); 1274 free(new); 1275 return; 1276 } 1277 1278 /* Check whether linking to the same file system instance. */ 1279 if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) || 1280 (old_node->service_id != new_par_lr.triplet.service_id)) { 1281 fibril_rwlock_write_unlock(&namespace_rwlock); 1282 vfs_node_put(old_node); 1283 async_answer_0(rid, EXDEV); /* different file systems */ 1284 free(old); 1285 free(new); 1286 return; 1287 } 1288 1289 /* Destroy the old link for the new name. */ 1290 vfs_node_t *new_node = NULL; 1291 rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL); 1292 1293 switch (rc) { 1294 case ENOENT: 1295 /* simply not in our way */ 1296 break; 1297 case EOK: 1298 new_node = vfs_node_get(&new_lr); 1299 if (!new_node) { 1300 fibril_rwlock_write_unlock(&namespace_rwlock); 1301 vfs_node_put(old_node); 1302 async_answer_0(rid, ENOMEM); 1303 free(old); 1304 free(new); 1305 return; 1306 } 1307 fibril_mutex_lock(&nodes_mutex); 1308 new_node->lnkcnt--; 1309 fibril_mutex_unlock(&nodes_mutex); 1310 break; 1311 default: 1312 fibril_rwlock_write_unlock(&namespace_rwlock); 1313 vfs_node_put(old_node); 1314 async_answer_0(rid, ENOTEMPTY); 1315 free(old); 1316 free(new); 1317 return; 1318 } 1319 1320 /* Create the new link for the new name. */ 1321 rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index); 1322 if (rc != EOK) { 1323 fibril_rwlock_write_unlock(&namespace_rwlock); 1324 vfs_node_put(old_node); 1325 if (new_node) 1326 vfs_node_put(new_node); 1327 async_answer_0(rid, rc); 1328 free(old); 1329 free(new); 1330 return; 1331 } 1332 1333 fibril_mutex_lock(&nodes_mutex); 1334 old_node->lnkcnt++; 1335 fibril_mutex_unlock(&nodes_mutex); 1336 1337 /* Destroy the link for the old name. */ 1338 rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL); 1339 if (rc != EOK) { 1340 fibril_rwlock_write_unlock(&namespace_rwlock); 1341 vfs_node_put(old_node); 1342 if (new_node) 1343 vfs_node_put(new_node); 1344 async_answer_0(rid, rc); 1345 free(old); 1346 free(new); 1347 return; 1348 } 1349 1350 fibril_mutex_lock(&nodes_mutex); 1351 old_node->lnkcnt--; 1352 fibril_mutex_unlock(&nodes_mutex); 1353 fibril_rwlock_write_unlock(&namespace_rwlock); 1354 vfs_node_put(old_node); 1355 1356 if (new_node) 1357 vfs_node_put(new_node); 1358 1359 free(old); 1360 free(new); 1361 async_answer_0(rid, EOK); 1206 } 1207 if (base) { 1208 vfs_file_put(base); 1209 } 1362 1210 } 1363 1211 … … 1487 1335 vfs_lookup_res_t lr; 1488 1336 fibril_rwlock_read_lock(&namespace_rwlock); 1489 rc = vfs_lookup_internal( path, L_NONE, &lr, NULL);1337 rc = vfs_lookup_internal(root, path, L_NONE, &lr); 1490 1338 free(path); 1491 1339 if (rc != EOK) {
Note:
See TracChangeset
for help on using the changeset viewer.