1 /* VTreeFS - link.c - support for symbolic links and device nodes */ 2 3 #include "inc.h" 4 5 /* 6 * Retrieve a symbolic link target. 7 */ 8 ssize_t 9 fs_rdlink(ino_t ino_nr, struct fsdriver_data * data, size_t bytes) 10 { 11 char path[PATH_MAX]; 12 struct inode *node; 13 size_t len; 14 int r; 15 16 if ((node = find_inode(ino_nr)) == NULL) 17 return EINVAL; 18 19 /* The hook should be provided for any FS that adds symlink inodes.. */ 20 if (vtreefs_hooks->rdlink_hook == NULL) 21 return ENOSYS; 22 23 assert(!is_inode_deleted(node)); /* symlinks cannot be opened */ 24 25 r = vtreefs_hooks->rdlink_hook(node, path, sizeof(path), 26 get_inode_cbdata(node)); 27 if (r != OK) return r; 28 29 len = strlen(path); 30 assert(len > 0 && len < sizeof(path)); 31 32 if (len > bytes) 33 len = bytes; 34 35 /* Copy out the result. */ 36 if ((r = fsdriver_copyout(data, 0, path, len)) != OK) 37 return r; 38 39 return len; 40 } 41 42 /* 43 * Create a symbolic link. 44 */ 45 int 46 fs_slink(ino_t dir_nr, char * name, uid_t uid, gid_t gid, 47 struct fsdriver_data * data, size_t bytes) 48 { 49 char path[PATH_MAX]; 50 struct inode *node; 51 struct inode_stat istat; 52 int r; 53 54 if ((node = find_inode(dir_nr)) == NULL) 55 return EINVAL; 56 57 if (vtreefs_hooks->slink_hook == NULL) 58 return ENOSYS; 59 60 if (get_inode_by_name(node, name) != NULL) 61 return EEXIST; 62 63 if (bytes >= sizeof(path)) 64 return ENAMETOOLONG; 65 66 if ((r = fsdriver_copyin(data, 0, path, bytes)) != OK) 67 return r; 68 path[bytes] = 0; 69 70 memset(&istat, 0, sizeof(istat)); 71 istat.mode = S_IFLNK | RWX_MODES; 72 istat.uid = uid; 73 istat.gid = gid; 74 istat.size = strlen(path); 75 istat.dev = 0; 76 77 return vtreefs_hooks->slink_hook(node, name, &istat, path, 78 get_inode_cbdata(node)); 79 } 80 81 /* 82 * Create a device node. 83 */ 84 int 85 fs_mknod(ino_t dir_nr, char * name, mode_t mode, uid_t uid, gid_t gid, 86 dev_t rdev) 87 { 88 struct inode *node; 89 struct inode_stat istat; 90 91 if ((node = find_inode(dir_nr)) == NULL) 92 return EINVAL; 93 94 if (get_inode_by_name(node, name) != NULL) 95 return EEXIST; 96 97 if (vtreefs_hooks->mknod_hook == NULL) 98 return ENOSYS; 99 100 memset(&istat, 0, sizeof(istat)); 101 istat.mode = mode; 102 istat.uid = uid; 103 istat.gid = gid; 104 istat.size = 0; 105 istat.dev = rdev; 106 107 return vtreefs_hooks->mknod_hook(node, name, &istat, 108 get_inode_cbdata(node)); 109 } 110 111 /* 112 * Unlink a node. 113 */ 114 int 115 fs_unlink(ino_t dir_nr, char * name, int __unused call) 116 { 117 struct inode *dir_node, *node; 118 119 if ((dir_node = find_inode(dir_nr)) == NULL) 120 return EINVAL; 121 122 if ((node = get_inode_by_name(dir_node, name)) == NULL) 123 return ENOENT; 124 125 if (vtreefs_hooks->unlink_hook == NULL) 126 return ENOSYS; 127 128 return vtreefs_hooks->unlink_hook(node, get_inode_cbdata(node)); 129 } 130