source: mainline/uspace/srv/vfs/vfs_ops.c@ 79ea5af

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 79ea5af was 79ea5af, checked in by Jakub Jermar <jakub@…>, 8 years ago

Rename unlink() to vfs_unlink_path() and _vfs_unlink() to vfs_unlink()

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