source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 23a0368

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

Rename stat() to vfs_stat_path() and fstat() to vfs_stat()

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