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

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

Return VFS handles separately from error codes.

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