source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 6e5562a

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

Introduce vfs_link_path() and replace mkdir() with it

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