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

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

Factor out code to lookup the parent and copy out the child component

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