vfs_ops.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include "vfs.h"
00039 #include <macros.h>
00040 #include <stdint.h>
00041 #include <async.h>
00042 #include <errno.h>
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <str.h>
00046 #include <bool.h>
00047 #include <fibril_synch.h>
00048 #include <adt/list.h>
00049 #include <unistd.h>
00050 #include <ctype.h>
00051 #include <fcntl.h>
00052 #include <assert.h>
00053 #include <vfs/canonify.h>
00054 
00055 /* Forward declarations of static functions. */
00056 static int vfs_truncate_internal(fs_handle_t, devmap_handle_t, fs_index_t,
00057     aoff64_t);
00058 
00063 FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
00064 
00065 vfs_pair_t rootfs = {
00066         .fs_handle = 0,
00067         .devmap_handle = 0
00068 };
00069 
00070 static void vfs_mount_internal(ipc_callid_t rid, devmap_handle_t devmap_handle,
00071     fs_handle_t fs_handle, char *mp, char *opts)
00072 {
00073         vfs_lookup_res_t mp_res;
00074         vfs_lookup_res_t mr_res;
00075         vfs_node_t *mp_node = NULL;
00076         vfs_node_t *mr_node;
00077         fs_index_t rindex;
00078         size_t rsize;
00079         unsigned rlnkcnt;
00080         sysarg_t rc;
00081         int phone;
00082         aid_t msg;
00083         ipc_call_t answer;
00084         
00085         /* Resolve the path to the mountpoint. */
00086         fibril_rwlock_write_lock(&namespace_rwlock);
00087         if (rootfs.fs_handle) {
00088                 /* We already have the root FS. */
00089                 if (str_cmp(mp, "/") == 0) {
00090                         /* Trying to mount root FS over root FS */
00091                         fibril_rwlock_write_unlock(&namespace_rwlock);
00092                         async_answer_0(rid, EBUSY);
00093                         return;
00094                 }
00095                 
00096                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
00097                 if (rc != EOK) {
00098                         /* The lookup failed for some reason. */
00099                         fibril_rwlock_write_unlock(&namespace_rwlock);
00100                         async_answer_0(rid, rc);
00101                         return;
00102                 }
00103                 
00104                 mp_node = vfs_node_get(&mp_res);
00105                 if (!mp_node) {
00106                         fibril_rwlock_write_unlock(&namespace_rwlock);
00107                         async_answer_0(rid, ENOMEM);
00108                         return;
00109                 }
00110                 
00111                 /*
00112                  * Now we hold a reference to mp_node.
00113                  * It will be dropped upon the corresponding VFS_IN_UNMOUNT.
00114                  * This prevents the mount point from being deleted.
00115                  */
00116         } else {
00117                 /* We still don't have the root file system mounted. */
00118                 if (str_cmp(mp, "/") == 0) {
00119                         /*
00120                          * For this simple, but important case,
00121                          * we are almost done.
00122                          */
00123                         
00124                         /* Tell the mountee that it is being mounted. */
00125                         phone = vfs_grab_phone(fs_handle);
00126                         msg = async_send_1(phone, VFS_OUT_MOUNTED,
00127                             (sysarg_t) devmap_handle, &answer);
00128                         /* send the mount options */
00129                         rc = async_data_write_start(phone, (void *)opts,
00130                             str_size(opts));
00131                         if (rc != EOK) {
00132                                 async_wait_for(msg, NULL);
00133                                 vfs_release_phone(fs_handle, phone);
00134                                 fibril_rwlock_write_unlock(&namespace_rwlock);
00135                                 async_answer_0(rid, rc);
00136                                 return;
00137                         }
00138                         async_wait_for(msg, &rc);
00139                         vfs_release_phone(fs_handle, phone);
00140                         
00141                         if (rc != EOK) {
00142                                 fibril_rwlock_write_unlock(&namespace_rwlock);
00143                                 async_answer_0(rid, rc);
00144                                 return;
00145                         }
00146 
00147                         rindex = (fs_index_t) IPC_GET_ARG1(answer);
00148                         rsize = (size_t) IPC_GET_ARG2(answer);
00149                         rlnkcnt = (unsigned) IPC_GET_ARG3(answer);
00150                         
00151                         mr_res.triplet.fs_handle = fs_handle;
00152                         mr_res.triplet.devmap_handle = devmap_handle;
00153                         mr_res.triplet.index = rindex;
00154                         mr_res.size = rsize;
00155                         mr_res.lnkcnt = rlnkcnt;
00156                         mr_res.type = VFS_NODE_DIRECTORY;
00157                         
00158                         rootfs.fs_handle = fs_handle;
00159                         rootfs.devmap_handle = devmap_handle;
00160                         
00161                         /* Add reference to the mounted root. */
00162                         mr_node = vfs_node_get(&mr_res); 
00163                         assert(mr_node);
00164                         
00165                         fibril_rwlock_write_unlock(&namespace_rwlock);
00166                         async_answer_0(rid, rc);
00167                         return;
00168                 } else {
00169                         /*
00170                          * We can't resolve this without the root filesystem
00171                          * being mounted first.
00172                          */
00173                         fibril_rwlock_write_unlock(&namespace_rwlock);
00174                         async_answer_0(rid, ENOENT);
00175                         return;
00176                 }
00177         }
00178         
00179         /*
00180          * At this point, we have all necessary pieces: file system and device
00181          * handles, and we know the mount point VFS node.
00182          */
00183         
00184         int mountee_phone = vfs_grab_phone(fs_handle);
00185         assert(mountee_phone >= 0);
00186 
00187         phone = vfs_grab_phone(mp_res.triplet.fs_handle);
00188         msg = async_send_4(phone, VFS_OUT_MOUNT,
00189             (sysarg_t) mp_res.triplet.devmap_handle,
00190             (sysarg_t) mp_res.triplet.index,
00191             (sysarg_t) fs_handle,
00192             (sysarg_t) devmap_handle, &answer);
00193         
00194         /* send connection */
00195         rc = async_req_1_0(phone, IPC_M_CONNECTION_CLONE, mountee_phone);
00196         if (rc != EOK) {
00197                 async_wait_for(msg, NULL);
00198                 vfs_release_phone(fs_handle, mountee_phone);
00199                 vfs_release_phone(mp_res.triplet.fs_handle, phone);
00200                 /* Mount failed, drop reference to mp_node. */
00201                 if (mp_node)
00202                         vfs_node_put(mp_node);
00203                 async_answer_0(rid, rc);
00204                 fibril_rwlock_write_unlock(&namespace_rwlock);
00205                 return;
00206         }
00207 
00208         vfs_release_phone(fs_handle, mountee_phone);
00209         
00210         /* send the mount options */
00211         rc = async_data_write_start(phone, (void *)opts, str_size(opts));
00212         if (rc != EOK) {
00213                 async_wait_for(msg, NULL);
00214                 vfs_release_phone(mp_res.triplet.fs_handle, phone);
00215                 /* Mount failed, drop reference to mp_node. */
00216                 if (mp_node)
00217                         vfs_node_put(mp_node);
00218                 fibril_rwlock_write_unlock(&namespace_rwlock);
00219                 async_answer_0(rid, rc);
00220                 return;
00221         }
00222         async_wait_for(msg, &rc);
00223         vfs_release_phone(mp_res.triplet.fs_handle, phone);
00224         
00225         if (rc == EOK) {
00226                 rindex = (fs_index_t) IPC_GET_ARG1(answer);
00227                 rsize = (size_t) IPC_GET_ARG2(answer);
00228                 rlnkcnt = (unsigned) IPC_GET_ARG3(answer);
00229         
00230                 mr_res.triplet.fs_handle = fs_handle;
00231                 mr_res.triplet.devmap_handle = devmap_handle;
00232                 mr_res.triplet.index = rindex;
00233                 mr_res.size = rsize;
00234                 mr_res.lnkcnt = rlnkcnt;
00235                 mr_res.type = VFS_NODE_DIRECTORY;
00236         
00237                 /* Add reference to the mounted root. */
00238                 mr_node = vfs_node_get(&mr_res); 
00239                 assert(mr_node);
00240         } else {
00241                 /* Mount failed, drop reference to mp_node. */
00242                 if (mp_node)
00243                         vfs_node_put(mp_node);
00244         }
00245 
00246         async_answer_0(rid, rc);
00247         fibril_rwlock_write_unlock(&namespace_rwlock);
00248 }
00249 
00250 void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
00251 {
00252         devmap_handle_t devmap_handle;
00253 
00254         /*
00255          * We expect the library to do the device-name to device-handle
00256          * translation for us, thus the device handle will arrive as ARG1
00257          * in the request.
00258          */
00259         devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00260         
00261         /*
00262          * Mount flags are passed as ARG2.
00263          */
00264         unsigned int flags = (unsigned int) IPC_GET_ARG2(*request);
00265         
00266         /*
00267          * For now, don't make use of ARG3, but it can be used to
00268          * carry mount options in the future.
00269          */
00270         
00271         /* We want the client to send us the mount point. */
00272         char *mp;
00273         int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
00274             0, NULL);
00275         if (rc != EOK) {
00276                 async_answer_0(rid, rc);
00277                 return;
00278         }
00279         
00280         /* Now we expect to receive the mount options. */
00281         char *opts;
00282         rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,
00283             0, NULL);
00284         if (rc != EOK) {
00285                 free(mp);
00286                 async_answer_0(rid, rc);
00287                 return;
00288         }
00289         
00290         /*
00291          * Now, we expect the client to send us data with the name of the file
00292          * system.
00293          */
00294         char *fs_name;
00295         rc = async_data_write_accept((void **) &fs_name, true, 0,
00296             FS_NAME_MAXLEN, 0, NULL);
00297         if (rc != EOK) {
00298                 free(mp);
00299                 free(opts);
00300                 async_answer_0(rid, rc);
00301                 return;
00302         }
00303         
00304         /*
00305          * Wait for IPC_M_PING so that we can return an error if we don't know
00306          * fs_name.
00307          */
00308         ipc_call_t data;
00309         ipc_callid_t callid = async_get_call(&data);
00310         if (IPC_GET_IMETHOD(data) != IPC_M_PING) {
00311                 async_answer_0(callid, ENOTSUP);
00312                 async_answer_0(rid, ENOTSUP);
00313                 free(mp);
00314                 free(opts);
00315                 free(fs_name);
00316                 return;
00317         }
00318 
00319         /*
00320          * Check if we know a file system with the same name as is in fs_name.
00321          * This will also give us its file system handle.
00322          */
00323         fibril_mutex_lock(&fs_head_lock);
00324         fs_handle_t fs_handle;
00325 recheck:
00326         fs_handle = fs_name_to_handle(fs_name, false);
00327         if (!fs_handle) {
00328                 if (flags & IPC_FLAG_BLOCKING) {
00329                         fibril_condvar_wait(&fs_head_cv, &fs_head_lock);
00330                         goto recheck;
00331                 }
00332                 
00333                 fibril_mutex_unlock(&fs_head_lock);
00334                 async_answer_0(callid, ENOENT);
00335                 async_answer_0(rid, ENOENT);
00336                 free(mp);
00337                 free(fs_name);
00338                 free(opts);
00339                 return;
00340         }
00341         fibril_mutex_unlock(&fs_head_lock);
00342         
00343         /* Acknowledge that we know fs_name. */
00344         async_answer_0(callid, EOK);
00345         
00346         /* Do the mount */
00347         vfs_mount_internal(rid, devmap_handle, fs_handle, mp, opts);
00348         free(mp);
00349         free(fs_name);
00350         free(opts);
00351 }
00352 
00353 void vfs_unmount(ipc_callid_t rid, ipc_call_t *request)
00354 {
00355         int rc;
00356         char *mp;
00357         vfs_lookup_res_t mp_res;
00358         vfs_lookup_res_t mr_res;
00359         vfs_node_t *mr_node;
00360         int phone;
00361 
00362         /*
00363          * Receive the mount point path.
00364          */
00365         rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
00366             0, NULL);
00367         if (rc != EOK)
00368                 async_answer_0(rid, rc);
00369 
00370         /*
00371          * Taking the namespace lock will do two things for us. First, it will
00372          * prevent races with other lookup operations. Second, it will stop new
00373          * references to already existing VFS nodes and creation of new VFS
00374          * nodes. This is because new references are added as a result of some
00375          * lookup operation or at least of some operation which is protected by
00376          * the namespace lock.
00377          */
00378         fibril_rwlock_write_lock(&namespace_rwlock);
00379         
00380         /*
00381          * Lookup the mounted root and instantiate it.
00382          */
00383         rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);
00384         if (rc != EOK) {
00385                 fibril_rwlock_write_unlock(&namespace_rwlock);
00386                 free(mp);
00387                 async_answer_0(rid, rc);
00388                 return;
00389         }
00390         mr_node = vfs_node_get(&mr_res);
00391         if (!mr_node) {
00392                 fibril_rwlock_write_unlock(&namespace_rwlock);
00393                 free(mp);
00394                 async_answer_0(rid, ENOMEM);
00395                 return;
00396         }
00397 
00398         /*
00399          * Count the total number of references for the mounted file system. We
00400          * are expecting at least two. One which we got above and one which we
00401          * got when the file system was mounted. If we find more, it means that
00402          * the file system cannot be gracefully unmounted at the moment because
00403          * someone is working with it.
00404          */
00405         if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
00406             mr_node->devmap_handle) != 2) {
00407                 fibril_rwlock_write_unlock(&namespace_rwlock);
00408                 vfs_node_put(mr_node);
00409                 free(mp);
00410                 async_answer_0(rid, EBUSY);
00411                 return;
00412         }
00413 
00414         if (str_cmp(mp, "/") == 0) {
00415 
00416                 /*
00417                  * Unmounting the root file system.
00418                  *
00419                  * In this case, there is no mount point node and we send
00420                  * VFS_OUT_UNMOUNTED directly to the mounted file system.
00421                  */
00422 
00423                 free(mp);
00424                 phone = vfs_grab_phone(mr_node->fs_handle);
00425                 rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED,
00426                     mr_node->devmap_handle);
00427                 vfs_release_phone(mr_node->fs_handle, phone);
00428                 if (rc != EOK) {
00429                         fibril_rwlock_write_unlock(&namespace_rwlock);
00430                         vfs_node_put(mr_node);
00431                         async_answer_0(rid, rc);
00432                         return;
00433                 }
00434                 rootfs.fs_handle = 0;
00435                 rootfs.devmap_handle = 0;
00436         } else {
00437 
00438                 /*
00439                  * Unmounting a non-root file system.
00440                  *
00441                  * We have a regular mount point node representing the parent
00442                  * file system, so we delegate the operation to it.
00443                  */
00444 
00445                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
00446                 free(mp);
00447                 if (rc != EOK) {
00448                         fibril_rwlock_write_unlock(&namespace_rwlock);
00449                         vfs_node_put(mr_node);
00450                         async_answer_0(rid, rc);
00451                         return;
00452                 }
00453                 vfs_node_t *mp_node = vfs_node_get(&mp_res);
00454                 if (!mp_node) {
00455                         fibril_rwlock_write_unlock(&namespace_rwlock);
00456                         vfs_node_put(mr_node);
00457                         async_answer_0(rid, ENOMEM);
00458                         return;
00459                 }
00460 
00461                 phone = vfs_grab_phone(mp_node->fs_handle);
00462                 rc = async_req_2_0(phone, VFS_OUT_UNMOUNT,
00463                     mp_node->devmap_handle, mp_node->index);
00464                 vfs_release_phone(mp_node->fs_handle, phone);
00465                 if (rc != EOK) {
00466                         fibril_rwlock_write_unlock(&namespace_rwlock);
00467                         vfs_node_put(mp_node);
00468                         vfs_node_put(mr_node);
00469                         async_answer_0(rid, rc);
00470                         return;
00471                 }
00472 
00473                 /* Drop the reference we got above. */
00474                 vfs_node_put(mp_node);
00475                 /* Drop the reference from when the file system was mounted. */
00476                 vfs_node_put(mp_node);
00477         }
00478 
00479 
00480         /*
00481          * All went well, the mounted file system was successfully unmounted.
00482          * The only thing left is to forget the unmounted root VFS node.
00483          */
00484         vfs_node_forget(mr_node);
00485 
00486         fibril_rwlock_write_unlock(&namespace_rwlock);
00487         async_answer_0(rid, EOK);
00488 }
00489 
00490 void vfs_open(ipc_callid_t rid, ipc_call_t *request)
00491 {
00492         /*
00493          * The POSIX interface is open(path, oflag, mode).
00494          * We can receive oflags and mode along with the VFS_IN_OPEN call;
00495          * the path will need to arrive in another call.
00496          *
00497          * We also receive one private, non-POSIX set of flags called lflag
00498          * used to pass information to vfs_lookup_internal().
00499          */
00500         int lflag = IPC_GET_ARG1(*request);
00501         int oflag = IPC_GET_ARG2(*request);
00502         int mode = IPC_GET_ARG3(*request);
00503 
00504         /* Ignore mode for now. */
00505         (void) mode;
00506         
00507         /*
00508          * Make sure that we are called with exactly one of L_FILE and
00509          * L_DIRECTORY. Make sure that the user does not pass L_OPEN,
00510          * L_ROOT or L_MP.
00511          */
00512         if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
00513             ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
00514             (lflag & (L_OPEN | L_ROOT | L_MP))) {
00515                 async_answer_0(rid, EINVAL);
00516                 return;
00517         }
00518         
00519         if (oflag & O_CREAT)
00520                 lflag |= L_CREATE;
00521         if (oflag & O_EXCL)
00522                 lflag |= L_EXCLUSIVE;
00523         
00524         char *path;
00525         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
00526         if (rc != EOK) {
00527                 async_answer_0(rid, rc);
00528                 return;
00529         }
00530         
00531         /*
00532          * Avoid the race condition in which the file can be deleted before we
00533          * find/create-and-lock the VFS node corresponding to the looked-up
00534          * triplet.
00535          */
00536         if (lflag & L_CREATE)
00537                 fibril_rwlock_write_lock(&namespace_rwlock);
00538         else
00539                 fibril_rwlock_read_lock(&namespace_rwlock);
00540         
00541         /* The path is now populated and we can call vfs_lookup_internal(). */
00542         vfs_lookup_res_t lr;
00543         rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);
00544         if (rc != EOK) {
00545                 if (lflag & L_CREATE)
00546                         fibril_rwlock_write_unlock(&namespace_rwlock);
00547                 else
00548                         fibril_rwlock_read_unlock(&namespace_rwlock);
00549                 async_answer_0(rid, rc);
00550                 free(path);
00551                 return;
00552         }
00553         
00554         /* Path is no longer needed. */
00555         free(path);
00556         
00557         vfs_node_t *node = vfs_node_get(&lr);
00558         if (lflag & L_CREATE)
00559                 fibril_rwlock_write_unlock(&namespace_rwlock);
00560         else
00561                 fibril_rwlock_read_unlock(&namespace_rwlock);
00562         
00563         /* Truncate the file if requested and if necessary. */
00564         if (oflag & O_TRUNC) {
00565                 fibril_rwlock_write_lock(&node->contents_rwlock);
00566                 if (node->size) {
00567                         rc = vfs_truncate_internal(node->fs_handle,
00568                             node->devmap_handle, node->index, 0);
00569                         if (rc) {
00570                                 fibril_rwlock_write_unlock(&node->contents_rwlock);
00571                                 vfs_node_put(node);
00572                                 async_answer_0(rid, rc);
00573                                 return;
00574                         }
00575                         node->size = 0;
00576                 }
00577                 fibril_rwlock_write_unlock(&node->contents_rwlock);
00578         }
00579         
00580         /*
00581          * Get ourselves a file descriptor and the corresponding vfs_file_t
00582          * structure.
00583          */
00584         int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
00585         if (fd < 0) {
00586                 vfs_node_put(node);
00587                 async_answer_0(rid, fd);
00588                 return;
00589         }
00590         vfs_file_t *file = vfs_file_get(fd);
00591         assert(file);
00592         file->node = node;
00593         if (oflag & O_APPEND)
00594                 file->append = true;
00595         
00596         /*
00597          * The following increase in reference count is for the fact that the
00598          * file is being opened and that a file structure is pointing to it.
00599          * It is necessary so that the file will not disappear when
00600          * vfs_node_put() is called. The reference will be dropped by the
00601          * respective VFS_IN_CLOSE.
00602          */
00603         vfs_node_addref(node);
00604         vfs_node_put(node);
00605         vfs_file_put(file);
00606         
00607         /* Success! Return the new file descriptor to the client. */
00608         async_answer_1(rid, EOK, fd);
00609 }
00610 
00611 void vfs_open_node(ipc_callid_t rid, ipc_call_t *request)
00612 {
00613         // FIXME: check for sanity of the supplied fs, dev and index
00614         
00615         /*
00616          * The interface is open_node(fs, dev, index, oflag).
00617          */
00618         vfs_lookup_res_t lr;
00619         
00620         lr.triplet.fs_handle = IPC_GET_ARG1(*request);
00621         lr.triplet.devmap_handle = IPC_GET_ARG2(*request);
00622         lr.triplet.index = IPC_GET_ARG3(*request);
00623         int oflag = IPC_GET_ARG4(*request);
00624         
00625         fibril_rwlock_read_lock(&namespace_rwlock);
00626         
00627         int rc = vfs_open_node_internal(&lr);
00628         if (rc != EOK) {
00629                 fibril_rwlock_read_unlock(&namespace_rwlock);
00630                 async_answer_0(rid, rc);
00631                 return;
00632         }
00633         
00634         vfs_node_t *node = vfs_node_get(&lr);
00635         fibril_rwlock_read_unlock(&namespace_rwlock);
00636         
00637         /* Truncate the file if requested and if necessary. */
00638         if (oflag & O_TRUNC) {
00639                 fibril_rwlock_write_lock(&node->contents_rwlock);
00640                 if (node->size) {
00641                         rc = vfs_truncate_internal(node->fs_handle,
00642                             node->devmap_handle, node->index, 0);
00643                         if (rc) {
00644                                 fibril_rwlock_write_unlock(&node->contents_rwlock);
00645                                 vfs_node_put(node);
00646                                 async_answer_0(rid, rc);
00647                                 return;
00648                         }
00649                         node->size = 0;
00650                 }
00651                 fibril_rwlock_write_unlock(&node->contents_rwlock);
00652         }
00653         
00654         /*
00655          * Get ourselves a file descriptor and the corresponding vfs_file_t
00656          * structure.
00657          */
00658         int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
00659         if (fd < 0) {
00660                 vfs_node_put(node);
00661                 async_answer_0(rid, fd);
00662                 return;
00663         }
00664         vfs_file_t *file = vfs_file_get(fd);
00665         file->node = node;
00666         if (oflag & O_APPEND)
00667                 file->append = true;
00668         
00669         /*
00670          * The following increase in reference count is for the fact that the
00671          * file is being opened and that a file structure is pointing to it.
00672          * It is necessary so that the file will not disappear when
00673          * vfs_node_put() is called. The reference will be dropped by the
00674          * respective VFS_IN_CLOSE.
00675          */
00676         vfs_node_addref(node);
00677         vfs_node_put(node);
00678         vfs_file_put(file);
00679         
00680         /* Success! Return the new file descriptor to the client. */
00681         async_answer_1(rid, EOK, fd);
00682 }
00683 
00684 void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
00685 {
00686         int fd = IPC_GET_ARG1(*request);
00687         
00688         /* Lookup the file structure corresponding to the file descriptor. */
00689         vfs_file_t *file = vfs_file_get(fd);
00690         if (!file) {
00691                 async_answer_0(rid, ENOENT);
00692                 return;
00693         }
00694         
00695         /*
00696          * Lock the open file structure so that no other thread can manipulate
00697          * the same open file at a time.
00698          */
00699         fibril_mutex_lock(&file->lock);
00700         int fs_phone = vfs_grab_phone(file->node->fs_handle);
00701         
00702         /* Make a VFS_OUT_SYMC request at the destination FS server. */
00703         aid_t msg;
00704         ipc_call_t answer;
00705         msg = async_send_2(fs_phone, VFS_OUT_SYNC, file->node->devmap_handle,
00706             file->node->index, &answer);
00707 
00708         /* Wait for reply from the FS server. */
00709         sysarg_t rc;
00710         async_wait_for(msg, &rc);
00711         
00712         vfs_release_phone(file->node->fs_handle, fs_phone);
00713         fibril_mutex_unlock(&file->lock);
00714 
00715         vfs_file_put(file);
00716         async_answer_0(rid, rc);
00717 }
00718 
00719 void vfs_close(ipc_callid_t rid, ipc_call_t *request)
00720 {
00721         int fd = IPC_GET_ARG1(*request);
00722         int ret;
00723         
00724         ret = vfs_fd_free(fd);
00725         async_answer_0(rid, ret);
00726 }
00727 
00728 static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
00729 {
00730         vfs_info_t *vi;
00731 
00732         /*
00733          * The following code strongly depends on the fact that the files data
00734          * structure can be only accessed by a single fibril and all file
00735          * operations are serialized (i.e. the reads and writes cannot
00736          * interleave and a file cannot be closed while it is being read).
00737          *
00738          * Additional synchronization needs to be added once the table of
00739          * open files supports parallel access!
00740          */
00741 
00742         int fd = IPC_GET_ARG1(*request);
00743         
00744         /* Lookup the file structure corresponding to the file descriptor. */
00745         vfs_file_t *file = vfs_file_get(fd);
00746         if (!file) {
00747                 async_answer_0(rid, ENOENT);
00748                 return;
00749         }
00750         
00751         /*
00752          * Lock the open file structure so that no other thread can manipulate
00753          * the same open file at a time.
00754          */
00755         fibril_mutex_lock(&file->lock);
00756 
00757         vi = fs_handle_to_info(file->node->fs_handle);
00758         assert(vi);
00759 
00760         /*
00761          * Lock the file's node so that no other client can read/write to it at
00762          * the same time unless the FS supports concurrent reads/writes and its
00763          * write implementation does not modify the file size.
00764          */
00765         if (read || (vi->concurrent_read_write && vi->write_retains_size))
00766                 fibril_rwlock_read_lock(&file->node->contents_rwlock);
00767         else
00768                 fibril_rwlock_write_lock(&file->node->contents_rwlock);
00769 
00770         if (file->node->type == VFS_NODE_DIRECTORY) {
00771                 /*
00772                  * Make sure that no one is modifying the namespace
00773                  * while we are in readdir().
00774                  */
00775                 assert(read);
00776                 fibril_rwlock_read_lock(&namespace_rwlock);
00777         }
00778         
00779         int fs_phone = vfs_grab_phone(file->node->fs_handle);
00780         
00781         /*
00782          * Make a VFS_READ/VFS_WRITE request at the destination FS server
00783          * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
00784          * destination FS server. The call will be routed as if sent by
00785          * ourselves. Note that call arguments are immutable in this case so we
00786          * don't have to bother.
00787          */
00788         sysarg_t rc;
00789         ipc_call_t answer;
00790         if (read) {
00791                 rc = async_data_read_forward_3_1(fs_phone, VFS_OUT_READ,
00792                     file->node->devmap_handle, file->node->index, file->pos,
00793                     &answer);
00794         } else {
00795                 if (file->append)
00796                         file->pos = file->node->size;
00797                 
00798                 rc = async_data_write_forward_3_1(fs_phone, VFS_OUT_WRITE,
00799                     file->node->devmap_handle, file->node->index, file->pos,
00800                     &answer);
00801         }
00802         
00803         vfs_release_phone(file->node->fs_handle, fs_phone);
00804         
00805         size_t bytes = IPC_GET_ARG1(answer);
00806         
00807         if (file->node->type == VFS_NODE_DIRECTORY)
00808                 fibril_rwlock_read_unlock(&namespace_rwlock);
00809         
00810         /* Unlock the VFS node. */
00811         if (read || (vi->concurrent_read_write && vi->write_retains_size))
00812                 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
00813         else {
00814                 /* Update the cached version of node's size. */
00815                 if (rc == EOK)
00816                         file->node->size = IPC_GET_ARG2(answer); 
00817                 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
00818         }
00819         
00820         /* Update the position pointer and unlock the open file. */
00821         if (rc == EOK)
00822                 file->pos += bytes;
00823         fibril_mutex_unlock(&file->lock);
00824         vfs_file_put(file);     
00825 
00826         /*
00827          * FS server's reply is the final result of the whole operation we
00828          * return to the client.
00829          */
00830         async_answer_1(rid, rc, bytes);
00831 }
00832 
00833 void vfs_read(ipc_callid_t rid, ipc_call_t *request)
00834 {
00835         vfs_rdwr(rid, request, true);
00836 }
00837 
00838 void vfs_write(ipc_callid_t rid, ipc_call_t *request)
00839 {
00840         vfs_rdwr(rid, request, false);
00841 }
00842 
00843 void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
00844 {
00845         int fd = (int) IPC_GET_ARG1(*request);
00846         off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
00847             IPC_GET_ARG3(*request));
00848         int whence = (int) IPC_GET_ARG4(*request);
00849         
00850         /* Lookup the file structure corresponding to the file descriptor. */
00851         vfs_file_t *file = vfs_file_get(fd);
00852         if (!file) {
00853                 async_answer_0(rid, ENOENT);
00854                 return;
00855         }
00856         
00857         fibril_mutex_lock(&file->lock);
00858         
00859         off64_t newoff;
00860         switch (whence) {
00861         case SEEK_SET:
00862                 if (off >= 0) {
00863                         file->pos = (aoff64_t) off;
00864                         fibril_mutex_unlock(&file->lock);
00865                         vfs_file_put(file);
00866                         async_answer_1(rid, EOK, off);
00867                         return;
00868                 }
00869                 break;
00870         case SEEK_CUR:
00871                 if ((off >= 0) && (file->pos + off < file->pos)) {
00872                         fibril_mutex_unlock(&file->lock);
00873                         vfs_file_put(file);
00874                         async_answer_0(rid, EOVERFLOW);
00875                         return;
00876                 }
00877                 
00878                 if ((off < 0) && (file->pos < (aoff64_t) -off)) {
00879                         fibril_mutex_unlock(&file->lock);
00880                         vfs_file_put(file);
00881                         async_answer_0(rid, EOVERFLOW);
00882                         return;
00883                 }
00884                 
00885                 file->pos += off;
00886                 newoff = (file->pos > OFF64_MAX) ?  OFF64_MAX : file->pos;
00887                 
00888                 fibril_mutex_unlock(&file->lock);
00889                 vfs_file_put(file);
00890                 async_answer_2(rid, EOK, LOWER32(newoff),
00891                     UPPER32(newoff));
00892                 return;
00893         case SEEK_END:
00894                 fibril_rwlock_read_lock(&file->node->contents_rwlock);
00895                 aoff64_t size = file->node->size;
00896                 
00897                 if ((off >= 0) && (size + off < size)) {
00898                         fibril_rwlock_read_unlock(&file->node->contents_rwlock);
00899                         fibril_mutex_unlock(&file->lock);
00900                         vfs_file_put(file);
00901                         async_answer_0(rid, EOVERFLOW);
00902                         return;
00903                 }
00904                 
00905                 if ((off < 0) && (size < (aoff64_t) -off)) {
00906                         fibril_rwlock_read_unlock(&file->node->contents_rwlock);
00907                         fibril_mutex_unlock(&file->lock);
00908                         vfs_file_put(file);
00909                         async_answer_0(rid, EOVERFLOW);
00910                         return;
00911                 }
00912                 
00913                 file->pos = size + off;
00914                 newoff = (file->pos > OFF64_MAX) ?  OFF64_MAX : file->pos;
00915                 
00916                 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
00917                 fibril_mutex_unlock(&file->lock);
00918                 vfs_file_put(file);
00919                 async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff));
00920                 return;
00921         }
00922         
00923         fibril_mutex_unlock(&file->lock);
00924         vfs_file_put(file);
00925         async_answer_0(rid, EINVAL);
00926 }
00927 
00928 int vfs_truncate_internal(fs_handle_t fs_handle, devmap_handle_t devmap_handle,
00929     fs_index_t index, aoff64_t size)
00930 {
00931         sysarg_t rc;
00932         int fs_phone;
00933         
00934         fs_phone = vfs_grab_phone(fs_handle);
00935         rc = async_req_4_0(fs_phone, VFS_OUT_TRUNCATE, (sysarg_t) devmap_handle,
00936             (sysarg_t) index, LOWER32(size), UPPER32(size));
00937         vfs_release_phone(fs_handle, fs_phone);
00938         return (int)rc;
00939 }
00940 
00941 void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
00942 {
00943         int fd = IPC_GET_ARG1(*request);
00944         aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
00945             IPC_GET_ARG3(*request));
00946         int rc;
00947 
00948         vfs_file_t *file = vfs_file_get(fd);
00949         if (!file) {
00950                 async_answer_0(rid, ENOENT);
00951                 return;
00952         }
00953         fibril_mutex_lock(&file->lock);
00954 
00955         fibril_rwlock_write_lock(&file->node->contents_rwlock);
00956         rc = vfs_truncate_internal(file->node->fs_handle,
00957             file->node->devmap_handle, file->node->index, size);
00958         if (rc == EOK)
00959                 file->node->size = size;
00960         fibril_rwlock_write_unlock(&file->node->contents_rwlock);
00961 
00962         fibril_mutex_unlock(&file->lock);
00963         vfs_file_put(file);
00964         async_answer_0(rid, (sysarg_t)rc);
00965 }
00966 
00967 void vfs_fstat(ipc_callid_t rid, ipc_call_t *request)
00968 {
00969         int fd = IPC_GET_ARG1(*request);
00970         sysarg_t rc;
00971 
00972         vfs_file_t *file = vfs_file_get(fd);
00973         if (!file) {
00974                 async_answer_0(rid, ENOENT);
00975                 return;
00976         }
00977 
00978         ipc_callid_t callid;
00979         if (!async_data_read_receive(&callid, NULL)) {
00980                 vfs_file_put(file);
00981                 async_answer_0(callid, EINVAL);
00982                 async_answer_0(rid, EINVAL);
00983                 return;
00984         }
00985 
00986         fibril_mutex_lock(&file->lock);
00987 
00988         int fs_phone = vfs_grab_phone(file->node->fs_handle);
00989         
00990         aid_t msg;
00991         msg = async_send_3(fs_phone, VFS_OUT_STAT, file->node->devmap_handle,
00992             file->node->index, true, NULL);
00993         async_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
00994         async_wait_for(msg, &rc);
00995         vfs_release_phone(file->node->fs_handle, fs_phone);
00996 
00997         fibril_mutex_unlock(&file->lock);
00998         vfs_file_put(file);
00999         async_answer_0(rid, rc);
01000 }
01001 
01002 void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
01003 {
01004         char *path;
01005         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
01006         if (rc != EOK) {
01007                 async_answer_0(rid, rc);
01008                 return;
01009         }
01010         
01011         ipc_callid_t callid;
01012         if (!async_data_read_receive(&callid, NULL)) {
01013                 free(path);
01014                 async_answer_0(callid, EINVAL);
01015                 async_answer_0(rid, EINVAL);
01016                 return;
01017         }
01018 
01019         vfs_lookup_res_t lr;
01020         fibril_rwlock_read_lock(&namespace_rwlock);
01021         rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
01022         free(path);
01023         if (rc != EOK) {
01024                 fibril_rwlock_read_unlock(&namespace_rwlock);
01025                 async_answer_0(callid, rc);
01026                 async_answer_0(rid, rc);
01027                 return;
01028         }
01029         vfs_node_t *node = vfs_node_get(&lr);
01030         if (!node) {
01031                 fibril_rwlock_read_unlock(&namespace_rwlock);
01032                 async_answer_0(callid, ENOMEM);
01033                 async_answer_0(rid, ENOMEM);
01034                 return;
01035         }
01036 
01037         fibril_rwlock_read_unlock(&namespace_rwlock);
01038 
01039         int fs_phone = vfs_grab_phone(node->fs_handle);
01040         aid_t msg;
01041         msg = async_send_3(fs_phone, VFS_OUT_STAT, node->devmap_handle,
01042             node->index, false, NULL);
01043         async_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
01044         
01045         sysarg_t rv;
01046         async_wait_for(msg, &rv);
01047         vfs_release_phone(node->fs_handle, fs_phone);
01048 
01049         async_answer_0(rid, rv);
01050 
01051         vfs_node_put(node);
01052 }
01053 
01054 void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
01055 {
01056         int mode = IPC_GET_ARG1(*request);
01057         
01058         char *path;
01059         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
01060         if (rc != EOK) {
01061                 async_answer_0(rid, rc);
01062                 return;
01063         }
01064         
01065         /* Ignore mode for now. */
01066         (void) mode;
01067         
01068         fibril_rwlock_write_lock(&namespace_rwlock);
01069         int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
01070         rc = vfs_lookup_internal(path, lflag, NULL, NULL);
01071         fibril_rwlock_write_unlock(&namespace_rwlock);
01072         free(path);
01073         async_answer_0(rid, rc);
01074 }
01075 
01076 void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
01077 {
01078         int lflag = IPC_GET_ARG1(*request);
01079         
01080         char *path;
01081         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
01082         if (rc != EOK) {
01083                 async_answer_0(rid, rc);
01084                 return;
01085         }
01086         
01087         fibril_rwlock_write_lock(&namespace_rwlock);
01088         lflag &= L_DIRECTORY;   /* sanitize lflag */
01089         vfs_lookup_res_t lr;
01090         rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
01091         free(path);
01092         if (rc != EOK) {
01093                 fibril_rwlock_write_unlock(&namespace_rwlock);
01094                 async_answer_0(rid, rc);
01095                 return;
01096         }
01097 
01098         /*
01099          * The name has already been unlinked by vfs_lookup_internal().
01100          * We have to get and put the VFS node to ensure that it is
01101          * VFS_OUT_DESTROY'ed after the last reference to it is dropped.
01102          */
01103         vfs_node_t *node = vfs_node_get(&lr);
01104         fibril_mutex_lock(&nodes_mutex);
01105         node->lnkcnt--;
01106         fibril_mutex_unlock(&nodes_mutex);
01107         fibril_rwlock_write_unlock(&namespace_rwlock);
01108         vfs_node_put(node);
01109         async_answer_0(rid, EOK);
01110 }
01111 
01112 void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
01113 {
01114         /* Retrieve the old path. */
01115         char *old;
01116         int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
01117         if (rc != EOK) {
01118                 async_answer_0(rid, rc);
01119                 return;
01120         }
01121         
01122         /* Retrieve the new path. */
01123         char *new;
01124         rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
01125         if (rc != EOK) {
01126                 free(old);
01127                 async_answer_0(rid, rc);
01128                 return;
01129         }
01130         
01131         size_t olen;
01132         size_t nlen;
01133         char *oldc = canonify(old, &olen);
01134         char *newc = canonify(new, &nlen);
01135         
01136         if ((!oldc) || (!newc)) {
01137                 async_answer_0(rid, EINVAL);
01138                 free(old);
01139                 free(new);
01140                 return;
01141         }
01142         
01143         oldc[olen] = '\0';
01144         newc[nlen] = '\0';
01145         
01146         if ((!str_lcmp(newc, oldc, str_length(oldc))) &&
01147             ((newc[str_length(oldc)] == '/') ||
01148             (str_length(oldc) == 1) ||
01149             (str_length(oldc) == str_length(newc)))) {
01150                 /*
01151                  * oldc is a prefix of newc and either
01152                  * - newc continues with a / where oldc ends, or
01153                  * - oldc was / itself, or
01154                  * - oldc and newc are equal.
01155                  */
01156                 async_answer_0(rid, EINVAL);
01157                 free(old);
01158                 free(new);
01159                 return;
01160         }
01161         
01162         vfs_lookup_res_t old_lr;
01163         vfs_lookup_res_t new_lr;
01164         vfs_lookup_res_t new_par_lr;
01165         fibril_rwlock_write_lock(&namespace_rwlock);
01166         
01167         /* Lookup the node belonging to the old file name. */
01168         rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
01169         if (rc != EOK) {
01170                 fibril_rwlock_write_unlock(&namespace_rwlock);
01171                 async_answer_0(rid, rc);
01172                 free(old);
01173                 free(new);
01174                 return;
01175         }
01176         
01177         vfs_node_t *old_node = vfs_node_get(&old_lr);
01178         if (!old_node) {
01179                 fibril_rwlock_write_unlock(&namespace_rwlock);
01180                 async_answer_0(rid, ENOMEM);
01181                 free(old);
01182                 free(new);
01183                 return;
01184         }
01185         
01186         /* Determine the path to the parent of the node with the new name. */
01187         char *parentc = str_dup(newc);
01188         if (!parentc) {
01189                 fibril_rwlock_write_unlock(&namespace_rwlock);
01190                 vfs_node_put(old_node);
01191                 async_answer_0(rid, rc);
01192                 free(old);
01193                 free(new);
01194                 return;
01195         }
01196         
01197         char *lastsl = str_rchr(parentc + 1, '/');
01198         if (lastsl)
01199                 *lastsl = '\0';
01200         else
01201                 parentc[1] = '\0';
01202         
01203         /* Lookup parent of the new file name. */
01204         rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
01205         free(parentc);  /* not needed anymore */
01206         if (rc != EOK) {
01207                 fibril_rwlock_write_unlock(&namespace_rwlock);
01208                 vfs_node_put(old_node);
01209                 async_answer_0(rid, rc);
01210                 free(old);
01211                 free(new);
01212                 return;
01213         }
01214         
01215         /* Check whether linking to the same file system instance. */
01216         if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
01217             (old_node->devmap_handle != new_par_lr.triplet.devmap_handle)) {
01218                 fibril_rwlock_write_unlock(&namespace_rwlock);
01219                 vfs_node_put(old_node);
01220                 async_answer_0(rid, EXDEV);     /* different file systems */
01221                 free(old);
01222                 free(new);
01223                 return;
01224         }
01225         
01226         /* Destroy the old link for the new name. */
01227         vfs_node_t *new_node = NULL;
01228         rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
01229         
01230         switch (rc) {
01231         case ENOENT:
01232                 /* simply not in our way */
01233                 break;
01234         case EOK:
01235                 new_node = vfs_node_get(&new_lr);
01236                 if (!new_node) {
01237                         fibril_rwlock_write_unlock(&namespace_rwlock);
01238                         vfs_node_put(old_node);
01239                         async_answer_0(rid, ENOMEM);
01240                         free(old);
01241                         free(new);
01242                         return;
01243                 }
01244                 fibril_mutex_lock(&nodes_mutex);
01245                 new_node->lnkcnt--;
01246                 fibril_mutex_unlock(&nodes_mutex);
01247                 break;
01248         default:
01249                 fibril_rwlock_write_unlock(&namespace_rwlock);
01250                 vfs_node_put(old_node);
01251                 async_answer_0(rid, ENOTEMPTY);
01252                 free(old);
01253                 free(new);
01254                 return;
01255         }
01256         
01257         /* Create the new link for the new name. */
01258         rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
01259         if (rc != EOK) {
01260                 fibril_rwlock_write_unlock(&namespace_rwlock);
01261                 vfs_node_put(old_node);
01262                 if (new_node)
01263                         vfs_node_put(new_node);
01264                 async_answer_0(rid, rc);
01265                 free(old);
01266                 free(new);
01267                 return;
01268         }
01269         
01270         fibril_mutex_lock(&nodes_mutex);
01271         old_node->lnkcnt++;
01272         fibril_mutex_unlock(&nodes_mutex);
01273         
01274         /* Destroy the link for the old name. */
01275         rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
01276         if (rc != EOK) {
01277                 fibril_rwlock_write_unlock(&namespace_rwlock);
01278                 vfs_node_put(old_node);
01279                 if (new_node)
01280                         vfs_node_put(new_node);
01281                 async_answer_0(rid, rc);
01282                 free(old);
01283                 free(new);
01284                 return;
01285         }
01286         
01287         fibril_mutex_lock(&nodes_mutex);
01288         old_node->lnkcnt--;
01289         fibril_mutex_unlock(&nodes_mutex);
01290         fibril_rwlock_write_unlock(&namespace_rwlock);
01291         vfs_node_put(old_node);
01292         
01293         if (new_node)
01294                 vfs_node_put(new_node);
01295         
01296         free(old);
01297         free(new);
01298         async_answer_0(rid, EOK);
01299 }
01300 
01301 void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
01302 {
01303         int oldfd = IPC_GET_ARG1(*request);
01304         int newfd = IPC_GET_ARG2(*request);
01305         
01306         /* If the file descriptors are the same, do nothing. */
01307         if (oldfd == newfd) {
01308                 async_answer_1(rid, EOK, newfd);
01309                 return;
01310         }
01311         
01312         /* Lookup the file structure corresponding to oldfd. */
01313         vfs_file_t *oldfile = vfs_file_get(oldfd);
01314         if (!oldfile) {
01315                 async_answer_0(rid, EBADF);
01316                 return;
01317         }
01318         
01319         /*
01320          * Lock the open file structure so that no other thread can manipulate
01321          * the same open file at a time.
01322          */
01323         fibril_mutex_lock(&oldfile->lock);
01324         
01325         /* Make sure newfd is closed. */
01326         (void) vfs_fd_free(newfd);
01327         
01328         /* Assign the old file to newfd. */
01329         int ret = vfs_fd_assign(oldfile, newfd);
01330         fibril_mutex_unlock(&oldfile->lock);
01331         vfs_file_put(oldfile);
01332         
01333         if (ret != EOK)
01334                 async_answer_0(rid, ret);
01335         else
01336                 async_answer_1(rid, EOK, newfd);
01337 }
01338 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7