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

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

Remove VFS_IN_UNLINK

  • Property mode set to 100644
File size: 25.3 KB
RevLine 
[2f02aa17]1/*
[64d2b10]2 * Copyright (c) 2008 Jakub Jermar
[2f02aa17]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
[19b28b0]34
[5fec355]35#include <vfs/canonify.h>
[79ae36dd]36#include <vfs/vfs.h>
[8ffedd8]37#include <vfs/vfs_mtab.h>
[79ae36dd]38#include <vfs/vfs_sess.h>
[ed903174]39#include <macros.h>
[d0dc74ae]40#include <stdlib.h>
[449c246]41#include <unistd.h>
[d0dc74ae]42#include <dirent.h>
[449c246]43#include <fcntl.h>
[923c39e]44#include <stdio.h>
[852b801]45#include <sys/stat.h>
[9dc6083]46#include <sys/statfs.h>
[72bde81]47#include <sys/types.h>
[2f02aa17]48#include <ipc/services.h>
[79ae36dd]49#include <ns.h>
[2f02aa17]50#include <async.h>
[a28ab12]51#include <fibril_synch.h>
[2f02aa17]52#include <errno.h>
[a28ab12]53#include <assert.h>
[19f857a]54#include <str.h>
[15f3c3f]55#include <loc.h>
[2595dab]56#include <ipc/vfs.h>
[15f3c3f]57#include <ipc/loc.h>
[2f02aa17]58
[79ae36dd]59static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
60static async_sess_t *vfs_sess = NULL;
[a28ab12]61
62static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
[5fec355]63
[2b88074b]64static int cwd_fd = -1;
65static char *cwd_path = NULL;
66static size_t cwd_size = 0;
[5fec355]67
[5126f80]68static FIBRIL_MUTEX_INITIALIZE(root_mutex);
69static int root_fd = -1;
70
71int vfs_root(void)
72{
73 fibril_mutex_lock(&root_mutex);
74 int r;
[61042de]75 if (root_fd < 0)
[5126f80]76 r = ENOENT;
[61042de]77 else
[5126f80]78 r = vfs_clone(root_fd, true);
79 fibril_mutex_unlock(&root_mutex);
80 return r;
81}
82
83void vfs_root_set(int nroot)
84{
85 fibril_mutex_lock(&root_mutex);
[61042de]86 if (root_fd >= 0)
[5126f80]87 close(root_fd);
88 root_fd = vfs_clone(nroot, true);
89 fibril_mutex_unlock(&root_mutex);
90}
91
[79ae36dd]92/** Start an async exchange on the VFS session.
93 *
94 * @return New exchange.
95 *
96 */
[866e627]97async_exch_t *vfs_exchange_begin(void)
[79ae36dd]98{
99 fibril_mutex_lock(&vfs_mutex);
100
[61042de]101 while (vfs_sess == NULL) {
[f9b2cb4c]102 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
[2133e02]103 0);
[61042de]104 }
[79ae36dd]105
106 fibril_mutex_unlock(&vfs_mutex);
107
108 return async_exchange_begin(vfs_sess);
109}
110
111/** Finish an async exchange on the VFS session.
112 *
113 * @param exch Exchange to be finished.
114 *
115 */
[866e627]116void vfs_exchange_end(async_exch_t *exch)
[79ae36dd]117{
118 async_exchange_end(exch);
119}
120
[0b18364]121int _vfs_walk(int parent, const char *path, int flags)
122{
123 async_exch_t *exch = vfs_exchange_begin();
124
125 ipc_call_t answer;
126 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
[3ef62df]127 sysarg_t rc = async_data_write_start(exch, path, str_size(path));
[0b18364]128 vfs_exchange_end(exch);
129
130 sysarg_t rc_orig;
131 async_wait_for(req, &rc_orig);
132
[61042de]133 if (rc_orig != EOK)
[0b18364]134 return (int) rc_orig;
135
[61042de]136 if (rc != EOK)
[0b18364]137 return (int) rc;
138
139 return (int) IPC_GET_ARG1(answer);
140}
141
[5126f80]142int vfs_lookup(const char *path, int flags)
[eca9fd0]143{
144 size_t size;
145 char *p = vfs_absolutize(path, &size);
[61042de]146 if (!p)
[eca9fd0]147 return ENOMEM;
[5126f80]148 int root = vfs_root();
[c725619]149 if (root < 0) {
[5126f80]150 free(p);
151 return ENOENT;
152 }
153 int rc = _vfs_walk(root, p, flags);
154 close(root);
[eca9fd0]155 free(p);
156 return rc;
157}
158
[0b18364]159int _vfs_open(int fildes, int mode)
160{
161 async_exch_t *exch = vfs_exchange_begin();
162 sysarg_t rc = async_req_2_0(exch, VFS_IN_OPEN2, fildes, mode);
163 vfs_exchange_end(exch);
164
165 return (int) rc;
166}
167
[6afc9d7]168char *vfs_absolutize(const char *path, size_t *retlen)
[5fec355]169{
170 char *ncwd_path;
[34a74ab]171 char *ncwd_path_nc;
[5fec355]172
[a28ab12]173 fibril_mutex_lock(&cwd_mutex);
[9eb3623]174 size_t size = str_size(path);
[5fec355]175 if (*path != '/') {
[6afc9d7]176 if (cwd_path == NULL) {
[a28ab12]177 fibril_mutex_unlock(&cwd_mutex);
[5fec355]178 return NULL;
179 }
[79ae36dd]180 ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
[6afc9d7]181 if (ncwd_path_nc == NULL) {
[a28ab12]182 fibril_mutex_unlock(&cwd_mutex);
[5fec355]183 return NULL;
184 }
[79ae36dd]185 str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
[9eb3623]186 ncwd_path_nc[cwd_size] = '/';
187 ncwd_path_nc[cwd_size + 1] = '\0';
[5fec355]188 } else {
[79ae36dd]189 ncwd_path_nc = malloc(size + 1);
[6afc9d7]190 if (ncwd_path_nc == NULL) {
[a28ab12]191 fibril_mutex_unlock(&cwd_mutex);
[5fec355]192 return NULL;
193 }
[34a74ab]194 ncwd_path_nc[0] = '\0';
[5fec355]195 }
[79ae36dd]196 str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
[34a74ab]197 ncwd_path = canonify(ncwd_path_nc, retlen);
[6afc9d7]198 if (ncwd_path == NULL) {
[a28ab12]199 fibril_mutex_unlock(&cwd_mutex);
[34a74ab]200 free(ncwd_path_nc);
201 return NULL;
202 }
203 /*
204 * We need to clone ncwd_path because canonify() works in-place and thus
205 * the address in ncwd_path need not be the same as ncwd_path_nc, even
206 * though they both point into the same dynamically allocated buffer.
207 */
[095003a8]208 ncwd_path = str_dup(ncwd_path);
[34a74ab]209 free(ncwd_path_nc);
[6afc9d7]210 if (ncwd_path == NULL) {
[a28ab12]211 fibril_mutex_unlock(&cwd_mutex);
[923c39e]212 return NULL;
213 }
[a28ab12]214 fibril_mutex_unlock(&cwd_mutex);
[5fec355]215 return ncwd_path;
216}
[2f02aa17]217
[5126f80]218int vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
[61042de]219 unsigned int flags, unsigned int instance, int *mountedfd)
[5126f80]220{
221 sysarg_t rc, rc1;
222
[61042de]223 if (!mountedfd)
[5126f80]224 flags |= VFS_MOUNT_NO_REF;
[61042de]225 if (mp < 0)
[5126f80]226 flags |= VFS_MOUNT_CONNECT_ONLY;
227
228 ipc_call_t answer;
229 async_exch_t *exch = vfs_exchange_begin();
[61042de]230 aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance,
231 &answer);
[5126f80]232
233 rc1 = async_data_write_start(exch, (void *) opts, str_size(opts));
234 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
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 */
452static int _read_short(int fildes, void *buf, size_t nbyte, 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
463 req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
[fa24efa]464 rc = async_data_read_start(exch, (void *) buf, nbyte);
[354b642]465
[79ae36dd]466 vfs_exchange_end(exch);
[354b642]467
[61042de]468 if (rc == EOK)
[354b642]469 async_wait_for(req, &rc);
[61042de]470 else
[354b642]471 async_forget(req);
[6afc9d7]472
473 if (rc != EOK)
[25becee8]474 return rc;
[6afc9d7]475
476 *nread = (ssize_t) IPC_GET_ARG1(answer);
477 return EOK;
[2f02aa17]478}
479
[6afc9d7]480/** Write bytes to file.
481 *
482 * Write up to @a nbyte bytes from file. The actual number of bytes written
483 * may be lower, but greater than zero.
484 *
485 * @param fildes File descriptor
486 * @param buf Buffer
487 * @param nbyte Maximum number of bytes to write
488 * @param nread Place to store actual number of bytes written (0 or more)
489 *
490 * @return EOK on success, non-zero error code on error.
491 */
492static int _write_short(int fildes, const void *buf, size_t nbyte,
493 ssize_t *nwritten)
[449c246]494{
[96b02eb9]495 sysarg_t rc;
[449c246]496 ipc_call_t answer;
497 aid_t req;
[19b28b0]498
[fa24efa]499 if (nbyte > DATA_XFER_LIMIT)
500 nbyte = DATA_XFER_LIMIT;
501
[79ae36dd]502 async_exch_t *exch = vfs_exchange_begin();
503
504 req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
[fa24efa]505 rc = async_data_write_start(exch, (void *) buf, nbyte);
[6afc9d7]506
[79ae36dd]507 vfs_exchange_end(exch);
[6afc9d7]508
[61042de]509 if (rc == EOK)
[354b642]510 async_wait_for(req, &rc);
[61042de]511 else
[354b642]512 async_forget(req);
513
[6afc9d7]514 if (rc != EOK)
515 return rc;
516
517 *nwritten = (ssize_t) IPC_GET_ARG1(answer);
518 return EOK;
[449c246]519}
[222e57c]520
[6afc9d7]521/** Read data.
[8fd04ba9]522 *
[6afc9d7]523 * Read up to @a nbytes bytes from file if available. This function always reads
524 * all the available bytes up to @a nbytes.
[8fd04ba9]525 *
526 * @param fildes File descriptor
527 * @param buf Buffer, @a nbytes bytes long
528 * @param nbytes Number of bytes to read
529 *
[6afc9d7]530 * @return On success, nonnegative number of bytes read.
531 * On failure, -1 and sets errno.
[8fd04ba9]532 */
[6afc9d7]533ssize_t read(int fildes, void *buf, size_t nbyte)
[8fd04ba9]534{
535 ssize_t cnt = 0;
536 size_t nread = 0;
537 uint8_t *bp = (uint8_t *) buf;
[6afc9d7]538 int rc;
539
[8fd04ba9]540 do {
541 bp += cnt;
542 nread += cnt;
[6afc9d7]543 rc = _read_short(fildes, bp, nbyte - nread, &cnt);
544 } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
545
546 if (rc != EOK) {
547 errno = rc;
548 return -1;
549 }
550
[8fd04ba9]551 return nread + cnt;
552}
553
[6afc9d7]554/** Write data.
[8fd04ba9]555 *
556 * This function fails if it cannot write exactly @a len bytes to the file.
557 *
558 * @param fildes File descriptor
559 * @param buf Data, @a nbytes bytes long
560 * @param nbytes Number of bytes to write
561 *
[6afc9d7]562 * @return On success, nonnegative number of bytes written.
563 * On failure, -1 and sets errno.
[8fd04ba9]564 */
[6afc9d7]565ssize_t write(int fildes, const void *buf, size_t nbyte)
[8fd04ba9]566{
567 ssize_t cnt = 0;
568 ssize_t nwritten = 0;
569 const uint8_t *bp = (uint8_t *) buf;
[6afc9d7]570 int rc;
[8fd04ba9]571
572 do {
573 bp += cnt;
574 nwritten += cnt;
[6afc9d7]575 rc = _write_short(fildes, bp, nbyte - nwritten, &cnt);
576 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
[8fd04ba9]577
[6afc9d7]578 if (rc != EOK) {
579 errno = rc;
580 return -1;
581 }
[8fd04ba9]582
583 return nbyte;
584}
585
[6afc9d7]586/** Synchronize file.
587 *
588 * @param fildes File descriptor
589 * @return 0 on success. On error returns -1 and sets errno.
590 */
[2595dab]591int fsync(int fildes)
592{
[79ae36dd]593 async_exch_t *exch = vfs_exchange_begin();
594 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes);
595 vfs_exchange_end(exch);
[2595dab]596
[6afc9d7]597 if (rc != EOK) {
598 errno = rc;
599 return -1;
600 }
601
602 return 0;
[2595dab]603}
604
[6afc9d7]605/** Seek to a position.
606 *
607 * @param fildes File descriptor
608 * @param offset Offset
609 * @param whence SEEK_SET, SEEK_CUR or SEEK_END
610 *
611 * @return On success the nonnegative offset from start of file. On error
612 * returns (off64_t)-1 and sets errno.
613 */
[ed903174]614off64_t lseek(int fildes, off64_t offset, int whence)
[222e57c]615{
[79ae36dd]616 async_exch_t *exch = vfs_exchange_begin();
[19b28b0]617
[96b02eb9]618 sysarg_t newoff_lo;
619 sysarg_t newoff_hi;
[79ae36dd]620 sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes,
[ed903174]621 LOWER32(offset), UPPER32(offset), whence,
622 &newoff_lo, &newoff_hi);
623
[79ae36dd]624 vfs_exchange_end(exch);
[ed903174]625
[6afc9d7]626 if (rc != EOK) {
627 errno = rc;
[ed903174]628 return (off64_t) -1;
[6afc9d7]629 }
[222e57c]630
[ed903174]631 return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
[222e57c]632}
633
[6afc9d7]634/** Truncate file to a specified length.
635 *
636 * Truncate file so that its size is exactly @a length
637 *
638 * @param fildes File descriptor
639 * @param length Length
640 *
641 * @return 0 on success, -1 on error and sets errno.
642 */
[ed903174]643int ftruncate(int fildes, aoff64_t length)
[0ee4322]644{
[96b02eb9]645 sysarg_t rc;
[0ee4322]646
[79ae36dd]647 async_exch_t *exch = vfs_exchange_begin();
648 rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes,
[ed903174]649 LOWER32(length), UPPER32(length));
[79ae36dd]650 vfs_exchange_end(exch);
[ed903174]651
[6afc9d7]652 if (rc != EOK) {
653 errno = rc;
654 return -1;
655 }
656
657 return 0;
[0ee4322]658}
659
[6afc9d7]660/** Get file status.
661 *
662 * @param fildes File descriptor
663 * @param stat Place to store file information
664 *
665 * @return 0 on success, -1 on error and sets errno.
666 */
[852b801]667int fstat(int fildes, struct stat *stat)
668{
[96b02eb9]669 sysarg_t rc;
[852b801]670 aid_t req;
671
[79ae36dd]672 async_exch_t *exch = vfs_exchange_begin();
673
674 req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
675 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
[852b801]676 if (rc != EOK) {
[79ae36dd]677 vfs_exchange_end(exch);
[6afc9d7]678
[96b02eb9]679 sysarg_t rc_orig;
[3734106]680 async_wait_for(req, &rc_orig);
[6afc9d7]681
682 if (rc_orig != EOK)
683 rc = rc_orig;
684 if (rc != EOK) {
685 errno = rc;
686 return -1;
687 }
688
689 return 0;
[852b801]690 }
[6afc9d7]691
[79ae36dd]692 vfs_exchange_end(exch);
[852b801]693 async_wait_for(req, &rc);
[6afc9d7]694
695 if (rc != EOK) {
696 errno = rc;
697 return -1;
698 }
699
700 return 0;
[852b801]701}
702
[6afc9d7]703/** Get file status.
704 *
705 * @param path Path to file
706 * @param stat Place to store file information
707 *
708 * @return 0 on success, -1 on error and sets errno.
709 */
[415c7e0d]710int stat(const char *path, struct stat *stat)
711{
[5126f80]712 int fd = vfs_lookup(path, 0);
[0ed9cb6]713 if (fd < 0) {
[0b97336]714 errno = fd;
715 return -1;
[415c7e0d]716 }
[0ed9cb6]717
718 int rc = fstat(fd, stat);
[0b97336]719 if (rc != EOK) {
720 close(fd);
721 errno = rc;
722 rc = -1;
723 } else
724 rc = close(fd);
725
[415c7e0d]726 return rc;
727}
728
[6afc9d7]729/** Open directory.
730 *
731 * @param dirname Directory pathname
732 *
733 * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
734 */
[d0dc74ae]735DIR *opendir(const char *dirname)
736{
737 DIR *dirp = malloc(sizeof(DIR));
[9b48c06]738 if (!dirp) {
[6afc9d7]739 errno = ENOMEM;
[d0dc74ae]740 return NULL;
[6afc9d7]741 }
[2b88074b]742
[0b97336]743 int fd = vfs_lookup(dirname, WALK_DIRECTORY);
744 if (fd < 0) {
[d0dc74ae]745 free(dirp);
[0b97336]746 errno = fd;
[9b48c06]747 return NULL;
748 }
749
[0b97336]750 int rc = _vfs_open(fd, MODE_READ);
[9b48c06]751 if (rc < 0) {
752 free(dirp);
[0b97336]753 close(fd);
[6afc9d7]754 errno = rc;
[d0dc74ae]755 return NULL;
756 }
[2b88074b]757
[0b97336]758 dirp->fd = fd;
[d0dc74ae]759 return dirp;
760}
761
[6afc9d7]762/** Read directory entry.
763 *
764 * @param dirp Open directory
765 * @return Non-NULL pointer to directory entry on success. On error returns
766 * @c NULL and sets errno.
767 */
[d0dc74ae]768struct dirent *readdir(DIR *dirp)
769{
[6afc9d7]770 int rc;
771 ssize_t len;
772
773 rc = _read_short(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1, &len);
774 if (rc != EOK) {
775 errno = rc;
[5973fd0]776 return NULL;
[6afc9d7]777 }
778
779 (void) len;
[5973fd0]780 return &dirp->res;
[d0dc74ae]781}
782
[6afc9d7]783/** Rewind directory position to the beginning.
784 *
785 * @param dirp Open directory
786 */
[d0dc74ae]787void rewinddir(DIR *dirp)
788{
[5973fd0]789 (void) lseek(dirp->fd, 0, SEEK_SET);
[d0dc74ae]790}
791
[6afc9d7]792/** Close directory.
793 *
794 * @param dirp Open directory
795 * @return 0 on success. On error returns -1 and sets errno.
796 */
[d0dc74ae]797int closedir(DIR *dirp)
798{
[6afc9d7]799 int rc;
800
801 rc = close(dirp->fd);
[d0dc74ae]802 free(dirp);
[6afc9d7]803
804 /* On error errno was set by close() */
805 return rc;
[d0dc74ae]806}
807
[6afc9d7]808/** Create directory.
809 *
810 * @param path Path
811 * @param mode File mode
812 * @return 0 on success. On error returns -1 and sets errno.
813 */
[72bde81]814int mkdir(const char *path, mode_t mode)
[d0dc74ae]815{
[0b97336]816 int fd = vfs_lookup(path, WALK_MUST_CREATE | WALK_DIRECTORY);
817 if (fd < 0) {
818 errno = fd;
819 return -1;
[6afc9d7]820 }
821
[0b97336]822 return close(fd);
[d0dc74ae]823}
824
[d18c404]825static int _vfs_unlink2(int parent, const char *path, int expect, int wflag)
[f15cf1a6]826{
[96b02eb9]827 sysarg_t rc;
[f15cf1a6]828 aid_t req;
829
[79ae36dd]830 async_exch_t *exch = vfs_exchange_begin();
831
[d18c404]832 req = async_send_3(exch, VFS_IN_UNLINK2, parent, expect, wflag, NULL);
833 rc = async_data_write_start(exch, path, str_size(path));
834
[79ae36dd]835 vfs_exchange_end(exch);
[d18c404]836
837 sysarg_t rc_orig;
838 async_wait_for(req, &rc_orig);
839
[61042de]840 if (rc_orig != EOK)
[d18c404]841 return (int) rc_orig;
[2595dab]842 return rc;
[f15cf1a6]843}
844
[6afc9d7]845/** Unlink file or directory.
846 *
847 * @param path Path
848 * @return EOk on success, error code on error
849 */
[f15cf1a6]850int unlink(const char *path)
851{
[d18c404]852 size_t pa_size;
[1dff985]853 char *pa = vfs_absolutize(path, &pa_size);
[d18c404]854 if (!pa) {
[0b97336]855 errno = ENOMEM;
856 return -1;
[6afc9d7]857 }
[d18c404]858
[5126f80]859 int root = vfs_root();
860 if (root < 0) {
861 free(pa);
[0b97336]862 errno = ENOENT;
863 return -1;
[5126f80]864 }
865
866 int rc = _vfs_unlink2(root, pa, -1, 0);
867
[0b97336]868 if (rc != EOK) {
869 errno = rc;
870 rc = -1;
871 }
872
[5126f80]873 free(pa);
874 close(root);
875 return rc;
[f15cf1a6]876}
877
[6afc9d7]878/** Remove empty directory.
879 *
880 * @param path Path
881 * @return 0 on success. On error returns -1 and sets errno.
882 */
[f15cf1a6]883int rmdir(const char *path)
884{
[d18c404]885 size_t pa_size;
[1dff985]886 char *pa = vfs_absolutize(path, &pa_size);
[d18c404]887 if (!pa) {
[0b97336]888 errno = ENOMEM;
889 return -1;
[6afc9d7]890 }
[d18c404]891
[5126f80]892 int root = vfs_root();
893 if (root < 0) {
894 free(pa);
[0b97336]895 errno = ENOENT;
896 return -1;
[5126f80]897 }
898
899 int rc = _vfs_unlink2(root, pa, -1, WALK_DIRECTORY);
[0b97336]900 if (rc != EOK) {
901 errno = rc;
902 rc = -1;
903 }
[5126f80]904
905 free(pa);
906 close(root);
907 return rc;
[f15cf1a6]908}
909
[6afc9d7]910/** Rename directory entry.
911 *
912 * @param old Old name
913 * @param new New name
914 *
915 * @return 0 on success. On error returns -1 and sets errno.
916 */
[a8e9ab8d]917int rename(const char *old, const char *new)
918{
[96b02eb9]919 sysarg_t rc;
920 sysarg_t rc_orig;
[a8e9ab8d]921 aid_t req;
922
[9eb3623]923 size_t olda_size;
[6afc9d7]924 char *olda = vfs_absolutize(old, &olda_size);
925 if (olda == NULL) {
926 errno = ENOMEM;
927 return -1;
928 }
[923c39e]929
[9eb3623]930 size_t newa_size;
[6afc9d7]931 char *newa = vfs_absolutize(new, &newa_size);
932 if (newa == NULL) {
[a8e9ab8d]933 free(olda);
[6afc9d7]934 errno = ENOMEM;
935 return -1;
[a8e9ab8d]936 }
[19b28b0]937
[79ae36dd]938 async_exch_t *exch = vfs_exchange_begin();
[5126f80]939 int root = vfs_root();
940 if (root < 0) {
941 free(olda);
942 free(newa);
[0b97336]943 errno = ENOENT;
944 return -1;
[5126f80]945 }
[79ae36dd]946
[5126f80]947 req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
[79ae36dd]948 rc = async_data_write_start(exch, olda, olda_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 rc = async_data_write_start(exch, newa, newa_size);
[a8e9ab8d]964 if (rc != EOK) {
[79ae36dd]965 vfs_exchange_end(exch);
[a8e9ab8d]966 free(olda);
967 free(newa);
[5126f80]968 close(root);
[a28ab12]969 async_wait_for(req, &rc_orig);
[6afc9d7]970 if (rc_orig != EOK)
971 rc = rc_orig;
972 if (rc != EOK) {
973 errno = rc;
974 return -1;
975 }
976 return 0;
[a8e9ab8d]977 }
[79ae36dd]978 vfs_exchange_end(exch);
[a8e9ab8d]979 free(olda);
980 free(newa);
[5126f80]981 close(root);
[a28ab12]982 async_wait_for(req, &rc);
[6afc9d7]983
984 if (rc != EOK) {
985 errno = rc;
986 return -1;
987 }
988
989 return 0;
[a8e9ab8d]990}
991
[6afc9d7]992/** Remove directory entry.
993 *
994 * @param path Path
995 * @return 0 on success. On error returns -1 and sets errno.
996 */
[38db6288]997int remove(const char *path)
998{
999 return unlink(path);
1000}
1001
[6afc9d7]1002/** Change working directory.
1003 *
1004 * @param path Path
1005 * @return 0 on success. On error returns -1 and sets errno.
1006 */
[5fec355]1007int chdir(const char *path)
1008{
[2b88074b]1009 size_t abs_size;
[6afc9d7]1010 char *abs = vfs_absolutize(path, &abs_size);
[0b97336]1011 if (!abs) {
1012 errno = ENOMEM;
1013 return -1;
1014 }
[2b88074b]1015
[5126f80]1016 int fd = vfs_lookup(abs, WALK_DIRECTORY);
[2b88074b]1017 if (fd < 0) {
1018 free(abs);
[1dff985]1019 errno = fd;
[6afc9d7]1020 return -1;
[5fec355]1021 }
[2b88074b]1022
[a28ab12]1023 fibril_mutex_lock(&cwd_mutex);
[2b88074b]1024
[61042de]1025 if (cwd_fd >= 0)
[2b88074b]1026 close(cwd_fd);
1027
[61042de]1028 if (cwd_path)
[2b88074b]1029 free(cwd_path);
1030
1031 cwd_fd = fd;
1032 cwd_path = abs;
1033 cwd_size = abs_size;
1034
[a28ab12]1035 fibril_mutex_unlock(&cwd_mutex);
[6afc9d7]1036 return 0;
[5fec355]1037}
1038
[6afc9d7]1039/** Get current working directory path.
1040 *
1041 * @param buf Buffer
1042 * @param size Size of @a buf
1043 * @return On success returns @a buf. On failure returns @c NULL and sets errno.
1044 */
[5fec355]1045char *getcwd(char *buf, size_t size)
1046{
[6afc9d7]1047 if (size == 0) {
1048 errno = EINVAL;
[5fec355]1049 return NULL;
[6afc9d7]1050 }
[2b88074b]1051
[a28ab12]1052 fibril_mutex_lock(&cwd_mutex);
[2b88074b]1053
1054 if ((cwd_size == 0) || (size < cwd_size + 1)) {
[a28ab12]1055 fibril_mutex_unlock(&cwd_mutex);
[6afc9d7]1056 errno = ERANGE;
[5fec355]1057 return NULL;
1058 }
[2b88074b]1059
[6eb2e96]1060 str_cpy(buf, size, cwd_path);
[a28ab12]1061 fibril_mutex_unlock(&cwd_mutex);
[2b88074b]1062
[5fec355]1063 return buf;
1064}
1065
[6afc9d7]1066/** Open session to service represented by a special file.
1067 *
1068 * Given that the file referred to by @a fildes represents a service,
1069 * open a session to that service.
1070 *
1071 * @param fildes File descriptor
1072 * @param iface Interface to connect to (XXX Should be automatic)
1073 * @return On success returns session pointer. On error returns @c NULL.
1074 */
1075async_sess_t *vfs_fd_session(int fildes, iface_t iface)
[852b801]1076{
1077 struct stat stat;
[8caaea7]1078 int rc = fstat(fildes, &stat);
[6afc9d7]1079 if (rc != 0)
[79ae36dd]1080 return NULL;
[8caaea7]1081
[6afc9d7]1082 if (stat.service == 0)
[79ae36dd]1083 return NULL;
[852b801]1084
[f9b2cb4c]1085 return loc_service_connect(stat.service, iface, 0);
[852b801]1086}
1087
[6afc9d7]1088/** Duplicate open file.
1089 *
1090 * Duplicate open file under a new file descriptor.
1091 *
1092 * @param oldfd Old file descriptor
1093 * @param newfd New file descriptor
1094 * @return 0 on success. On error -1 is returned and errno is set
1095 */
[2b88074b]1096int dup2(int oldfd, int newfd)
[852b801]1097{
[79ae36dd]1098 async_exch_t *exch = vfs_exchange_begin();
[852b801]1099
[96b02eb9]1100 sysarg_t ret;
[79ae36dd]1101 sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret);
[852b801]1102
[79ae36dd]1103 vfs_exchange_end(exch);
[2b88074b]1104
1105 if (rc == EOK)
[6afc9d7]1106 rc = ret;
[2b88074b]1107
[6afc9d7]1108 if (rc != EOK) {
1109 errno = rc;
1110 return -1;
1111 }
1112
1113 return 0;
[852b801]1114}
1115
[8ffedd8]1116static void process_mp(const char *path, struct stat *stat, list_t *mtab_list)
[10e4cd7]1117{
[8ffedd8]1118 mtab_ent_t *ent;
1119
1120 ent = (mtab_ent_t *) malloc(sizeof(mtab_ent_t));
1121 if (!ent)
1122 return;
1123
1124 link_initialize(&ent->link);
1125 str_cpy(ent->mp, sizeof(ent->mp), path);
1126 ent->service_id = stat->service_id;
[5a2b765]1127
1128 struct statfs stfs;
1129 if (statfs(path, &stfs) == EOK)
1130 str_cpy(ent->fs_name, sizeof(ent->fs_name), stfs.fs_name);
1131 else
1132 str_cpy(ent->fs_name, sizeof(ent->fs_name), "?");
[10e4cd7]1133
[8ffedd8]1134 list_append(&ent->link, mtab_list);
1135}
1136
1137static int vfs_get_mtab_visit(const char *path, list_t *mtab_list,
1138 fs_handle_t fs_handle, service_id_t service_id)
1139{
1140 DIR *dir;
1141 struct dirent *dirent;
1142
1143 dir = opendir(path);
1144 if (!dir)
[0b97336]1145 return ENOENT;
[8ffedd8]1146
1147 while ((dirent = readdir(dir)) != NULL) {
1148 char *child;
1149 struct stat st;
1150 int rc;
1151
1152 rc = asprintf(&child, "%s/%s", path, dirent->d_name);
1153 if (rc < 0) {
1154 closedir(dir);
[0b97336]1155 return rc;
[8ffedd8]1156 }
1157
[61600e7]1158 char *pa = vfs_absolutize(child, NULL);
1159 if (!pa) {
1160 free(child);
1161 closedir(dir);
1162 return ENOMEM;
1163 }
1164
1165 free(child);
1166 child = pa;
1167
[8ffedd8]1168 rc = stat(child, &st);
1169 if (rc != 0) {
1170 free(child);
1171 closedir(dir);
[0b97336]1172 return rc;
[8ffedd8]1173 }
1174
1175 if (st.fs_handle != fs_handle || st.service_id != service_id) {
1176 /*
1177 * We have discovered a mountpoint.
1178 */
1179 process_mp(child, &st, mtab_list);
1180 }
1181
1182 if (st.is_directory) {
1183 (void) vfs_get_mtab_visit(child, mtab_list,
1184 st.fs_handle, st.service_id);
1185 }
1186
1187 free(child);
1188 }
1189
1190 closedir(dir);
1191 return EOK;
1192}
1193
1194int vfs_get_mtab_list(list_t *mtab_list)
1195{
1196 struct stat st;
1197
1198 int rc = stat("/", &st);
1199 if (rc != 0)
1200 return rc;
1201
1202 process_mp("/", &st, mtab_list);
1203
[61600e7]1204 return vfs_get_mtab_visit("/", mtab_list, st.fs_handle, st.service_id);
[10e4cd7]1205}
1206
[6afc9d7]1207/** Get filesystem statistics.
1208 *
1209 * @param path Mount point path
1210 * @param st Buffer for storing information
1211 * @return 0 on success. On error -1 is returned and errno is set.
1212 */
[73fbcbb]1213int statfs(const char *path, struct statfs *st)
[66366470]1214{
[5126f80]1215 int fd = vfs_lookup(path, 0);
[a737667e]1216 if (fd < 0) {
1217 errno = fd;
1218 return -1;
1219 }
1220
1221 sysarg_t rc, ret;
1222 aid_t req;
[73fbcbb]1223
[a737667e]1224 async_exch_t *exch = vfs_exchange_begin();
[73fbcbb]1225
[a737667e]1226 req = async_send_1(exch, VFS_IN_STATFS, fd, NULL);
[73fbcbb]1227 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
1228
[66366470]1229 vfs_exchange_end(exch);
[a737667e]1230 async_wait_for(req, &ret);
1231 close(fd);
[6afc9d7]1232
[a737667e]1233 rc = (ret != EOK ? ret : rc);
[6afc9d7]1234 if (rc != EOK) {
1235 errno = rc;
1236 return -1;
1237 }
1238
1239 return 0;
[66366470]1240}
1241
[354b642]1242int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
1243{
[61042de]1244 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
1245 0, vfs_exch);
[354b642]1246}
1247
[bb9ec2d]1248int vfs_receive_handle(bool high_descriptor)
[354b642]1249{
1250 ipc_callid_t callid;
1251 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
1252 async_answer_0(callid, EINVAL);
1253 return EINVAL;
1254 }
1255
1256 async_exch_t *vfs_exch = vfs_exchange_begin();
1257
1258 async_state_change_finalize(callid, vfs_exch);
1259
1260 sysarg_t ret;
[61042de]1261 sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE,
1262 high_descriptor, &ret);
[354b642]1263
1264 async_exchange_end(vfs_exch);
1265
[61042de]1266 if (rc != EOK)
[354b642]1267 return rc;
1268 return ret;
1269}
1270
1271int vfs_clone(int file, bool high_descriptor)
1272{
1273 async_exch_t *vfs_exch = vfs_exchange_begin();
[61042de]1274 int rc = async_req_2_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file,
1275 (sysarg_t) high_descriptor);
[354b642]1276 vfs_exchange_end(vfs_exch);
1277 return rc;
1278}
1279
[2f02aa17]1280/** @}
1281 */
Note: See TracBrowser for help on using the repository browser.