source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 39330200

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 39330200 was 39330200, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Rename struct stat and struct statfs to vfs_stat_t and vfs_statfs_t,
respectively. They are nonstandard vestiges of times when native file API
was modeled after POSIX API.

  • Property mode set to 100644
File size: 33.0 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(), ...
65 *
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);
266
267 if ((cwd_size == 0) || (size < cwd_size + 1)) {
268 fibril_mutex_unlock(&cwd_mutex);
269 return ERANGE;
[5126f80]270 }
271
[3ba431a]272 str_cpy(buf, size, cwd_path);
273 fibril_mutex_unlock(&cwd_mutex);
274
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;
287 char *abs = vfs_absolutize(path, &abs_size);
288 if (!abs)
289 return ENOMEM;
290
[f77c1c9]291 int fd;
[b7fd2a0]292 errno_t rc = vfs_lookup(abs, WALK_DIRECTORY, &fd);
[f77c1c9]293 if (rc != EOK) {
[3ba431a]294 free(abs);
[f77c1c9]295 return rc;
[3ba431a]296 }
297
298 fibril_mutex_lock(&cwd_mutex);
299
300 if (cwd_fd >= 0)
301 vfs_put(cwd_fd);
302
303 if (cwd_path)
304 free(cwd_path);
305
306 cwd_fd = fd;
307 cwd_path = abs;
308 cwd_size = abs_size;
309
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);
321
322 while (vfs_sess == NULL) {
323 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
324 0);
325 }
326
327 fibril_mutex_unlock(&vfs_mutex);
328
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;
358
359 if (stat.service == 0)
360 return NULL;
361
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;
[d2c8533]378
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);
382
383 rc = async_data_write_start(exch, (void *) fs_name,
384 str_size(fs_name));
385
386 async_wait_for(req, &rc);
387
388 if (rc != EOK) {
389 vfs_exchange_end(exch);
390 return rc;
391 }
392
393 rc = async_data_read_start(exch, info, sizeof(*info));
394 vfs_exchange_end(exch);
395
396 return rc;
397}
398
399
[b14d9f9]400/** Return a list of currently available file system types
401 *
402 * @param fstypes Points to structure where list of filesystem types is
403 * stored. It is read as a null-terminated list of strings
404 * fstypes->fstypes[0..]. To free the list use vfs_fstypes_free().
405 *
[cde999a]406 * @return EOK on success or an error code
[b14d9f9]407 */
[b7fd2a0]408errno_t vfs_fstypes(vfs_fstypes_t *fstypes)
[b14d9f9]409{
410 sysarg_t size;
411 char *buf;
412 char dummybuf[1];
413 size_t count, i;
414
415 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]416 errno_t rc = async_req_0_1(exch, VFS_IN_FSTYPES, &size);
[b14d9f9]417
418 if (rc != EOK) {
419 vfs_exchange_end(exch);
420 return rc;
421 }
422
423 buf = malloc(size);
424 if (buf == NULL) {
425 buf = dummybuf;
426 size = 1;
427 }
428
429 rc = async_data_read_start(exch, buf, size);
430 vfs_exchange_end(exch);
431
432 if (buf == dummybuf)
433 return ENOMEM;
434
435 /*
436 * Buffer should contain a number of null-terminated strings.
437 * Count them so that we can allocate an index
438 */
439 count = 0;
440 i = 0;
441 while (i < size) {
442 if (buf[i] == '\0')
443 ++count;
444 ++i;
445 }
446
447 if (count == 0) {
448 free(buf);
449 return EIO;
450 }
451
452 fstypes->fstypes = calloc(sizeof(char *), count + 1);
453 if (fstypes->fstypes == NULL) {
454 free(buf);
455 return ENOMEM;
456 }
457
458 /* Now fill the index */
459 if (buf[0] != '\0')
460 fstypes->fstypes[0] = &buf[0];
461 count = 0;
462 i = 0;
463 while (i < size) {
464 if (buf[i] == '\0')
465 fstypes->fstypes[++count] = &buf[i + 1];
466 ++i;
467 }
468 fstypes->fstypes[count] = NULL;
469 fstypes->buf = buf;
470 fstypes->size = size;
471
472 return rc;
473}
474
475/** Free list of file system types.
476 *
477 * @param fstypes List of file system types
478 */
479void vfs_fstypes_free(vfs_fstypes_t *fstypes)
480{
481 free(fstypes->buf);
482 fstypes->buf = NULL;
483 free(fstypes->fstypes);
484 fstypes->fstypes = NULL;
485 fstypes->size = 0;
486}
487
[3ba431a]488/** Link a file or directory
489 *
490 * Create a new name and an empty file or an empty directory in a parent
491 * directory. If child with the same name already exists, the function returns
492 * a failure, the existing file remains untouched and no file system object
493 * is created.
494 *
495 * @param parent File handle of the parent directory node
496 * @param child New name to be linked
497 * @param kind Kind of the object to be created: KIND_FILE or
498 * KIND_DIRECTORY
[a6fc88a]499 * @param[out] linkedfd If not NULL, will receive a file handle to the linked
500 * child
[cde999a]501 * @return EOK on success or an error code
[3ba431a]502 */
[b7fd2a0]503errno_t vfs_link(int parent, const char *child, vfs_file_kind_t kind, int *linkedfd)
[3ba431a]504{
505 int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR;
[f77c1c9]506 int file = -1;
[b7fd2a0]507 errno_t rc = vfs_walk(parent, child, WALK_MUST_CREATE | flags, &file);
[f77c1c9]508 if (rc != EOK)
509 return rc;
[3ba431a]510
[a6fc88a]511 if (linkedfd)
512 *linkedfd = file;
513 else
514 vfs_put(file);
[3ba431a]515
516 return EOK;
517}
518
519/** Link a file or directory
520 *
521 * Create a new name and an empty file or an empty directory at given path.
522 * If a link with the same name already exists, the function returns
523 * a failure, the existing file remains untouched and no file system object
524 * is created.
525 *
526 * @param path New path to be linked
527 * @param kind Kind of the object to be created: KIND_FILE or
528 * KIND_DIRECTORY
[a6fc88a]529 * @param[out] linkedfd If not NULL, will receive a file handle to the linked
530 * child
[cde999a]531 * @return EOK on success or an error code
[3ba431a]532 */
[b7fd2a0]533errno_t vfs_link_path(const char *path, vfs_file_kind_t kind, int *linkedfd)
[3ba431a]534{
535 char *child;
[f77c1c9]536 int parent;
[b7fd2a0]537 errno_t rc = get_parent_and_child(path, &parent, &child);
[f77c1c9]538 if (rc != EOK)
539 return rc;
[3ba431a]540
[f77c1c9]541 rc = vfs_link(parent, child, kind, linkedfd);
[3ba431a]542
543 free(child);
544 vfs_put(parent);
545 return rc;
[f77c1c9]546}
[3ba431a]547
548/** Lookup a path relative to the local root
549 *
550 * @param path Path to be looked up
551 * @param flags Walk flags
[f77c1c9]552 * @param[out] handle Pointer to variable where handle is to be written.
[3ba431a]553 *
[f77c1c9]554 * @return EOK on success or an error code.
[3ba431a]555 */
[b7fd2a0]556errno_t vfs_lookup(const char *path, int flags, int *handle)
[3ba431a]557{
558 size_t size;
559 char *p = vfs_absolutize(path, &size);
560 if (!p)
561 return ENOMEM;
[f77c1c9]562
[3ba431a]563 int root = vfs_root();
564 if (root < 0) {
565 free(p);
566 return ENOENT;
567 }
[f77c1c9]568
[0d0b319]569 // XXX: Workaround for GCC diagnostics.
570 *handle = -1;
571
[b7fd2a0]572 errno_t rc = vfs_walk(root, p, flags, handle);
[3ba431a]573 vfs_put(root);
574 free(p);
575 return rc;
576}
577
578/** Lookup a path relative to the local root and open the result
579 *
580 * This function is a convenience combo for vfs_lookup() and vfs_open().
581 *
582 * @param path Path to be looked up
583 * @param flags Walk flags
584 * @param mode Mode in which to open file in
[f77c1c9]585 * @param[out] handle Pointer to variable where handle is to be written.
[3ba431a]586 *
[cde999a]587 * @return EOK on success or an error code
[3ba431a]588 */
[b7fd2a0]589errno_t vfs_lookup_open(const char *path, int flags, int mode, int *handle)
[3ba431a]590{
[f77c1c9]591 int file;
[b7fd2a0]592 errno_t rc = vfs_lookup(path, flags, &file);
[f77c1c9]593 if (rc != EOK)
594 return rc;
[3ba431a]595
[f77c1c9]596 rc = vfs_open(file, mode);
[3ba431a]597 if (rc != EOK) {
598 vfs_put(file);
599 return rc;
600 }
[f77c1c9]601
602 *handle = file;
603 return EOK;
[3ba431a]604}
605
606/** Mount a file system
607 *
608 * @param[in] mp File handle representing the mount-point
609 * @param[in] fs_name File system name
610 * @param[in] serv Service representing the mountee
611 * @param[in] opts Mount options for the endpoint file system
612 * @param[in] flags Mount flags
613 * @param[in] instance Instance number of the file system server
614 * @param[out] mountedfd File handle of the mounted root if not NULL
615 *
[cde999a]616 * @return EOK on success or an error code
[3ba431a]617 */
[b7fd2a0]618errno_t vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
[3ba431a]619 unsigned int flags, unsigned int instance, int *mountedfd)
620{
[b7fd2a0]621 errno_t rc, rc1;
[3ba431a]622
623 if (!mountedfd)
624 flags |= VFS_MOUNT_NO_REF;
625 if (mp < 0)
626 flags |= VFS_MOUNT_CONNECT_ONLY;
627
628 ipc_call_t answer;
629 async_exch_t *exch = vfs_exchange_begin();
630 aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance,
631 &answer);
632
633 rc1 = async_data_write_start(exch, (void *) opts, str_size(opts));
634 if (rc1 == EOK) {
635 rc1 = async_data_write_start(exch, (void *) fs_name,
636 str_size(fs_name));
637 }
638
639 vfs_exchange_end(exch);
640
641 async_wait_for(req, &rc);
642
643 if (mountedfd)
644 *mountedfd = (int) IPC_GET_ARG1(answer);
645
646 if (rc != EOK)
647 return rc;
648 return rc1;
649}
[5126f80]650
[ca7506f]651/** Mount a file system
652 *
653 * @param[in] mp Path representing the mount-point
654 * @param[in] fs_name File system name
655 * @param[in] fqsn Fully qualified service name of the mountee
656 * @param[in] opts Mount options for the endpoint file system
657 * @param[in] flags Mount flags
658 * @param[in] instance Instance number of the file system server
659 *
[cde999a]660 * @return EOK on success or an error code
[ca7506f]661 */
[b7fd2a0]662errno_t vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
[4979403]663 const char *opts, unsigned int flags, unsigned int instance)
[2f02aa17]664{
[210e50a]665 int null_id = -1;
[15f3c3f]666 char null[LOC_NAME_MAXLEN];
[210e50a]667
[15f3c3f]668 if (str_cmp(fqsn, "") == 0) {
[61042de]669 /*
670 * No device specified, create a fresh null/%d device instead.
671 */
[15f3c3f]672 null_id = loc_null_create();
[210e50a]673
674 if (null_id == -1)
675 return ENOMEM;
676
[15f3c3f]677 snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
678 fqsn = null;
[210e50a]679 }
[82405266]680
[61042de]681 if (flags & IPC_FLAG_BLOCKING)
[5126f80]682 flags = VFS_MOUNT_BLOCKING;
[61042de]683 else
[5126f80]684 flags = 0;
685
[15f3c3f]686 service_id_t service_id;
[b7fd2a0]687 errno_t res = loc_service_get_id(fqsn, &service_id, flags);
[210e50a]688 if (res != EOK) {
689 if (null_id != -1)
[15f3c3f]690 loc_null_destroy(null_id);
[210e50a]691
[82405266]692 return res;
[210e50a]693 }
[82405266]694
[9eb3623]695 size_t mpa_size;
[6afc9d7]696 char *mpa = vfs_absolutize(mp, &mpa_size);
697 if (mpa == NULL) {
[210e50a]698 if (null_id != -1)
[15f3c3f]699 loc_null_destroy(null_id);
[210e50a]700
[5fec355]701 return ENOMEM;
[210e50a]702 }
[19b28b0]703
[5126f80]704 fibril_mutex_lock(&root_mutex);
[19b28b0]705
[b7fd2a0]706 errno_t rc;
[210e50a]707
[5126f80]708 if (str_cmp(mpa, "/") == 0) {
709 /* Mounting root. */
[210e50a]710
[5126f80]711 if (root_fd >= 0) {
712 fibril_mutex_unlock(&root_mutex);
[61042de]713 if (null_id != -1)
[5126f80]714 loc_null_destroy(null_id);
715 return EBUSY;
716 }
[210e50a]717
[5126f80]718 int root;
[61042de]719 rc = vfs_mount(-1, fs_name, service_id, opts, flags, instance,
720 &root);
721 if (rc == EOK)
[5126f80]722 root_fd = root;
723 } else {
724 if (root_fd < 0) {
725 fibril_mutex_unlock(&root_mutex);
[61042de]726 if (null_id != -1)
[5126f80]727 loc_null_destroy(null_id);
728 return EINVAL;
729 }
730
[f77c1c9]731 int mpfd;
732 rc = vfs_walk(root_fd, mpa, WALK_DIRECTORY, &mpfd);
733 if (rc == EOK) {
[61042de]734 rc = vfs_mount(mpfd, fs_name, service_id, opts, flags,
735 instance, NULL);
[9c4cf0d]736 vfs_put(mpfd);
[5126f80]737 }
[2f02aa17]738 }
[210e50a]739
[5126f80]740 fibril_mutex_unlock(&root_mutex);
[19b28b0]741
[210e50a]742 if ((rc != EOK) && (null_id != -1))
[15f3c3f]743 loc_null_destroy(null_id);
[210e50a]744
[b7fd2a0]745 return (errno_t) rc;
[2f02aa17]746}
747
[3ba431a]748
749/** Open a file handle for I/O
[ca7506f]750 *
[3ba431a]751 * @param file File handle to enable I/O on
752 * @param mode Mode in which to open file in
[ca7506f]753 *
[cde999a]754 * @return EOK on success or an error code
[ca7506f]755 */
[b7fd2a0]756errno_t vfs_open(int file, int mode)
[21f32ee1]757{
[3ba431a]758 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]759 errno_t rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode);
[3ba431a]760 vfs_exchange_end(exch);
[b9067dfa]761
[5126f80]762 return rc;
[21f32ee1]763}
764
[3ba431a]765/** Pass a file handle to another VFS client
766 *
767 * @param vfs_exch Donor's VFS exchange
768 * @param file Donor's file handle to pass
769 * @param exch Exchange to the acceptor
770 *
[cde999a]771 * @return EOK on success or an error code
[3ba431a]772 */
[b7fd2a0]773errno_t vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
[3ba431a]774{
775 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
776 0, vfs_exch);
777}
778
[ca7506f]779/** Stop working with a file handle
780 *
781 * @param file File handle to put
[6afc9d7]782 *
[cde999a]783 * @return EOK on success or an error code
[6afc9d7]784 */
[b7fd2a0]785errno_t vfs_put(int file)
[72bde81]786{
[79ae36dd]787 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]788 errno_t rc = async_req_1_0(exch, VFS_IN_PUT, file);
[79ae36dd]789 vfs_exchange_end(exch);
[19b28b0]790
[ca7506f]791 return rc;
[72bde81]792}
793
[3ba431a]794/** Receive a file handle from another VFS client
[6afc9d7]795 *
[3ba431a]796 * @param high If true, the received file handle will be allocated from high
797 * indices
[f77c1c9]798 * @param[out] handle Received handle.
[6afc9d7]799 *
[cde999a]800 * @return EOK on success or an error code
[6afc9d7]801 */
[b7fd2a0]802errno_t vfs_receive_handle(bool high, int *handle)
[2f02aa17]803{
[3ba431a]804 ipc_callid_t callid;
805 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
806 async_answer_0(callid, EINVAL);
807 return EINVAL;
808 }
[354b642]809
[3ba431a]810 async_exch_t *vfs_exch = vfs_exchange_begin();
[2f02aa17]811
[3ba431a]812 async_state_change_finalize(callid, vfs_exch);
813
814 sysarg_t ret;
[b7fd2a0]815 errno_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret);
[3ba431a]816
817 async_exchange_end(vfs_exch);
[354b642]818
[f77c1c9]819 if (rc == EOK) {
820 *handle = (int) ret;
821 }
822
823 return rc;
[449c246]824}
[222e57c]825
[ca7506f]826/** Read data
[8fd04ba9]827 *
[6afc9d7]828 * Read up to @a nbytes bytes from file if available. This function always reads
829 * all the available bytes up to @a nbytes.
[8fd04ba9]830 *
[ca7506f]831 * @param file File handle to read from
832 * @param[inout] pos Position to read from, updated by the actual bytes read
[8fd04ba9]833 * @param buf Buffer, @a nbytes bytes long
834 * @param nbytes Number of bytes to read
[8e3498b]835 * @param nread Place to store number of bytes actually read
[8fd04ba9]836 *
[8e3498b]837 * @return On success, EOK and @a *nread is filled with number
838 * of bytes actually read.
839 * @return On failure, an error code
[8fd04ba9]840 */
[b7fd2a0]841errno_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte, size_t *nread)
[8fd04ba9]842{
843 ssize_t cnt = 0;
[8e3498b]844 size_t nr = 0;
[8fd04ba9]845 uint8_t *bp = (uint8_t *) buf;
[b7fd2a0]846 errno_t rc;
[6afc9d7]847
[8fd04ba9]848 do {
849 bp += cnt;
[8e3498b]850 nr += cnt;
[58898d1d]851 *pos += cnt;
[8e3498b]852 rc = vfs_read_short(file, *pos, bp, nbyte - nr, &cnt);
853 } while (rc == EOK && cnt > 0 && (nbyte - nr - cnt) > 0);
[6afc9d7]854
[8e3498b]855 if (rc != EOK) {
856 *nread = nr;
[ce04ea44]857 return rc;
[8e3498b]858 }
[6afc9d7]859
[8e3498b]860 nr += cnt;
[58898d1d]861 *pos += cnt;
[8e3498b]862 *nread = nr;
863 return EOK;
[8fd04ba9]864}
865
[3ba431a]866/** Read bytes from a file
[8fd04ba9]867 *
[3ba431a]868 * Read up to @a nbyte bytes from file. The actual number of bytes read
869 * may be lower, but greater than zero if there are any bytes available.
870 * If there are no bytes available for reading, then the function will
871 * return success with zero bytes read.
[8fd04ba9]872 *
[3ba431a]873 * @param file File handle to read from
874 * @param[in] pos Position to read from
875 * @param buf Buffer to read from
876 * @param nbyte Maximum number of bytes to read
877 * @param[out] nread Actual number of bytes read (0 or more)
[8fd04ba9]878 *
[cde999a]879 * @return EOK on success or an error code
[8fd04ba9]880 */
[b7fd2a0]881errno_t vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
[3ba431a]882 ssize_t *nread)
[8fd04ba9]883{
[b7fd2a0]884 errno_t rc;
[3ba431a]885 ipc_call_t answer;
886 aid_t req;
887
888 if (nbyte > DATA_XFER_LIMIT)
889 nbyte = DATA_XFER_LIMIT;
890
891 async_exch_t *exch = vfs_exchange_begin();
892
893 req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos),
894 UPPER32(pos), &answer);
895 rc = async_data_read_start(exch, (void *) buf, nbyte);
[8fd04ba9]896
[3ba431a]897 vfs_exchange_end(exch);
898
899 if (rc == EOK)
900 async_wait_for(req, &rc);
901 else
902 async_forget(req);
903
[ce04ea44]904 if (rc != EOK)
905 return rc;
[3ba431a]906
907 *nread = (ssize_t) IPC_GET_ARG1(answer);
908 return EOK;
[8fd04ba9]909}
910
[3ba431a]911/** Rename a file or directory
[6afc9d7]912 *
[3ba431a]913 * There is no file-handle-based variant to disallow attempts to introduce loops
914 * and breakage in the directory tree when relinking eg. a node under its own
915 * descendant. The path-based variant is not susceptible because the VFS can
916 * prevent this lexically by comparing the paths.
917 *
918 * @param old Old path
919 * @param new New path
[ca7506f]920 *
[cde999a]921 * @return EOK on success or an error code
[6afc9d7]922 */
[b7fd2a0]923errno_t vfs_rename_path(const char *old, const char *new)
[2595dab]924{
[b7fd2a0]925 errno_t rc;
926 errno_t rc_orig;
[3ba431a]927 aid_t req;
928
929 size_t olda_size;
930 char *olda = vfs_absolutize(old, &olda_size);
931 if (olda == NULL)
932 return ENOMEM;
933
934 size_t newa_size;
935 char *newa = vfs_absolutize(new, &newa_size);
936 if (newa == NULL) {
937 free(olda);
938 return ENOMEM;
939 }
940
[79ae36dd]941 async_exch_t *exch = vfs_exchange_begin();
[3ba431a]942 int root = vfs_root();
943 if (root < 0) {
944 free(olda);
945 free(newa);
946 return ENOENT;
947 }
[2595dab]948
[3ba431a]949 req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
950 rc = async_data_write_start(exch, olda, olda_size);
951 if (rc != EOK) {
952 vfs_exchange_end(exch);
953 free(olda);
954 free(newa);
955 vfs_put(root);
956 async_wait_for(req, &rc_orig);
957 if (rc_orig != EOK)
958 rc = rc_orig;
959 return rc;
960 }
961 rc = async_data_write_start(exch, newa, newa_size);
962 if (rc != EOK) {
963 vfs_exchange_end(exch);
964 free(olda);
965 free(newa);
966 vfs_put(root);
967 async_wait_for(req, &rc_orig);
968 if (rc_orig != EOK)
969 rc = rc_orig;
970 return rc;
971 }
972 vfs_exchange_end(exch);
973 free(olda);
974 free(newa);
975 vfs_put(root);
976 async_wait_for(req, &rc);
977
[a56cef9]978 return rc;
[2595dab]979}
980
[ca7506f]981/** Resize file to a specified length
[6afc9d7]982 *
[ca7506f]983 * Resize file so that its size is exactly @a length.
[6afc9d7]984 *
[ca7506f]985 * @param file File handle to resize
986 * @param length New length
[6afc9d7]987 *
[cde999a]988 * @return EOK on success or an error code
[6afc9d7]989 */
[b7fd2a0]990errno_t vfs_resize(int file, aoff64_t length)
[0ee4322]991{
[79ae36dd]992 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]993 errno_t rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
[67e881c]994 UPPER32(length));
[79ae36dd]995 vfs_exchange_end(exch);
[ed903174]996
[67e881c]997 return rc;
[0ee4322]998}
999
[3ba431a]1000/** Return a new file handle representing the local root
1001 *
[f77c1c9]1002 * @return A clone of the local root file handle or -1
[3ba431a]1003 */
1004int vfs_root(void)
1005{
[f77c1c9]1006 fibril_mutex_lock(&root_mutex);
1007 int fd;
1008 if (root_fd < 0) {
1009 fd = -1;
1010 } else {
[b7fd2a0]1011 errno_t rc = vfs_clone(root_fd, -1, true, &fd);
[f77c1c9]1012 if (rc != EOK) {
1013 fd = -1;
1014 }
1015 }
[3ba431a]1016 fibril_mutex_unlock(&root_mutex);
[f77c1c9]1017 return fd;
[3ba431a]1018}
1019
1020/** Set a new local root
1021 *
1022 * Note that it is still possible to have file handles for other roots and pass
1023 * them to the API functions. Functions like vfs_root() and vfs_lookup() will
1024 * however consider the file set by this function to be the root.
1025 *
1026 * @param nroot The new local root file handle
[f77c1c9]1027 *
1028 * @return Error code
[3ba431a]1029 */
[b7fd2a0]1030errno_t vfs_root_set(int nroot)
[3ba431a]1031{
[f77c1c9]1032 int new_root;
[b7fd2a0]1033 errno_t rc = vfs_clone(nroot, -1, true, &new_root);
[f77c1c9]1034 if (rc != EOK) {
1035 return rc;
1036 }
1037
[3ba431a]1038 fibril_mutex_lock(&root_mutex);
1039 if (root_fd >= 0)
1040 vfs_put(root_fd);
[f77c1c9]1041 root_fd = new_root;
[3ba431a]1042 fibril_mutex_unlock(&root_mutex);
[f77c1c9]1043
1044 return EOK;
[3ba431a]1045}
1046
[ca7506f]1047/** Get file information
[6afc9d7]1048 *
[ca7506f]1049 * @param file File handle to get information about
1050 * @param[out] stat Place to store file information
[6afc9d7]1051 *
[cde999a]1052 * @return EOK on success or an error code
[6afc9d7]1053 */
[39330200]1054errno_t vfs_stat(int file, vfs_stat_t *stat)
[852b801]1055{
[b7fd2a0]1056 errno_t rc;
[852b801]1057 aid_t req;
1058
[79ae36dd]1059 async_exch_t *exch = vfs_exchange_begin();
1060
[23a0368]1061 req = async_send_1(exch, VFS_IN_STAT, file, NULL);
[39330200]1062 rc = async_data_read_start(exch, (void *) stat, sizeof(vfs_stat_t));
[852b801]1063 if (rc != EOK) {
[79ae36dd]1064 vfs_exchange_end(exch);
[6afc9d7]1065
[b7fd2a0]1066 errno_t rc_orig;
[3734106]1067 async_wait_for(req, &rc_orig);
[6afc9d7]1068
1069 if (rc_orig != EOK)
1070 rc = rc_orig;
1071
[23a0368]1072 return rc;
[852b801]1073 }
[6afc9d7]1074
[79ae36dd]1075 vfs_exchange_end(exch);
[852b801]1076 async_wait_for(req, &rc);
[6afc9d7]1077
[23a0368]1078 return rc;
[852b801]1079}
1080
[ca7506f]1081/** Get file information
[6afc9d7]1082 *
[ca7506f]1083 * @param path File path to get information about
1084 * @param[out] stat Place to store file information
[6afc9d7]1085 *
[cde999a]1086 * @return EOK on success or an error code
[6afc9d7]1087 */
[39330200]1088errno_t vfs_stat_path(const char *path, vfs_stat_t *stat)
[415c7e0d]1089{
[f77c1c9]1090 int file;
[b7fd2a0]1091 errno_t rc = vfs_lookup(path, 0, &file);
[f77c1c9]1092 if (rc != EOK)
1093 return rc;
[0ed9cb6]1094
[f77c1c9]1095 rc = vfs_stat(file, stat);
[23a0368]1096
[9c4cf0d]1097 vfs_put(file);
[0b97336]1098
[415c7e0d]1099 return rc;
1100}
1101
[3ba431a]1102/** Get filesystem statistics
1103 *
1104 * @param file File located on the queried file system
1105 * @param[out] st Buffer for storing information
1106 *
[cde999a]1107 * @return EOK on success or an error code
[3ba431a]1108 */
[39330200]1109errno_t vfs_statfs(int file, vfs_statfs_t *st)
[3ba431a]1110{
[b7fd2a0]1111 errno_t rc, ret;
[3ba431a]1112 aid_t req;
[1e2e5795]1113
[3ba431a]1114 async_exch_t *exch = vfs_exchange_begin();
[1e2e5795]1115
[3ba431a]1116 req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
1117 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
1118
1119 vfs_exchange_end(exch);
1120 async_wait_for(req, &ret);
1121
1122 rc = (ret != EOK ? ret : rc);
1123
1124 return rc;
[1e2e5795]1125}
1126
[3ba431a]1127/** Get filesystem statistics
[ca7506f]1128 *
[3ba431a]1129 * @param file Path pointing to the queried file system
1130 * @param[out] st Buffer for storing information
[ca7506f]1131 *
[cde999a]1132 * @return EOK on success or an error code
[ca7506f]1133 */
[39330200]1134errno_t vfs_statfs_path(const char *path, vfs_statfs_t *st)
[6e5562a]1135{
[f77c1c9]1136 int file;
[b7fd2a0]1137 errno_t rc = vfs_lookup(path, 0, &file);
[f77c1c9]1138 if (rc != EOK)
1139 return rc;
[3ba431a]1140
[f77c1c9]1141 rc = vfs_statfs(file, st);
[6e5562a]1142
[9c4cf0d]1143 vfs_put(file);
[6e5562a]1144
[3ba431a]1145 return rc;
[6e5562a]1146}
1147
[3ba431a]1148/** Synchronize file
[6afc9d7]1149 *
[3ba431a]1150 * @param file File handle to synchronize
[ca7506f]1151 *
[cde999a]1152 * @return EOK on success or an error code
[6afc9d7]1153 */
[b7fd2a0]1154errno_t vfs_sync(int file)
[d0dc74ae]1155{
[3ba431a]1156 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]1157 errno_t rc = async_req_1_0(exch, VFS_IN_SYNC, file);
[3ba431a]1158 vfs_exchange_end(exch);
1159
[6e5562a]1160 return rc;
[3ba431a]1161}
[d0dc74ae]1162
[ca7506f]1163/** Unlink a file or directory
1164 *
1165 * Unlink a name from a parent directory. The caller can supply the file handle
1166 * of the unlinked child in order to detect a possible race with vfs_link() and
1167 * avoid unlinking a wrong file. If the last link for a file or directory is
1168 * removed, the FS implementation will deallocate its resources.
1169 *
1170 * @param parent File handle of the parent directory node
1171 * @param child Old name to be unlinked
1172 * @param expect File handle of the unlinked child
1173 *
[cde999a]1174 * @return EOK on success or an error code
[ca7506f]1175 */
[b7fd2a0]1176errno_t vfs_unlink(int parent, const char *child, int expect)
[f15cf1a6]1177{
[b7fd2a0]1178 errno_t rc;
[f15cf1a6]1179 aid_t req;
1180
[79ae36dd]1181 async_exch_t *exch = vfs_exchange_begin();
1182
[79ea5af]1183 req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
1184 rc = async_data_write_start(exch, child, str_size(child));
[d18c404]1185
[79ae36dd]1186 vfs_exchange_end(exch);
[d18c404]1187
[b7fd2a0]1188 errno_t rc_orig;
[d18c404]1189 async_wait_for(req, &rc_orig);
1190
[61042de]1191 if (rc_orig != EOK)
[b7fd2a0]1192 return (errno_t) rc_orig;
[2595dab]1193 return rc;
[f15cf1a6]1194}
1195
[ca7506f]1196/** Unlink a file or directory
[6afc9d7]1197 *
[ca7506f]1198 * Unlink a path. If the last link for a file or directory is removed, the FS
1199 * implementation will deallocate its resources.
1200 *
1201 * @param path Old path to be unlinked
1202 *
[cde999a]1203 * @return EOK on success or an error code
[6afc9d7]1204 */
[b7fd2a0]1205errno_t vfs_unlink_path(const char *path)
[f15cf1a6]1206{
[f77c1c9]1207 int expect;
[b7fd2a0]1208 errno_t rc = vfs_lookup(path, 0, &expect);
[f77c1c9]1209 if (rc != EOK)
1210 return rc;
[79ea5af]1211
[1e2e5795]1212 char *child;
[f77c1c9]1213 int parent;
1214 rc = get_parent_and_child(path, &parent, &child);
1215 if (rc != EOK) {
[9c4cf0d]1216 vfs_put(expect);
[f77c1c9]1217 return rc;
[0b97336]1218 }
[79ea5af]1219
[f77c1c9]1220 rc = vfs_unlink(parent, child, expect);
[5126f80]1221
[1e2e5795]1222 free(child);
[9c4cf0d]1223 vfs_put(parent);
1224 vfs_put(expect);
[5126f80]1225 return rc;
[f15cf1a6]1226}
1227
[3ba431a]1228/** Unmount a file system
[6afc9d7]1229 *
[3ba431a]1230 * @param mp File handle representing the mount-point
[6afc9d7]1231 *
[cde999a]1232 * @return EOK on success or an error code
[6afc9d7]1233 */
[b7fd2a0]1234errno_t vfs_unmount(int mp)
[a8e9ab8d]1235{
[79ae36dd]1236 async_exch_t *exch = vfs_exchange_begin();
[b7fd2a0]1237 errno_t rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp);
[79ae36dd]1238 vfs_exchange_end(exch);
[163fc09]1239 return rc;
[a8e9ab8d]1240}
1241
[3ba431a]1242/** Unmount a file system
[6afc9d7]1243 *
[3ba431a]1244 * @param mpp Mount-point path
[ca7506f]1245 *
[cde999a]1246 * @return EOK on success or an error code
[6afc9d7]1247 */
[b7fd2a0]1248errno_t vfs_unmount_path(const char *mpp)
[5fec355]1249{
[f77c1c9]1250 int mp;
[b7fd2a0]1251 errno_t rc = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY, &mp);
[f77c1c9]1252 if (rc != EOK)
1253 return rc;
[2b88074b]1254
[f77c1c9]1255 rc = vfs_unmount(mp);
[3ba431a]1256 vfs_put(mp);
1257 return rc;
[5fec355]1258}
1259
[3ba431a]1260/** Walk a path starting in a parent node
[ca7506f]1261 *
[3ba431a]1262 * @param parent File handle of the parent node where the walk starts
1263 * @param path Parent-relative path to be walked
1264 * @param flags Flags influencing the walk
[f77c1c9]1265 * @param[out] handle File handle representing the result on success.
[6afc9d7]1266 *
[f77c1c9]1267 * @return Error code.
[6afc9d7]1268 */
[b7fd2a0]1269errno_t vfs_walk(int parent, const char *path, int flags, int *handle)
[5fec355]1270{
[3ba431a]1271 async_exch_t *exch = vfs_exchange_begin();
[2b88074b]1272
[3ba431a]1273 ipc_call_t answer;
1274 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
[b7fd2a0]1275 errno_t rc = async_data_write_start(exch, path, str_size(path));
[3ba431a]1276 vfs_exchange_end(exch);
1277
[b7fd2a0]1278 errno_t rc_orig;
[3ba431a]1279 async_wait_for(req, &rc_orig);
[5fec355]1280
[3ba431a]1281 if (rc_orig != EOK)
[b7fd2a0]1282 return (errno_t) rc_orig;
[3ba431a]1283
1284 if (rc != EOK)
[b7fd2a0]1285 return (errno_t) rc;
[852b801]1286
[f77c1c9]1287 *handle = (int) IPC_GET_ARG1(answer);
1288 return EOK;
[852b801]1289}
1290
[3ba431a]1291/** Write data
[6afc9d7]1292 *
[3ba431a]1293 * This function fails if it cannot write exactly @a len bytes to the file.
[ca7506f]1294 *
[3ba431a]1295 * @param file File handle to write to
1296 * @param[inout] pos Position to write to, updated by the actual bytes
1297 * written
1298 * @param buf Data, @a nbytes bytes long
1299 * @param nbytes Number of bytes to write
[8e3498b]1300 * @param nwritten Place to store number of bytes written
[3ba431a]1301 *
[8e3498b]1302 * @return On success, EOK, @a *nwr is filled with number
1303 * of bytes written
1304 * @return On failure, an error code
[6afc9d7]1305 */
[b7fd2a0]1306errno_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte,
[8e3498b]1307 size_t *nwritten)
[66366470]1308{
[3ba431a]1309 ssize_t cnt = 0;
[8e3498b]1310 ssize_t nwr = 0;
[3ba431a]1311 const uint8_t *bp = (uint8_t *) buf;
[b7fd2a0]1312 errno_t rc;
[73fbcbb]1313
[3ba431a]1314 do {
1315 bp += cnt;
[8e3498b]1316 nwr += cnt;
[3ba431a]1317 *pos += cnt;
[8e3498b]1318 rc = vfs_write_short(file, *pos, bp, nbyte - nwr, &cnt);
1319 } while (rc == EOK && ((ssize_t )nbyte - nwr - cnt) > 0);
[6afc9d7]1320
[8e3498b]1321 if (rc != EOK) {
1322 *nwritten = nwr;
[3ba431a]1323 return rc;
[8e3498b]1324 }
[6afc9d7]1325
[8e3498b]1326 nwr += cnt;
[3ba431a]1327 *pos += cnt;
[8e3498b]1328 *nwritten = nwr;
1329 return EOK;
[b5b5d84]1330}
[ca7506f]1331
[3ba431a]1332/** Write bytes to a file
[ca7506f]1333 *
[3ba431a]1334 * Write up to @a nbyte bytes from file. The actual number of bytes written
1335 * may be lower, but greater than zero.
[ca7506f]1336 *
[3ba431a]1337 * @param file File handle to write to
1338 * @param[in] pos Position to write to
1339 * @param buf Buffer to write to
1340 * @param nbyte Maximum number of bytes to write
1341 * @param[out] nread Actual number of bytes written (0 or more)
[ca7506f]1342 *
[cde999a]1343 * @return EOK on success or an error code
[ca7506f]1344 */
[b7fd2a0]1345errno_t vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte,
[3ba431a]1346 ssize_t *nwritten)
[354b642]1347{
[b7fd2a0]1348 errno_t rc;
[3ba431a]1349 ipc_call_t answer;
1350 aid_t req;
1351
1352 if (nbyte > DATA_XFER_LIMIT)
1353 nbyte = DATA_XFER_LIMIT;
1354
1355 async_exch_t *exch = vfs_exchange_begin();
1356
1357 req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos),
1358 UPPER32(pos), &answer);
1359 rc = async_data_write_start(exch, (void *) buf, nbyte);
1360
1361 vfs_exchange_end(exch);
1362
1363 if (rc == EOK)
1364 async_wait_for(req, &rc);
1365 else
1366 async_forget(req);
[354b642]1367
[61042de]1368 if (rc != EOK)
[354b642]1369 return rc;
[3ba431a]1370
1371 *nwritten = (ssize_t) IPC_GET_ARG1(answer);
1372 return EOK;
[354b642]1373}
1374
[2f02aa17]1375/** @}
1376 */
Note: See TracBrowser for help on using the repository browser.