source: mainline/uspace/srv/vfs/vfs_ops.c@ f86c184

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f86c184 was 6c89f20, checked in by Martin Decky <martin@…>, 17 years ago

disable extensive debugging output

  • Property mode set to 100644
File size: 21.6 KB
RevLine 
[861e7d1]1/*
2 * Copyright (c) 2008 Jakub Jermar
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 fs
30 * @{
31 */
32
33/**
34 * @file vfs_ops.c
35 * @brief Operations that VFS offers to its clients.
36 */
37
[a8e9ab8d]38#include "vfs.h"
[861e7d1]39#include <ipc/ipc.h>
40#include <async.h>
41#include <errno.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <bool.h>
46#include <futex.h>
47#include <rwlock.h>
48#include <libadt/list.h>
49#include <unistd.h>
50#include <ctype.h>
[2db4ac8]51#include <fcntl.h>
[861e7d1]52#include <assert.h>
[a8e9ab8d]53#include <vfs/canonify.h>
[861e7d1]54
[7fe1f75]55/* Forward declarations of static functions. */
[f2ec8c8]56static int vfs_truncate_internal(fs_handle_t, dev_handle_t, fs_index_t, size_t);
[7fe1f75]57
[861e7d1]58/**
59 * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
60 * concurrent VFS operation which modifies the file system namespace.
61 */
62RWLOCK_INITIALIZE(namespace_rwlock);
63
[c31d773]64futex_t rootfs_futex = FUTEX_INITIALIZER;
[861e7d1]65vfs_triplet_t rootfs = {
66 .fs_handle = 0,
67 .dev_handle = 0,
68 .index = 0,
69};
70
[f2ec8c8]71static int
72lookup_root(fs_handle_t fs_handle, dev_handle_t dev_handle,
73 vfs_lookup_res_t *result)
[861e7d1]74{
75 vfs_pair_t altroot = {
76 .fs_handle = fs_handle,
77 .dev_handle = dev_handle,
78 };
79
[d6084ef]80 return vfs_lookup_internal("/", L_DIRECTORY, result, &altroot);
[861e7d1]81}
82
83void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
84{
[f2ec8c8]85 dev_handle_t dev_handle;
[861e7d1]86 vfs_node_t *mp_node = NULL;
[ce7311fc]87 int rc;
[64b67c3]88 int phone;
[861e7d1]89
90 /*
91 * We expect the library to do the device-name to device-handle
92 * translation for us, thus the device handle will arrive as ARG1
93 * in the request.
94 */
[f2ec8c8]95 dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
[861e7d1]96
97 /*
98 * For now, don't make use of ARG2 and ARG3, but they can be used to
99 * carry mount options in the future.
100 */
101
102 ipc_callid_t callid;
103 size_t size;
104
105 /*
106 * Now, we expect the client to send us data with the name of the file
107 * system.
108 */
109 if (!ipc_data_write_receive(&callid, &size)) {
110 ipc_answer_0(callid, EINVAL);
111 ipc_answer_0(rid, EINVAL);
112 return;
113 }
114
115 /*
116 * Don't receive more than is necessary for storing a full file system
117 * name.
118 */
119 if (size < 1 || size > FS_NAME_MAXLEN) {
120 ipc_answer_0(callid, EINVAL);
121 ipc_answer_0(rid, EINVAL);
122 return;
123 }
124
[72bde81]125 /* Deliver the file system name. */
[861e7d1]126 char fs_name[FS_NAME_MAXLEN + 1];
127 (void) ipc_data_write_finalize(callid, fs_name, size);
128 fs_name[size] = '\0';
129
130 /*
131 * Check if we know a file system with the same name as is in fs_name.
132 * This will also give us its file system handle.
133 */
[f2ec8c8]134 fs_handle_t fs_handle = fs_name_to_handle(fs_name, true);
[861e7d1]135 if (!fs_handle) {
136 ipc_answer_0(rid, ENOENT);
137 return;
138 }
139
[72bde81]140 /* Now, we want the client to send us the mount point. */
[861e7d1]141 if (!ipc_data_write_receive(&callid, &size)) {
142 ipc_answer_0(callid, EINVAL);
143 ipc_answer_0(rid, EINVAL);
144 return;
145 }
146
[72bde81]147 /* Check whether size is reasonable wrt. the mount point. */
[861e7d1]148 if (size < 1 || size > MAX_PATH_LEN) {
149 ipc_answer_0(callid, EINVAL);
150 ipc_answer_0(rid, EINVAL);
151 return;
152 }
[72bde81]153 /* Allocate buffer for the mount point data being received. */
[861e7d1]154 uint8_t *buf;
[d6084ef]155 buf = malloc(size + 1);
[861e7d1]156 if (!buf) {
157 ipc_answer_0(callid, ENOMEM);
158 ipc_answer_0(rid, ENOMEM);
159 return;
160 }
161
[72bde81]162 /* Deliver the mount point. */
[861e7d1]163 (void) ipc_data_write_finalize(callid, buf, size);
[d6084ef]164 buf[size] = '\0';
[861e7d1]165
166 /*
167 * Lookup the root node of the filesystem being mounted.
168 * In this case, we don't need to take the namespace_futex as the root
169 * node cannot be removed. However, we do take a reference to it so
170 * that we can track how many times it has been mounted.
171 */
[eb27ce5a]172 vfs_lookup_res_t mr_res;
173 rc = lookup_root(fs_handle, dev_handle, &mr_res);
[861e7d1]174 if (rc != EOK) {
175 free(buf);
176 ipc_answer_0(rid, rc);
177 return;
178 }
[eb27ce5a]179 vfs_node_t *mr_node = vfs_node_get(&mr_res);
[861e7d1]180 if (!mr_node) {
181 free(buf);
182 ipc_answer_0(rid, ENOMEM);
183 return;
184 }
185
[72bde81]186 /* Finally, we need to resolve the path to the mountpoint. */
[eb27ce5a]187 vfs_lookup_res_t mp_res;
[861e7d1]188 futex_down(&rootfs_futex);
189 if (rootfs.fs_handle) {
[72bde81]190 /* We already have the root FS. */
[861e7d1]191 rwlock_write_lock(&namespace_rwlock);
[2f60a529]192 if ((size == 1) && (buf[0] == '/')) {
193 /* Trying to mount root FS over root FS */
194 rwlock_write_unlock(&namespace_rwlock);
195 futex_up(&rootfs_futex);
196 vfs_node_put(mr_node);
197 free(buf);
198 ipc_answer_0(rid, EBUSY);
199 return;
200 }
[d6084ef]201 rc = vfs_lookup_internal(buf, L_DIRECTORY, &mp_res, NULL);
[861e7d1]202 if (rc != EOK) {
[72bde81]203 /* The lookup failed for some reason. */
[861e7d1]204 rwlock_write_unlock(&namespace_rwlock);
205 futex_up(&rootfs_futex);
206 vfs_node_put(mr_node); /* failed -> drop reference */
207 free(buf);
208 ipc_answer_0(rid, rc);
209 return;
210 }
[eb27ce5a]211 mp_node = vfs_node_get(&mp_res);
[861e7d1]212 if (!mp_node) {
213 rwlock_write_unlock(&namespace_rwlock);
214 futex_up(&rootfs_futex);
215 vfs_node_put(mr_node); /* failed -> drop reference */
216 free(buf);
217 ipc_answer_0(rid, ENOMEM);
218 return;
219 }
220 /*
221 * Now we hold a reference to mp_node.
222 * It will be dropped upon the corresponding VFS_UNMOUNT.
223 * This prevents the mount point from being deleted.
224 */
225 rwlock_write_unlock(&namespace_rwlock);
226 } else {
[72bde81]227 /* We still don't have the root file system mounted. */
[861e7d1]228 if ((size == 1) && (buf[0] == '/')) {
[64b67c3]229 /*
230 * For this simple, but important case,
231 * we are almost done.
232 */
[861e7d1]233 free(buf);
[64b67c3]234
235 /* Inform the mount point about the root mount. */
236 phone = vfs_grab_phone(mr_res.triplet.fs_handle);
237 rc = async_req_5_0(phone, VFS_MOUNT,
238 (ipcarg_t) mr_res.triplet.dev_handle,
239 (ipcarg_t) mr_res.triplet.index,
240 (ipcarg_t) mr_res.triplet.fs_handle,
241 (ipcarg_t) mr_res.triplet.dev_handle,
242 (ipcarg_t) mr_res.triplet.index);
243 vfs_release_phone(phone);
244
245 if (rc == EOK)
246 rootfs = mr_res.triplet;
247 else
248 vfs_node_put(mr_node);
249
250 futex_up(&rootfs_futex);
251 ipc_answer_0(rid, rc);
[861e7d1]252 return;
253 } else {
254 /*
255 * We can't resolve this without the root filesystem
256 * being mounted first.
257 */
258 futex_up(&rootfs_futex);
259 free(buf);
260 vfs_node_put(mr_node); /* failed -> drop reference */
261 ipc_answer_0(rid, ENOENT);
262 return;
263 }
264 }
265 futex_up(&rootfs_futex);
266
267 free(buf); /* The buffer is not needed anymore. */
268
269 /*
270 * At this point, we have all necessary pieces: file system and device
271 * handles, and we know the mount point VFS node and also the root node
272 * of the file system being mounted.
273 */
274
[ce7311fc]275 /**
276 * @todo
277 * Add more IPC parameters so that we can send mount mode/flags.
278 */
[64b67c3]279 phone = vfs_grab_phone(mp_res.triplet.fs_handle);
[ce7311fc]280 rc = async_req_5_0(phone, VFS_MOUNT,
[eb27ce5a]281 (ipcarg_t) mp_res.triplet.dev_handle,
[ce7311fc]282 (ipcarg_t) mp_res.triplet.index,
[eb27ce5a]283 (ipcarg_t) mr_res.triplet.fs_handle,
284 (ipcarg_t) mr_res.triplet.dev_handle,
[ce7311fc]285 (ipcarg_t) mr_res.triplet.index);
[861e7d1]286 vfs_release_phone(phone);
287
[ce7311fc]288 if (rc != EOK) {
[861e7d1]289 /* Mount failed, drop references to mr_node and mp_node. */
290 vfs_node_put(mr_node);
291 if (mp_node)
292 vfs_node_put(mp_node);
293 }
294
[ce7311fc]295 ipc_answer_0(rid, rc);
[861e7d1]296}
297
298void vfs_open(ipc_callid_t rid, ipc_call_t *request)
299{
300 if (!vfs_files_init()) {
301 ipc_answer_0(rid, ENOMEM);
302 return;
303 }
304
305 /*
[ae78b530]306 * The POSIX interface is open(path, oflag, mode).
307 * We can receive oflags and mode along with the VFS_OPEN call; the path
[861e7d1]308 * will need to arrive in another call.
[ae78b530]309 *
310 * We also receive one private, non-POSIX set of flags called lflag
311 * used to pass information to vfs_lookup_internal().
[861e7d1]312 */
[ae78b530]313 int lflag = IPC_GET_ARG1(*request);
314 int oflag = IPC_GET_ARG2(*request);
315 int mode = IPC_GET_ARG3(*request);
[861e7d1]316 size_t len;
317
[2db4ac8]318 if (oflag & O_CREAT)
319 lflag |= L_CREATE;
320 if (oflag & O_EXCL)
321 lflag |= L_EXCLUSIVE;
322
[861e7d1]323 ipc_callid_t callid;
324
325 if (!ipc_data_write_receive(&callid, &len)) {
326 ipc_answer_0(callid, EINVAL);
327 ipc_answer_0(rid, EINVAL);
328 return;
329 }
[d6084ef]330 char *path = malloc(len + 1);
[861e7d1]331 if (!path) {
332 ipc_answer_0(callid, ENOMEM);
333 ipc_answer_0(rid, ENOMEM);
334 return;
335 }
336 int rc;
337 if ((rc = ipc_data_write_finalize(callid, path, len))) {
338 ipc_answer_0(rid, rc);
339 free(path);
340 return;
341 }
[d6084ef]342 path[len] = '\0';
[861e7d1]343
344 /*
345 * Avoid the race condition in which the file can be deleted before we
346 * find/create-and-lock the VFS node corresponding to the looked-up
347 * triplet.
348 */
[2db4ac8]349 if (lflag & L_CREATE)
350 rwlock_write_lock(&namespace_rwlock);
351 else
352 rwlock_read_lock(&namespace_rwlock);
[861e7d1]353
[72bde81]354 /* The path is now populated and we can call vfs_lookup_internal(). */
[eb27ce5a]355 vfs_lookup_res_t lr;
[d6084ef]356 rc = vfs_lookup_internal(path, lflag, &lr, NULL);
[861e7d1]357 if (rc) {
[2db4ac8]358 if (lflag & L_CREATE)
359 rwlock_write_unlock(&namespace_rwlock);
360 else
361 rwlock_read_unlock(&namespace_rwlock);
[861e7d1]362 ipc_answer_0(rid, rc);
363 free(path);
364 return;
365 }
366
[7fe1f75]367 /* Path is no longer needed. */
[861e7d1]368 free(path);
369
[eb27ce5a]370 vfs_node_t *node = vfs_node_get(&lr);
[2db4ac8]371 if (lflag & L_CREATE)
372 rwlock_write_unlock(&namespace_rwlock);
373 else
374 rwlock_read_unlock(&namespace_rwlock);
[861e7d1]375
[7fe1f75]376 /* Truncate the file if requested and if necessary. */
377 if (oflag & O_TRUNC) {
[ee68e4bc]378 rwlock_write_lock(&node->contents_rwlock);
[7fe1f75]379 if (node->size) {
380 rc = vfs_truncate_internal(node->fs_handle,
381 node->dev_handle, node->index, 0);
382 if (rc) {
[ee68e4bc]383 rwlock_write_unlock(&node->contents_rwlock);
[7fe1f75]384 vfs_node_put(node);
385 ipc_answer_0(rid, rc);
386 return;
387 }
388 node->size = 0;
389 }
[ee68e4bc]390 rwlock_write_unlock(&node->contents_rwlock);
[7fe1f75]391 }
392
[861e7d1]393 /*
394 * Get ourselves a file descriptor and the corresponding vfs_file_t
395 * structure.
396 */
397 int fd = vfs_fd_alloc();
398 if (fd < 0) {
399 vfs_node_put(node);
400 ipc_answer_0(rid, fd);
401 return;
402 }
403 vfs_file_t *file = vfs_file_get(fd);
404 file->node = node;
[f7017572]405 if (oflag & O_APPEND)
[15b9970]406 file->append = true;
[861e7d1]407
408 /*
409 * The following increase in reference count is for the fact that the
410 * file is being opened and that a file structure is pointing to it.
411 * It is necessary so that the file will not disappear when
412 * vfs_node_put() is called. The reference will be dropped by the
413 * respective VFS_CLOSE.
414 */
415 vfs_node_addref(node);
416 vfs_node_put(node);
417
[72bde81]418 /* Success! Return the new file descriptor to the client. */
[861e7d1]419 ipc_answer_1(rid, EOK, fd);
420}
421
[e704503]422void vfs_close(ipc_callid_t rid, ipc_call_t *request)
423{
424 int fd = IPC_GET_ARG1(*request);
425 if (fd >= MAX_OPEN_FILES) {
426 ipc_answer_0(rid, EBADF);
427 return;
428 }
429 vfs_fd_free(fd);
430 ipc_answer_0(rid, EOK);
431}
432
[861e7d1]433static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
434{
435
436 /*
437 * The following code strongly depends on the fact that the files data
438 * structure can be only accessed by a single fibril and all file
439 * operations are serialized (i.e. the reads and writes cannot
440 * interleave and a file cannot be closed while it is being read).
441 *
442 * Additional synchronization needs to be added once the table of
443 * open files supports parallel access!
444 */
445
446 int fd = IPC_GET_ARG1(*request);
[6c89f20]447
[72bde81]448 /* Lookup the file structure corresponding to the file descriptor. */
[861e7d1]449 vfs_file_t *file = vfs_file_get(fd);
450 if (!file) {
451 ipc_answer_0(rid, ENOENT);
452 return;
453 }
[6c89f20]454
[861e7d1]455 /*
456 * Now we need to receive a call with client's
457 * IPC_M_DATA_READ/IPC_M_DATA_WRITE request.
458 */
459 ipc_callid_t callid;
460 int res;
461 if (read)
462 res = ipc_data_read_receive(&callid, NULL);
463 else
464 res = ipc_data_write_receive(&callid, NULL);
465 if (!res) {
466 ipc_answer_0(callid, EINVAL);
467 ipc_answer_0(rid, EINVAL);
468 return;
469 }
[6c89f20]470
[861e7d1]471 /*
472 * Lock the open file structure so that no other thread can manipulate
473 * the same open file at a time.
474 */
475 futex_down(&file->lock);
[6c89f20]476
[861e7d1]477 /*
478 * Lock the file's node so that no other client can read/write to it at
479 * the same time.
480 */
481 if (read)
482 rwlock_read_lock(&file->node->contents_rwlock);
483 else
484 rwlock_write_lock(&file->node->contents_rwlock);
[6c89f20]485
[861e7d1]486 int fs_phone = vfs_grab_phone(file->node->fs_handle);
487
[72bde81]488 /* Make a VFS_READ/VFS_WRITE request at the destination FS server. */
[861e7d1]489 aid_t msg;
490 ipc_call_t answer;
[15b9970]491 if (!read && file->append)
492 file->pos = file->node->size;
[861e7d1]493 msg = async_send_3(fs_phone, IPC_GET_METHOD(*request),
494 file->node->dev_handle, file->node->index, file->pos, &answer);
495
496 /*
497 * Forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
498 * destination FS server. The call will be routed as if sent by
499 * ourselves. Note that call arguments are immutable in this case so we
500 * don't have to bother.
501 */
502 ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
[6c89f20]503
[861e7d1]504 vfs_release_phone(fs_phone);
[6c89f20]505
[72bde81]506 /* Wait for reply from the FS server. */
[861e7d1]507 ipcarg_t rc;
508 async_wait_for(msg, &rc);
509 size_t bytes = IPC_GET_ARG1(answer);
[6c89f20]510
[72bde81]511 /* Unlock the VFS node. */
[861e7d1]512 if (read)
513 rwlock_read_unlock(&file->node->contents_rwlock);
514 else {
515 /* Update the cached version of node's size. */
[f7017572]516 if (rc == EOK)
517 file->node->size = IPC_GET_ARG2(answer);
[861e7d1]518 rwlock_write_unlock(&file->node->contents_rwlock);
519 }
[6c89f20]520
[72bde81]521 /* Update the position pointer and unlock the open file. */
[f7017572]522 if (rc == EOK)
523 file->pos += bytes;
[861e7d1]524 futex_up(&file->lock);
[6c89f20]525
[861e7d1]526 /*
527 * FS server's reply is the final result of the whole operation we
528 * return to the client.
529 */
530 ipc_answer_1(rid, rc, bytes);
531}
532
533void vfs_read(ipc_callid_t rid, ipc_call_t *request)
534{
535 vfs_rdwr(rid, request, true);
536}
537
538void vfs_write(ipc_callid_t rid, ipc_call_t *request)
539{
540 vfs_rdwr(rid, request, false);
541}
542
543void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
544{
545 int fd = (int) IPC_GET_ARG1(*request);
546 off_t off = (off_t) IPC_GET_ARG2(*request);
547 int whence = (int) IPC_GET_ARG3(*request);
548
549
[72bde81]550 /* Lookup the file structure corresponding to the file descriptor. */
[861e7d1]551 vfs_file_t *file = vfs_file_get(fd);
552 if (!file) {
553 ipc_answer_0(rid, ENOENT);
554 return;
555 }
556
557 off_t newpos;
558 futex_down(&file->lock);
559 if (whence == SEEK_SET) {
560 file->pos = off;
561 futex_up(&file->lock);
562 ipc_answer_1(rid, EOK, off);
563 return;
564 }
565 if (whence == SEEK_CUR) {
566 if (file->pos + off < file->pos) {
567 futex_up(&file->lock);
568 ipc_answer_0(rid, EOVERFLOW);
569 return;
570 }
571 file->pos += off;
572 newpos = file->pos;
573 futex_up(&file->lock);
574 ipc_answer_1(rid, EOK, newpos);
575 return;
576 }
577 if (whence == SEEK_END) {
578 rwlock_read_lock(&file->node->contents_rwlock);
579 size_t size = file->node->size;
580 rwlock_read_unlock(&file->node->contents_rwlock);
581 if (size + off < size) {
582 futex_up(&file->lock);
583 ipc_answer_0(rid, EOVERFLOW);
584 return;
585 }
586 newpos = size + off;
587 futex_up(&file->lock);
588 ipc_answer_1(rid, EOK, newpos);
589 return;
590 }
591 futex_up(&file->lock);
592 ipc_answer_0(rid, EINVAL);
593}
594
[f2ec8c8]595int
596vfs_truncate_internal(fs_handle_t fs_handle, dev_handle_t dev_handle,
597 fs_index_t index, size_t size)
[7fe1f75]598{
599 ipcarg_t rc;
600 int fs_phone;
601
602 fs_phone = vfs_grab_phone(fs_handle);
603 rc = async_req_3_0(fs_phone, VFS_TRUNCATE, (ipcarg_t)dev_handle,
604 (ipcarg_t)index, (ipcarg_t)size);
605 vfs_release_phone(fs_phone);
606 return (int)rc;
607}
608
[0ee4322]609void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
610{
611 int fd = IPC_GET_ARG1(*request);
612 size_t size = IPC_GET_ARG2(*request);
[7fe1f75]613 int rc;
[0ee4322]614
615 vfs_file_t *file = vfs_file_get(fd);
616 if (!file) {
617 ipc_answer_0(rid, ENOENT);
618 return;
619 }
620 futex_down(&file->lock);
621
622 rwlock_write_lock(&file->node->contents_rwlock);
[7fe1f75]623 rc = vfs_truncate_internal(file->node->fs_handle,
624 file->node->dev_handle, file->node->index, size);
[0ee4322]625 if (rc == EOK)
626 file->node->size = size;
627 rwlock_write_unlock(&file->node->contents_rwlock);
628
629 futex_up(&file->lock);
[7fe1f75]630 ipc_answer_0(rid, (ipcarg_t)rc);
[861e7d1]631}
632
[72bde81]633void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
634{
635 int mode = IPC_GET_ARG1(*request);
636
[f15cf1a6]637 size_t len;
[72bde81]638 ipc_callid_t callid;
639
640 if (!ipc_data_write_receive(&callid, &len)) {
641 ipc_answer_0(callid, EINVAL);
642 ipc_answer_0(rid, EINVAL);
643 return;
644 }
[d6084ef]645 char *path = malloc(len + 1);
[72bde81]646 if (!path) {
647 ipc_answer_0(callid, ENOMEM);
648 ipc_answer_0(rid, ENOMEM);
649 return;
650 }
651 int rc;
652 if ((rc = ipc_data_write_finalize(callid, path, len))) {
653 ipc_answer_0(rid, rc);
654 free(path);
655 return;
656 }
[d6084ef]657 path[len] = '\0';
[72bde81]658
659 rwlock_write_lock(&namespace_rwlock);
660 int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
[d6084ef]661 rc = vfs_lookup_internal(path, lflag, NULL, NULL);
[72bde81]662 rwlock_write_unlock(&namespace_rwlock);
663 free(path);
664 ipc_answer_0(rid, rc);
665}
666
[f15cf1a6]667void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
668{
669 int lflag = IPC_GET_ARG1(*request);
670
671 size_t len;
672 ipc_callid_t callid;
673
674 if (!ipc_data_write_receive(&callid, &len)) {
675 ipc_answer_0(callid, EINVAL);
676 ipc_answer_0(rid, EINVAL);
677 return;
678 }
[d6084ef]679 char *path = malloc(len + 1);
[f15cf1a6]680 if (!path) {
681 ipc_answer_0(callid, ENOMEM);
682 ipc_answer_0(rid, ENOMEM);
683 return;
684 }
685 int rc;
686 if ((rc = ipc_data_write_finalize(callid, path, len))) {
687 ipc_answer_0(rid, rc);
688 free(path);
689 return;
690 }
[d6084ef]691 path[len] = '\0';
[f15cf1a6]692
693 rwlock_write_lock(&namespace_rwlock);
694 lflag &= L_DIRECTORY; /* sanitize lflag */
695 vfs_lookup_res_t lr;
[a8e9ab8d]696 rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
[f15cf1a6]697 free(path);
698 if (rc != EOK) {
699 rwlock_write_unlock(&namespace_rwlock);
700 ipc_answer_0(rid, rc);
701 return;
702 }
703
704 /*
705 * The name has already been unlinked by vfs_lookup_internal().
706 * We have to get and put the VFS node to ensure that it is
[fdb7795]707 * VFS_DESTROY'ed after the last reference to it is dropped.
[f15cf1a6]708 */
709 vfs_node_t *node = vfs_node_get(&lr);
[c31d773]710 futex_down(&nodes_futex);
[f15cf1a6]711 node->lnkcnt--;
[c31d773]712 futex_up(&nodes_futex);
[f15cf1a6]713 rwlock_write_unlock(&namespace_rwlock);
714 vfs_node_put(node);
715 ipc_answer_0(rid, EOK);
716}
717
[a8e9ab8d]718void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
719{
720 size_t len;
721 ipc_callid_t callid;
722 int rc;
723
724 /* Retrieve the old path. */
725 if (!ipc_data_write_receive(&callid, &len)) {
726 ipc_answer_0(callid, EINVAL);
727 ipc_answer_0(rid, EINVAL);
728 return;
729 }
730 char *old = malloc(len + 1);
731 if (!old) {
732 ipc_answer_0(callid, ENOMEM);
733 ipc_answer_0(rid, ENOMEM);
734 return;
735 }
736 if ((rc = ipc_data_write_finalize(callid, old, len))) {
737 ipc_answer_0(rid, rc);
738 free(old);
739 return;
740 }
741 old[len] = '\0';
742
743 /* Retrieve the new path. */
744 if (!ipc_data_write_receive(&callid, &len)) {
745 ipc_answer_0(callid, EINVAL);
746 ipc_answer_0(rid, EINVAL);
747 free(old);
748 return;
749 }
750 char *new = malloc(len + 1);
751 if (!new) {
752 ipc_answer_0(callid, ENOMEM);
753 ipc_answer_0(rid, ENOMEM);
754 free(old);
755 return;
756 }
757 if ((rc = ipc_data_write_finalize(callid, new, len))) {
758 ipc_answer_0(rid, rc);
759 free(old);
760 free(new);
761 return;
762 }
763 new[len] = '\0';
764
765 char *oldc = canonify(old, &len);
766 char *newc = canonify(new, NULL);
767 if (!oldc || !newc) {
768 ipc_answer_0(rid, EINVAL);
769 free(old);
770 free(new);
771 return;
772 }
773 if (!strncmp(newc, oldc, len)) {
774 /* oldc is a prefix of newc */
775 ipc_answer_0(rid, EINVAL);
776 free(old);
777 free(new);
778 return;
779 }
780
781 vfs_lookup_res_t old_lr;
782 vfs_lookup_res_t new_lr;
783 vfs_lookup_res_t new_par_lr;
784 rwlock_write_lock(&namespace_rwlock);
785 /* Lookup the node belonging to the old file name. */
786 rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
787 if (rc != EOK) {
788 rwlock_write_unlock(&namespace_rwlock);
789 ipc_answer_0(rid, rc);
790 free(old);
791 free(new);
792 return;
793 }
794 vfs_node_t *old_node = vfs_node_get(&old_lr);
795 if (!old_node) {
796 rwlock_write_unlock(&namespace_rwlock);
797 ipc_answer_0(rid, ENOMEM);
798 free(old);
799 free(new);
800 return;
801 }
802 /* Lookup parent of the new file name. */
803 rc = vfs_lookup_internal(newc, L_PARENT, &new_par_lr, NULL);
804 if (rc != EOK) {
805 rwlock_write_unlock(&namespace_rwlock);
806 ipc_answer_0(rid, rc);
807 free(old);
808 free(new);
809 return;
810 }
811 /* Check whether linking to the same file system instance. */
812 if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
813 (old_node->dev_handle != new_par_lr.triplet.dev_handle)) {
814 rwlock_write_unlock(&namespace_rwlock);
815 ipc_answer_0(rid, EXDEV); /* different file systems */
816 free(old);
817 free(new);
818 return;
819 }
820 /* Destroy the old link for the new name. */
821 vfs_node_t *new_node = NULL;
822 rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
823 switch (rc) {
824 case ENOENT:
825 /* simply not in our way */
826 break;
827 case EOK:
828 new_node = vfs_node_get(&new_lr);
829 if (!new_node) {
830 rwlock_write_unlock(&namespace_rwlock);
831 ipc_answer_0(rid, ENOMEM);
832 free(old);
833 free(new);
834 return;
835 }
[c31d773]836 futex_down(&nodes_futex);
[a8e9ab8d]837 new_node->lnkcnt--;
[c31d773]838 futex_up(&nodes_futex);
[a8e9ab8d]839 break;
840 default:
841 rwlock_write_unlock(&namespace_rwlock);
842 ipc_answer_0(rid, ENOTEMPTY);
843 free(old);
844 free(new);
845 return;
846 }
847 /* Create the new link for the new name. */
848 rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
849 if (rc != EOK) {
850 rwlock_write_unlock(&namespace_rwlock);
851 if (new_node)
852 vfs_node_put(new_node);
853 ipc_answer_0(rid, rc);
854 free(old);
855 free(new);
856 return;
857 }
[c31d773]858 futex_down(&nodes_futex);
[a8e9ab8d]859 old_node->lnkcnt++;
[c31d773]860 futex_up(&nodes_futex);
[a8e9ab8d]861 /* Destroy the link for the old name. */
862 rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
863 if (rc != EOK) {
864 rwlock_write_unlock(&namespace_rwlock);
865 vfs_node_put(old_node);
866 if (new_node)
867 vfs_node_put(new_node);
868 ipc_answer_0(rid, rc);
869 free(old);
870 free(new);
871 return;
872 }
[c31d773]873 futex_down(&nodes_futex);
[a8e9ab8d]874 old_node->lnkcnt--;
[c31d773]875 futex_up(&nodes_futex);
[a8e9ab8d]876 rwlock_write_unlock(&namespace_rwlock);
877 vfs_node_put(old_node);
878 if (new_node)
879 vfs_node_put(new_node);
880 free(old);
881 free(new);
882 ipc_answer_0(rid, EOK);
883}
884
[861e7d1]885/**
886 * @}
887 */
Note: See TracBrowser for help on using the repository browser.