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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b14d9f9 was b14d9f9, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Mount should be able to print the list of available file system types.

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