source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 58898d1d

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

Remove VFS_IN_SEEK from VFS

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