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

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

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5/ revision 1946

Original commit messages:

1946: Jiri Zarevucky 2013-08-06 Relativize mount, add root handle to libc and remove root from VFS server. This wraps up the "relativization" phase.

Breakage:

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