source: mainline/uspace/srv/vfs/vfs_ops.c@ 35e81e2

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

Streamline vfs_op_statfs()

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