source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 354b642

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

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5/ revisions 1932-1936

Original commit messages:

1936: Jiri Zarevucky 2013-08-05 Modifications to vfs_rdwr.
1935: Jiri Zarevucky 2013-08-05 Fix a bug in read/write.
1934: Jiri Zarevucky 2013-08-05 Fix a hidden bug in handle passing.
1933: Jiri Zarevucky 2013-08-05 Add VFS_IN_CLONE.
1932: Jiri Zarevucky 2013-08-05 Add functions for passing handles around.

Modifications:

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