source: mainline/uspace/srv/vfs/vfs_ops.c@ 7fa8589

Last change on this file since 7fa8589 was 7fa8589, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

Removing unneeded casts from errno_t to errno_t

  • Property mode set to 100644
File size: 22.1 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup vfs
30 * @{
31 */
32
33/**
34 * @file vfs_ops.c
35 * @brief Operations that VFS offers to its clients.
36 */
37
38#include "vfs.h"
39#include <macros.h>
40#include <stdint.h>
41#include <async.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <str.h>
46#include <stdbool.h>
47#include <fibril_synch.h>
48#include <adt/list.h>
49#include <ctype.h>
50#include <assert.h>
51#include <vfs/canonify.h>
52#include <sysman/ctl.h>
53
54/* Forward declarations of static functions. */
55static errno_t vfs_truncate_internal(fs_handle_t, service_id_t, fs_index_t,
56 aoff64_t);
57
58static errno_t vfs_fs_request_start(const char *fs_name, unsigned int instance);
59
60/**
61 * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
62 * concurrent VFS operation which modifies the file system namespace.
63 */
64FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
65
66static size_t shared_path(char *a, char *b)
67{
68 size_t res = 0;
69
70 while (a[res] == b[res] && a[res] != 0)
71 res++;
72
73 if (a[res] == b[res])
74 return res;
75
76 res--;
77 while (a[res] != '/')
78 res--;
79 return res;
80}
81
82/* This call destroys the file if and only if there are no hard links left. */
83static void out_destroy(vfs_triplet_t *file)
84{
85 async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
86 async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) file->service_id,
87 (sysarg_t) file->index);
88 vfs_exchange_release(exch);
89}
90
91errno_t vfs_op_clone(int oldfd, int newfd, bool desc, int *out_fd)
92{
93 errno_t rc;
94
95 /* Lookup the file structure corresponding to fd. */
96 vfs_file_t *oldfile = vfs_file_get(oldfd);
97 if (oldfile == NULL)
98 return EBADF;
99
100 assert(oldfile->node != NULL);
101
102 /* If the file descriptors are the same, do nothing. */
103 if (oldfd == newfd) {
104 vfs_file_put(oldfile);
105 return EOK;
106 }
107
108 if (newfd != -1) {
109 /* Assign the old file to newfd. */
110 rc = vfs_fd_assign(oldfile, newfd);
111 *out_fd = newfd;
112 } else {
113 vfs_file_t *newfile;
114 rc = vfs_fd_alloc(&newfile, desc, out_fd);
115 if (rc == EOK) {
116 newfile->node = oldfile->node;
117 newfile->permissions = oldfile->permissions;
118 vfs_node_addref(newfile->node);
119
120 vfs_file_put(newfile);
121 }
122 }
123 vfs_file_put(oldfile);
124
125 return rc;
126}
127
128errno_t vfs_op_put(int fd)
129{
130 return vfs_fd_free(fd);
131}
132
133static errno_t vfs_connect_internal(service_id_t service_id, unsigned flags,
134 unsigned instance, const char *options, const char *fsname,
135 vfs_node_t **root)
136{
137 fs_handle_t fs_handle = 0;
138
139 fibril_mutex_lock(&fs_list_lock);
140 while (true) {
141 fs_handle = fs_name_to_handle(fsname, instance, false);
142 if (!fs_handle) {
143 if ((flags & IPC_FLAG_AUTOSTART_)) {
144 /*
145 * Temporarily release the lock, we don't need it while
146 * waiting for start request (which may lead to deadlock).
147 */
148 fibril_mutex_unlock(&fs_list_lock);
149 errno_t rc = vfs_fs_request_start(fsname, instance);
150 fibril_mutex_lock(&fs_list_lock);
151
152 if (rc != EOK) {
153 return rc;
154 }
155
156 /*
157 * Succesful start request, new server should be
158 * registered.
159 */
160 continue;
161 }
162 }
163
164 if (fs_handle != 0 || !(flags & VFS_MOUNT_BLOCKING))
165 break;
166
167 fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
168 }
169 fibril_mutex_unlock(&fs_list_lock);
170
171 if (fs_handle == 0)
172 return ENOFS;
173
174 /* Tell the mountee that it is being mounted. */
175 ipc_call_t answer;
176 async_exch_t *exch = vfs_exchange_grab(fs_handle);
177 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id,
178 &answer);
179 /* Send the mount options */
180 errno_t rc = async_data_write_start(exch, options, str_size(options));
181 if (rc != EOK) {
182 async_forget(msg);
183 vfs_exchange_release(exch);
184 return rc;
185 }
186
187 async_wait_for(msg, &rc);
188 if (rc != EOK) {
189 vfs_exchange_release(exch);
190 return rc;
191 }
192
193 vfs_lookup_res_t res;
194 res.triplet.fs_handle = fs_handle;
195 res.triplet.service_id = service_id;
196 res.triplet.index = (fs_index_t) ipc_get_arg1(&answer);
197 res.size = (int64_t) MERGE_LOUP32(ipc_get_arg2(&answer),
198 ipc_get_arg3(&answer));
199 res.type = VFS_NODE_DIRECTORY;
200
201 /* Add reference to the mounted root. */
202 *root = vfs_node_get(&res);
203 if (!*root) {
204 aid_t msg = async_send_1(exch, VFS_OUT_UNMOUNTED,
205 (sysarg_t) service_id, NULL);
206 async_forget(msg);
207 vfs_exchange_release(exch);
208 return ENOMEM;
209 }
210
211 vfs_exchange_release(exch);
212
213 return EOK;
214}
215
216static errno_t vfs_fs_request_start(const char *fs_name, unsigned int instance)
217{
218 char *unit_name = NULL;
219
220 errno_t rc = fs_unit_name(fs_name, instance, &unit_name);
221 if (rc != EOK) {
222 return rc;
223 }
224
225 rc = sysman_unit_start_by_name(unit_name, IPC_FLAG_BLOCKING);
226
227 free(unit_name);
228 return rc;
229}
230
231errno_t vfs_op_fsprobe(const char *fs_name, service_id_t sid,
232 vfs_fs_probe_info_t *info)
233{
234 fs_handle_t fs_handle = 0;
235 errno_t rc;
236 errno_t retval;
237
238 fibril_mutex_lock(&fs_list_lock);
239 fs_handle = fs_name_to_handle(fs_name, 0, false);
240 fibril_mutex_unlock(&fs_list_lock);
241
242 if (fs_handle == 0)
243 return ENOFS;
244
245 /* Send probe request to the file system server */
246 ipc_call_t answer;
247 async_exch_t *exch = vfs_exchange_grab(fs_handle);
248 aid_t msg = async_send_1(exch, VFS_OUT_FSPROBE, (sysarg_t) sid,
249 &answer);
250 if (msg == 0)
251 return EINVAL;
252
253 /* Read probe information */
254 retval = async_data_read_start(exch, info, sizeof(*info));
255 if (retval != EOK) {
256 async_forget(msg);
257 return retval;
258 }
259
260 async_wait_for(msg, &rc);
261 vfs_exchange_release(exch);
262 return rc;
263}
264
265errno_t vfs_op_mount(int mpfd, unsigned service_id, unsigned flags,
266 unsigned instance, const char *opts, const char *fs_name, int *out_fd)
267{
268 errno_t rc;
269 vfs_file_t *mp = NULL;
270 vfs_file_t *file = NULL;
271 *out_fd = -1;
272
273 if (!(flags & VFS_MOUNT_CONNECT_ONLY)) {
274 mp = vfs_file_get(mpfd);
275 if (mp == NULL) {
276 rc = EBADF;
277 goto out;
278 }
279
280 if (mp->node->mount != NULL) {
281 rc = EBUSY;
282 goto out;
283 }
284
285 if (mp->node->type != VFS_NODE_DIRECTORY) {
286 rc = ENOTDIR;
287 goto out;
288 }
289
290 if (vfs_node_has_children(mp->node)) {
291 rc = ENOTEMPTY;
292 goto out;
293 }
294 }
295
296 if (!(flags & VFS_MOUNT_NO_REF)) {
297 rc = vfs_fd_alloc(&file, false, out_fd);
298 if (rc != EOK) {
299 goto out;
300 }
301 }
302
303 vfs_node_t *root = NULL;
304
305 fibril_rwlock_write_lock(&namespace_rwlock);
306
307 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name,
308 &root);
309 if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) {
310 vfs_node_addref(mp->node);
311 vfs_node_addref(root);
312 mp->node->mount = root;
313 }
314
315 fibril_rwlock_write_unlock(&namespace_rwlock);
316
317 if (rc != EOK)
318 goto out;
319
320 if (flags & VFS_MOUNT_NO_REF) {
321 vfs_node_delref(root);
322 } else {
323 assert(file != NULL);
324
325 file->node = root;
326 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
327 file->open_read = false;
328 file->open_write = false;
329 }
330
331out:
332 if (mp)
333 vfs_file_put(mp);
334 if (file)
335 vfs_file_put(file);
336
337 if (rc != EOK && *out_fd >= 0) {
338 vfs_fd_free(*out_fd);
339 *out_fd = -1;
340 }
341
342 return rc;
343}
344
345errno_t vfs_op_open(int fd, int mode)
346{
347 if (mode == 0)
348 return EINVAL;
349
350 vfs_file_t *file = vfs_file_get(fd);
351 if (!file)
352 return EBADF;
353
354 if ((mode & ~file->permissions) != 0) {
355 vfs_file_put(file);
356 return EPERM;
357 }
358
359 if (file->open_read || file->open_write) {
360 vfs_file_put(file);
361 return EBUSY;
362 }
363
364 file->open_read = (mode & MODE_READ) != 0;
365 file->open_write = (mode & (MODE_WRITE | MODE_APPEND)) != 0;
366 file->append = (mode & MODE_APPEND) != 0;
367
368 if (!file->open_read && !file->open_write) {
369 vfs_file_put(file);
370 return EINVAL;
371 }
372
373 if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) {
374 file->open_read = file->open_write = false;
375 vfs_file_put(file);
376 return EINVAL;
377 }
378
379 errno_t rc = vfs_open_node_remote(file->node);
380 if (rc != EOK) {
381 file->open_read = file->open_write = false;
382 vfs_file_put(file);
383 return rc;
384 }
385
386 vfs_file_put(file);
387 return EOK;
388}
389
390typedef errno_t (*rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, aoff64_t,
391 ipc_call_t *, bool, void *);
392
393static errno_t rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
394 ipc_call_t *answer, bool read, void *data)
395{
396 size_t *bytes = (size_t *) data;
397 errno_t rc;
398
399 /*
400 * Make a VFS_READ/VFS_WRITE request at the destination FS server
401 * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
402 * destination FS server. The call will be routed as if sent by
403 * ourselves. Note that call arguments are immutable in this case so we
404 * don't have to bother.
405 */
406
407 if (read) {
408 rc = async_data_read_forward_4_1(exch, VFS_OUT_READ,
409 file->node->service_id, file->node->index,
410 LOWER32(pos), UPPER32(pos), answer);
411 } else {
412 rc = async_data_write_forward_4_1(exch, VFS_OUT_WRITE,
413 file->node->service_id, file->node->index,
414 LOWER32(pos), UPPER32(pos), answer);
415 }
416
417 *bytes = ipc_get_arg1(answer);
418 return rc;
419}
420
421static errno_t rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
422 ipc_call_t *answer, bool read, void *data)
423{
424 rdwr_io_chunk_t *chunk = (rdwr_io_chunk_t *) data;
425
426 if (exch == NULL)
427 return ENOENT;
428
429 aid_t msg = async_send_4(exch, read ? VFS_OUT_READ : VFS_OUT_WRITE,
430 file->node->service_id, file->node->index, LOWER32(pos),
431 UPPER32(pos), answer);
432 if (msg == 0)
433 return EINVAL;
434
435 errno_t retval = async_data_read_start(exch, chunk->buffer, chunk->size);
436 if (retval != EOK) {
437 async_forget(msg);
438 return retval;
439 }
440
441 errno_t rc;
442 async_wait_for(msg, &rc);
443
444 chunk->size = ipc_get_arg1(answer);
445
446 return rc;
447}
448
449static errno_t vfs_rdwr(int fd, aoff64_t pos, bool read, rdwr_ipc_cb_t ipc_cb,
450 void *ipc_cb_data)
451{
452 /*
453 * The following code strongly depends on the fact that the files data
454 * structure can be only accessed by a single fibril and all file
455 * operations are serialized (i.e. the reads and writes cannot
456 * interleave and a file cannot be closed while it is being read).
457 *
458 * Additional synchronization needs to be added once the table of
459 * open files supports parallel access!
460 */
461
462 /* Lookup the file structure corresponding to the file descriptor. */
463 vfs_file_t *file = vfs_file_get(fd);
464 if (!file)
465 return EBADF;
466
467 if ((read && !file->open_read) || (!read && !file->open_write)) {
468 vfs_file_put(file);
469 return EINVAL;
470 }
471
472 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
473 assert(fs_info);
474
475 bool rlock = read ||
476 (fs_info->concurrent_read_write && fs_info->write_retains_size);
477
478 /*
479 * Lock the file's node so that no other client can read/write to it at
480 * the same time unless the FS supports concurrent reads/writes and its
481 * write implementation does not modify the file size.
482 */
483 if (rlock)
484 fibril_rwlock_read_lock(&file->node->contents_rwlock);
485 else
486 fibril_rwlock_write_lock(&file->node->contents_rwlock);
487
488 if (file->node->type == VFS_NODE_DIRECTORY) {
489 /*
490 * Make sure that no one is modifying the namespace
491 * while we are in readdir().
492 */
493
494 if (!read) {
495 if (rlock) {
496 fibril_rwlock_read_unlock(
497 &file->node->contents_rwlock);
498 } else {
499 fibril_rwlock_write_unlock(
500 &file->node->contents_rwlock);
501 }
502 vfs_file_put(file);
503 return EINVAL;
504 }
505
506 fibril_rwlock_read_lock(&namespace_rwlock);
507 }
508
509 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
510
511 if (!read && file->append)
512 pos = file->node->size;
513
514 /*
515 * Handle communication with the endpoint FS.
516 */
517 ipc_call_t answer;
518 errno_t rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data);
519
520 vfs_exchange_release(fs_exch);
521
522 if (file->node->type == VFS_NODE_DIRECTORY)
523 fibril_rwlock_read_unlock(&namespace_rwlock);
524
525 /* Unlock the VFS node. */
526 if (rlock) {
527 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
528 } else {
529 /* Update the cached version of node's size. */
530 if (rc == EOK) {
531 file->node->size = MERGE_LOUP32(ipc_get_arg2(&answer),
532 ipc_get_arg3(&answer));
533 }
534 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
535 }
536
537 vfs_file_put(file);
538
539 return rc;
540}
541
542errno_t vfs_rdwr_internal(int fd, aoff64_t pos, bool read, rdwr_io_chunk_t *chunk)
543{
544 return vfs_rdwr(fd, pos, read, rdwr_ipc_internal, chunk);
545}
546
547errno_t vfs_op_read(int fd, aoff64_t pos, size_t *out_bytes)
548{
549 return vfs_rdwr(fd, pos, true, rdwr_ipc_client, out_bytes);
550}
551
552errno_t vfs_op_rename(int basefd, char *old, char *new)
553{
554 vfs_file_t *base_file = vfs_file_get(basefd);
555 if (!base_file)
556 return EBADF;
557
558 vfs_node_t *base = base_file->node;
559 vfs_node_addref(base);
560 vfs_file_put(base_file);
561
562 vfs_lookup_res_t base_lr;
563 vfs_lookup_res_t old_lr;
564 vfs_lookup_res_t new_lr_orig;
565 bool orig_unlinked = false;
566
567 errno_t rc;
568
569 size_t shared = shared_path(old, new);
570
571 /* Do not allow one path to be a prefix of the other. */
572 if (old[shared] == 0 || new[shared] == 0) {
573 vfs_node_put(base);
574 return EINVAL;
575 }
576 assert(old[shared] == '/');
577 assert(new[shared] == '/');
578
579 fibril_rwlock_write_lock(&namespace_rwlock);
580
581 /* Resolve the shared portion of the path first. */
582 if (shared != 0) {
583 old[shared] = 0;
584 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
585 if (rc != EOK) {
586 vfs_node_put(base);
587 fibril_rwlock_write_unlock(&namespace_rwlock);
588 return rc;
589 }
590
591 vfs_node_put(base);
592 base = vfs_node_get(&base_lr);
593 if (!base) {
594 fibril_rwlock_write_unlock(&namespace_rwlock);
595 return ENOMEM;
596 }
597 old[shared] = '/';
598 old += shared;
599 new += shared;
600 }
601
602 rc = vfs_lookup_internal(base, old, L_DISABLE_MOUNTS, &old_lr);
603 if (rc != EOK) {
604 vfs_node_put(base);
605 fibril_rwlock_write_unlock(&namespace_rwlock);
606 return rc;
607 }
608
609 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS,
610 &new_lr_orig);
611 if (rc == EOK) {
612 orig_unlinked = true;
613 } else if (rc != ENOENT) {
614 vfs_node_put(base);
615 fibril_rwlock_write_unlock(&namespace_rwlock);
616 return rc;
617 }
618
619 rc = vfs_link_internal(base, new, &old_lr.triplet);
620 if (rc != EOK) {
621 vfs_link_internal(base, old, &old_lr.triplet);
622 if (orig_unlinked)
623 vfs_link_internal(base, new, &new_lr_orig.triplet);
624 vfs_node_put(base);
625 fibril_rwlock_write_unlock(&namespace_rwlock);
626 return rc;
627 }
628
629 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS,
630 &old_lr);
631 if (rc != EOK) {
632 if (orig_unlinked)
633 vfs_link_internal(base, new, &new_lr_orig.triplet);
634 vfs_node_put(base);
635 fibril_rwlock_write_unlock(&namespace_rwlock);
636 return rc;
637 }
638
639 /* If the node is not held by anyone, try to destroy it. */
640 if (orig_unlinked) {
641 vfs_node_t *node = vfs_node_peek(&new_lr_orig);
642 if (!node)
643 out_destroy(&new_lr_orig.triplet);
644 else
645 vfs_node_put(node);
646 }
647
648 vfs_node_put(base);
649 fibril_rwlock_write_unlock(&namespace_rwlock);
650 return EOK;
651}
652
653errno_t vfs_op_resize(int fd, int64_t size)
654{
655 vfs_file_t *file = vfs_file_get(fd);
656 if (!file)
657 return EBADF;
658
659 if (!file->open_write || file->node->type != VFS_NODE_FILE) {
660 vfs_file_put(file);
661 return EINVAL;
662 }
663
664 fibril_rwlock_write_lock(&file->node->contents_rwlock);
665
666 errno_t rc = vfs_truncate_internal(file->node->fs_handle,
667 file->node->service_id, file->node->index, size);
668 if (rc == EOK)
669 file->node->size = size;
670
671 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
672 vfs_file_put(file);
673 return rc;
674}
675
676errno_t vfs_op_stat(int fd)
677{
678 vfs_file_t *file = vfs_file_get(fd);
679 if (!file)
680 return EBADF;
681
682 vfs_node_t *node = file->node;
683
684 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
685 errno_t rc = async_data_read_forward_3_0(exch, VFS_OUT_STAT,
686 node->service_id, node->index, true);
687 vfs_exchange_release(exch);
688
689 vfs_file_put(file);
690 return rc;
691}
692
693errno_t vfs_op_statfs(int fd)
694{
695 vfs_file_t *file = vfs_file_get(fd);
696 if (!file)
697 return EBADF;
698
699 vfs_node_t *node = file->node;
700
701 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
702 errno_t rc = async_data_read_forward_3_0(exch, VFS_OUT_STATFS,
703 node->service_id, node->index, false);
704 vfs_exchange_release(exch);
705
706 vfs_file_put(file);
707 return rc;
708}
709
710errno_t vfs_op_sync(int fd)
711{
712 vfs_file_t *file = vfs_file_get(fd);
713 if (!file)
714 return EBADF;
715
716 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
717
718 aid_t msg;
719 ipc_call_t answer;
720 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
721 file->node->index, &answer);
722
723 vfs_exchange_release(fs_exch);
724
725 errno_t rc;
726 async_wait_for(msg, &rc);
727
728 vfs_file_put(file);
729 return rc;
730
731}
732
733static errno_t vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
734 fs_index_t index, aoff64_t size)
735{
736 async_exch_t *exch = vfs_exchange_grab(fs_handle);
737 errno_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
738 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
739 UPPER32(size));
740 vfs_exchange_release(exch);
741
742 return rc;
743}
744
745errno_t vfs_op_unlink(int parentfd, int expectfd, char *path)
746{
747 errno_t rc = EOK;
748 vfs_file_t *parent = NULL;
749 vfs_file_t *expect = NULL;
750
751 if (parentfd == expectfd)
752 return EINVAL;
753
754 fibril_rwlock_write_lock(&namespace_rwlock);
755
756 /*
757 * Files are retrieved in order of file descriptors, to prevent
758 * deadlock.
759 */
760 if (parentfd < expectfd) {
761 parent = vfs_file_get(parentfd);
762 if (!parent) {
763 rc = EBADF;
764 goto exit;
765 }
766 }
767
768 if (expectfd >= 0) {
769 expect = vfs_file_get(expectfd);
770 if (!expect) {
771 rc = EBADF;
772 goto exit;
773 }
774 }
775
776 if (parentfd > expectfd) {
777 parent = vfs_file_get(parentfd);
778 if (!parent) {
779 rc = EBADF;
780 goto exit;
781 }
782 }
783
784 assert(parent != NULL);
785
786 if (expectfd >= 0) {
787 vfs_lookup_res_t lr;
788 rc = vfs_lookup_internal(parent->node, path, 0, &lr);
789 if (rc != EOK)
790 goto exit;
791
792 vfs_node_t *found_node = vfs_node_peek(&lr);
793 vfs_node_put(found_node);
794 if (expect->node != found_node) {
795 rc = ENOENT;
796 goto exit;
797 }
798
799 vfs_file_put(expect);
800 expect = NULL;
801 }
802
803 vfs_lookup_res_t lr;
804 rc = vfs_lookup_internal(parent->node, path, L_UNLINK, &lr);
805 if (rc != EOK)
806 goto exit;
807
808 /* If the node is not held by anyone, try to destroy it. */
809 vfs_node_t *node = vfs_node_peek(&lr);
810 if (!node)
811 out_destroy(&lr.triplet);
812 else
813 vfs_node_put(node);
814
815exit:
816 if (path)
817 free(path);
818 if (parent)
819 vfs_file_put(parent);
820 if (expect)
821 vfs_file_put(expect);
822 fibril_rwlock_write_unlock(&namespace_rwlock);
823 return rc;
824}
825
826errno_t vfs_op_unmount(int mpfd)
827{
828 vfs_file_t *mp = vfs_file_get(mpfd);
829 if (mp == NULL)
830 return EBADF;
831
832 if (mp->node->mount == NULL) {
833 vfs_file_put(mp);
834 return ENOENT;
835 }
836
837 fibril_rwlock_write_lock(&namespace_rwlock);
838
839 /*
840 * Count the total number of references for the mounted file system. We
841 * are expecting at least one, which is held by the mount point.
842 * If we find more, it means that
843 * the file system cannot be gracefully unmounted at the moment because
844 * someone is working with it.
845 */
846 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle,
847 mp->node->mount->service_id) != 1) {
848 vfs_file_put(mp);
849 fibril_rwlock_write_unlock(&namespace_rwlock);
850 return EBUSY;
851 }
852
853 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
854 errno_t rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
855 mp->node->mount->service_id);
856 vfs_exchange_release(exch);
857
858 if (rc != EOK) {
859 vfs_file_put(mp);
860 fibril_rwlock_write_unlock(&namespace_rwlock);
861 return rc;
862 }
863
864 vfs_node_forget(mp->node->mount);
865 vfs_node_put(mp->node);
866 mp->node->mount = NULL;
867
868 fibril_rwlock_write_unlock(&namespace_rwlock);
869
870 vfs_file_put(mp);
871 return EOK;
872}
873
874errno_t vfs_op_wait_handle(bool high_fd, int *out_fd)
875{
876 return vfs_wait_handle_internal(high_fd, out_fd);
877}
878
879static inline bool walk_flags_valid(int flags)
880{
881 if ((flags & ~WALK_ALL_FLAGS) != 0)
882 return false;
883 if ((flags & WALK_MAY_CREATE) && (flags & WALK_MUST_CREATE))
884 return false;
885 if ((flags & WALK_REGULAR) && (flags & WALK_DIRECTORY))
886 return false;
887 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) {
888 if (!(flags & WALK_DIRECTORY) && !(flags & WALK_REGULAR))
889 return false;
890 }
891 return true;
892}
893
894static inline int walk_lookup_flags(int flags)
895{
896 int lflags = 0;
897 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE))
898 lflags |= L_CREATE;
899 if (flags & WALK_MUST_CREATE)
900 lflags |= L_EXCLUSIVE;
901 if (flags & WALK_REGULAR)
902 lflags |= L_FILE;
903 if (flags & WALK_DIRECTORY)
904 lflags |= L_DIRECTORY;
905 if (flags & WALK_MOUNT_POINT)
906 lflags |= L_MP;
907 return lflags;
908}
909
910errno_t vfs_op_walk(int parentfd, int flags, char *path, int *out_fd)
911{
912 if (!walk_flags_valid(flags))
913 return EINVAL;
914
915 vfs_file_t *parent = vfs_file_get(parentfd);
916 if (!parent)
917 return EBADF;
918
919 fibril_rwlock_read_lock(&namespace_rwlock);
920
921 vfs_lookup_res_t lr;
922 errno_t rc = vfs_lookup_internal(parent->node, path,
923 walk_lookup_flags(flags), &lr);
924 if (rc != EOK) {
925 fibril_rwlock_read_unlock(&namespace_rwlock);
926 vfs_file_put(parent);
927 return rc;
928 }
929
930 vfs_node_t *node = vfs_node_get(&lr);
931 if (!node) {
932 fibril_rwlock_read_unlock(&namespace_rwlock);
933 vfs_file_put(parent);
934 return ENOMEM;
935 }
936
937 vfs_file_t *file;
938 rc = vfs_fd_alloc(&file, false, out_fd);
939 if (rc != EOK) {
940 fibril_rwlock_read_unlock(&namespace_rwlock);
941 vfs_node_put(node);
942 vfs_file_put(parent);
943 return rc;
944 }
945 assert(file != NULL);
946
947 file->node = node;
948 file->permissions = parent->permissions;
949 file->open_read = false;
950 file->open_write = false;
951
952 vfs_file_put(file);
953 vfs_file_put(parent);
954
955 fibril_rwlock_read_unlock(&namespace_rwlock);
956
957 return EOK;
958}
959
960errno_t vfs_op_write(int fd, aoff64_t pos, size_t *out_bytes)
961{
962 return vfs_rdwr(fd, pos, false, rdwr_ipc_client, out_bytes);
963}
964
965/**
966 * @}
967 */
Note: See TracBrowser for help on using the repository browser.