source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 1be7bee

Last change on this file since 1be7bee was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

  • Property mode set to 100644
File size: 32.9 KB
RevLine 
[2f02aa17]1/*
[64d2b10]2 * Copyright (c) 2008 Jakub Jermar
[2f02aa17]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 libc
30 * @{
31 */
32/** @file
33 */
[19b28b0]34
[79ae36dd]35#include <vfs/vfs.h>
[438f355]36#include <vfs/canonify.h>
[8ffedd8]37#include <vfs/vfs_mtab.h>
[79ae36dd]38#include <vfs/vfs_sess.h>
[ed903174]39#include <macros.h>
[d0dc74ae]40#include <stdlib.h>
[8d2dd7f2]41#include <stddef.h>
42#include <stdint.h>
[2f02aa17]43#include <ipc/services.h>
[79ae36dd]44#include <ns.h>
[2f02aa17]45#include <async.h>
[a28ab12]46#include <fibril_synch.h>
[2f02aa17]47#include <errno.h>
[a28ab12]48#include <assert.h>
[19f857a]49#include <str.h>
[15f3c3f]50#include <loc.h>
[2595dab]51#include <ipc/vfs.h>
[15f3c3f]52#include <ipc/loc.h>
[2f02aa17]53
[ca7506f]54/*
55 * This file contains the implementation of the native HelenOS file system API.
56 *
57 * The API supports client-side file system roots, client-side IO cursors and
58 * uses file handles as a primary means to refer to files. In order to call the
59 * API functions, one just includes vfs/vfs.h.
60 *
61 * The API functions come in two main flavors:
62 *
63 * - functions that operate on integer file handles, such as:
64 * vfs_walk(), vfs_open(), vfs_read(), vfs_link(), ...
[1b20da0]65 *
[ca7506f]66 * - functions that operate on paths, such as:
67 * vfs_lookup(), vfs_link_path(), vfs_unlink_path(), vfs_rename_path(), ...
68 *
69 * There is usually a corresponding path function for each file handle function
70 * that exists mostly as a convenience wrapper, except for cases when only a
71 * path version exists due to file system consistency considerations (see
72 * vfs_rename_path()). Sometimes one of the versions does not make sense, in
73 * which case it is also omitted.
74 *
75 * Besides of that, the API provides some convenience wrappers for frequently
76 * performed pairs of operations, for example there is a combo API for
77 * vfs_lookup() and vfs_open(): vfs_lookup_open().
78 *
79 * Some of the functions here return a file handle that can be passed to other
80 * functions. Note that a file handle does not automatically represent a file
81 * from which one can read or to which one can write. In order to do so, the
82 * file handle must be opened first for reading/writing using vfs_open().
83 *
84 * All file handles, no matter whether opened or not, must be eventually
85 * returned to the system using vfs_put(). Non-returned file handles are in use
86 * and consume system resources.
87 *
[b7fd2a0]88 * Functions that return errno_t return an error code on error and do not
[ca7506f]89 * set errno. Depending on function, success is signalled by returning either
90 * EOK or a non-negative file handle.
91 *
92 * An example life-cycle of a file handle is as follows:
93 *
94 * #include <vfs/vfs.h>
95 *
96 * int file = vfs_lookup("/foo/bar/foobar", WALK_REGULAR);
97 * if (file < 0)
98 * return file;
[b7fd2a0]99 * errno_t rc = vfs_open(file, MODE_READ);
[ca7506f]100 * if (rc != EOK) {
101 * (void) vfs_put(file);
102 * return rc;
103 * }
104 * aoff64_t pos = 42;
105 * char buf[512];
[8e3498b]106 * size_t nread;
107 * rc = vfs_read(file, &pos, buf, sizeof(buf), &nread);
108 * if (rc != EOK) {
[ca7506f]109 * vfs_put(file);
[8e3498b]110 * return rc;
[ca7506f]111 * }
112 *
[8e3498b]113 * // buf is now filled with nread bytes from file
[ca7506f]114 *
115 * vfs_put(file);
116 */
117
[79ae36dd]118static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
119static async_sess_t *vfs_sess = NULL;
[a28ab12]120
121static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
[5fec355]122
[2b88074b]123static int cwd_fd = -1;
124static char *cwd_path = NULL;
125static size_t cwd_size = 0;
[5fec355]126
[5126f80]127static FIBRIL_MUTEX_INITIALIZE(root_mutex);
128static int root_fd = -1;
129
[b7fd2a0]130static errno_t get_parent_and_child(const char *path, int *parent, char **child)
[eca9fd0]131{
132 size_t size;
[3ba431a]133 char *apath = vfs_absolutize(path, &size);
134 if (!apath)
[eca9fd0]135 return ENOMEM;
[b19e892]136
[3ba431a]137 char *slash = str_rchr(apath, L'/');
138 if (slash == apath) {
[f77c1c9]139 *parent = vfs_root();
140 if (*parent < 0) {
141 free(apath);
142 return EBADF;
143 }
[3ba431a]144 *child = apath;
[f77c1c9]145 return EOK;
[3ba431a]146 } else {
147 *slash = '\0';
[b7fd2a0]148 errno_t rc = vfs_lookup(apath, WALK_DIRECTORY, parent);
[f77c1c9]149 if (rc != EOK) {
[3ba431a]150 free(apath);
[f77c1c9]151 return rc;
[3ba431a]152 }
153 *slash = '/';
154 *child = str_dup(slash);
155 free(apath);
156 if (!*child) {
[f77c1c9]157 vfs_put(*parent);
[3ba431a]158 return ENOMEM;
159 }
[f77c1c9]160
161 return rc;
[b19e892]162 }
[3ba431a]163
[0b18364]164}
165
[ca7506f]166/** Make a potentially relative path absolute
167 *
168 * This function coverts a current-working-directory-relative path into a
169 * well-formed, absolute path. The caller is responsible for deallocating the
170 * returned buffer.
171 *
172 * @param[in] path Path to be absolutized
173 * @param[out] retlen Length of the absolutized path
174 *
175 * @return New buffer holding the absolutized path or NULL
176 */
[6afc9d7]177char *vfs_absolutize(const char *path, size_t *retlen)
[5fec355]178{
179 char *ncwd_path;
[34a74ab]180 char *ncwd_path_nc;
[5fec355]181
[a28ab12]182 fibril_mutex_lock(&cwd_mutex);
[9eb3623]183 size_t size = str_size(path);
[5fec355]184 if (*path != '/') {
[6afc9d7]185 if (cwd_path == NULL) {
[a28ab12]186 fibril_mutex_unlock(&cwd_mutex);
[5fec355]187 return NULL;
188 }
[79ae36dd]189 ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
[6afc9d7]190 if (ncwd_path_nc == NULL) {
[a28ab12]191 fibril_mutex_unlock(&cwd_mutex);
[5fec355]192 return NULL;
193 }
[79ae36dd]194 str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
[9eb3623]195 ncwd_path_nc[cwd_size] = '/';
196 ncwd_path_nc[cwd_size + 1] = '\0';
[5fec355]197 } else {
[79ae36dd]198 ncwd_path_nc = malloc(size + 1);
[6afc9d7]199 if (ncwd_path_nc == NULL) {
[a28ab12]200 fibril_mutex_unlock(&cwd_mutex);
[5fec355]201 return NULL;
202 }
[34a74ab]203 ncwd_path_nc[0] = '\0';
[5fec355]204 }
[79ae36dd]205 str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
[34a74ab]206 ncwd_path = canonify(ncwd_path_nc, retlen);
[6afc9d7]207 if (ncwd_path == NULL) {
[a28ab12]208 fibril_mutex_unlock(&cwd_mutex);
[34a74ab]209 free(ncwd_path_nc);
210 return NULL;
211 }
212 /*
213 * We need to clone ncwd_path because canonify() works in-place and thus
214 * the address in ncwd_path need not be the same as ncwd_path_nc, even
215 * though they both point into the same dynamically allocated buffer.
216 */
[095003a8]217 ncwd_path = str_dup(ncwd_path);
[34a74ab]218 free(ncwd_path_nc);
[6afc9d7]219 if (ncwd_path == NULL) {
[a28ab12]220 fibril_mutex_unlock(&cwd_mutex);
[923c39e]221 return NULL;
222 }
[a28ab12]223 fibril_mutex_unlock(&cwd_mutex);
[5fec355]224 return ncwd_path;
225}
[2f02aa17]226
[3ba431a]227/** Clone a file handle
[ca7506f]228 *
[3ba431a]229 * The caller can choose whether to clone an existing file handle into another
230 * already existing file handle (in which case it is first closed) or to a new
231 * file handle allocated either from low or high indices.
[ca7506f]232 *
[3ba431a]233 * @param file_from Source file handle
234 * @param file_to Destination file handle or -1
235 * @param high If file_to is -1, high controls whether the new file
236 * handle will be allocated from high indices
237 *
[cde999a]238 * @return New file handle on success or an error code
[ca7506f]239 */
[b7fd2a0]240errno_t vfs_clone(int file_from, int file_to, bool high, int *handle)
[5126f80]241{
[f77c1c9]242 assert(handle != NULL);
243
[3ba431a]244 async_exch_t *vfs_exch = vfs_exchange_begin();
[f77c1c9]245 sysarg_t ret;
[b7fd2a0]246 errno_t rc = async_req_3_1(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
[f77c1c9]247 (sysarg_t) file_to, (sysarg_t) high, &ret);
[3ba431a]248 vfs_exchange_end(vfs_exch);
[f77c1c9]249
250 if (rc == EOK) {
251 *handle = ret;
252 }
[3ba431a]253 return rc;
254}
[5126f80]255
[3ba431a]256/** Get current working directory path
257 *
258 * @param[out] buf Buffer
259 * @param size Size of @a buf
260 *
[cde999a]261 * @return EOK on success or a non-error code
[3ba431a]262 */
[b7fd2a0]263errno_t vfs_cwd_get(char *buf, size_t size)
[3ba431a]264{
265 fibril_mutex_lock(&cwd_mutex);
[a35b458]266
[3ba431a]267 if ((cwd_size == 0) || (size < cwd_size + 1)) {
268 fibril_mutex_unlock(&cwd_mutex);
269 return ERANGE;
[5126f80]270 }
[a35b458]271
[3ba431a]272 str_cpy(buf, size, cwd_path);
273 fibril_mutex_unlock(&cwd_mutex);
[a35b458]274
[3ba431a]275 return EOK;
[5126f80]276}
277
[3ba431a]278/** Change working directory
[ca7506f]279 *
[3ba431a]280 * @param path Path of the new working directory
[ca7506f]281 *
[cde999a]282 * @return EOK on success or an error code
[ca7506f]283 */
[b7fd2a0]284errno_t vfs_cwd_set(const char *path)
[5126f80]285{
[3ba431a]286 size_t abs_size;
[7d7bc09]287 char *abs_path = vfs_absolutize(path, &abs_size);
288 if (abs_path == NULL)
[3ba431a]289 return ENOMEM;
[a35b458]290
[f77c1c9]291 int fd;
[7d7bc09]292 errno_t rc = vfs_lookup(abs_path, WALK_DIRECTORY, &fd);
[f77c1c9]293 if (rc != EOK) {
[7d7bc09]294 free(abs_path);
[f77c1c9]295 return rc;
[3ba431a]296 }
[a35b458]297
[3ba431a]298 fibril_mutex_lock(&cwd_mutex);
[a35b458]299
[3ba431a]300 if (cwd_fd >= 0)
301 vfs_put(cwd_fd);
[a35b458]302
[3ba431a]303 if (cwd_path)
304 free(cwd_path);
[a35b458]305
[3ba431a]306 cwd_fd = fd;
[7d7bc09]307 cwd_path = abs_path;
[3ba431a]308 cwd_size = abs_size;
[a35b458]309
[3ba431a]310 fibril_mutex_unlock(&cwd_mutex);
311 return EOK;
312}
313
314/** Start an async exchange on the VFS session
315 *
316 * @return New exchange
317 */
318async_exch_t *vfs_exchange_begin(void)
319{
320 fibril_mutex_lock(&vfs_mutex);
[a35b458]321
[3ba431a]322 while (vfs_sess == NULL) {
323 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
324 0);
325 }
[a35b458]326
[3ba431a]327 fibril_mutex_unlock(&vfs_mutex);
[a35b458]328
[3ba431a]329 return async_exchange_begin(vfs_sess);
330}
331
332/** Finish an async exchange on the VFS session
333 *
334 * @param exch Exchange to be finished
335 */
336void vfs_exchange_end(async_exch_t *exch)
337{
338 async_exchange_end(exch);
339}
340
341/** Open session to service represented by a special file
342 *
343 * Given that the file referred to by @a file represents a service,
344 * open a session to that service.
345 *
346 * @param file File handle representing a service
347 * @param iface Interface to connect to (XXX Should be automatic)
348 *
349 * @return Session pointer on success.
350 * @return @c NULL or error.
351 */
352async_sess_t *vfs_fd_session(int file, iface_t iface)
353{
[39330200]354 vfs_stat_t stat;
[b7fd2a0]355 errno_t rc = vfs_stat(file, &stat);
[a53ed3a]356 if (rc != EOK)
[3ba431a]357 return NULL;
[a35b458]358
[3ba431a]359 if (stat.service == 0)
360 return NULL;
[a35b458]361
[3ba431a]362 return loc_service_connect(stat.service, iface, 0);
363}
364
[d2c8533]365/** Determine if a device contains the specified file system type. If so,
366 * return identification information.
367 *
368 * @param fs_name File system name
369 * @param serv Service representing the mountee
370 * @param info Place to store volume identification information
371 *
[cde999a]372 * @return EOK on success or an error code
[d2c8533]373 */
[b7fd2a0]374errno_t vfs_fsprobe(const char *fs_name, service_id_t serv,
[d2c8533]375 vfs_fs_probe_info_t *info)
376{
[b7fd2a0]377 errno_t rc;
[a35b458]378
[d2c8533]379 ipc_call_t answer;
380 async_exch_t *exch = vfs_exchange_begin();
381 aid_t req = async_send_1(exch, VFS_IN_FSPROBE, serv, &answer);
[a35b458]382
[d2c8533]383 rc = async_data_write_start(exch, (void *) fs_name,
384 str_size(fs_name));
[a35b458]385
[d2c8533]386 async_wait_for(req, &rc);
[a35b458]387
[d2c8533]388 if (rc != EOK) {
389 vfs_exchange_end(exch);
390 return rc;
391 }
[a35b458]392
[d2c8533]393 rc = async_data_read_start(exch, info, sizeof(*info));
394 vfs_exchange_end(exch);
[a35b458]395
[d2c8533]396 return rc;
397}
398
[b14d9f9]399/** Return a list of currently available file system types
400 *
401 * @param fstypes Points to structure where list of filesystem types is
402 * stored. It is read as a null-terminated list of strings
403 * fstypes->fstypes[0..]. To free the list use vfs_fstypes_free().
404 *
[cde999a]405 * @return EOK on success or an error code
[b14d9f9]406 */
[b7fd2a0]407errno_t vfs_fstypes(vfs_fstypes_t *fstypes)
[b14d9f9]408{
409 sysarg_t size;
410 char *buf;
411 char dummybuf[1];
412 size_t count, i;
413
414 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]415 errno_t rc = async_req_0_1(exch, VFS_IN_FSTYPES, &size);
[b14d9f9]416
417 if (rc != EOK) {
418 vfs_exchange_end(exch);
419 return rc;
420 }
421
422 buf = malloc(size);
423 if (buf == NULL) {
424 buf = dummybuf;
425 size = 1;
426 }
427
428 rc = async_data_read_start(exch, buf, size);
429 vfs_exchange_end(exch);
430
431 if (buf == dummybuf)
432 return ENOMEM;
433
434 /*
435 * Buffer should contain a number of null-terminated strings.
436 * Count them so that we can allocate an index
437 */
438 count = 0;
439 i = 0;
440 while (i < size) {
441 if (buf[i] == '\0')
442 ++count;
443 ++i;
444 }
445
446 if (count == 0) {
447 free(buf);
448 return EIO;
449 }
450
451 fstypes->fstypes = calloc(sizeof(char *), count + 1);
452 if (fstypes->fstypes == NULL) {
453 free(buf);
454 return ENOMEM;
455 }
456
457 /* Now fill the index */
458 if (buf[0] != '\0')
459 fstypes->fstypes[0] = &buf[0];
460 count = 0;
461 i = 0;
462 while (i < size) {
463 if (buf[i] == '\0')
464 fstypes->fstypes[++count] = &buf[i + 1];
465 ++i;
466 }
467 fstypes->fstypes[count] = NULL;
468 fstypes->buf = buf;
469 fstypes->size = size;
470
471 return rc;
472}
473
474/** Free list of file system types.
475 *
476 * @param fstypes List of file system types
477 */
478void vfs_fstypes_free(vfs_fstypes_t *fstypes)
479{
480 free(fstypes->buf);
481 fstypes->buf = NULL;
482 free(fstypes->fstypes);
483 fstypes->fstypes = NULL;
484 fstypes->size = 0;
485}
486
[3ba431a]487/** Link a file or directory
488 *
489 * Create a new name and an empty file or an empty directory in a parent
490 * directory. If child with the same name already exists, the function returns
491 * a failure, the existing file remains untouched and no file system object
492 * is created.
493 *
494 * @param parent File handle of the parent directory node
495 * @param child New name to be linked
496 * @param kind Kind of the object to be created: KIND_FILE or
497 * KIND_DIRECTORY
[a6fc88a]498 * @param[out] linkedfd If not NULL, will receive a file handle to the linked
499 * child
[cde999a]500 * @return EOK on success or an error code
[3ba431a]501 */
[b7fd2a0]502errno_t vfs_link(int parent, const char *child, vfs_file_kind_t kind, int *linkedfd)
[3ba431a]503{
504 int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR;
[f77c1c9]505 int file = -1;
[b7fd2a0]506 errno_t rc = vfs_walk(parent, child, WALK_MUST_CREATE | flags, &file);
[f77c1c9]507 if (rc != EOK)
508 return rc;
[3ba431a]509
[a6fc88a]510 if (linkedfd)
511 *linkedfd = file;
512 else
513 vfs_put(file);
[3ba431a]514
515 return EOK;
516}
517
518/** Link a file or directory
519 *
520 * Create a new name and an empty file or an empty directory at given path.
521 * If a link with the same name already exists, the function returns
522 * a failure, the existing file remains untouched and no file system object
523 * is created.
524 *
525 * @param path New path to be linked
526 * @param kind Kind of the object to be created: KIND_FILE or
527 * KIND_DIRECTORY
[a6fc88a]528 * @param[out] linkedfd If not NULL, will receive a file handle to the linked
529 * child
[cde999a]530 * @return EOK on success or an error code
[3ba431a]531 */
[b7fd2a0]532errno_t vfs_link_path(const char *path, vfs_file_kind_t kind, int *linkedfd)
[3ba431a]533{
534 char *child;
[f77c1c9]535 int parent;
[b7fd2a0]536 errno_t rc = get_parent_and_child(path, &parent, &child);
[f77c1c9]537 if (rc != EOK)
538 return rc;
[3ba431a]539
[f77c1c9]540 rc = vfs_link(parent, child, kind, linkedfd);
[3ba431a]541
542 free(child);
543 vfs_put(parent);
544 return rc;
[f77c1c9]545}
[3ba431a]546
547/** Lookup a path relative to the local root
548 *
549 * @param path Path to be looked up
550 * @param flags Walk flags
[f77c1c9]551 * @param[out] handle Pointer to variable where handle is to be written.
[3ba431a]552 *
[f77c1c9]553 * @return EOK on success or an error code.
[3ba431a]554 */
[b7fd2a0]555errno_t vfs_lookup(const char *path, int flags, int *handle)
[3ba431a]556{
557 size_t size;
558 char *p = vfs_absolutize(path, &size);
559 if (!p)
560 return ENOMEM;
[f77c1c9]561
[3ba431a]562 int root = vfs_root();
563 if (root < 0) {
564 free(p);
565 return ENOENT;
566 }
[f77c1c9]567
[0d0b319]568 // XXX: Workaround for GCC diagnostics.
569 *handle = -1;
570
[b7fd2a0]571 errno_t rc = vfs_walk(root, p, flags, handle);
[3ba431a]572 vfs_put(root);
573 free(p);
574 return rc;
575}
576
577/** Lookup a path relative to the local root and open the result
578 *
579 * This function is a convenience combo for vfs_lookup() and vfs_open().
580 *
581 * @param path Path to be looked up
582 * @param flags Walk flags
583 * @param mode Mode in which to open file in
[f77c1c9]584 * @param[out] handle Pointer to variable where handle is to be written.
[3ba431a]585 *
[cde999a]586 * @return EOK on success or an error code
[3ba431a]587 */
[b7fd2a0]588errno_t vfs_lookup_open(const char *path, int flags, int mode, int *handle)
[3ba431a]589{
[f77c1c9]590 int file;
[b7fd2a0]591 errno_t rc = vfs_lookup(path, flags, &file);
[f77c1c9]592 if (rc != EOK)
593 return rc;
[3ba431a]594
[f77c1c9]595 rc = vfs_open(file, mode);
[3ba431a]596 if (rc != EOK) {
597 vfs_put(file);
598 return rc;
599 }
[f77c1c9]600
601 *handle = file;
602 return EOK;
[3ba431a]603}
604
605/** Mount a file system
606 *
607 * @param[in] mp File handle representing the mount-point
608 * @param[in] fs_name File system name
609 * @param[in] serv Service representing the mountee
610 * @param[in] opts Mount options for the endpoint file system
611 * @param[in] flags Mount flags
612 * @param[in] instance Instance number of the file system server
613 * @param[out] mountedfd File handle of the mounted root if not NULL
614 *
[cde999a]615 * @return EOK on success or an error code
[3ba431a]616 */
[b7fd2a0]617errno_t vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
[3ba431a]618 unsigned int flags, unsigned int instance, int *mountedfd)
619{
[b7fd2a0]620 errno_t rc, rc1;
[a35b458]621
[3ba431a]622 if (!mountedfd)
623 flags |= VFS_MOUNT_NO_REF;
624 if (mp < 0)
625 flags |= VFS_MOUNT_CONNECT_ONLY;
[a35b458]626
[3ba431a]627 ipc_call_t answer;
628 async_exch_t *exch = vfs_exchange_begin();
629 aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance,
630 &answer);
631
632 rc1 = async_data_write_start(exch, (void *) opts, str_size(opts));
633 if (rc1 == EOK) {
634 rc1 = async_data_write_start(exch, (void *) fs_name,
635 str_size(fs_name));
636 }
637
638 vfs_exchange_end(exch);
639
640 async_wait_for(req, &rc);
641
642 if (mountedfd)
[fafb8e5]643 *mountedfd = (int) ipc_get_arg1(&answer);
[a35b458]644
[3ba431a]645 if (rc != EOK)
646 return rc;
647 return rc1;
648}
[5126f80]649
[ca7506f]650/** Mount a file system
651 *
652 * @param[in] mp Path representing the mount-point
653 * @param[in] fs_name File system name
654 * @param[in] fqsn Fully qualified service name of the mountee
655 * @param[in] opts Mount options for the endpoint file system
656 * @param[in] flags Mount flags
657 * @param[in] instance Instance number of the file system server
658 *
[cde999a]659 * @return EOK on success or an error code
[ca7506f]660 */
[b7fd2a0]661errno_t vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
[4979403]662 const char *opts, unsigned int flags, unsigned int instance)
[2f02aa17]663{
[210e50a]664 int null_id = -1;
[15f3c3f]665 char null[LOC_NAME_MAXLEN];
[a35b458]666
[15f3c3f]667 if (str_cmp(fqsn, "") == 0) {
[61042de]668 /*
669 * No device specified, create a fresh null/%d device instead.
[ae7d03c]670 */
[15f3c3f]671 null_id = loc_null_create();
[a35b458]672
[210e50a]673 if (null_id == -1)
674 return ENOMEM;
[a35b458]675
[15f3c3f]676 snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
677 fqsn = null;
[210e50a]678 }
[a35b458]679
[61042de]680 if (flags & IPC_FLAG_BLOCKING)
[5126f80]681 flags = VFS_MOUNT_BLOCKING;
[61042de]682 else
[5126f80]683 flags = 0;
[a35b458]684
[15f3c3f]685 service_id_t service_id;
[b7fd2a0]686 errno_t res = loc_service_get_id(fqsn, &service_id, flags);
[210e50a]687 if (res != EOK) {
688 if (null_id != -1)
[15f3c3f]689 loc_null_destroy(null_id);
[a35b458]690
[82405266]691 return res;
[210e50a]692 }
[a35b458]693
[9eb3623]694 size_t mpa_size;
[6afc9d7]695 char *mpa = vfs_absolutize(mp, &mpa_size);
696 if (mpa == NULL) {
[210e50a]697 if (null_id != -1)
[15f3c3f]698 loc_null_destroy(null_id);
[a35b458]699
[5fec355]700 return ENOMEM;
[210e50a]701 }
[a35b458]702
[5126f80]703 fibril_mutex_lock(&root_mutex);
[a35b458]704
[b7fd2a0]705 errno_t rc;
[a35b458]706
[5126f80]707 if (str_cmp(mpa, "/") == 0) {
708 /* Mounting root. */
[a35b458]709
[5126f80]710 if (root_fd >= 0) {
711 fibril_mutex_unlock(&root_mutex);
[61042de]712 if (null_id != -1)
[5126f80]713 loc_null_destroy(null_id);
714 return EBUSY;
715 }
[a35b458]716
[5126f80]717 int root;
[61042de]718 rc = vfs_mount(-1, fs_name, service_id, opts, flags, instance,
719 &root);
720 if (rc == EOK)
[5126f80]721 root_fd = root;
722 } else {
723 if (root_fd < 0) {
724 fibril_mutex_unlock(&root_mutex);
[61042de]725 if (null_id != -1)
[5126f80]726 loc_null_destroy(null_id);
727 return EINVAL;
728 }
[a35b458]729
[f77c1c9]730 int mpfd;
731 rc = vfs_walk(root_fd, mpa, WALK_DIRECTORY, &mpfd);
732 if (rc == EOK) {
[61042de]733 rc = vfs_mount(mpfd, fs_name, service_id, opts, flags,
734 instance, NULL);
[9c4cf0d]735 vfs_put(mpfd);
[5126f80]736 }
[2f02aa17]737 }
[a35b458]738
[5126f80]739 fibril_mutex_unlock(&root_mutex);
[a35b458]740
[210e50a]741 if ((rc != EOK) && (null_id != -1))
[15f3c3f]742 loc_null_destroy(null_id);
[a35b458]743
[b7fd2a0]744 return (errno_t) rc;
[2f02aa17]745}
746
[3ba431a]747/** Open a file handle for I/O
[ca7506f]748 *
[3ba431a]749 * @param file File handle to enable I/O on
750 * @param mode Mode in which to open file in
[ca7506f]751 *
[cde999a]752 * @return EOK on success or an error code
[ca7506f]753 */
[b7fd2a0]754errno_t vfs_open(int file, int mode)
[21f32ee1]755{
[3ba431a]756 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]757 errno_t rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode);
[3ba431a]758 vfs_exchange_end(exch);
[a35b458]759
[5126f80]760 return rc;
[21f32ee1]761}
762
[3ba431a]763/** Pass a file handle to another VFS client
764 *
765 * @param vfs_exch Donor's VFS exchange
766 * @param file Donor's file handle to pass
767 * @param exch Exchange to the acceptor
768 *
[cde999a]769 * @return EOK on success or an error code
[3ba431a]770 */
[b7fd2a0]771errno_t vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
[3ba431a]772{
773 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
774 0, vfs_exch);
775}
776
[ca7506f]777/** Stop working with a file handle
778 *
779 * @param file File handle to put
[6afc9d7]780 *
[cde999a]781 * @return EOK on success or an error code
[6afc9d7]782 */
[b7fd2a0]783errno_t vfs_put(int file)
[72bde81]784{
[79ae36dd]785 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]786 errno_t rc = async_req_1_0(exch, VFS_IN_PUT, file);
[79ae36dd]787 vfs_exchange_end(exch);
[a35b458]788
[ca7506f]789 return rc;
[72bde81]790}
791
[3ba431a]792/** Receive a file handle from another VFS client
[6afc9d7]793 *
[3ba431a]794 * @param high If true, the received file handle will be allocated from high
795 * indices
[f77c1c9]796 * @param[out] handle Received handle.
[6afc9d7]797 *
[cde999a]798 * @return EOK on success or an error code
[6afc9d7]799 */
[b7fd2a0]800errno_t vfs_receive_handle(bool high, int *handle)
[2f02aa17]801{
[984a9ba]802 ipc_call_t call;
803 if (!async_state_change_receive(&call)) {
804 async_answer_0(&call, EINVAL);
[3ba431a]805 return EINVAL;
806 }
[354b642]807
[3ba431a]808 async_exch_t *vfs_exch = vfs_exchange_begin();
[2f02aa17]809
[984a9ba]810 async_state_change_finalize(&call, vfs_exch);
[3ba431a]811
812 sysarg_t ret;
[b7fd2a0]813 errno_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret);
[3ba431a]814
815 async_exchange_end(vfs_exch);
[354b642]816
[f77c1c9]817 if (rc == EOK) {
818 *handle = (int) ret;
819 }
820
821 return rc;
[449c246]822}
[222e57c]823
[ca7506f]824/** Read data
[8fd04ba9]825 *
[6afc9d7]826 * Read up to @a nbytes bytes from file if available. This function always reads
827 * all the available bytes up to @a nbytes.
[8fd04ba9]828 *
[ca7506f]829 * @param file File handle to read from
830 * @param[inout] pos Position to read from, updated by the actual bytes read
[8fd04ba9]831 * @param buf Buffer, @a nbytes bytes long
832 * @param nbytes Number of bytes to read
[8e3498b]833 * @param nread Place to store number of bytes actually read
[8fd04ba9]834 *
[8e3498b]835 * @return On success, EOK and @a *nread is filled with number
836 * of bytes actually read.
837 * @return On failure, an error code
[8fd04ba9]838 */
[b7fd2a0]839errno_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte, size_t *nread)
[8fd04ba9]840{
841 ssize_t cnt = 0;
[8e3498b]842 size_t nr = 0;
[8fd04ba9]843 uint8_t *bp = (uint8_t *) buf;
[b7fd2a0]844 errno_t rc;
[a35b458]845
[8fd04ba9]846 do {
847 bp += cnt;
[8e3498b]848 nr += cnt;
[58898d1d]849 *pos += cnt;
[8e3498b]850 rc = vfs_read_short(file, *pos, bp, nbyte - nr, &cnt);
851 } while (rc == EOK && cnt > 0 && (nbyte - nr - cnt) > 0);
[a35b458]852
[8e3498b]853 if (rc != EOK) {
854 *nread = nr;
[ce04ea44]855 return rc;
[8e3498b]856 }
[a35b458]857
[8e3498b]858 nr += cnt;
[58898d1d]859 *pos += cnt;
[8e3498b]860 *nread = nr;
861 return EOK;
[8fd04ba9]862}
863
[3ba431a]864/** Read bytes from a file
[8fd04ba9]865 *
[3ba431a]866 * Read up to @a nbyte bytes from file. The actual number of bytes read
867 * may be lower, but greater than zero if there are any bytes available.
868 * If there are no bytes available for reading, then the function will
869 * return success with zero bytes read.
[8fd04ba9]870 *
[3ba431a]871 * @param file File handle to read from
872 * @param[in] pos Position to read from
873 * @param buf Buffer to read from
874 * @param nbyte Maximum number of bytes to read
875 * @param[out] nread Actual number of bytes read (0 or more)
[8fd04ba9]876 *
[cde999a]877 * @return EOK on success or an error code
[8fd04ba9]878 */
[b7fd2a0]879errno_t vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
[3ba431a]880 ssize_t *nread)
[8fd04ba9]881{
[b7fd2a0]882 errno_t rc;
[3ba431a]883 ipc_call_t answer;
884 aid_t req;
[a35b458]885
[3ba431a]886 if (nbyte > DATA_XFER_LIMIT)
887 nbyte = DATA_XFER_LIMIT;
[a35b458]888
[3ba431a]889 async_exch_t *exch = vfs_exchange_begin();
[a35b458]890
[3ba431a]891 req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos),
892 UPPER32(pos), &answer);
893 rc = async_data_read_start(exch, (void *) buf, nbyte);
[8fd04ba9]894
[3ba431a]895 vfs_exchange_end(exch);
[a35b458]896
[3ba431a]897 if (rc == EOK)
898 async_wait_for(req, &rc);
899 else
900 async_forget(req);
[a35b458]901
[ce04ea44]902 if (rc != EOK)
903 return rc;
[a35b458]904
[fafb8e5]905 *nread = (ssize_t) ipc_get_arg1(&answer);
[3ba431a]906 return EOK;
[8fd04ba9]907}
908
[3ba431a]909/** Rename a file or directory
[6afc9d7]910 *
[3ba431a]911 * There is no file-handle-based variant to disallow attempts to introduce loops
912 * and breakage in the directory tree when relinking eg. a node under its own
913 * descendant. The path-based variant is not susceptible because the VFS can
914 * prevent this lexically by comparing the paths.
915 *
916 * @param old Old path
917 * @param new New path
[ca7506f]918 *
[cde999a]919 * @return EOK on success or an error code
[6afc9d7]920 */
[b7fd2a0]921errno_t vfs_rename_path(const char *old, const char *new)
[2595dab]922{
[b7fd2a0]923 errno_t rc;
924 errno_t rc_orig;
[3ba431a]925 aid_t req;
[a35b458]926
[3ba431a]927 size_t olda_size;
928 char *olda = vfs_absolutize(old, &olda_size);
929 if (olda == NULL)
930 return ENOMEM;
931
932 size_t newa_size;
933 char *newa = vfs_absolutize(new, &newa_size);
934 if (newa == NULL) {
935 free(olda);
936 return ENOMEM;
937 }
[a35b458]938
[79ae36dd]939 async_exch_t *exch = vfs_exchange_begin();
[3ba431a]940 int root = vfs_root();
941 if (root < 0) {
942 free(olda);
943 free(newa);
944 return ENOENT;
945 }
[a35b458]946
[3ba431a]947 req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
948 rc = async_data_write_start(exch, olda, olda_size);
949 if (rc != EOK) {
950 vfs_exchange_end(exch);
951 free(olda);
952 free(newa);
953 vfs_put(root);
954 async_wait_for(req, &rc_orig);
955 if (rc_orig != EOK)
956 rc = rc_orig;
957 return rc;
958 }
959 rc = async_data_write_start(exch, newa, newa_size);
960 if (rc != EOK) {
961 vfs_exchange_end(exch);
962 free(olda);
963 free(newa);
964 vfs_put(root);
965 async_wait_for(req, &rc_orig);
966 if (rc_orig != EOK)
967 rc = rc_orig;
968 return rc;
969 }
970 vfs_exchange_end(exch);
971 free(olda);
972 free(newa);
973 vfs_put(root);
974 async_wait_for(req, &rc);
975
[a56cef9]976 return rc;
[2595dab]977}
978
[ca7506f]979/** Resize file to a specified length
[6afc9d7]980 *
[ca7506f]981 * Resize file so that its size is exactly @a length.
[6afc9d7]982 *
[ca7506f]983 * @param file File handle to resize
984 * @param length New length
[6afc9d7]985 *
[cde999a]986 * @return EOK on success or an error code
[6afc9d7]987 */
[b7fd2a0]988errno_t vfs_resize(int file, aoff64_t length)
[0ee4322]989{
[79ae36dd]990 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]991 errno_t rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
[67e881c]992 UPPER32(length));
[79ae36dd]993 vfs_exchange_end(exch);
[a35b458]994
[67e881c]995 return rc;
[0ee4322]996}
997
[3ba431a]998/** Return a new file handle representing the local root
999 *
[f77c1c9]1000 * @return A clone of the local root file handle or -1
[3ba431a]1001 */
1002int vfs_root(void)
1003{
[f77c1c9]1004 fibril_mutex_lock(&root_mutex);
1005 int fd;
1006 if (root_fd < 0) {
1007 fd = -1;
1008 } else {
[b7fd2a0]1009 errno_t rc = vfs_clone(root_fd, -1, true, &fd);
[f77c1c9]1010 if (rc != EOK) {
1011 fd = -1;
1012 }
1013 }
[3ba431a]1014 fibril_mutex_unlock(&root_mutex);
[f77c1c9]1015 return fd;
[3ba431a]1016}
1017
1018/** Set a new local root
1019 *
1020 * Note that it is still possible to have file handles for other roots and pass
1021 * them to the API functions. Functions like vfs_root() and vfs_lookup() will
1022 * however consider the file set by this function to be the root.
1023 *
1024 * @param nroot The new local root file handle
[f77c1c9]1025 *
1026 * @return Error code
[3ba431a]1027 */
[b7fd2a0]1028errno_t vfs_root_set(int nroot)
[3ba431a]1029{
[f77c1c9]1030 int new_root;
[b7fd2a0]1031 errno_t rc = vfs_clone(nroot, -1, true, &new_root);
[f77c1c9]1032 if (rc != EOK) {
1033 return rc;
1034 }
1035
[3ba431a]1036 fibril_mutex_lock(&root_mutex);
1037 if (root_fd >= 0)
1038 vfs_put(root_fd);
[f77c1c9]1039 root_fd = new_root;
[3ba431a]1040 fibril_mutex_unlock(&root_mutex);
[f77c1c9]1041
1042 return EOK;
[3ba431a]1043}
1044
[ca7506f]1045/** Get file information
[6afc9d7]1046 *
[ca7506f]1047 * @param file File handle to get information about
1048 * @param[out] stat Place to store file information
[6afc9d7]1049 *
[cde999a]1050 * @return EOK on success or an error code
[6afc9d7]1051 */
[39330200]1052errno_t vfs_stat(int file, vfs_stat_t *stat)
[852b801]1053{
[b7fd2a0]1054 errno_t rc;
[852b801]1055 aid_t req;
[a35b458]1056
[79ae36dd]1057 async_exch_t *exch = vfs_exchange_begin();
[a35b458]1058
[23a0368]1059 req = async_send_1(exch, VFS_IN_STAT, file, NULL);
[39330200]1060 rc = async_data_read_start(exch, (void *) stat, sizeof(vfs_stat_t));
[852b801]1061 if (rc != EOK) {
[79ae36dd]1062 vfs_exchange_end(exch);
[a35b458]1063
[b7fd2a0]1064 errno_t rc_orig;
[3734106]1065 async_wait_for(req, &rc_orig);
[a35b458]1066
[6afc9d7]1067 if (rc_orig != EOK)
1068 rc = rc_orig;
[a35b458]1069
[23a0368]1070 return rc;
[852b801]1071 }
[a35b458]1072
[79ae36dd]1073 vfs_exchange_end(exch);
[852b801]1074 async_wait_for(req, &rc);
[a35b458]1075
[23a0368]1076 return rc;
[852b801]1077}
1078
[1b20da0]1079/** Get file information
[6afc9d7]1080 *
[ca7506f]1081 * @param path File path to get information about
1082 * @param[out] stat Place to store file information
[6afc9d7]1083 *
[cde999a]1084 * @return EOK on success or an error code
[6afc9d7]1085 */
[39330200]1086errno_t vfs_stat_path(const char *path, vfs_stat_t *stat)
[415c7e0d]1087{
[f77c1c9]1088 int file;
[b7fd2a0]1089 errno_t rc = vfs_lookup(path, 0, &file);
[f77c1c9]1090 if (rc != EOK)
1091 return rc;
[a35b458]1092
[f77c1c9]1093 rc = vfs_stat(file, stat);
[23a0368]1094
[9c4cf0d]1095 vfs_put(file);
[0b97336]1096
[415c7e0d]1097 return rc;
1098}
1099
[3ba431a]1100/** Get filesystem statistics
1101 *
1102 * @param file File located on the queried file system
1103 * @param[out] st Buffer for storing information
1104 *
[cde999a]1105 * @return EOK on success or an error code
[3ba431a]1106 */
[39330200]1107errno_t vfs_statfs(int file, vfs_statfs_t *st)
[3ba431a]1108{
[b7fd2a0]1109 errno_t rc, ret;
[3ba431a]1110 aid_t req;
[1e2e5795]1111
[3ba431a]1112 async_exch_t *exch = vfs_exchange_begin();
[1e2e5795]1113
[3ba431a]1114 req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
1115 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
1116
1117 vfs_exchange_end(exch);
1118 async_wait_for(req, &ret);
1119
1120 rc = (ret != EOK ? ret : rc);
1121
1122 return rc;
[1e2e5795]1123}
1124
[3ba431a]1125/** Get filesystem statistics
[ca7506f]1126 *
[3ba431a]1127 * @param file Path pointing to the queried file system
1128 * @param[out] st Buffer for storing information
[ca7506f]1129 *
[cde999a]1130 * @return EOK on success or an error code
[ca7506f]1131 */
[39330200]1132errno_t vfs_statfs_path(const char *path, vfs_statfs_t *st)
[6e5562a]1133{
[f77c1c9]1134 int file;
[b7fd2a0]1135 errno_t rc = vfs_lookup(path, 0, &file);
[f77c1c9]1136 if (rc != EOK)
1137 return rc;
[a35b458]1138
[f77c1c9]1139 rc = vfs_statfs(file, st);
[6e5562a]1140
[9c4cf0d]1141 vfs_put(file);
[6e5562a]1142
[1b20da0]1143 return rc;
[6e5562a]1144}
1145
[3ba431a]1146/** Synchronize file
[6afc9d7]1147 *
[3ba431a]1148 * @param file File handle to synchronize
[ca7506f]1149 *
[cde999a]1150 * @return EOK on success or an error code
[6afc9d7]1151 */
[b7fd2a0]1152errno_t vfs_sync(int file)
[d0dc74ae]1153{
[3ba431a]1154 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]1155 errno_t rc = async_req_1_0(exch, VFS_IN_SYNC, file);
[3ba431a]1156 vfs_exchange_end(exch);
[a35b458]1157
[6e5562a]1158 return rc;
[3ba431a]1159}
[d0dc74ae]1160
[ca7506f]1161/** Unlink a file or directory
1162 *
1163 * Unlink a name from a parent directory. The caller can supply the file handle
1164 * of the unlinked child in order to detect a possible race with vfs_link() and
1165 * avoid unlinking a wrong file. If the last link for a file or directory is
1166 * removed, the FS implementation will deallocate its resources.
1167 *
1168 * @param parent File handle of the parent directory node
1169 * @param child Old name to be unlinked
1170 * @param expect File handle of the unlinked child
1171 *
[cde999a]1172 * @return EOK on success or an error code
[ca7506f]1173 */
[b7fd2a0]1174errno_t vfs_unlink(int parent, const char *child, int expect)
[f15cf1a6]1175{
[b7fd2a0]1176 errno_t rc;
[f15cf1a6]1177 aid_t req;
[a35b458]1178
[79ae36dd]1179 async_exch_t *exch = vfs_exchange_begin();
[a35b458]1180
[79ea5af]1181 req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
1182 rc = async_data_write_start(exch, child, str_size(child));
[a35b458]1183
[79ae36dd]1184 vfs_exchange_end(exch);
[a35b458]1185
[b7fd2a0]1186 errno_t rc_orig;
[d18c404]1187 async_wait_for(req, &rc_orig);
[a35b458]1188
[61042de]1189 if (rc_orig != EOK)
[b7fd2a0]1190 return (errno_t) rc_orig;
[2595dab]1191 return rc;
[f15cf1a6]1192}
1193
[ca7506f]1194/** Unlink a file or directory
[6afc9d7]1195 *
[ca7506f]1196 * Unlink a path. If the last link for a file or directory is removed, the FS
1197 * implementation will deallocate its resources.
1198 *
1199 * @param path Old path to be unlinked
1200 *
[cde999a]1201 * @return EOK on success or an error code
[6afc9d7]1202 */
[b7fd2a0]1203errno_t vfs_unlink_path(const char *path)
[f15cf1a6]1204{
[f77c1c9]1205 int expect;
[b7fd2a0]1206 errno_t rc = vfs_lookup(path, 0, &expect);
[f77c1c9]1207 if (rc != EOK)
1208 return rc;
[79ea5af]1209
[1e2e5795]1210 char *child;
[f77c1c9]1211 int parent;
1212 rc = get_parent_and_child(path, &parent, &child);
1213 if (rc != EOK) {
[9c4cf0d]1214 vfs_put(expect);
[f77c1c9]1215 return rc;
[0b97336]1216 }
[79ea5af]1217
[f77c1c9]1218 rc = vfs_unlink(parent, child, expect);
[a35b458]1219
[1e2e5795]1220 free(child);
[9c4cf0d]1221 vfs_put(parent);
1222 vfs_put(expect);
[5126f80]1223 return rc;
[f15cf1a6]1224}
1225
[3ba431a]1226/** Unmount a file system
[6afc9d7]1227 *
[3ba431a]1228 * @param mp File handle representing the mount-point
[6afc9d7]1229 *
[cde999a]1230 * @return EOK on success or an error code
[6afc9d7]1231 */
[b7fd2a0]1232errno_t vfs_unmount(int mp)
[a8e9ab8d]1233{
[79ae36dd]1234 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]1235 errno_t rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp);
[79ae36dd]1236 vfs_exchange_end(exch);
[163fc09]1237 return rc;
[a8e9ab8d]1238}
1239
[3ba431a]1240/** Unmount a file system
[6afc9d7]1241 *
[3ba431a]1242 * @param mpp Mount-point path
[ca7506f]1243 *
[cde999a]1244 * @return EOK on success or an error code
[6afc9d7]1245 */
[b7fd2a0]1246errno_t vfs_unmount_path(const char *mpp)
[5fec355]1247{
[f77c1c9]1248 int mp;
[b7fd2a0]1249 errno_t rc = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY, &mp);
[f77c1c9]1250 if (rc != EOK)
1251 return rc;
[a35b458]1252
[f77c1c9]1253 rc = vfs_unmount(mp);
[3ba431a]1254 vfs_put(mp);
1255 return rc;
[5fec355]1256}
1257
[3ba431a]1258/** Walk a path starting in a parent node
[ca7506f]1259 *
[3ba431a]1260 * @param parent File handle of the parent node where the walk starts
1261 * @param path Parent-relative path to be walked
1262 * @param flags Flags influencing the walk
[f77c1c9]1263 * @param[out] handle File handle representing the result on success.
[6afc9d7]1264 *
[f77c1c9]1265 * @return Error code.
[6afc9d7]1266 */
[b7fd2a0]1267errno_t vfs_walk(int parent, const char *path, int flags, int *handle)
[5fec355]1268{
[3ba431a]1269 async_exch_t *exch = vfs_exchange_begin();
[a35b458]1270
[3ba431a]1271 ipc_call_t answer;
1272 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
[b7fd2a0]1273 errno_t rc = async_data_write_start(exch, path, str_size(path));
[3ba431a]1274 vfs_exchange_end(exch);
[a35b458]1275
[b7fd2a0]1276 errno_t rc_orig;
[3ba431a]1277 async_wait_for(req, &rc_orig);
[5fec355]1278
[3ba431a]1279 if (rc_orig != EOK)
[b7fd2a0]1280 return (errno_t) rc_orig;
[a35b458]1281
[3ba431a]1282 if (rc != EOK)
[b7fd2a0]1283 return (errno_t) rc;
[a35b458]1284
[fafb8e5]1285 *handle = (int) ipc_get_arg1(&answer);
[f77c1c9]1286 return EOK;
[852b801]1287}
1288
[3ba431a]1289/** Write data
[6afc9d7]1290 *
[3ba431a]1291 * This function fails if it cannot write exactly @a len bytes to the file.
[ca7506f]1292 *
[3ba431a]1293 * @param file File handle to write to
1294 * @param[inout] pos Position to write to, updated by the actual bytes
1295 * written
1296 * @param buf Data, @a nbytes bytes long
1297 * @param nbytes Number of bytes to write
[8e3498b]1298 * @param nwritten Place to store number of bytes written
[3ba431a]1299 *
[8e3498b]1300 * @return On success, EOK, @a *nwr is filled with number
1301 * of bytes written
1302 * @return On failure, an error code
[6afc9d7]1303 */
[b7fd2a0]1304errno_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte,
[8e3498b]1305 size_t *nwritten)
[66366470]1306{
[3ba431a]1307 ssize_t cnt = 0;
[8e3498b]1308 ssize_t nwr = 0;
[3ba431a]1309 const uint8_t *bp = (uint8_t *) buf;
[b7fd2a0]1310 errno_t rc;
[73fbcbb]1311
[3ba431a]1312 do {
1313 bp += cnt;
[8e3498b]1314 nwr += cnt;
[3ba431a]1315 *pos += cnt;
[8e3498b]1316 rc = vfs_write_short(file, *pos, bp, nbyte - nwr, &cnt);
[1433ecda]1317 } while (rc == EOK && ((ssize_t)nbyte - nwr - cnt) > 0);
[6afc9d7]1318
[8e3498b]1319 if (rc != EOK) {
1320 *nwritten = nwr;
[3ba431a]1321 return rc;
[8e3498b]1322 }
[6afc9d7]1323
[8e3498b]1324 nwr += cnt;
[3ba431a]1325 *pos += cnt;
[8e3498b]1326 *nwritten = nwr;
1327 return EOK;
[b5b5d84]1328}
[ca7506f]1329
[3ba431a]1330/** Write bytes to a file
[ca7506f]1331 *
[3ba431a]1332 * Write up to @a nbyte bytes from file. The actual number of bytes written
1333 * may be lower, but greater than zero.
[ca7506f]1334 *
[3ba431a]1335 * @param file File handle to write to
1336 * @param[in] pos Position to write to
1337 * @param buf Buffer to write to
1338 * @param nbyte Maximum number of bytes to write
1339 * @param[out] nread Actual number of bytes written (0 or more)
[ca7506f]1340 *
[cde999a]1341 * @return EOK on success or an error code
[ca7506f]1342 */
[b7fd2a0]1343errno_t vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte,
[3ba431a]1344 ssize_t *nwritten)
[354b642]1345{
[b7fd2a0]1346 errno_t rc;
[3ba431a]1347 ipc_call_t answer;
1348 aid_t req;
[a35b458]1349
[3ba431a]1350 if (nbyte > DATA_XFER_LIMIT)
1351 nbyte = DATA_XFER_LIMIT;
[a35b458]1352
[3ba431a]1353 async_exch_t *exch = vfs_exchange_begin();
[a35b458]1354
[3ba431a]1355 req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos),
1356 UPPER32(pos), &answer);
1357 rc = async_data_write_start(exch, (void *) buf, nbyte);
[a35b458]1358
[3ba431a]1359 vfs_exchange_end(exch);
[a35b458]1360
[3ba431a]1361 if (rc == EOK)
1362 async_wait_for(req, &rc);
1363 else
1364 async_forget(req);
[354b642]1365
[61042de]1366 if (rc != EOK)
[354b642]1367 return rc;
[a35b458]1368
[fafb8e5]1369 *nwritten = (ssize_t) ipc_get_arg1(&answer);
[3ba431a]1370 return EOK;
[354b642]1371}
1372
[2f02aa17]1373/** @}
1374 */
Note: See TracBrowser for help on using the repository browser.