source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 3bbd921

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

Use absolute path in vfs_get_mtab_list()

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