Changes in uspace/srv/vfs/vfs_lookup.c [3e6a98c5:51774cd] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/vfs/vfs_lookup.c
r3e6a98c5 r51774cd 46 46 #include <adt/list.h> 47 47 #include <vfs/canonify.h> 48 49 # define min(a, b) ((a) < (b) ? (a) : (b))48 #include <dirent.h> 49 #include <assert.h> 50 50 51 51 FIBRIL_MUTEX_INITIALIZE(plb_mutex); … … 53 53 uint8_t *plb = NULL; 54 54 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 55 static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start, 56 size_t len) 57 { 95 58 fibril_mutex_lock(&plb_mutex); 96 59 97 plb_entry_t entry; 98 link_initialize(&entry.plb_link); 99 entry.len = len; 60 link_initialize(&entry->plb_link); 61 entry->len = len; 100 62 101 63 size_t first; /* the first free index */ … … 138 100 */ 139 101 140 entry .index = first;141 entry .len = len;102 entry->index = first; 103 entry->len = len; 142 104 143 105 /* … … 145 107 * buffer. 146 108 */ 147 list_append(&entry .plb_link, &plb_entries);109 list_append(&entry->plb_link, &plb_entries); 148 110 149 111 fibril_mutex_unlock(&plb_mutex); … … 158 120 memcpy(plb, &path[cnt1], cnt2); 159 121 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 122 *start = first; 123 return EOK; 124 } 125 126 static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len) 127 { 171 128 fibril_mutex_lock(&plb_mutex); 172 list_remove(&entry .plb_link);129 list_remove(&entry->plb_link); 173 130 /* 174 131 * Erasing the path from PLB will come handy for debugging purposes. 175 132 */ 133 size_t cnt1 = min(len, (PLB_SIZE - first) + 1); 134 size_t cnt2 = len - cnt1; 176 135 memset(&plb[first], 0, cnt1); 177 136 memset(plb, 0, cnt2); 178 137 fibril_mutex_unlock(&plb_mutex); 179 180 if ((int) rc < EOK) 138 } 139 140 int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child) 141 { 142 assert(base != NULL); 143 assert(child != NULL); 144 assert(base->fs_handle); 145 assert(child->fs_handle); 146 assert(path != NULL); 147 148 vfs_lookup_res_t res; 149 char component[NAME_MAX + 1]; 150 int rc; 151 152 size_t len; 153 char *npath = canonify(path, &len); 154 if (!npath) { 155 rc = EINVAL; 156 goto out; 157 } 158 path = npath; 159 160 vfs_triplet_t *triplet; 161 162 char *slash = str_rchr(path, L'/'); 163 if (slash && slash != path) { 164 if (slash[1] == 0) { 165 rc = EINVAL; 166 goto out; 167 } 168 169 memcpy(component, slash + 1, str_size(slash)); 170 *slash = 0; 171 172 rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res); 173 if (rc != EOK) 174 goto out; 175 triplet = &res.triplet; 176 177 *slash = '/'; 178 } else { 179 if (base->mount != NULL) { 180 rc = EINVAL; 181 goto out; 182 } 183 184 memcpy(component, path + 1, str_size(path)); 185 triplet = (vfs_triplet_t *) base; 186 } 187 188 if (triplet->fs_handle != child->fs_handle || 189 triplet->service_id != child->service_id) { 190 rc = EXDEV; 191 goto out; 192 } 193 194 async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle); 195 aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id, 196 triplet->index, child->index, NULL); 197 198 rc = async_data_write_start(exch, component, str_size(component) + 1); 199 sysarg_t orig_rc; 200 async_wait_for(req, &orig_rc); 201 vfs_exchange_release(exch); 202 if (orig_rc != EOK) 203 rc = orig_rc; 204 205 out: 206 return rc; 207 } 208 209 static int out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen, 210 int lflag, vfs_lookup_res_t *result) 211 { 212 assert(base); 213 assert(result); 214 215 sysarg_t rc; 216 ipc_call_t answer; 217 async_exch_t *exch = vfs_exchange_grab(base->fs_handle); 218 aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst, 219 (sysarg_t) *plen, (sysarg_t) base->service_id, 220 (sysarg_t) base->index, (sysarg_t) lflag, &answer); 221 async_wait_for(req, &rc); 222 vfs_exchange_release(exch); 223 224 if ((int) rc < 0) 181 225 return (int) rc; 182 183 if (!result) 184 return EOK; 226 227 unsigned last = *pfirst + *plen; 228 *pfirst = IPC_GET_ARG3(answer) & 0xffff; 229 *plen = last - *pfirst; 185 230 186 231 result->triplet.fs_handle = (fs_handle_t) rc; 187 232 result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer); 188 233 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 234 result->size = MERGE_LOUP32(IPC_GET_ARG4(answer), IPC_GET_ARG5(answer)); 235 result->type = (IPC_GET_ARG3(answer) >> 16) ? 236 VFS_NODE_DIRECTORY : VFS_NODE_FILE; 200 237 return EOK; 238 } 239 240 static int _vfs_lookup_internal(vfs_node_t *base, char *path, int lflag, 241 vfs_lookup_res_t *result, size_t len) 242 { 243 size_t first; 244 int rc; 245 246 plb_entry_t entry; 247 rc = plb_insert_entry(&entry, path, &first, len); 248 if (rc != EOK) 249 return rc; 250 251 size_t next = first; 252 size_t nlen = len; 253 254 vfs_lookup_res_t res; 255 256 /* Resolve path as long as there are mount points to cross. */ 257 while (nlen > 0) { 258 while (base->mount) { 259 if (lflag & L_DISABLE_MOUNTS) { 260 rc = EXDEV; 261 goto out; 262 } 263 264 base = base->mount; 265 } 266 267 rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag, 268 &res); 269 if (rc != EOK) 270 goto out; 271 272 if (nlen > 0) { 273 base = vfs_node_peek(&res); 274 if (!base) { 275 rc = ENOENT; 276 goto out; 277 } 278 if (!base->mount) { 279 vfs_node_put(base); 280 rc = ENOENT; 281 goto out; 282 } 283 vfs_node_put(base); 284 if (lflag & L_DISABLE_MOUNTS) { 285 rc = EXDEV; 286 goto out; 287 } 288 } 289 } 290 291 assert(nlen == 0); 292 rc = EOK; 293 294 if (result != NULL) { 295 /* The found file may be a mount point. Try to cross it. */ 296 if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) { 297 base = vfs_node_peek(&res); 298 if (base && base->mount) { 299 while (base->mount) { 300 vfs_node_addref(base->mount); 301 vfs_node_t *nbase = base->mount; 302 vfs_node_put(base); 303 base = nbase; 304 } 305 306 result->triplet = *((vfs_triplet_t *) base); 307 result->type = base->type; 308 result->size = base->size; 309 vfs_node_put(base); 310 goto out; 311 } 312 if (base) 313 vfs_node_put(base); 314 } 315 316 *result = res; 317 } 318 319 out: 320 plb_clear_entry(&entry, first, len); 321 return rc; 322 } 323 324 /** Perform a path lookup. 325 * 326 * @param base The file from which to perform the lookup. 327 * @param path Path to be resolved; it must be a NULL-terminated 328 * string. 329 * @param lflag Flags to be used during lookup. 330 * @param result Empty structure where the lookup result will be stored. 331 * Can be NULL. 332 * 333 * @return EOK on success or an error code from errno.h. 334 * 335 */ 336 int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag, 337 vfs_lookup_res_t *result) 338 { 339 assert(base != NULL); 340 assert(path != NULL); 341 342 size_t len; 343 int rc; 344 char *npath = canonify(path, &len); 345 if (!npath) { 346 rc = EINVAL; 347 return rc; 348 } 349 path = npath; 350 351 assert(path[0] == '/'); 352 353 354 if (lflag & (L_CREATE | L_UNLINK)) { 355 356 /* 357 * Creation and destruction of names must be done in two 358 * separate steps: lookup of the parent node and the name 359 * link/unlink operation itself. Otherwise the parent 360 * filesystem would not be able to tell when a mountpoint is 361 * crossed. It would attempt to perform the link/unlink in 362 * itself instead of letting the mounted filesystem do it, 363 * resulting in wrong behavior. This is the wages of server-side 364 * mountpoints. 365 */ 366 367 char *slash = str_rchr(path, L'/'); 368 vfs_node_t *parent = base; 369 370 if (slash != path) { 371 int tflag = lflag; 372 vfs_lookup_res_t tres; 373 374 tflag &= ~(L_CREATE | L_EXCLUSIVE | L_UNLINK | L_FILE); 375 tflag |= L_DIRECTORY; 376 rc = _vfs_lookup_internal(base, path, tflag, &tres, 377 slash - path); 378 if (rc != EOK) 379 return rc; 380 parent = vfs_node_get(&tres); 381 if (!parent) 382 return ENOMEM; 383 } else 384 vfs_node_addref(parent); 385 386 rc = _vfs_lookup_internal(parent, slash, lflag, result, 387 len - (slash - path)); 388 389 vfs_node_put(parent); 390 391 } else { 392 rc = _vfs_lookup_internal(base, path, lflag, result, len); 393 } 394 395 return rc; 201 396 } 202 397
Note:
See TracChangeset
for help on using the changeset viewer.