source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 438f355

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

Move mtab emulation to its own file

  • Property mode set to 100644
File size: 20.4 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
[79ae36dd]53static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
54static async_sess_t *vfs_sess = NULL;
[a28ab12]55
56static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
[5fec355]57
[2b88074b]58static int cwd_fd = -1;
59static char *cwd_path = NULL;
60static size_t cwd_size = 0;
[5fec355]61
[5126f80]62static FIBRIL_MUTEX_INITIALIZE(root_mutex);
63static int root_fd = -1;
64
65int vfs_root(void)
66{
67 fibril_mutex_lock(&root_mutex);
68 int r;
[61042de]69 if (root_fd < 0)
[5126f80]70 r = ENOENT;
[61042de]71 else
[fcab7ef]72 r = vfs_clone(root_fd, -1, true);
[5126f80]73 fibril_mutex_unlock(&root_mutex);
74 return r;
75}
76
77void vfs_root_set(int nroot)
78{
79 fibril_mutex_lock(&root_mutex);
[61042de]80 if (root_fd >= 0)
[9c4cf0d]81 vfs_put(root_fd);
[fcab7ef]82 root_fd = vfs_clone(nroot, -1, true);
[5126f80]83 fibril_mutex_unlock(&root_mutex);
84}
85
[79ae36dd]86/** Start an async exchange on the VFS session.
87 *
88 * @return New exchange.
89 *
90 */
[866e627]91async_exch_t *vfs_exchange_begin(void)
[79ae36dd]92{
93 fibril_mutex_lock(&vfs_mutex);
94
[61042de]95 while (vfs_sess == NULL) {
[f9b2cb4c]96 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
[2133e02]97 0);
[61042de]98 }
[79ae36dd]99
100 fibril_mutex_unlock(&vfs_mutex);
101
102 return async_exchange_begin(vfs_sess);
103}
104
105/** Finish an async exchange on the VFS session.
106 *
107 * @param exch Exchange to be finished.
108 *
109 */
[866e627]110void vfs_exchange_end(async_exch_t *exch)
[79ae36dd]111{
112 async_exchange_end(exch);
113}
114
[151f1cc]115int vfs_walk(int parent, const char *path, int flags)
[0b18364]116{
117 async_exch_t *exch = vfs_exchange_begin();
118
119 ipc_call_t answer;
120 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
[3ef62df]121 sysarg_t rc = async_data_write_start(exch, path, str_size(path));
[0b18364]122 vfs_exchange_end(exch);
123
124 sysarg_t rc_orig;
125 async_wait_for(req, &rc_orig);
126
[61042de]127 if (rc_orig != EOK)
[0b18364]128 return (int) rc_orig;
129
[61042de]130 if (rc != EOK)
[0b18364]131 return (int) rc;
132
133 return (int) IPC_GET_ARG1(answer);
134}
135
[5126f80]136int vfs_lookup(const char *path, int flags)
[eca9fd0]137{
138 size_t size;
139 char *p = vfs_absolutize(path, &size);
[61042de]140 if (!p)
[eca9fd0]141 return ENOMEM;
[5126f80]142 int root = vfs_root();
[c725619]143 if (root < 0) {
[5126f80]144 free(p);
145 return ENOENT;
146 }
[151f1cc]147 int rc = vfs_walk(root, p, flags);
[9c4cf0d]148 vfs_put(root);
[eca9fd0]149 free(p);
150 return rc;
151}
152
[b19e892]153int vfs_open(int file, int mode)
[0b18364]154{
155 async_exch_t *exch = vfs_exchange_begin();
[b19e892]156 int rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode);
[0b18364]157 vfs_exchange_end(exch);
158
[b19e892]159 return rc;
160}
161
162int vfs_lookup_open(const char *path, int flags, int mode)
163{
164 int file = vfs_lookup(path, flags);
165 if (file < 0)
166 return file;
167
168 int rc = vfs_open(file, mode);
169 if (rc != EOK) {
[9c4cf0d]170 vfs_put(file);
[b19e892]171 return rc;
172 }
173
174 return file;
[0b18364]175}
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
[5126f80]227int vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
[61042de]228 unsigned int flags, unsigned int instance, int *mountedfd)
[5126f80]229{
230 sysarg_t rc, rc1;
231
[61042de]232 if (!mountedfd)
[5126f80]233 flags |= VFS_MOUNT_NO_REF;
[61042de]234 if (mp < 0)
[5126f80]235 flags |= VFS_MOUNT_CONNECT_ONLY;
236
237 ipc_call_t answer;
238 async_exch_t *exch = vfs_exchange_begin();
[61042de]239 aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance,
240 &answer);
[5126f80]241
242 rc1 = async_data_write_start(exch, (void *) opts, str_size(opts));
243 if (rc1 == EOK) {
[61042de]244 rc1 = async_data_write_start(exch, (void *) fs_name,
245 str_size(fs_name));
[5126f80]246 }
247
248 vfs_exchange_end(exch);
249
250 async_wait_for(req, &rc);
251
[61042de]252 if (mountedfd)
[5126f80]253 *mountedfd = (int) IPC_GET_ARG1(answer);
254
[61042de]255 if (rc != EOK)
[5126f80]256 return rc;
257 return rc1;
258}
259
260int vfs_unmount(int mp)
261{
262 async_exch_t *exch = vfs_exchange_begin();
263 int rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp);
264 vfs_exchange_end(exch);
265 return rc;
266}
267
[80743a1]268int vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
[4979403]269 const char *opts, unsigned int flags, unsigned int instance)
[2f02aa17]270{
[210e50a]271 int null_id = -1;
[15f3c3f]272 char null[LOC_NAME_MAXLEN];
[210e50a]273
[15f3c3f]274 if (str_cmp(fqsn, "") == 0) {
[61042de]275 /*
276 * No device specified, create a fresh null/%d device instead.
277 */
[15f3c3f]278 null_id = loc_null_create();
[210e50a]279
280 if (null_id == -1)
281 return ENOMEM;
282
[15f3c3f]283 snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
284 fqsn = null;
[210e50a]285 }
[82405266]286
[61042de]287 if (flags & IPC_FLAG_BLOCKING)
[5126f80]288 flags = VFS_MOUNT_BLOCKING;
[61042de]289 else
[5126f80]290 flags = 0;
291
[15f3c3f]292 service_id_t service_id;
293 int res = loc_service_get_id(fqsn, &service_id, flags);
[210e50a]294 if (res != EOK) {
295 if (null_id != -1)
[15f3c3f]296 loc_null_destroy(null_id);
[210e50a]297
[82405266]298 return res;
[210e50a]299 }
[82405266]300
[9eb3623]301 size_t mpa_size;
[6afc9d7]302 char *mpa = vfs_absolutize(mp, &mpa_size);
303 if (mpa == NULL) {
[210e50a]304 if (null_id != -1)
[15f3c3f]305 loc_null_destroy(null_id);
[210e50a]306
[5fec355]307 return ENOMEM;
[210e50a]308 }
[19b28b0]309
[5126f80]310 fibril_mutex_lock(&root_mutex);
[19b28b0]311
[5126f80]312 int rc;
[210e50a]313
[5126f80]314 if (str_cmp(mpa, "/") == 0) {
315 /* Mounting root. */
[210e50a]316
[5126f80]317 if (root_fd >= 0) {
318 fibril_mutex_unlock(&root_mutex);
[61042de]319 if (null_id != -1)
[5126f80]320 loc_null_destroy(null_id);
321 return EBUSY;
322 }
[210e50a]323
[5126f80]324 int root;
[61042de]325 rc = vfs_mount(-1, fs_name, service_id, opts, flags, instance,
326 &root);
327 if (rc == EOK)
[5126f80]328 root_fd = root;
329 } else {
330 if (root_fd < 0) {
331 fibril_mutex_unlock(&root_mutex);
[61042de]332 if (null_id != -1)
[5126f80]333 loc_null_destroy(null_id);
334 return EINVAL;
335 }
336
[151f1cc]337 int mpfd = vfs_walk(root_fd, mpa, WALK_DIRECTORY);
[5126f80]338 if (mpfd >= 0) {
[61042de]339 rc = vfs_mount(mpfd, fs_name, service_id, opts, flags,
340 instance, NULL);
[9c4cf0d]341 vfs_put(mpfd);
[5126f80]342 } else {
343 rc = mpfd;
344 }
[2f02aa17]345 }
[210e50a]346
[5126f80]347 fibril_mutex_unlock(&root_mutex);
[19b28b0]348
[210e50a]349 if ((rc != EOK) && (null_id != -1))
[15f3c3f]350 loc_null_destroy(null_id);
[210e50a]351
[2f02aa17]352 return (int) rc;
353}
354
[80743a1]355int vfs_unmount_path(const char *mpp)
[21f32ee1]356{
[5126f80]357 int mp = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY);
[61042de]358 if (mp < 0)
[5126f80]359 return mp;
[b9067dfa]360
[5126f80]361 int rc = vfs_unmount(mp);
[9c4cf0d]362 vfs_put(mp);
[5126f80]363 return rc;
[21f32ee1]364}
365
[6afc9d7]366/** Close file.
367 *
368 * @param fildes File descriptor
[9c4cf0d]369 * @return EOK on success or a negative error code otherwise.
[6afc9d7]370 */
[9c4cf0d]371int vfs_put(int fildes)
[72bde81]372{
[96b02eb9]373 sysarg_t rc;
[19b28b0]374
[79ae36dd]375 async_exch_t *exch = vfs_exchange_begin();
[9c4cf0d]376 rc = async_req_1_0(exch, VFS_IN_PUT, fildes);
[79ae36dd]377 vfs_exchange_end(exch);
[19b28b0]378
[6afc9d7]379 if (rc != EOK) {
380 errno = rc;
381 return -1;
382 }
383
384 return 0;
[72bde81]385}
386
[6afc9d7]387/** Read bytes from file.
388 *
389 * Read up to @a nbyte bytes from file. The actual number of bytes read
390 * may be lower, but greater than zero if there are any bytes available.
391 * If there are no bytes available for reading, then the function will
392 * return success with zero bytes read.
393 *
[ce04ea44]394 * @param file File descriptor
[58898d1d]395 * @param pos Position to read from
[6afc9d7]396 * @param buf Buffer
397 * @param nbyte Maximum number of bytes to read
398 * @param nread Place to store actual number of bytes read (0 or more)
399 *
400 * @return EOK on success, non-zero error code on error.
401 */
[ce04ea44]402int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
[58898d1d]403 ssize_t *nread)
[2f02aa17]404{
[96b02eb9]405 sysarg_t rc;
[2f02aa17]406 ipc_call_t answer;
407 aid_t req;
[19b28b0]408
[fa24efa]409 if (nbyte > DATA_XFER_LIMIT)
410 nbyte = DATA_XFER_LIMIT;
411
[79ae36dd]412 async_exch_t *exch = vfs_exchange_begin();
413
[ce04ea44]414 req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos),
[58898d1d]415 UPPER32(pos), &answer);
[fa24efa]416 rc = async_data_read_start(exch, (void *) buf, nbyte);
[354b642]417
[79ae36dd]418 vfs_exchange_end(exch);
[354b642]419
[61042de]420 if (rc == EOK)
[354b642]421 async_wait_for(req, &rc);
[61042de]422 else
[354b642]423 async_forget(req);
[6afc9d7]424
425 if (rc != EOK)
[25becee8]426 return rc;
[6afc9d7]427
428 *nread = (ssize_t) IPC_GET_ARG1(answer);
429 return EOK;
[2f02aa17]430}
431
[6afc9d7]432/** Write bytes to file.
433 *
434 * Write up to @a nbyte bytes from file. The actual number of bytes written
435 * may be lower, but greater than zero.
436 *
[ce04ea44]437 * @param file File descriptor
[58898d1d]438 * @param pos Position to write to
[6afc9d7]439 * @param buf Buffer
440 * @param nbyte Maximum number of bytes to write
441 * @param nread Place to store actual number of bytes written (0 or more)
442 *
443 * @return EOK on success, non-zero error code on error.
444 */
[ce04ea44]445int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte,
[6afc9d7]446 ssize_t *nwritten)
[449c246]447{
[96b02eb9]448 sysarg_t rc;
[449c246]449 ipc_call_t answer;
450 aid_t req;
[19b28b0]451
[fa24efa]452 if (nbyte > DATA_XFER_LIMIT)
453 nbyte = DATA_XFER_LIMIT;
454
[79ae36dd]455 async_exch_t *exch = vfs_exchange_begin();
456
[ce04ea44]457 req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos),
[58898d1d]458 UPPER32(pos), &answer);
[fa24efa]459 rc = async_data_write_start(exch, (void *) buf, nbyte);
[6afc9d7]460
[79ae36dd]461 vfs_exchange_end(exch);
[6afc9d7]462
[61042de]463 if (rc == EOK)
[354b642]464 async_wait_for(req, &rc);
[61042de]465 else
[354b642]466 async_forget(req);
467
[6afc9d7]468 if (rc != EOK)
469 return rc;
470
471 *nwritten = (ssize_t) IPC_GET_ARG1(answer);
472 return EOK;
[449c246]473}
[222e57c]474
[6afc9d7]475/** Read data.
[8fd04ba9]476 *
[6afc9d7]477 * Read up to @a nbytes bytes from file if available. This function always reads
478 * all the available bytes up to @a nbytes.
[8fd04ba9]479 *
480 * @param fildes File descriptor
[58898d1d]481 * @param pos Pointer to position to read from
[8fd04ba9]482 * @param buf Buffer, @a nbytes bytes long
483 * @param nbytes Number of bytes to read
484 *
[ce04ea44]485 * @return On success, non-negative number of bytes red.
486 * On failure, a negative error code.
[8fd04ba9]487 */
[ce04ea44]488ssize_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte)
[8fd04ba9]489{
490 ssize_t cnt = 0;
491 size_t nread = 0;
492 uint8_t *bp = (uint8_t *) buf;
[6afc9d7]493 int rc;
494
[8fd04ba9]495 do {
496 bp += cnt;
497 nread += cnt;
[58898d1d]498 *pos += cnt;
[ce04ea44]499 rc = vfs_read_short(file, *pos, bp, nbyte - nread, &cnt);
[6afc9d7]500 } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
501
[ce04ea44]502 if (rc != EOK)
503 return rc;
[6afc9d7]504
[58898d1d]505 *pos += cnt;
[8fd04ba9]506 return nread + cnt;
507}
508
[6afc9d7]509/** Write data.
[8fd04ba9]510 *
511 * This function fails if it cannot write exactly @a len bytes to the file.
512 *
[ce04ea44]513 * @param file File descriptor
[58898d1d]514 * @param pos Pointer to position to write to
[8fd04ba9]515 * @param buf Data, @a nbytes bytes long
516 * @param nbytes Number of bytes to write
517 *
[ce04ea44]518 * @return On success, non-negative number of bytes written.
519 * On failure, a negative error code.
[8fd04ba9]520 */
[ce04ea44]521ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte)
[8fd04ba9]522{
523 ssize_t cnt = 0;
524 ssize_t nwritten = 0;
525 const uint8_t *bp = (uint8_t *) buf;
[6afc9d7]526 int rc;
[8fd04ba9]527
528 do {
529 bp += cnt;
530 nwritten += cnt;
[58898d1d]531 *pos += cnt;
[ce04ea44]532 rc = vfs_write_short(file, *pos, bp, nbyte - nwritten, &cnt);
[6afc9d7]533 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
[8fd04ba9]534
[ce04ea44]535 if (rc != EOK)
536 return rc;
[8fd04ba9]537
[58898d1d]538 *pos += cnt;
[8fd04ba9]539 return nbyte;
540}
541
[6afc9d7]542/** Synchronize file.
543 *
544 * @param fildes File descriptor
[a56cef9]545 * @return EOK on success or a negative error code otherwise.
[6afc9d7]546 */
[a56cef9]547int vfs_sync(int file)
[2595dab]548{
[79ae36dd]549 async_exch_t *exch = vfs_exchange_begin();
[a56cef9]550 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, file);
[79ae36dd]551 vfs_exchange_end(exch);
[2595dab]552
[a56cef9]553 return rc;
[2595dab]554}
555
[6afc9d7]556/** Truncate file to a specified length.
557 *
558 * Truncate file so that its size is exactly @a length
559 *
560 * @param fildes File descriptor
561 * @param length Length
562 *
[a56cef9]563 * @return EOK on success or a negative erroc code otherwise.
[6afc9d7]564 */
[67e881c]565int vfs_resize(int file, aoff64_t length)
[0ee4322]566{
[96b02eb9]567 sysarg_t rc;
[0ee4322]568
[79ae36dd]569 async_exch_t *exch = vfs_exchange_begin();
[67e881c]570 rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
571 UPPER32(length));
[79ae36dd]572 vfs_exchange_end(exch);
[ed903174]573
[67e881c]574 return rc;
[0ee4322]575}
576
[6afc9d7]577/** Get file status.
578 *
[23a0368]579 * @param file File descriptor
[6afc9d7]580 * @param stat Place to store file information
581 *
[23a0368]582 * @return EOK on success or a negative error code otherwise.
[6afc9d7]583 */
[23a0368]584int vfs_stat(int file, struct stat *stat)
[852b801]585{
[96b02eb9]586 sysarg_t rc;
[852b801]587 aid_t req;
588
[79ae36dd]589 async_exch_t *exch = vfs_exchange_begin();
590
[23a0368]591 req = async_send_1(exch, VFS_IN_STAT, file, NULL);
[79ae36dd]592 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
[852b801]593 if (rc != EOK) {
[79ae36dd]594 vfs_exchange_end(exch);
[6afc9d7]595
[96b02eb9]596 sysarg_t rc_orig;
[3734106]597 async_wait_for(req, &rc_orig);
[6afc9d7]598
599 if (rc_orig != EOK)
600 rc = rc_orig;
601
[23a0368]602 return rc;
[852b801]603 }
[6afc9d7]604
[79ae36dd]605 vfs_exchange_end(exch);
[852b801]606 async_wait_for(req, &rc);
[6afc9d7]607
[23a0368]608 return rc;
[852b801]609}
610
[6afc9d7]611/** Get file status.
612 *
613 * @param path Path to file
614 * @param stat Place to store file information
615 *
[23a0368]616 * @return EOK on success or a negative error code otherwise.
[6afc9d7]617 */
[23a0368]618int vfs_stat_path(const char *path, struct stat *stat)
[415c7e0d]619{
[23a0368]620 int file = vfs_lookup(path, 0);
621 if (file < 0)
622 return file;
[0ed9cb6]623
[23a0368]624 int rc = vfs_stat(file, stat);
625
[9c4cf0d]626 vfs_put(file);
[0b97336]627
[415c7e0d]628 return rc;
629}
630
[1e2e5795]631static int get_parent_and_child(const char *path, char **child)
632{
633 size_t size;
634 char *apath = vfs_absolutize(path, &size);
635 if (!apath)
636 return ENOMEM;
637
638 char *slash = str_rchr(apath, L'/');
639 int parent;
640 if (slash == apath) {
641 parent = vfs_root();
642 *child = apath;
643 } else {
644 *slash = '\0';
645 parent = vfs_lookup(apath, WALK_DIRECTORY);
646 if (parent < 0) {
647 free(apath);
648 return parent;
649 }
650 *slash = '/';
651 *child = str_dup(slash);
652 free(apath);
653 if (!*child) {
654 vfs_put(parent);
655 return ENOMEM;
656 }
657 }
658
659 return parent;
660}
661
[6e5562a]662int vfs_link(int parent, const char *child, vfs_file_kind_t kind)
663{
664 int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR;
[151f1cc]665 int file = vfs_walk(parent, child, WALK_MUST_CREATE | flags);
[6e5562a]666
667 if (file < 0)
668 return file;
669
[9c4cf0d]670 vfs_put(file);
[6e5562a]671
672 return EOK;
673}
674
675/** Link a file or directory.
[6afc9d7]676 *
677 * @param path Path
[6e5562a]678 * @param kind Kind of the file to be created.
679 * @return EOK on success or a negative error code otherwise
[6afc9d7]680 */
[6e5562a]681int vfs_link_path(const char *path, vfs_file_kind_t kind)
[d0dc74ae]682{
[1e2e5795]683 char *child;
684 int parent = get_parent_and_child(path, &child);
685 if (parent < 0)
[6e5562a]686 return parent;
687
[1e2e5795]688 int rc = vfs_link(parent, child, kind);
[6e5562a]689
[1e2e5795]690 free(child);
[9c4cf0d]691 vfs_put(parent);
[6e5562a]692 return rc;
693}
[d0dc74ae]694
[79ea5af]695int vfs_unlink(int parent, const char *child, int expect)
[f15cf1a6]696{
[96b02eb9]697 sysarg_t rc;
[f15cf1a6]698 aid_t req;
699
[79ae36dd]700 async_exch_t *exch = vfs_exchange_begin();
701
[79ea5af]702 req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
703 rc = async_data_write_start(exch, child, str_size(child));
[d18c404]704
[79ae36dd]705 vfs_exchange_end(exch);
[d18c404]706
707 sysarg_t rc_orig;
708 async_wait_for(req, &rc_orig);
709
[61042de]710 if (rc_orig != EOK)
[d18c404]711 return (int) rc_orig;
[2595dab]712 return rc;
[f15cf1a6]713}
714
[6e5562a]715/** Unlink a file or directory.
[6afc9d7]716 *
717 * @param path Path
[6e5562a]718 * @return EOK on success or a negative error code otherwise
[6afc9d7]719 */
[79ea5af]720int vfs_unlink_path(const char *path)
[f15cf1a6]721{
[79ea5af]722 int expect = vfs_lookup(path, 0);
[1e2e5795]723 if (expect < 0)
[79ea5af]724 return expect;
725
[1e2e5795]726 char *child;
727 int parent = get_parent_and_child(path, &child);
[79ea5af]728 if (parent < 0) {
[9c4cf0d]729 vfs_put(expect);
[79ea5af]730 return parent;
[0b97336]731 }
[79ea5af]732
[1e2e5795]733 int rc = vfs_unlink(parent, child, expect);
[5126f80]734
[1e2e5795]735 free(child);
[9c4cf0d]736 vfs_put(parent);
737 vfs_put(expect);
[5126f80]738 return rc;
[f15cf1a6]739}
740
[6afc9d7]741/** Rename directory entry.
742 *
743 * @param old Old name
744 * @param new New name
745 *
[163fc09]746 * @return EOK on success or a negative error code otherwise.
[6afc9d7]747 */
[163fc09]748int vfs_rename_path(const char *old, const char *new)
[a8e9ab8d]749{
[96b02eb9]750 sysarg_t rc;
751 sysarg_t rc_orig;
[a8e9ab8d]752 aid_t req;
753
[9eb3623]754 size_t olda_size;
[6afc9d7]755 char *olda = vfs_absolutize(old, &olda_size);
[163fc09]756 if (olda == NULL)
757 return ENOMEM;
[923c39e]758
[9eb3623]759 size_t newa_size;
[6afc9d7]760 char *newa = vfs_absolutize(new, &newa_size);
761 if (newa == NULL) {
[a8e9ab8d]762 free(olda);
[163fc09]763 return ENOMEM;
[a8e9ab8d]764 }
[19b28b0]765
[79ae36dd]766 async_exch_t *exch = vfs_exchange_begin();
[5126f80]767 int root = vfs_root();
768 if (root < 0) {
769 free(olda);
770 free(newa);
[163fc09]771 return ENOENT;
[5126f80]772 }
[79ae36dd]773
[5126f80]774 req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
[79ae36dd]775 rc = async_data_write_start(exch, olda, olda_size);
[a8e9ab8d]776 if (rc != EOK) {
[79ae36dd]777 vfs_exchange_end(exch);
[a8e9ab8d]778 free(olda);
779 free(newa);
[9c4cf0d]780 vfs_put(root);
[a28ab12]781 async_wait_for(req, &rc_orig);
[6afc9d7]782 if (rc_orig != EOK)
783 rc = rc_orig;
[163fc09]784 return rc;
[a8e9ab8d]785 }
[79ae36dd]786 rc = async_data_write_start(exch, newa, newa_size);
[a8e9ab8d]787 if (rc != EOK) {
[79ae36dd]788 vfs_exchange_end(exch);
[a8e9ab8d]789 free(olda);
790 free(newa);
[9c4cf0d]791 vfs_put(root);
[a28ab12]792 async_wait_for(req, &rc_orig);
[6afc9d7]793 if (rc_orig != EOK)
794 rc = rc_orig;
[163fc09]795 return rc;
[a8e9ab8d]796 }
[79ae36dd]797 vfs_exchange_end(exch);
[a8e9ab8d]798 free(olda);
799 free(newa);
[9c4cf0d]800 vfs_put(root);
[a28ab12]801 async_wait_for(req, &rc);
[6afc9d7]802
[163fc09]803 return rc;
[a8e9ab8d]804}
805
[6afc9d7]806/** Change working directory.
807 *
808 * @param path Path
[d96d9bc]809 * @return EOK on success or a negative error code otherwise.
[6afc9d7]810 */
[d96d9bc]811int vfs_cwd_set(const char *path)
[5fec355]812{
[2b88074b]813 size_t abs_size;
[6afc9d7]814 char *abs = vfs_absolutize(path, &abs_size);
[d96d9bc]815 if (!abs)
816 return ENOMEM;
[2b88074b]817
[5126f80]818 int fd = vfs_lookup(abs, WALK_DIRECTORY);
[2b88074b]819 if (fd < 0) {
820 free(abs);
[d96d9bc]821 return fd;
[5fec355]822 }
[2b88074b]823
[a28ab12]824 fibril_mutex_lock(&cwd_mutex);
[2b88074b]825
[61042de]826 if (cwd_fd >= 0)
[9c4cf0d]827 vfs_put(cwd_fd);
[2b88074b]828
[61042de]829 if (cwd_path)
[2b88074b]830 free(cwd_path);
831
832 cwd_fd = fd;
833 cwd_path = abs;
834 cwd_size = abs_size;
835
[a28ab12]836 fibril_mutex_unlock(&cwd_mutex);
[d96d9bc]837 return EOK;
[5fec355]838}
839
[6afc9d7]840/** Get current working directory path.
841 *
842 * @param buf Buffer
843 * @param size Size of @a buf
[d96d9bc]844 * @return EOK on success and a non-negative error code otherwise.
[6afc9d7]845 */
[d96d9bc]846int vfs_cwd_get(char *buf, size_t size)
[5fec355]847{
[a28ab12]848 fibril_mutex_lock(&cwd_mutex);
[2b88074b]849
850 if ((cwd_size == 0) || (size < cwd_size + 1)) {
[a28ab12]851 fibril_mutex_unlock(&cwd_mutex);
[d96d9bc]852 return ERANGE;
[5fec355]853 }
[2b88074b]854
[6eb2e96]855 str_cpy(buf, size, cwd_path);
[a28ab12]856 fibril_mutex_unlock(&cwd_mutex);
[2b88074b]857
[d96d9bc]858 return EOK;
[5fec355]859}
860
[6afc9d7]861/** Open session to service represented by a special file.
862 *
863 * Given that the file referred to by @a fildes represents a service,
864 * open a session to that service.
865 *
866 * @param fildes File descriptor
867 * @param iface Interface to connect to (XXX Should be automatic)
868 * @return On success returns session pointer. On error returns @c NULL.
869 */
[23a0368]870async_sess_t *vfs_fd_session(int file, iface_t iface)
[852b801]871{
872 struct stat stat;
[23a0368]873 int rc = vfs_stat(file, &stat);
[6afc9d7]874 if (rc != 0)
[79ae36dd]875 return NULL;
[8caaea7]876
[6afc9d7]877 if (stat.service == 0)
[79ae36dd]878 return NULL;
[852b801]879
[f9b2cb4c]880 return loc_service_connect(stat.service, iface, 0);
[852b801]881}
882
[6afc9d7]883/** Get filesystem statistics.
884 *
[b5b5d84]885 * @param file File located on the queried file system
[6afc9d7]886 * @param st Buffer for storing information
[23a0368]887 * @return EOK on success or a negative error code otherwise.
[6afc9d7]888 */
[b5b5d84]889int vfs_statfs(int file, struct statfs *st)
[66366470]890{
[a737667e]891 sysarg_t rc, ret;
892 aid_t req;
[73fbcbb]893
[a737667e]894 async_exch_t *exch = vfs_exchange_begin();
[73fbcbb]895
[b5b5d84]896 req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
[73fbcbb]897 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
898
[66366470]899 vfs_exchange_end(exch);
[a737667e]900 async_wait_for(req, &ret);
[6afc9d7]901
[a737667e]902 rc = (ret != EOK ? ret : rc);
[6afc9d7]903
[b5b5d84]904 return rc;
905}
906/** Get filesystem statistics.
907 *
908 * @param path Mount point path
909 * @param st Buffer for storing information
910 * @return EOK on success or a negative error code otherwise.
911 */
912int vfs_statfs_path(const char *path, struct statfs *st)
913{
914 int file = vfs_lookup(path, 0);
915 if (file < 0)
916 return file;
917
918 int rc = vfs_statfs(file, st);
919
[9c4cf0d]920 vfs_put(file);
[b5b5d84]921
922 return rc;
[66366470]923}
924
[354b642]925int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
926{
[61042de]927 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
928 0, vfs_exch);
[354b642]929}
930
[bb9ec2d]931int vfs_receive_handle(bool high_descriptor)
[354b642]932{
933 ipc_callid_t callid;
934 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
935 async_answer_0(callid, EINVAL);
936 return EINVAL;
937 }
938
939 async_exch_t *vfs_exch = vfs_exchange_begin();
940
941 async_state_change_finalize(callid, vfs_exch);
942
943 sysarg_t ret;
[61042de]944 sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE,
945 high_descriptor, &ret);
[354b642]946
947 async_exchange_end(vfs_exch);
948
[61042de]949 if (rc != EOK)
[354b642]950 return rc;
951 return ret;
952}
953
[fcab7ef]954int vfs_clone(int file_from, int file_to, bool high_descriptor)
[354b642]955{
956 async_exch_t *vfs_exch = vfs_exchange_begin();
[fcab7ef]957 int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
958 (sysarg_t) file_to, (sysarg_t) high_descriptor);
[354b642]959 vfs_exchange_end(vfs_exch);
960 return rc;
961}
962
[2f02aa17]963/** @}
964 */
Note: See TracBrowser for help on using the repository browser.