Changes in / [1dff985:5b46ec8] in mainline
- Location:
- uspace
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/trace/trace.c
r1dff985 r5b46ec8 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); 698 700 o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def); 699 701 proto_add_oper(p, VFS_IN_READ, o); … … 714 716 o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def); 715 717 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); 716 722 o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def); 717 723 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); 718 726 o = oper_new("statfs", 0, arg_def, V_ERRNO, 0, resp_def); 719 727 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);726 728 727 729 proto_register(SERVICE_VFS, p); -
uspace/lib/c/generic/vfs/vfs.c
r1dff985 r5b46ec8 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 127 95 char *vfs_absolutize(const char *path, size_t *retlen) 128 96 { … … 261 229 } 262 230 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 else 244 return (int) rc_orig; 245 } 246 263 247 vfs_exchange_end(exch); 264 248 free(mpa); … … 305 289 } 306 290 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; 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; 318 330 } 319 331 … … 329 341 int open(const char *path, int oflag, ...) 330 342 { 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 338 343 size_t abs_size; 339 344 char *abs = vfs_absolutize(path, &abs_size); 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; 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; 371 361 } 372 362 … … 680 670 int stat(const char *path, struct stat *stat) 681 671 { 672 sysarg_t rc; 673 sysarg_t rc_orig; 674 aid_t req; 675 682 676 size_t pa_size; 683 677 char *pa = vfs_absolutize(path, &pa_size); 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; 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; 696 718 } 697 719 … … 705 727 { 706 728 DIR *dirp = malloc(sizeof(DIR)); 707 if (!dirp) { 729 int fd = -1; 730 731 if (dirp == NULL) { 708 732 errno = ENOMEM; 709 733 return NULL; … … 718 742 } 719 743 720 int r et = _vfs_walk(-1, abs, WALK_DIRECTORY);744 int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd); 721 745 free(abs); 722 746 723 if (r et <EOK) {747 if (rc != EOK) { 724 748 free(dirp); 725 errno = r et;749 errno = rc; 726 750 return NULL; 727 751 } 728 752 729 int rc = _vfs_open(ret, MODE_READ); 730 if (rc < 0) { 731 free(dirp); 732 close(ret); 733 errno = rc; 734 return NULL; 735 } 736 737 dirp->fd = ret; 753 dirp->fd = fd; 738 754 return dirp; 739 755 } … … 793 809 int mkdir(const char *path, mode_t mode) 794 810 { 811 sysarg_t rc; 812 aid_t req; 813 795 814 size_t pa_size; 796 815 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) 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) 811 862 { 812 863 sysarg_t rc; 813 864 aid_t req; 814 865 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 } 866 size_t pa_size; 867 char *pa = vfs_absolutize(path, &pa_size); 868 if (pa == NULL) 869 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); 828 890 return rc; 829 891 } … … 836 898 int unlink(const char *path) 837 899 { 838 size_t pa_size; 839 char *pa = vfs_absolutize(path, &pa_size); 840 if (!pa) { 841 return ENOMEM; 842 } 843 844 return _vfs_unlink2(-1, pa, -1, 0); 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; 845 909 } 846 910 … … 852 916 int rmdir(const char *path) 853 917 { 854 size_t pa_size; 855 char *pa = vfs_absolutize(path, &pa_size); 856 if (!pa) { 857 return ENOMEM; 858 } 859 860 return _vfs_unlink2(-1, pa, -1, WALK_DIRECTORY); 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; 861 927 } 862 928 … … 891 957 async_exch_t *exch = vfs_exchange_begin(); 892 958 893 req = async_send_ 1(exch, VFS_IN_RENAME, -1, NULL);959 req = async_send_0(exch, VFS_IN_RENAME, NULL); 894 960 rc = async_data_write_start(exch, olda, olda_size); 895 961 if (rc != EOK) { … … 952 1018 size_t abs_size; 953 1019 char *abs = vfs_absolutize(path, &abs_size); 954 if (!abs) 955 return ENOMEM; 956 957 int fd = _vfs_walk(-1, abs, WALK_DIRECTORY); 958 if (fd < 0) { 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) { 959 1030 free(abs); 960 errno = fd;1031 errno = rc; 961 1032 return -1; 962 1033 } -
uspace/lib/c/include/ipc/vfs.h
r1dff985 r5b46ec8 63 63 64 64 typedef enum { 65 VFS_IN_READ = IPC_FIRST_USER_METHOD, 65 VFS_IN_OPEN = IPC_FIRST_USER_METHOD, 66 VFS_IN_READ, 66 67 VFS_IN_WRITE, 67 68 VFS_IN_SEEK, … … 74 75 VFS_IN_SYNC, 75 76 VFS_IN_REGISTER, 77 VFS_IN_MKDIR, 76 78 VFS_IN_UNLINK, 77 79 VFS_IN_RENAME, 80 VFS_IN_STAT, 78 81 VFS_IN_DUP, 79 82 VFS_IN_WAIT_HANDLE, 80 83 VFS_IN_MTAB_GET, 81 VFS_IN_STATFS, 82 VFS_IN_WALK, 83 VFS_IN_OPEN2, 84 VFS_IN_UNLINK2, 84 VFS_IN_STATFS 85 85 } vfs_in_request_t; 86 86 … … 91 91 VFS_OUT_TRUNCATE, 92 92 VFS_OUT_CLOSE, 93 VFS_OUT_MOUNT, 93 94 VFS_OUT_MOUNTED, 95 VFS_OUT_UNMOUNT, 94 96 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,101 100 VFS_OUT_DESTROY, 102 101 VFS_OUT_STATFS, … … 128 127 129 128 /** 130 * Lookup will not cross any mount points.131 * If the lookup would have to cross a mount point, it returns EXDEV instead.129 * Lookup will succeed only if the object is a root directory. The flag is 130 * mutually exclusive with L_FILE and L_MP. 132 131 */ 133 #define L_ DISABLE_MOUNTS4132 #define L_ROOT 4 134 133 135 134 /** … … 152 151 153 152 /** 153 * L_LINK is used for linking to an already existing nodes. 154 */ 155 #define L_LINK 64 156 157 /** 154 158 * L_UNLINK is used to remove leaves from the file system namespace. This flag 155 159 * cannot be passed directly by the client, but will be set by VFS during … … 166 170 #define L_OPEN 256 167 171 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, along175 * 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 194 172 #endif 195 173 -
uspace/lib/c/include/vfs/vfs.h
r1dff985 r5b46ec8 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 69 66 #endif 70 67 -
uspace/lib/fs/libfs.c
r1dff985 r5b46ec8 36 36 37 37 #include "libfs.h" 38 #include "../../srv/vfs/vfs.h" 38 39 #include <macros.h> 39 40 #include <errno.h> … … 46 47 #include <sys/statfs.h> 47 48 #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 70 65 static fs_reg_t reg; 71 66 … … 73 68 static libfs_ops_t *libfs_ops = NULL; 74 69 75 static void libfs_ link(libfs_ops_t *, fs_handle_t, ipc_callid_t,76 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 *); 77 72 static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t, 78 73 ipc_call_t *); … … 109 104 } 110 105 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_link(ipc_callid_t rid, ipc_call_t *req) 122 { 123 libfs_link(libfs_ops, reg.fs_handle, rid, req); 121 static void vfs_out_unmount(ipc_callid_t rid, ipc_call_t *req) 122 { 123 124 libfs_unmount(libfs_ops, rid, req); 124 125 } 125 126 … … 192 193 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req); 193 194 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req); 194 195 195 int rc; 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 } 196 197 rc = vfs_out_ops->destroy(service_id, index); 198 205 199 async_answer_0(rid, rc); 206 200 } … … 231 225 libfs_statfs(libfs_ops, reg.fs_handle, rid, req); 232 226 } 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 280 227 static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 281 228 { … … 300 247 vfs_out_mounted(callid, &call); 301 248 break; 249 case VFS_OUT_MOUNT: 250 vfs_out_mount(callid, &call); 251 break; 302 252 case VFS_OUT_UNMOUNTED: 303 253 vfs_out_unmounted(callid, &call); 304 254 break; 305 case VFS_OUT_ LINK:306 vfs_out_ link(callid, &call);255 case VFS_OUT_UNMOUNT: 256 vfs_out_unmount(callid, &call); 307 257 break; 308 258 case VFS_OUT_LOOKUP: … … 335 285 case VFS_OUT_STATFS: 336 286 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);343 287 break; 344 288 default: … … 439 383 } 440 384 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); 396 return; 397 } 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)); 405 return; 406 } 407 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); 413 return; 414 } 415 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 441 494 static char plb_get_char(unsigned pos) 442 495 { 443 496 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);503 return;504 }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);510 return;511 }512 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);518 return;519 }520 521 rc = ops->link(parent, child, component);522 ops->node_put(parent);523 ops->node_put(child);524 async_answer_0(rid, rc);525 497 } 526 498 … … 541 513 ipc_call_t *req) 542 514 { 543 unsigned first = IPC_GET_ARG1(*req); 544 unsigned len = IPC_GET_ARG2(*req); 515 unsigned int first = IPC_GET_ARG1(*req); 516 unsigned int last = IPC_GET_ARG2(*req); 517 unsigned int next = first; 545 518 service_id_t service_id = IPC_GET_ARG3(*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 519 int lflag = IPC_GET_ARG4(*req); 520 fs_index_t index = IPC_GET_ARG5(*req); 558 521 char component[NAME_MAX + 1]; 522 int len; 559 523 int rc; 524 525 if (last < next) 526 last += PLB_SIZE; 560 527 561 528 fs_node_t *par = NULL; 562 529 fs_node_t *cur = NULL; 563 530 fs_node_t *tmp = NULL; 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; 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); 541 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; 552 553 rc = ops->has_children(&has_children, cur); 554 on_error(rc, goto out_with_answer); 555 if (!has_children) 556 break; 557 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++; 583 569 } 584 585 if (!ops->is_directory(cur)) { 586 async_answer_0(rid, ENOTDIR); 587 LOG_EXIT(ENOTDIR); 570 571 assert(len); 572 component[len] = '\0'; 573 /* Eat slash */ 574 next++; 575 576 /* Match the component */ 577 rc = ops->match(&tmp, cur, component); 578 on_error(rc, goto out_with_answer); 579 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--; 596 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); 615 goto out; 616 } 617 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 651 goto out; 652 } 653 654 async_answer_0(rid, ENOENT); 588 655 goto out; 589 656 } 590 657 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 }600 601 if (clen == 0) {602 /* The path is just "/". */603 break;604 }605 606 assert(component[clen] == 0);607 608 /* Match the component */609 rc = ops->match(&tmp, cur, component);610 if (rc != EOK) {611 async_answer_0(rid, rc);612 LOG_EXIT(rc);613 goto out;614 }615 616 /* Descend one level */617 658 if (par) { 618 659 rc = ops->node_put(par); 619 if (rc != EOK) { 620 async_answer_0(rid, rc); 621 LOG_EXIT(rc); 622 goto out; 623 } 660 on_error(rc, goto out_with_answer); 624 661 } 625 662 663 /* Descend one level */ 626 664 par = cur; 627 665 cur = tmp; … … 629 667 } 630 668 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 } 673 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); 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); 704 681 goto out; 705 682 } 706 683 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); 713 goto out; 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++; 714 702 } 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); 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 732 730 goto out; 733 731 } 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); 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 746 793 out: 747 if (par) { 794 795 if (par) 748 796 (void) ops->node_put(par); 749 } 750 751 if (cur) { 797 798 if (cur) 752 799 (void) ops->node_put(cur); 753 } 754 755 if (tmp) { 800 801 if (tmp) 756 802 (void) ops->node_put(tmp); 757 }758 803 } 759 804 -
uspace/lib/fs/libfs.h
r1dff985 r5b46ec8 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. */ 58 66 void *data; /**< Data of the file system implementation. */ 59 67 } fs_node_t; -
uspace/srv/vfs/vfs.c
r1dff985 r5b46ec8 104 104 vfs_unmount_srv(callid, &call); 105 105 break; 106 case VFS_IN_WALK: 107 vfs_walk(callid, &call); 108 break; 109 case VFS_IN_OPEN2: 110 vfs_open2(callid, &call); 106 case VFS_IN_OPEN: 107 vfs_open(callid, &call); 111 108 break; 112 109 case VFS_IN_CLOSE: … … 128 125 vfs_fstat(callid, &call); 129 126 break; 130 case VFS_IN_UNLINK2: 131 vfs_unlink2(callid, &call); 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); 132 135 break; 133 136 case VFS_IN_RENAME: -
uspace/srv/vfs/vfs.h
r1dff985 r5b46ec8 94 94 vfs_node_type_t type; 95 95 aoff64_t size; 96 unsigned int lnkcnt; 96 97 } vfs_lookup_res_t; 97 98 … … 100 101 * which may be associated with it. 101 102 */ 102 typedef struct _vfs_node{103 typedef struct { 103 104 VFS_TRIPLET; /**< Identity of the node. */ 104 105 … … 109 110 unsigned refcnt; 110 111 112 /** Number of names this node has in the file system namespace. */ 113 unsigned lnkcnt; 114 111 115 ht_link_t nh_link; /**< Node hash-table link. */ 112 116 113 117 vfs_node_type_t type; /**< Partial info about the node type. */ 114 118 115 int64_t size; /**< Cached size if the node is a file. */119 aoff64_t size; /**< Cached size if the node is a file. */ 116 120 117 121 /** … … 119 123 */ 120 124 fibril_rwlock_t contents_rwlock; 121 122 struct _vfs_node *mount;123 125 } vfs_node_t; 124 126 … … 136 138 unsigned refcnt; 137 139 138 int permissions;139 bool open_read;140 bool open_write;141 142 140 /** Append on write. */ 143 141 bool append; … … 178 176 extern vfs_info_t *fs_handle_to_info(fs_handle_t); 179 177 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 *);178 extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *, 179 vfs_pair_t *, ...); 182 180 183 181 extern bool vfs_nodes_init(void); 184 182 extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *); 185 extern vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result);186 183 extern void vfs_node_put(vfs_node_t *); 187 184 extern void vfs_node_forget(vfs_node_t *); 188 185 extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t); 189 186 190 extern int64_t vfs_node_get_size(vfs_node_t *node);191 extern bool vfs_node_has_children(vfs_node_t *node);192 187 193 188 #define MAX_OPEN_FILES 128 … … 212 207 extern void vfs_mount_srv(ipc_callid_t, ipc_call_t *); 213 208 extern void vfs_unmount_srv(ipc_callid_t, ipc_call_t *); 209 extern void vfs_open(ipc_callid_t, ipc_call_t *); 214 210 extern void vfs_sync(ipc_callid_t, ipc_call_t *); 215 211 extern void vfs_dup(ipc_callid_t, ipc_call_t *); … … 220 216 extern void vfs_truncate(ipc_callid_t, ipc_call_t *); 221 217 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 *); 222 221 extern void vfs_rename(ipc_callid_t, ipc_call_t *); 223 222 extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *); … … 234 233 extern int vfs_rdwr_internal(int, bool, rdwr_io_chunk_t *); 235 234 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 240 235 #endif 241 236 -
uspace/srv/vfs/vfs_file.c
r1dff985 r5b46ec8 177 177 * endpoint FS and drop our reference to the underlying VFS node. 178 178 */ 179 if (file->open_read || file->open_write) { 180 rc = vfs_file_close_remote(file); 181 } 179 rc = vfs_file_close_remote(file); 182 180 vfs_node_delref(file->node); 183 181 free(file); … … 395 393 */ 396 394 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. 395 acceptor_file->append = donor_file->append; 400 396 acceptor_file->pos = donor_file->pos; 401 acceptor_file->append = donor_file->append;402 acceptor_file->open_read = donor_file->open_read;403 acceptor_file->open_write = donor_file->open_write;404 397 405 398 out: -
uspace/srv/vfs/vfs_lookup.c
r1dff985 r5b46ec8 46 46 #include <adt/list.h> 47 47 #include <vfs/canonify.h> 48 #include <dirent.h>49 #include <assert.h>50 51 #define DPRINTF(...)52 48 53 49 #define min(a, b) ((a) < (b) ? (a) : (b)) … … 57 53 uint8_t *plb = NULL; 58 54 59 static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start, size_t len) 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, ...) 60 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 61 95 fibril_mutex_lock(&plb_mutex); 62 96 63 link_initialize(&entry->plb_link); 64 entry->len = len; 97 plb_entry_t entry; 98 link_initialize(&entry.plb_link); 99 entry.len = len; 65 100 66 101 size_t first; /* the first free index */ … … 103 138 */ 104 139 105 entry ->index = first;106 entry ->len = len;140 entry.index = first; 141 entry.len = len; 107 142 108 143 /* … … 110 145 * buffer. 111 146 */ 112 list_append(&entry ->plb_link, &plb_entries);147 list_append(&entry.plb_link, &plb_entries); 113 148 114 149 fibril_mutex_unlock(&plb_mutex); … … 123 158 memcpy(plb, &path[cnt1], cnt2); 124 159 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 { 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 131 171 fibril_mutex_lock(&plb_mutex); 132 list_remove(&entry ->plb_link);172 list_remove(&entry.plb_link); 133 173 /* 134 174 * Erasing the path from PLB will come handy for debugging purposes. 135 175 */ 136 size_t cnt1 = min(len, (PLB_SIZE - first) + 1);137 size_t cnt2 = len - cnt1;138 176 memset(&plb[first], 0, cnt1); 139 177 memset(plb, 0, cnt2); 140 178 fibril_mutex_unlock(&plb_mutex); 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) { 179 180 if ((int) rc < EOK) 240 181 return (int) rc; 241 } 242 243 unsigned last = *pfirst + *plen; 244 *pfirst = IPC_GET_ARG3(answer); 245 *plen = last - *pfirst; 182 183 if (!result) 184 return EOK; 246 185 247 186 result->triplet.fs_handle = (fs_handle_t) rc; 248 187 result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer); 249 188 result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer); 250 result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer); 251 result->type = IPC_GET_ARG5(answer) ? VFS_NODE_DIRECTORY : VFS_NODE_FILE; 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 252 200 return EOK; 253 201 } 254 202 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-terminated259 * 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;353 }354 355 203 /** 356 204 * @} -
uspace/srv/vfs/vfs_node.c
r1dff985 r5b46ec8 45 45 #include <async.h> 46 46 #include <errno.h> 47 #include <macros.h>48 47 49 48 /** Mutex protecting the VFS node hash table. */ … … 107 106 void vfs_node_delref(vfs_node_t *node) 108 107 { 109 bool free_ node = false;110 111 fibril_mutex_lock(&nodes_mutex);112 113 node->refcnt--;114 if (node->refcnt == 0) {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) { 115 114 116 115 /* … … 120 119 121 120 hash_table_remove_item(&nodes, &node->nh_link); 122 free_node = true; 121 free_vfs_node = true; 122 123 if (!node->lnkcnt) 124 free_fs_node = true; 123 125 } 124 126 125 127 fibril_mutex_unlock(&nodes_mutex); 126 128 127 if (free_node) { 129 if (free_fs_node) { 130 128 131 /* 129 * DESTROY will free up the file's resources if there are no more hard links. 132 * The node is not visible in the file system namespace. 133 * Free up its resources. 130 134 */ 131 135 132 136 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 133 async_msg_2(exch, VFS_OUT_DESTROY, 134 (sysarg_t) node->service_id, (sysarg_t)node->index); 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); 135 141 vfs_exchange_release(exch); 136 142 } 143 144 if (free_vfs_node) 137 145 free(node); 138 }139 146 } 140 147 … … 183 190 node->index = result->triplet.index; 184 191 node->size = result->size; 192 node->lnkcnt = result->lnkcnt; 185 193 node->type = result->type; 186 194 fibril_rwlock_initialize(&node->contents_rwlock); … … 188 196 } else { 189 197 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 } 190 203 } 191 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); 208 192 209 _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 }207 210 fibril_mutex_unlock(&nodes_mutex); 208 211 … … 315 318 } 316 319 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 341 320 /** 342 321 * @} -
uspace/srv/vfs/vfs_ops.c
r1dff985 r5b46ec8 68 68 FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock); 69 69 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. */ 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; 94 88 ipc_call_t answer; 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); 89 90 /* 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 { 122 /* 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 */ 121 128 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 { 128 /* Resolve the path to the mountpoint. */ 129 130 if (root == NULL) { 131 /* We still don't have the root file system mounted. */ 132 if (str_cmp(mp, "/") != 0) { 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 { 133 175 /* 134 176 * We can't resolve this without the root filesystem 135 177 * being mounted first. 136 178 */ 179 fibril_rwlock_write_unlock(&namespace_rwlock); 180 async_answer_0(rid, ENOENT); 137 181 return ENOENT; 138 182 } 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. */ 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); 153 214 return rc; 154 215 } 155 216 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; 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; 188 266 } 189 267 190 268 void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request) 191 269 { 270 service_id_t service_id; 271 192 272 /* 193 273 * We expect the library to do the device-name to device-handle … … 195 275 * in the request. 196 276 */ 197 service_id _t service_id= (service_id_t) IPC_GET_ARG1(*request);277 service_id = (service_id_t) IPC_GET_ARG1(*request); 198 278 199 279 /* … … 221 301 0, NULL); 222 302 if (rc != EOK) { 223 async_answer_0(rid, rc);224 303 free(mp); 304 async_answer_0(rid, rc); 225 305 return; 226 306 } … … 234 314 FS_NAME_MAXLEN, 0, NULL); 235 315 if (rc != EOK) { 236 async_answer_0(rid, rc);237 316 free(mp); 238 317 free(opts); 239 return; 240 } 241 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 242 361 /* Add the filesystem info to the list of mounted filesystems */ 243 362 mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t)); 244 363 if (!mtab_ent) { 364 async_answer_0(callid, ENOMEM); 245 365 async_answer_0(rid, ENOMEM); 246 366 free(mp); … … 249 369 return; 250 370 } 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); 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 } 256 383 257 384 /* Add the filesystem info to the list of mounted filesystems */ 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); 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); 274 398 275 399 free(mp); 276 400 free(fs_name); 277 401 free(opts); 402 403 /* Acknowledge that we know fs_name. */ 404 async_answer_0(callid, EOK); 278 405 } 279 406 280 407 void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request) 281 408 { 409 int rc; 410 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 282 416 /* 283 417 * Receive the mount point path. 284 418 */ 285 char *mp; 286 int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN, 419 rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN, 287 420 0, NULL); 288 421 if (rc != EOK) … … 298 431 */ 299 432 fibril_rwlock_write_lock(&namespace_rwlock); 300 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); 440 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. We 454 * are expecting at least two. One which we got above and one which we 455 * got when the file system was mounted. If we find more, it means that 456 * the file system cannot be gracefully unmounted at the moment because 457 * 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 301 468 if (str_cmp(mp, "/") == 0) { 302 free(mp);303 469 304 470 /* … … 309 475 */ 310 476 311 if (!root) { 477 exch = vfs_exchange_grab(mr_node->fs_handle); 478 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, 479 mr_node->service_id); 480 vfs_exchange_release(exch); 481 482 if (rc != EOK) { 312 483 fibril_rwlock_write_unlock(&namespace_rwlock); 313 async_answer_0(rid, ENOENT); 484 free(mp); 485 vfs_node_put(mr_node); 486 async_answer_0(rid, rc); 314 487 return; 315 488 } 316 489 490 rootfs.fs_handle = 0; 491 rootfs.service_id = 0; 492 } else { 493 317 494 /* 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. 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. 323 499 */ 324 if (vfs_nodes_refcount_sum_get(root->fs_handle, root->service_id) != 1) { 500 501 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL); 502 if (rc != EOK) { 325 503 fibril_rwlock_write_unlock(&namespace_rwlock); 326 async_answer_0(rid, EBUSY); 504 free(mp); 505 vfs_node_put(mr_node); 506 async_answer_0(rid, rc); 327 507 return; 328 508 } 329 509 330 async_exch_t *exch = vfs_exchange_grab(root->fs_handle); 331 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, root->service_id); 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); 332 522 vfs_exchange_release(exch); 333 523 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); 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. */ 364 534 vfs_node_put(mp_node); 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); 535 /* Drop the reference from when the file system was mounted. */ 379 536 vfs_node_put(mp_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); 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); 394 544 fibril_rwlock_write_unlock(&namespace_rwlock); 395 545 396 546 fibril_mutex_lock(&mtab_list_lock); 547 397 548 int found = 0; 398 549 … … 409 560 fibril_mutex_unlock(&mtab_list_lock); 410 561 411 free(mp); 412 562 free(mp); 563 413 564 async_answer_0(rid, EOK); 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)) { 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))) { 464 592 async_answer_0(rid, EINVAL); 465 593 return; 466 594 } 467 595 596 if (oflag & O_CREAT) 597 lflag |= L_CREATE; 598 if (oflag & O_EXCL) 599 lflag |= L_EXCLUSIVE; 600 468 601 char *path; 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 602 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 603 if (rc != EOK) { 604 async_answer_0(rid, rc); 605 return; 606 } 607 608 /* 609 * Avoid the race condition in which the file can be deleted before we 610 * find/create-and-lock the VFS node corresponding to the looked-up 611 * triplet. 612 */ 613 if (lflag & L_CREATE) 614 fibril_rwlock_write_lock(&namespace_rwlock); 615 else 616 fibril_rwlock_read_lock(&namespace_rwlock); 617 618 /* The path is now populated and we can call vfs_lookup_internal(). */ 487 619 vfs_lookup_res_t lr; 488 rc = vfs_lookup_internal(parent_node, path, walk_lookup_flags(flags), &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 else 625 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. */ 489 632 free(path); 490 491 if (rc != EOK) { 633 634 vfs_node_t *node = vfs_node_get(&lr); 635 if (lflag & L_CREATE) 636 fibril_rwlock_write_unlock(&namespace_rwlock); 637 else 492 638 fibril_rwlock_read_unlock(&namespace_rwlock); 493 if (parent) { 494 vfs_file_put(parent); 495 } 496 async_answer_0(rid, rc); 497 return; 498 } 499 500 vfs_node_t *node = vfs_node_get(&lr); 501 502 int fd = vfs_fd_alloc(false); 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); 503 667 if (fd < 0) { 504 668 vfs_node_put(node); 505 if (parent) {506 vfs_file_put(parent);507 }508 669 async_answer_0(rid, fd); 509 670 return; 510 671 } 511 512 672 vfs_file_t *file = vfs_file_get(fd); 513 assert(file != NULL); 514 673 assert(file); 515 674 file->node = 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 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); 524 687 vfs_file_put(file); 525 if (parent) { 526 vfs_file_put(parent); 527 } 528 529 fibril_rwlock_read_unlock(&namespace_rwlock); 530 688 689 /* Success! Return the new file descriptor to the client. */ 531 690 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);583 691 } 584 692 … … 708 816 fibril_mutex_lock(&file->lock); 709 817 710 if ((read && !file->open_read) || (!read && !file->open_write)) {711 fibril_mutex_unlock(&file->lock);712 return EINVAL;713 }714 715 818 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle); 716 819 assert(fs_info); … … 751 854 size_t bytes = IPC_GET_ARG1(answer); 752 855 753 if (file->node->type == VFS_NODE_DIRECTORY) {856 if (file->node->type == VFS_NODE_DIRECTORY) 754 857 fibril_rwlock_read_unlock(&namespace_rwlock); 755 }756 858 757 859 /* Unlock the VFS node. */ … … 851 953 case SEEK_END: 852 954 fibril_rwlock_read_lock(&file->node->contents_rwlock); 853 aoff64_t size = vfs_node_get_size(file->node);955 aoff64_t size = file->node->size; 854 956 855 957 if ((off >= 0) && (size + off < size)) { … … 959 1061 } 960 1062 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); 1063 void vfs_stat(ipc_callid_t rid, ipc_call_t *request) 1064 { 1065 char *path; 1066 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 1067 if (rc != EOK) { 1068 async_answer_0(rid, rc); 1069 return; 1070 } 1071 1072 ipc_callid_t callid; 1073 if (!async_data_read_receive(&callid, NULL)) { 1074 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 966 1107 vfs_exchange_release(exch); 967 } 968 969 void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request) 970 { 971 int rc; 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 972 1121 char *path; 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); 982 if (rc != EOK) { 983 async_answer_0(rid, rc); 984 return; 985 } 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; 986 1130 987 1131 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 1132 int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE; 1133 rc = vfs_lookup_internal(path, lflag, NULL, NULL); 1134 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 */ 1022 1152 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) { 1035 free(path); 1036 } 1037 if (parent) { 1038 vfs_file_put(parent); 1039 } 1040 if (expect) { 1041 vfs_file_put(expect); 1042 } 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); 1043 1170 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] == '/'); 1087 1088 fibril_rwlock_write_lock(&namespace_rwlock); 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); 1144 fibril_rwlock_write_unlock(&namespace_rwlock); 1145 return EOK; 1171 vfs_node_put(node); 1172 async_answer_0(rid, EOK); 1146 1173 } 1147 1174 1148 1175 void vfs_rename(ipc_callid_t rid, ipc_call_t *request) 1149 1176 { 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 1159 1177 /* Retrieve the old path. */ 1160 rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1161 if (rc != EOK) { 1162 goto out; 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; 1163 1183 } 1164 1184 1165 1185 /* Retrieve the new path. */ 1186 char *new; 1166 1187 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL); 1167 1188 if (rc != EOK) { 1168 goto out; 1189 free(old); 1190 async_answer_0(rid, rc); 1191 return; 1169 1192 } 1170 1193 … … 1175 1198 1176 1199 if ((!oldc) || (!newc)) { 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) { 1200 async_answer_0(rid, EINVAL); 1202 1201 free(old); 1203 }1204 if (new) {1205 1202 free(new); 1206 } 1207 if (base) { 1208 vfs_file_put(base); 1209 } 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); 1210 1362 } 1211 1363 … … 1335 1487 vfs_lookup_res_t lr; 1336 1488 fibril_rwlock_read_lock(&namespace_rwlock); 1337 rc = vfs_lookup_internal( root, path, L_NONE, &lr);1489 rc = vfs_lookup_internal(path, L_NONE, &lr, NULL); 1338 1490 free(path); 1339 1491 if (rc != EOK) {
Note:
See TracChangeset
for help on using the changeset viewer.