source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 163fc09

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

Rename rename() to vfs_rename_path()

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