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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b272c67a was 6afc9d7, checked in by Jiri Svoboda <jiri@…>, 10 years ago

UNIX-like I/O functions should use errno to return error code for many reasons.

  • Property mode set to 100644
File size: 24.5 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
[6afc9d7]95char *vfs_absolutize(const char *path, size_t *retlen)
[5fec355]96{
97 char *ncwd_path;
[34a74ab]98 char *ncwd_path_nc;
[5fec355]99
[a28ab12]100 fibril_mutex_lock(&cwd_mutex);
[9eb3623]101 size_t size = str_size(path);
[5fec355]102 if (*path != '/') {
[6afc9d7]103 if (cwd_path == NULL) {
[a28ab12]104 fibril_mutex_unlock(&cwd_mutex);
[5fec355]105 return NULL;
106 }
[79ae36dd]107 ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
[6afc9d7]108 if (ncwd_path_nc == NULL) {
[a28ab12]109 fibril_mutex_unlock(&cwd_mutex);
[5fec355]110 return NULL;
111 }
[79ae36dd]112 str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
[9eb3623]113 ncwd_path_nc[cwd_size] = '/';
114 ncwd_path_nc[cwd_size + 1] = '\0';
[5fec355]115 } else {
[79ae36dd]116 ncwd_path_nc = malloc(size + 1);
[6afc9d7]117 if (ncwd_path_nc == NULL) {
[a28ab12]118 fibril_mutex_unlock(&cwd_mutex);
[5fec355]119 return NULL;
120 }
[34a74ab]121 ncwd_path_nc[0] = '\0';
[5fec355]122 }
[79ae36dd]123 str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
[34a74ab]124 ncwd_path = canonify(ncwd_path_nc, retlen);
[6afc9d7]125 if (ncwd_path == NULL) {
[a28ab12]126 fibril_mutex_unlock(&cwd_mutex);
[34a74ab]127 free(ncwd_path_nc);
128 return NULL;
129 }
130 /*
131 * We need to clone ncwd_path because canonify() works in-place and thus
132 * the address in ncwd_path need not be the same as ncwd_path_nc, even
133 * though they both point into the same dynamically allocated buffer.
134 */
[095003a8]135 ncwd_path = str_dup(ncwd_path);
[34a74ab]136 free(ncwd_path_nc);
[6afc9d7]137 if (ncwd_path == NULL) {
[a28ab12]138 fibril_mutex_unlock(&cwd_mutex);
[923c39e]139 return NULL;
140 }
[a28ab12]141 fibril_mutex_unlock(&cwd_mutex);
[5fec355]142 return ncwd_path;
143}
[2f02aa17]144
[6afc9d7]145int vfs_mount(const char *fs_name, const char *mp, const char *fqsn,
[4979403]146 const char *opts, unsigned int flags, unsigned int instance)
[2f02aa17]147{
[210e50a]148 int null_id = -1;
[15f3c3f]149 char null[LOC_NAME_MAXLEN];
[210e50a]150
[15f3c3f]151 if (str_cmp(fqsn, "") == 0) {
[210e50a]152 /* No device specified, create a fresh
153 null/%d device instead */
[15f3c3f]154 null_id = loc_null_create();
[210e50a]155
156 if (null_id == -1)
157 return ENOMEM;
158
[15f3c3f]159 snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
160 fqsn = null;
[210e50a]161 }
[82405266]162
[15f3c3f]163 service_id_t service_id;
164 int res = loc_service_get_id(fqsn, &service_id, flags);
[210e50a]165 if (res != EOK) {
166 if (null_id != -1)
[15f3c3f]167 loc_null_destroy(null_id);
[210e50a]168
[82405266]169 return res;
[210e50a]170 }
[82405266]171
[9eb3623]172 size_t mpa_size;
[6afc9d7]173 char *mpa = vfs_absolutize(mp, &mpa_size);
174 if (mpa == NULL) {
[210e50a]175 if (null_id != -1)
[15f3c3f]176 loc_null_destroy(null_id);
[210e50a]177
[5fec355]178 return ENOMEM;
[210e50a]179 }
[19b28b0]180
[79ae36dd]181 async_exch_t *exch = vfs_exchange_begin();
[a28ab12]182
[96b02eb9]183 sysarg_t rc_orig;
[4979403]184 aid_t req = async_send_3(exch, VFS_IN_MOUNT, service_id, flags,
[286286c]185 instance, NULL);
[79ae36dd]186 sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size);
[12fc042]187 if (rc != EOK) {
[79ae36dd]188 vfs_exchange_end(exch);
[12fc042]189 free(mpa);
[a28ab12]190 async_wait_for(req, &rc_orig);
[210e50a]191
192 if (null_id != -1)
[15f3c3f]193 loc_null_destroy(null_id);
[210e50a]194
[3734106]195 if (rc_orig == EOK)
196 return (int) rc;
197 else
198 return (int) rc_orig;
[12fc042]199 }
[19b28b0]200
[79ae36dd]201 rc = async_data_write_start(exch, (void *) opts, str_size(opts));
[594303b]202 if (rc != EOK) {
[79ae36dd]203 vfs_exchange_end(exch);
[594303b]204 free(mpa);
[a28ab12]205 async_wait_for(req, &rc_orig);
[210e50a]206
207 if (null_id != -1)
[15f3c3f]208 loc_null_destroy(null_id);
[210e50a]209
[3734106]210 if (rc_orig == EOK)
211 return (int) rc;
212 else
213 return (int) rc_orig;
[594303b]214 }
[210e50a]215
[79ae36dd]216 rc = async_data_write_start(exch, (void *) fs_name, str_size(fs_name));
[2f02aa17]217 if (rc != EOK) {
[79ae36dd]218 vfs_exchange_end(exch);
[5fec355]219 free(mpa);
[a28ab12]220 async_wait_for(req, &rc_orig);
[210e50a]221
222 if (null_id != -1)
[15f3c3f]223 loc_null_destroy(null_id);
[210e50a]224
[3734106]225 if (rc_orig == EOK)
226 return (int) rc;
227 else
228 return (int) rc_orig;
[2f02aa17]229 }
[210e50a]230
[c08c355]231 /* Ask VFS whether it likes fs_name. */
[79ae36dd]232 rc = async_req_0_0(exch, VFS_IN_PING);
[c08c355]233 if (rc != EOK) {
[79ae36dd]234 vfs_exchange_end(exch);
[c08c355]235 free(mpa);
[a28ab12]236 async_wait_for(req, &rc_orig);
[210e50a]237
238 if (null_id != -1)
[15f3c3f]239 loc_null_destroy(null_id);
[210e50a]240
[3734106]241 if (rc_orig == EOK)
242 return (int) rc;
243 else
244 return (int) rc_orig;
[c08c355]245 }
[19b28b0]246
[79ae36dd]247 vfs_exchange_end(exch);
[5fec355]248 free(mpa);
[a28ab12]249 async_wait_for(req, &rc);
[19b28b0]250
[210e50a]251 if ((rc != EOK) && (null_id != -1))
[15f3c3f]252 loc_null_destroy(null_id);
[210e50a]253
[2f02aa17]254 return (int) rc;
255}
256
[6afc9d7]257int vfs_unmount(const char *mp)
[21f32ee1]258{
[96b02eb9]259 sysarg_t rc;
260 sysarg_t rc_orig;
[b9067dfa]261 aid_t req;
262 size_t mpa_size;
263 char *mpa;
264
[6afc9d7]265 mpa = vfs_absolutize(mp, &mpa_size);
266 if (mpa == NULL)
[b9067dfa]267 return ENOMEM;
268
[79ae36dd]269 async_exch_t *exch = vfs_exchange_begin();
[b9067dfa]270
[79ae36dd]271 req = async_send_0(exch, VFS_IN_UNMOUNT, NULL);
272 rc = async_data_write_start(exch, (void *) mpa, mpa_size);
[b9067dfa]273 if (rc != EOK) {
[79ae36dd]274 vfs_exchange_end(exch);
[b9067dfa]275 free(mpa);
[a28ab12]276 async_wait_for(req, &rc_orig);
[b9067dfa]277 if (rc_orig == EOK)
278 return (int) rc;
279 else
280 return (int) rc_orig;
281 }
282
283
[79ae36dd]284 vfs_exchange_end(exch);
[b9067dfa]285 free(mpa);
[a28ab12]286 async_wait_for(req, &rc);
[b9067dfa]287
288 return (int) rc;
[21f32ee1]289}
290
[6afc9d7]291/** Open file (internal).
292 *
293 * @param abs Absolute path to file
294 * @param abs_size Size of @a abs string
295 * @param lflag L_xxx flags
296 * @param oflag O_xxx flags
297 * @param fd Place to store new file descriptor
298 *
299 * @return EOK on success, non-zero error code on error
300 */
301static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag,
302 int *fd)
[2f02aa17]303{
[79ae36dd]304 async_exch_t *exch = vfs_exchange_begin();
[19b28b0]305
[2b88074b]306 ipc_call_t answer;
[79ae36dd]307 aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer);
308 sysarg_t rc = async_data_write_start(exch, abs, abs_size);
[2b88074b]309
[2f02aa17]310 if (rc != EOK) {
[79ae36dd]311 vfs_exchange_end(exch);
[a28ab12]312
[96b02eb9]313 sysarg_t rc_orig;
[3734106]314 async_wait_for(req, &rc_orig);
[2b88074b]315
[3734106]316 if (rc_orig == EOK)
317 return (int) rc;
318 else
319 return (int) rc_orig;
[2f02aa17]320 }
[2b88074b]321
[79ae36dd]322 vfs_exchange_end(exch);
[2f02aa17]323 async_wait_for(req, &rc);
[2595dab]324
[57b4f46]325 if (rc != EOK)
326 return (int) rc;
[2595dab]327
[6afc9d7]328 *fd = (int) IPC_GET_ARG1(answer);
329 return EOK;
[2f02aa17]330}
331
[6afc9d7]332/** Open file.
333 *
334 * @param path File path
335 * @param oflag O_xxx flags
336 * @param mode File mode (only with O_CREAT)
337 *
338 * @return Nonnegative file descriptor on success. On error -1 is returned
339 * and errno is set.
340 */
[ae78b530]341int open(const char *path, int oflag, ...)
342{
[2b88074b]343 size_t abs_size;
[6afc9d7]344 char *abs = vfs_absolutize(path, &abs_size);
345 int fd = -1;
346
347 if (abs == NULL) {
348 errno = ENOMEM;
349 return -1;
350 }
[2b88074b]351
[6afc9d7]352 int rc = open_internal(abs, abs_size, L_FILE, oflag, &fd);
[2b88074b]353 free(abs);
354
[6afc9d7]355 if (rc != EOK) {
356 errno = rc;
357 return -1;
358 }
359
360 return fd;
[ae78b530]361}
362
[6afc9d7]363/** Close file.
364 *
365 * @param fildes File descriptor
366 * @return Zero on success. On error -1 is returned and errno is set.
367 */
[72bde81]368int close(int fildes)
369{
[96b02eb9]370 sysarg_t rc;
[19b28b0]371
[79ae36dd]372 async_exch_t *exch = vfs_exchange_begin();
373 rc = async_req_1_0(exch, VFS_IN_CLOSE, fildes);
374 vfs_exchange_end(exch);
[19b28b0]375
[6afc9d7]376 if (rc != EOK) {
377 errno = rc;
378 return -1;
379 }
380
381 return 0;
[72bde81]382}
383
[6afc9d7]384/** Read bytes from file.
385 *
386 * Read up to @a nbyte bytes from file. The actual number of bytes read
387 * may be lower, but greater than zero if there are any bytes available.
388 * If there are no bytes available for reading, then the function will
389 * return success with zero bytes read.
390 *
391 * @param fildes File descriptor
392 * @param buf Buffer
393 * @param nbyte Maximum number of bytes to read
394 * @param nread Place to store actual number of bytes read (0 or more)
395 *
396 * @return EOK on success, non-zero error code on error.
397 */
398static int _read_short(int fildes, void *buf, size_t nbyte, ssize_t *nread)
[2f02aa17]399{
[96b02eb9]400 sysarg_t rc;
[2f02aa17]401 ipc_call_t answer;
402 aid_t req;
[19b28b0]403
[fa24efa]404 if (nbyte > DATA_XFER_LIMIT)
405 nbyte = DATA_XFER_LIMIT;
406
[79ae36dd]407 async_exch_t *exch = vfs_exchange_begin();
408
409 req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
[fa24efa]410 rc = async_data_read_start(exch, (void *) buf, nbyte);
[07e01e6]411 if (rc != EOK) {
[79ae36dd]412 vfs_exchange_end(exch);
[6afc9d7]413
[96b02eb9]414 sysarg_t rc_orig;
[3734106]415 async_wait_for(req, &rc_orig);
[6afc9d7]416
[3734106]417 if (rc_orig == EOK)
[6afc9d7]418 return rc;
[3734106]419 else
[6afc9d7]420 return rc_orig;
[2f02aa17]421 }
[6afc9d7]422
[79ae36dd]423 vfs_exchange_end(exch);
[2f02aa17]424 async_wait_for(req, &rc);
[6afc9d7]425
426 if (rc != EOK)
[25becee8]427 return rc;
[6afc9d7]428
429 *nread = (ssize_t) IPC_GET_ARG1(answer);
430 return EOK;
[2f02aa17]431}
432
[6afc9d7]433/** Write bytes to file.
434 *
435 * Write up to @a nbyte bytes from file. The actual number of bytes written
436 * may be lower, but greater than zero.
437 *
438 * @param fildes File descriptor
439 * @param buf Buffer
440 * @param nbyte Maximum number of bytes to write
441 * @param nread Place to store actual number of bytes written (0 or more)
442 *
443 * @return EOK on success, non-zero error code on error.
444 */
445static int _write_short(int fildes, const void *buf, size_t nbyte,
446 ssize_t *nwritten)
[449c246]447{
[96b02eb9]448 sysarg_t rc;
[449c246]449 ipc_call_t answer;
450 aid_t req;
[19b28b0]451
[fa24efa]452 if (nbyte > DATA_XFER_LIMIT)
453 nbyte = DATA_XFER_LIMIT;
454
[79ae36dd]455 async_exch_t *exch = vfs_exchange_begin();
456
457 req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
[fa24efa]458 rc = async_data_write_start(exch, (void *) buf, nbyte);
[07e01e6]459 if (rc != EOK) {
[79ae36dd]460 vfs_exchange_end(exch);
[6afc9d7]461
[96b02eb9]462 sysarg_t rc_orig;
[3734106]463 async_wait_for(req, &rc_orig);
[6afc9d7]464
[3734106]465 if (rc_orig == EOK)
[6afc9d7]466 return rc;
[3734106]467 else
[6afc9d7]468 return rc_orig;
[449c246]469 }
[6afc9d7]470
[79ae36dd]471 vfs_exchange_end(exch);
[449c246]472 async_wait_for(req, &rc);
[6afc9d7]473
474 if (rc != EOK)
475 return rc;
476
477 *nwritten = (ssize_t) IPC_GET_ARG1(answer);
478 return EOK;
[449c246]479}
[222e57c]480
[6afc9d7]481/** Read data.
[8fd04ba9]482 *
[6afc9d7]483 * Read up to @a nbytes bytes from file if available. This function always reads
484 * all the available bytes up to @a nbytes.
[8fd04ba9]485 *
486 * @param fildes File descriptor
487 * @param buf Buffer, @a nbytes bytes long
488 * @param nbytes Number of bytes to read
489 *
[6afc9d7]490 * @return On success, nonnegative number of bytes read.
491 * On failure, -1 and sets errno.
[8fd04ba9]492 */
[6afc9d7]493ssize_t read(int fildes, void *buf, size_t nbyte)
[8fd04ba9]494{
495 ssize_t cnt = 0;
496 size_t nread = 0;
497 uint8_t *bp = (uint8_t *) buf;
[6afc9d7]498 int rc;
499
[8fd04ba9]500 do {
501 bp += cnt;
502 nread += cnt;
[6afc9d7]503 rc = _read_short(fildes, bp, nbyte - nread, &cnt);
504 } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
505
506 if (rc != EOK) {
507 errno = rc;
508 return -1;
509 }
510
[8fd04ba9]511 return nread + cnt;
512}
513
[6afc9d7]514/** Write data.
[8fd04ba9]515 *
516 * This function fails if it cannot write exactly @a len bytes to the file.
517 *
518 * @param fildes File descriptor
519 * @param buf Data, @a nbytes bytes long
520 * @param nbytes Number of bytes to write
521 *
[6afc9d7]522 * @return On success, nonnegative number of bytes written.
523 * On failure, -1 and sets errno.
[8fd04ba9]524 */
[6afc9d7]525ssize_t write(int fildes, const void *buf, size_t nbyte)
[8fd04ba9]526{
527 ssize_t cnt = 0;
528 ssize_t nwritten = 0;
529 const uint8_t *bp = (uint8_t *) buf;
[6afc9d7]530 int rc;
[8fd04ba9]531
532 do {
533 bp += cnt;
534 nwritten += cnt;
[6afc9d7]535 rc = _write_short(fildes, bp, nbyte - nwritten, &cnt);
536 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
[8fd04ba9]537
[6afc9d7]538 if (rc != EOK) {
539 errno = rc;
540 return -1;
541 }
[8fd04ba9]542
543 return nbyte;
544}
545
[6afc9d7]546/** Synchronize file.
547 *
548 * @param fildes File descriptor
549 * @return 0 on success. On error returns -1 and sets errno.
550 */
[2595dab]551int fsync(int fildes)
552{
[79ae36dd]553 async_exch_t *exch = vfs_exchange_begin();
554 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes);
555 vfs_exchange_end(exch);
[2595dab]556
[6afc9d7]557 if (rc != EOK) {
558 errno = rc;
559 return -1;
560 }
561
562 return 0;
[2595dab]563}
564
[6afc9d7]565/** Seek to a position.
566 *
567 * @param fildes File descriptor
568 * @param offset Offset
569 * @param whence SEEK_SET, SEEK_CUR or SEEK_END
570 *
571 * @return On success the nonnegative offset from start of file. On error
572 * returns (off64_t)-1 and sets errno.
573 */
[ed903174]574off64_t lseek(int fildes, off64_t offset, int whence)
[222e57c]575{
[79ae36dd]576 async_exch_t *exch = vfs_exchange_begin();
[19b28b0]577
[96b02eb9]578 sysarg_t newoff_lo;
579 sysarg_t newoff_hi;
[79ae36dd]580 sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes,
[ed903174]581 LOWER32(offset), UPPER32(offset), whence,
582 &newoff_lo, &newoff_hi);
583
[79ae36dd]584 vfs_exchange_end(exch);
[ed903174]585
[6afc9d7]586 if (rc != EOK) {
587 errno = rc;
[ed903174]588 return (off64_t) -1;
[6afc9d7]589 }
[222e57c]590
[ed903174]591 return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
[222e57c]592}
593
[6afc9d7]594/** Truncate file to a specified length.
595 *
596 * Truncate file so that its size is exactly @a length
597 *
598 * @param fildes File descriptor
599 * @param length Length
600 *
601 * @return 0 on success, -1 on error and sets errno.
602 */
[ed903174]603int ftruncate(int fildes, aoff64_t length)
[0ee4322]604{
[96b02eb9]605 sysarg_t rc;
[0ee4322]606
[79ae36dd]607 async_exch_t *exch = vfs_exchange_begin();
608 rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes,
[ed903174]609 LOWER32(length), UPPER32(length));
[79ae36dd]610 vfs_exchange_end(exch);
[ed903174]611
[6afc9d7]612 if (rc != EOK) {
613 errno = rc;
614 return -1;
615 }
616
617 return 0;
[0ee4322]618}
619
[6afc9d7]620/** Get file status.
621 *
622 * @param fildes File descriptor
623 * @param stat Place to store file information
624 *
625 * @return 0 on success, -1 on error and sets errno.
626 */
[852b801]627int fstat(int fildes, struct stat *stat)
628{
[96b02eb9]629 sysarg_t rc;
[852b801]630 aid_t req;
631
[79ae36dd]632 async_exch_t *exch = vfs_exchange_begin();
633
634 req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
635 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
[852b801]636 if (rc != EOK) {
[79ae36dd]637 vfs_exchange_end(exch);
[6afc9d7]638
[96b02eb9]639 sysarg_t rc_orig;
[3734106]640 async_wait_for(req, &rc_orig);
[6afc9d7]641
642 if (rc_orig != EOK)
643 rc = rc_orig;
644 if (rc != EOK) {
645 errno = rc;
646 return -1;
647 }
648
649 return 0;
[852b801]650 }
[6afc9d7]651
[79ae36dd]652 vfs_exchange_end(exch);
[852b801]653 async_wait_for(req, &rc);
[6afc9d7]654
655 if (rc != EOK) {
656 errno = rc;
657 return -1;
658 }
659
660 return 0;
[852b801]661}
662
[6afc9d7]663/** Get file status.
664 *
665 * @param path Path to file
666 * @param stat Place to store file information
667 *
668 * @return 0 on success, -1 on error and sets errno.
669 */
[415c7e0d]670int stat(const char *path, struct stat *stat)
671{
[96b02eb9]672 sysarg_t rc;
673 sysarg_t rc_orig;
[415c7e0d]674 aid_t req;
675
676 size_t pa_size;
[6afc9d7]677 char *pa = vfs_absolutize(path, &pa_size);
678 if (pa == NULL) {
679 errno = ENOMEM;
680 return -1;
681 }
[415c7e0d]682
[79ae36dd]683 async_exch_t *exch = vfs_exchange_begin();
[415c7e0d]684
[79ae36dd]685 req = async_send_0(exch, VFS_IN_STAT, NULL);
686 rc = async_data_write_start(exch, pa, pa_size);
[415c7e0d]687 if (rc != EOK) {
[79ae36dd]688 vfs_exchange_end(exch);
[415c7e0d]689 free(pa);
[a28ab12]690 async_wait_for(req, &rc_orig);
[6afc9d7]691 if (rc_orig != EOK)
692 rc = rc_orig;
693 if (rc != EOK) {
694 errno = rc;
695 return -1;
696 }
[415c7e0d]697 }
[79ae36dd]698 rc = async_data_read_start(exch, stat, sizeof(struct stat));
[415c7e0d]699 if (rc != EOK) {
[79ae36dd]700 vfs_exchange_end(exch);
[415c7e0d]701 free(pa);
[a28ab12]702 async_wait_for(req, &rc_orig);
[6afc9d7]703 if (rc_orig != EOK)
704 rc = rc_orig;
705 if (rc != EOK) {
706 errno = rc;
707 return -1;
708 }
[415c7e0d]709 }
[79ae36dd]710 vfs_exchange_end(exch);
[415c7e0d]711 free(pa);
[a28ab12]712 async_wait_for(req, &rc);
[6afc9d7]713 if (rc != EOK) {
714 errno = rc;
715 return -1;
716 }
717 return 0;
[415c7e0d]718}
719
[6afc9d7]720/** Open directory.
721 *
722 * @param dirname Directory pathname
723 *
724 * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
725 */
[d0dc74ae]726DIR *opendir(const char *dirname)
727{
728 DIR *dirp = malloc(sizeof(DIR));
[6afc9d7]729 int fd = -1;
730
731 if (dirp == NULL) {
732 errno = ENOMEM;
[d0dc74ae]733 return NULL;
[6afc9d7]734 }
[2b88074b]735
736 size_t abs_size;
[6afc9d7]737 char *abs = vfs_absolutize(dirname, &abs_size);
738 if (abs == NULL) {
[2b88074b]739 free(dirp);
[6afc9d7]740 errno = ENOMEM;
[ed903174]741 return NULL;
[2b88074b]742 }
743
[6afc9d7]744 int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd);
[2b88074b]745 free(abs);
746
[6afc9d7]747 if (rc != EOK) {
[d0dc74ae]748 free(dirp);
[6afc9d7]749 errno = rc;
[d0dc74ae]750 return NULL;
751 }
[2b88074b]752
[6afc9d7]753 dirp->fd = fd;
[d0dc74ae]754 return dirp;
755}
756
[6afc9d7]757/** Read directory entry.
758 *
759 * @param dirp Open directory
760 * @return Non-NULL pointer to directory entry on success. On error returns
761 * @c NULL and sets errno.
762 */
[d0dc74ae]763struct dirent *readdir(DIR *dirp)
764{
[6afc9d7]765 int rc;
766 ssize_t len;
767
768 rc = _read_short(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1, &len);
769 if (rc != EOK) {
770 errno = rc;
[5973fd0]771 return NULL;
[6afc9d7]772 }
773
774 (void) len;
[5973fd0]775 return &dirp->res;
[d0dc74ae]776}
777
[6afc9d7]778/** Rewind directory position to the beginning.
779 *
780 * @param dirp Open directory
781 */
[d0dc74ae]782void rewinddir(DIR *dirp)
783{
[5973fd0]784 (void) lseek(dirp->fd, 0, SEEK_SET);
[d0dc74ae]785}
786
[6afc9d7]787/** Close directory.
788 *
789 * @param dirp Open directory
790 * @return 0 on success. On error returns -1 and sets errno.
791 */
[d0dc74ae]792int closedir(DIR *dirp)
793{
[6afc9d7]794 int rc;
795
796 rc = close(dirp->fd);
[d0dc74ae]797 free(dirp);
[6afc9d7]798
799 /* On error errno was set by close() */
800 return rc;
[d0dc74ae]801}
802
[6afc9d7]803/** Create directory.
804 *
805 * @param path Path
806 * @param mode File mode
807 * @return 0 on success. On error returns -1 and sets errno.
808 */
[72bde81]809int mkdir(const char *path, mode_t mode)
[d0dc74ae]810{
[96b02eb9]811 sysarg_t rc;
[72bde81]812 aid_t req;
813
[9eb3623]814 size_t pa_size;
[6afc9d7]815 char *pa = vfs_absolutize(path, &pa_size);
816 if (pa == NULL) {
817 errno = ENOMEM;
818 return -1;
819 }
[19b28b0]820
[79ae36dd]821 async_exch_t *exch = vfs_exchange_begin();
[19b28b0]822
[79ae36dd]823 req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
824 rc = async_data_write_start(exch, pa, pa_size);
[72bde81]825 if (rc != EOK) {
[79ae36dd]826 vfs_exchange_end(exch);
[a28ab12]827 free(pa);
[6afc9d7]828
[96b02eb9]829 sysarg_t rc_orig;
[3734106]830 async_wait_for(req, &rc_orig);
[6afc9d7]831
832 if (rc_orig != EOK)
833 rc = rc_orig;
834
835 if (rc != EOK) {
836 errno = rc;
837 return -1;
838 }
839
840 return 0;
[72bde81]841 }
[6afc9d7]842
[79ae36dd]843 vfs_exchange_end(exch);
[5fec355]844 free(pa);
[a28ab12]845 async_wait_for(req, &rc);
[6afc9d7]846
847 if (rc != EOK) {
848 errno = rc;
849 return -1;
850 }
851
852 return 0;
[d0dc74ae]853}
854
[6afc9d7]855/** Unlink a file or directory.
856 *
857 * @param path Path to file or empty directory
858 * @param lflag L_xxx flag (L_NONE, L_FILE or L_DIRECTORY)
859 * @return EOK on success, non-zero error code on error
860 */
[f15cf1a6]861static int _unlink(const char *path, int lflag)
862{
[96b02eb9]863 sysarg_t rc;
[f15cf1a6]864 aid_t req;
865
[9eb3623]866 size_t pa_size;
[6afc9d7]867 char *pa = vfs_absolutize(path, &pa_size);
868 if (pa == NULL)
[5fec355]869 return ENOMEM;
[19b28b0]870
[79ae36dd]871 async_exch_t *exch = vfs_exchange_begin();
872
[9ea7d90]873 req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL);
[79ae36dd]874 rc = async_data_write_start(exch, pa, pa_size);
[f15cf1a6]875 if (rc != EOK) {
[79ae36dd]876 vfs_exchange_end(exch);
[a28ab12]877 free(pa);
[3734106]878
[a28ab12]879 sysarg_t rc_orig;
[3734106]880 async_wait_for(req, &rc_orig);
[a28ab12]881
[3734106]882 if (rc_orig == EOK)
883 return (int) rc;
884 else
885 return (int) rc_orig;
[f15cf1a6]886 }
[79ae36dd]887 vfs_exchange_end(exch);
[5fec355]888 free(pa);
[a28ab12]889 async_wait_for(req, &rc);
[2595dab]890 return rc;
[f15cf1a6]891}
892
[6afc9d7]893/** Unlink file or directory.
894 *
895 * @param path Path
896 * @return EOk on success, error code on error
897 */
[f15cf1a6]898int unlink(const char *path)
899{
[6afc9d7]900 int rc;
901
902 rc = _unlink(path, L_NONE);
903 if (rc != EOK) {
904 errno = rc;
905 return -1;
906 }
907
908 return 0;
[f15cf1a6]909}
910
[6afc9d7]911/** Remove empty directory.
912 *
913 * @param path Path
914 * @return 0 on success. On error returns -1 and sets errno.
915 */
[f15cf1a6]916int rmdir(const char *path)
917{
[6afc9d7]918 int rc;
919
920 rc = _unlink(path, L_DIRECTORY);
921 if (rc != EOK) {
922 errno = rc;
923 return -1;
924 }
925
926 return 0;
[f15cf1a6]927}
928
[6afc9d7]929/** Rename directory entry.
930 *
931 * @param old Old name
932 * @param new New name
933 *
934 * @return 0 on success. On error returns -1 and sets errno.
935 */
[a8e9ab8d]936int rename(const char *old, const char *new)
937{
[96b02eb9]938 sysarg_t rc;
939 sysarg_t rc_orig;
[a8e9ab8d]940 aid_t req;
941
[9eb3623]942 size_t olda_size;
[6afc9d7]943 char *olda = vfs_absolutize(old, &olda_size);
944 if (olda == NULL) {
945 errno = ENOMEM;
946 return -1;
947 }
[923c39e]948
[9eb3623]949 size_t newa_size;
[6afc9d7]950 char *newa = vfs_absolutize(new, &newa_size);
951 if (newa == NULL) {
[a8e9ab8d]952 free(olda);
[6afc9d7]953 errno = ENOMEM;
954 return -1;
[a8e9ab8d]955 }
[19b28b0]956
[79ae36dd]957 async_exch_t *exch = vfs_exchange_begin();
958
959 req = async_send_0(exch, VFS_IN_RENAME, NULL);
960 rc = async_data_write_start(exch, olda, olda_size);
[a8e9ab8d]961 if (rc != EOK) {
[79ae36dd]962 vfs_exchange_end(exch);
[a8e9ab8d]963 free(olda);
964 free(newa);
[a28ab12]965 async_wait_for(req, &rc_orig);
[6afc9d7]966 if (rc_orig != EOK)
967 rc = rc_orig;
968 if (rc != EOK) {
969 errno = rc;
970 return -1;
971 }
972 return 0;
[a8e9ab8d]973 }
[79ae36dd]974 rc = async_data_write_start(exch, newa, newa_size);
[a8e9ab8d]975 if (rc != EOK) {
[79ae36dd]976 vfs_exchange_end(exch);
[a8e9ab8d]977 free(olda);
978 free(newa);
[a28ab12]979 async_wait_for(req, &rc_orig);
[6afc9d7]980 if (rc_orig != EOK)
981 rc = rc_orig;
982 if (rc != EOK) {
983 errno = rc;
984 return -1;
985 }
986 return 0;
[a8e9ab8d]987 }
[79ae36dd]988 vfs_exchange_end(exch);
[a8e9ab8d]989 free(olda);
990 free(newa);
[a28ab12]991 async_wait_for(req, &rc);
[6afc9d7]992
993 if (rc != EOK) {
994 errno = rc;
995 return -1;
996 }
997
998 return 0;
[a8e9ab8d]999}
1000
[6afc9d7]1001/** Remove directory entry.
1002 *
1003 * @param path Path
1004 * @return 0 on success. On error returns -1 and sets errno.
1005 */
[38db6288]1006int remove(const char *path)
1007{
1008 return unlink(path);
1009}
1010
[6afc9d7]1011/** Change working directory.
1012 *
1013 * @param path Path
1014 * @return 0 on success. On error returns -1 and sets errno.
1015 */
[5fec355]1016int chdir(const char *path)
1017{
[2b88074b]1018 size_t abs_size;
[6afc9d7]1019 char *abs = vfs_absolutize(path, &abs_size);
1020 int fd = -1;
1021
1022 if (abs == NULL) {
1023 errno = ENOMEM;
1024 return -1;
1025 }
[2b88074b]1026
[6afc9d7]1027 int rc = open_internal(abs, abs_size, L_DIRECTORY, O_DESC, &fd);
[2b88074b]1028
[6afc9d7]1029 if (rc != EOK) {
[2b88074b]1030 free(abs);
[6afc9d7]1031 errno = rc;
1032 return -1;
[5fec355]1033 }
[2b88074b]1034
[a28ab12]1035 fibril_mutex_lock(&cwd_mutex);
[2b88074b]1036
1037 if (cwd_fd >= 0)
1038 close(cwd_fd);
1039
1040 if (cwd_path)
1041 free(cwd_path);
1042
1043 cwd_fd = fd;
1044 cwd_path = abs;
1045 cwd_size = abs_size;
1046
[a28ab12]1047 fibril_mutex_unlock(&cwd_mutex);
[6afc9d7]1048 return 0;
[5fec355]1049}
1050
[6afc9d7]1051/** Get current working directory path.
1052 *
1053 * @param buf Buffer
1054 * @param size Size of @a buf
1055 * @return On success returns @a buf. On failure returns @c NULL and sets errno.
1056 */
[5fec355]1057char *getcwd(char *buf, size_t size)
1058{
[6afc9d7]1059 if (size == 0) {
1060 errno = EINVAL;
[5fec355]1061 return NULL;
[6afc9d7]1062 }
[2b88074b]1063
[a28ab12]1064 fibril_mutex_lock(&cwd_mutex);
[2b88074b]1065
1066 if ((cwd_size == 0) || (size < cwd_size + 1)) {
[a28ab12]1067 fibril_mutex_unlock(&cwd_mutex);
[6afc9d7]1068 errno = ERANGE;
[5fec355]1069 return NULL;
1070 }
[2b88074b]1071
[6eb2e96]1072 str_cpy(buf, size, cwd_path);
[a28ab12]1073 fibril_mutex_unlock(&cwd_mutex);
[2b88074b]1074
[5fec355]1075 return buf;
1076}
1077
[6afc9d7]1078/** Open session to service represented by a special file.
1079 *
1080 * Given that the file referred to by @a fildes represents a service,
1081 * open a session to that service.
1082 *
1083 * @param fildes File descriptor
1084 * @param iface Interface to connect to (XXX Should be automatic)
1085 * @return On success returns session pointer. On error returns @c NULL.
1086 */
1087async_sess_t *vfs_fd_session(int fildes, iface_t iface)
[852b801]1088{
1089 struct stat stat;
[8caaea7]1090 int rc = fstat(fildes, &stat);
[6afc9d7]1091 if (rc != 0)
[79ae36dd]1092 return NULL;
[8caaea7]1093
[6afc9d7]1094 if (stat.service == 0)
[79ae36dd]1095 return NULL;
[852b801]1096
[f9b2cb4c]1097 return loc_service_connect(stat.service, iface, 0);
[852b801]1098}
1099
[6afc9d7]1100/** Duplicate open file.
1101 *
1102 * Duplicate open file under a new file descriptor.
1103 *
1104 * @param oldfd Old file descriptor
1105 * @param newfd New file descriptor
1106 * @return 0 on success. On error -1 is returned and errno is set
1107 */
[2b88074b]1108int dup2(int oldfd, int newfd)
[852b801]1109{
[79ae36dd]1110 async_exch_t *exch = vfs_exchange_begin();
[852b801]1111
[96b02eb9]1112 sysarg_t ret;
[79ae36dd]1113 sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret);
[852b801]1114
[79ae36dd]1115 vfs_exchange_end(exch);
[2b88074b]1116
1117 if (rc == EOK)
[6afc9d7]1118 rc = ret;
[2b88074b]1119
[6afc9d7]1120 if (rc != EOK) {
1121 errno = rc;
1122 return -1;
1123 }
1124
1125 return 0;
[852b801]1126}
1127
[6afc9d7]1128int vfs_fd_wait(void)
[2b88074b]1129{
[79ae36dd]1130 async_exch_t *exch = vfs_exchange_begin();
[2b88074b]1131
[96b02eb9]1132 sysarg_t ret;
[27b76ca]1133 sysarg_t rc = async_req_0_1(exch, VFS_IN_WAIT_HANDLE, &ret);
[2b88074b]1134
[79ae36dd]1135 vfs_exchange_end(exch);
[2b88074b]1136
1137 if (rc == EOK)
1138 return (int) ret;
1139
1140 return (int) rc;
1141}
1142
[6afc9d7]1143int vfs_get_mtab_list(list_t *mtab_list)
[10e4cd7]1144{
1145 sysarg_t rc;
[4965357f]1146 aid_t req;
[10e4cd7]1147 size_t i;
[4965357f]1148 sysarg_t num_mounted_fs;
[10e4cd7]1149
1150 async_exch_t *exch = vfs_exchange_begin();
1151
[41e9ef7]1152 req = async_send_0(exch, VFS_IN_MTAB_GET, NULL);
[10e4cd7]1153
1154 /* Ask VFS how many filesystems are mounted */
1155 rc = async_req_0_1(exch, VFS_IN_PING, &num_mounted_fs);
1156 if (rc != EOK)
1157 goto exit;
1158
1159 for (i = 0; i < num_mounted_fs; ++i) {
1160 mtab_ent_t *mtab_ent;
1161
[8d6a41c]1162 mtab_ent = malloc(sizeof(mtab_ent_t));
[6afc9d7]1163 if (mtab_ent == NULL) {
[10e4cd7]1164 rc = ENOMEM;
1165 goto exit;
1166 }
1167
[8d6a41c]1168 memset(mtab_ent, 0, sizeof(mtab_ent_t));
[10e4cd7]1169
[4965357f]1170 rc = async_data_read_start(exch, (void *) mtab_ent->mp,
[10e4cd7]1171 MAX_PATH_LEN);
1172 if (rc != EOK)
1173 goto exit;
1174
[4965357f]1175 rc = async_data_read_start(exch, (void *) mtab_ent->opts,
[10e4cd7]1176 MAX_MNTOPTS_LEN);
1177 if (rc != EOK)
1178 goto exit;
1179
[4965357f]1180 rc = async_data_read_start(exch, (void *) mtab_ent->fs_name,
[10e4cd7]1181 FS_NAME_MAXLEN);
1182 if (rc != EOK)
1183 goto exit;
1184
[6b8e5b74]1185 sysarg_t p[2];
[10e4cd7]1186
[6b8e5b74]1187 rc = async_req_0_2(exch, VFS_IN_PING, &p[0], &p[1]);
[f8838b8]1188 if (rc != EOK)
1189 goto exit;
[10e4cd7]1190
[6b8e5b74]1191 mtab_ent->instance = p[0];
1192 mtab_ent->service_id = p[1];
[10e4cd7]1193
[8d6a41c]1194 link_initialize(&mtab_ent->link);
1195 list_append(&mtab_ent->link, mtab_list);
[10e4cd7]1196 }
1197
1198exit:
[4965357f]1199 async_wait_for(req, &rc);
[10e4cd7]1200 vfs_exchange_end(exch);
1201 return rc;
1202}
1203
[6afc9d7]1204/** Get filesystem statistics.
1205 *
1206 * @param path Mount point path
1207 * @param st Buffer for storing information
1208 * @return 0 on success. On error -1 is returned and errno is set.
1209 */
[73fbcbb]1210int statfs(const char *path, struct statfs *st)
[66366470]1211{
[73fbcbb]1212 sysarg_t rc, rc_orig;
[9dc6083]1213 aid_t req;
1214 size_t pa_size;
[73fbcbb]1215
[6afc9d7]1216 char *pa = vfs_absolutize(path, &pa_size);
1217 if (pa == NULL) {
1218 errno = ENOMEM;
1219 return -1;
1220 }
[73fbcbb]1221
[9dc6083]1222 async_exch_t *exch = vfs_exchange_begin();
[73fbcbb]1223
[9dc6083]1224 req = async_send_0(exch, VFS_IN_STATFS, NULL);
1225 rc = async_data_write_start(exch, pa, pa_size);
[73fbcbb]1226 if (rc != EOK)
1227 goto exit;
1228
1229 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
1230
1231exit:
[66366470]1232 vfs_exchange_end(exch);
[9dc6083]1233 free(pa);
[73fbcbb]1234 async_wait_for(req, &rc_orig);
[6afc9d7]1235 rc = (rc_orig != EOK ? rc_orig : rc);
1236
1237 if (rc != EOK) {
1238 errno = rc;
1239 return -1;
1240 }
1241
1242 return 0;
[66366470]1243}
1244
[2f02aa17]1245/** @}
1246 */
Note: See TracBrowser for help on using the repository browser.