source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 79ea5af

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

Rename unlink() to vfs_unlink_path() and _vfs_unlink() to vfs_unlink()

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