Changes in / [1dff985:5b46ec8] in mainline


Ignore:
Location:
uspace
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/trace/trace.c

    r1dff985 r5b46ec8  
    696696
    697697        p = proto_new("vfs");
     698        o = oper_new("open", 2, arg_def, V_INT_ERRNO, 0, resp_def);
     699        proto_add_oper(p, VFS_IN_OPEN, o);
    698700        o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def);
    699701        proto_add_oper(p, VFS_IN_READ, o);
     
    714716        o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def);
    715717        proto_add_oper(p, VFS_IN_SYNC, o);
     718        o = oper_new("mkdir", 1, arg_def, V_ERRNO, 0, resp_def);
     719        proto_add_oper(p, VFS_IN_MKDIR, o);
     720        o = oper_new("unlink", 0, arg_def, V_ERRNO, 0, resp_def);
     721        proto_add_oper(p, VFS_IN_UNLINK, o);
    716722        o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
    717723        proto_add_oper(p, VFS_IN_RENAME, o);
     724        o = oper_new("stat", 0, arg_def, V_ERRNO, 0, resp_def);
     725        proto_add_oper(p, VFS_IN_STAT, o);
    718726        o = oper_new("statfs", 0, arg_def, V_ERRNO, 0, resp_def);
    719727        proto_add_oper(p, VFS_IN_STATFS, o);
    720         o = oper_new("walk", 2, arg_def, V_INT_ERRNO, 0, resp_def);
    721         proto_add_oper(p, VFS_IN_WALK, o);
    722         o = oper_new("open2", 2, arg_def, V_ERRNO, 0, resp_def);
    723         proto_add_oper(p, VFS_IN_OPEN2, o);
    724         o = oper_new("unlink2", 3, arg_def, V_ERRNO, 0, resp_def);
    725         proto_add_oper(p, VFS_IN_UNLINK2, o);
    726728
    727729        proto_register(SERVICE_VFS, p);
  • uspace/lib/c/generic/vfs/vfs.c

    r1dff985 r5b46ec8  
    9393}
    9494
    95 int _vfs_walk(int parent, const char *path, int flags)
    96 {
    97         async_exch_t *exch = vfs_exchange_begin();
    98        
    99         ipc_call_t answer;
    100         aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
    101         sysarg_t rc = async_data_write_start(exch, path, str_size(path));
    102         vfs_exchange_end(exch);
    103                
    104         sysarg_t rc_orig;
    105         async_wait_for(req, &rc_orig);
    106 
    107         if (rc_orig != EOK) {
    108                 return (int) rc_orig;
    109         }
    110                
    111         if (rc != EOK) {
    112                 return (int) rc;
    113         }
    114        
    115         return (int) IPC_GET_ARG1(answer);
    116 }
    117 
    118 int _vfs_open(int fildes, int mode)
    119 {
    120         async_exch_t *exch = vfs_exchange_begin();
    121         sysarg_t rc = async_req_2_0(exch, VFS_IN_OPEN2, fildes, mode);
    122         vfs_exchange_end(exch);
    123        
    124         return (int) rc;
    125 }
    126 
    12795char *vfs_absolutize(const char *path, size_t *retlen)
    12896{
     
    261229        }
    262230       
     231        /* Ask VFS whether it likes fs_name. */
     232        rc = async_req_0_0(exch, VFS_IN_PING);
     233        if (rc != EOK) {
     234                vfs_exchange_end(exch);
     235                free(mpa);
     236                async_wait_for(req, &rc_orig);
     237               
     238                if (null_id != -1)
     239                        loc_null_destroy(null_id);
     240               
     241                if (rc_orig == EOK)
     242                        return (int) rc;
     243                else
     244                        return (int) rc_orig;
     245        }
     246       
    263247        vfs_exchange_end(exch);
    264248        free(mpa);
     
    305289}
    306290
    307 static int walk_flags(int oflags)
    308 {
    309         int flags = 0;
    310         if (oflags & O_CREAT) {
    311                 if (oflags & O_EXCL) {
    312                         flags |= WALK_MUST_CREATE;
    313                 } else {
    314                         flags |= WALK_MAY_CREATE;
    315                 }
    316         }
    317         return flags;
     291/** Open file (internal).
     292 *
     293 * @param abs Absolute path to file
     294 * @param abs_size Size of @a abs string
     295 * @param lflag L_xxx flags
     296 * @param oflag O_xxx flags
     297 * @param fd Place to store new file descriptor
     298 *
     299 * @return EOK on success, non-zero error code on error
     300 */
     301static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag,
     302    int *fd)
     303{
     304        async_exch_t *exch = vfs_exchange_begin();
     305       
     306        ipc_call_t answer;
     307        aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer);
     308        sysarg_t rc = async_data_write_start(exch, abs, abs_size);
     309       
     310        if (rc != EOK) {
     311                vfs_exchange_end(exch);
     312
     313                sysarg_t rc_orig;
     314                async_wait_for(req, &rc_orig);
     315               
     316                if (rc_orig == EOK)
     317                        return (int) rc;
     318                else
     319                        return (int) rc_orig;
     320        }
     321       
     322        vfs_exchange_end(exch);
     323        async_wait_for(req, &rc);
     324       
     325        if (rc != EOK)
     326            return (int) rc;
     327       
     328        *fd = (int) IPC_GET_ARG1(answer);
     329        return EOK;
    318330}
    319331
     
    329341int open(const char *path, int oflag, ...)
    330342{
    331         // FIXME: Some applications call this incorrectly.
    332         if ((oflag & (O_RDONLY|O_WRONLY|O_RDWR)) == 0) {
    333                 oflag |= O_RDWR;
    334         }
    335 
    336         assert((((oflag & O_RDONLY) != 0) + ((oflag & O_WRONLY) != 0) + ((oflag & O_RDWR) != 0)) == 1);
    337        
    338343        size_t abs_size;
    339344        char *abs = vfs_absolutize(path, &abs_size);
    340         if (!abs) {
    341                 return ENOMEM;
    342         }
    343        
    344         int ret = _vfs_walk(-1, abs, walk_flags(oflag) | WALK_REGULAR);
    345         if (ret < 0) {
    346                 return ret;
    347         }
    348        
    349         int mode =
    350                 ((oflag & O_RDWR) ? MODE_READ|MODE_WRITE : 0) |
    351                 ((oflag & O_RDONLY) ? MODE_READ : 0) |
    352                 ((oflag & O_WRONLY) ? MODE_WRITE : 0) |
    353                 ((oflag & O_APPEND) ? MODE_APPEND : 0);
    354        
    355         int rc = _vfs_open(ret, mode);
    356         if (rc < 0) {
    357                 // _vfs_put(ret);
    358                 close(ret);
    359                 return rc;
    360         }
    361        
    362         if (oflag & O_TRUNC) {
    363                 assert(oflag & O_WRONLY || oflag & O_RDWR);
    364                 assert(!(oflag & O_APPEND));
    365                
    366                 // _vfs_resize
    367                 (void) ftruncate(ret, 0);
    368         }
    369 
    370         return ret;
     345        int fd = -1;
     346       
     347        if (abs == NULL) {
     348                errno = ENOMEM;
     349                return -1;
     350        }
     351       
     352        int rc = open_internal(abs, abs_size, L_FILE, oflag, &fd);
     353        free(abs);
     354       
     355        if (rc != EOK) {
     356                errno = rc;
     357                return -1;
     358        }
     359       
     360        return fd;
    371361}
    372362
     
    680670int stat(const char *path, struct stat *stat)
    681671{
     672        sysarg_t rc;
     673        sysarg_t rc_orig;
     674        aid_t req;
     675       
    682676        size_t pa_size;
    683677        char *pa = vfs_absolutize(path, &pa_size);
    684         if (!pa) {
    685                 return ENOMEM;
    686         }
    687        
    688         int fd = _vfs_walk(-1, pa, 0);
    689         if (fd < 0) {
    690                 return fd;
    691         }
    692        
    693         int rc = fstat(fd, stat);
    694         close(fd);
    695         return rc;
     678        if (pa == NULL) {
     679                errno = ENOMEM;
     680                return -1;
     681        }
     682       
     683        async_exch_t *exch = vfs_exchange_begin();
     684       
     685        req = async_send_0(exch, VFS_IN_STAT, NULL);
     686        rc = async_data_write_start(exch, pa, pa_size);
     687        if (rc != EOK) {
     688                vfs_exchange_end(exch);
     689                free(pa);
     690                async_wait_for(req, &rc_orig);
     691                if (rc_orig != EOK)
     692                        rc = rc_orig;
     693                if (rc != EOK) {
     694                        errno = rc;
     695                        return -1;
     696                }
     697        }
     698        rc = async_data_read_start(exch, stat, sizeof(struct stat));
     699        if (rc != EOK) {
     700                vfs_exchange_end(exch);
     701                free(pa);
     702                async_wait_for(req, &rc_orig);
     703                if (rc_orig != EOK)
     704                        rc = rc_orig;
     705                if (rc != EOK) {
     706                        errno = rc;
     707                        return -1;
     708                }
     709        }
     710        vfs_exchange_end(exch);
     711        free(pa);
     712        async_wait_for(req, &rc);
     713        if (rc != EOK) {
     714                errno = rc;
     715                return -1;
     716        }
     717        return 0;
    696718}
    697719
     
    705727{
    706728        DIR *dirp = malloc(sizeof(DIR));
    707         if (!dirp) {
     729        int fd = -1;
     730       
     731        if (dirp == NULL) {
    708732                errno = ENOMEM;
    709733                return NULL;
     
    718742        }
    719743       
    720         int ret = _vfs_walk(-1, abs, WALK_DIRECTORY);
     744        int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd);
    721745        free(abs);
    722746       
    723         if (ret < EOK) {
     747        if (rc != EOK) {
    724748                free(dirp);
    725                 errno = ret;
     749                errno = rc;
    726750                return NULL;
    727751        }
    728752       
    729         int rc = _vfs_open(ret, MODE_READ);
    730         if (rc < 0) {
    731                 free(dirp);
    732                 close(ret);
    733                 errno = rc;
    734                 return NULL;
    735         }
    736        
    737         dirp->fd = ret;
     753        dirp->fd = fd;
    738754        return dirp;
    739755}
     
    793809int mkdir(const char *path, mode_t mode)
    794810{
     811        sysarg_t rc;
     812        aid_t req;
     813       
    795814        size_t pa_size;
    796815        char *pa = vfs_absolutize(path, &pa_size);
    797         if (!pa) {
    798                 return ENOMEM;
    799         }
    800        
    801         int ret = _vfs_walk(-1, pa, WALK_MUST_CREATE | WALK_DIRECTORY);
    802         if (ret < 0) {
    803                 return ret;
    804         }
    805        
    806         close(ret);
    807         return EOK;
    808 }
    809 
    810 static int _vfs_unlink2(int parent, const char *path, int expect, int wflag)
     816        if (pa == NULL) {
     817                errno = ENOMEM;
     818                return -1;
     819        }
     820       
     821        async_exch_t *exch = vfs_exchange_begin();
     822       
     823        req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
     824        rc = async_data_write_start(exch, pa, pa_size);
     825        if (rc != EOK) {
     826                vfs_exchange_end(exch);
     827                free(pa);
     828               
     829                sysarg_t rc_orig;
     830                async_wait_for(req, &rc_orig);
     831               
     832                if (rc_orig != EOK)
     833                        rc = rc_orig;
     834               
     835                if (rc != EOK) {
     836                        errno = rc;
     837                        return -1;
     838                }
     839               
     840                return 0;
     841        }
     842       
     843        vfs_exchange_end(exch);
     844        free(pa);
     845        async_wait_for(req, &rc);
     846       
     847        if (rc != EOK) {
     848                errno = rc;
     849                return -1;
     850        }
     851       
     852        return 0;
     853}
     854
     855/** Unlink a file or directory.
     856 *
     857 * @param path Path to file or empty directory
     858 * @param lflag L_xxx flag (L_NONE, L_FILE or L_DIRECTORY)
     859 * @return EOK on success, non-zero error code on error
     860 */
     861static int _unlink(const char *path, int lflag)
    811862{
    812863        sysarg_t rc;
    813864        aid_t req;
    814865       
    815         async_exch_t *exch = vfs_exchange_begin();
    816        
    817         req = async_send_3(exch, VFS_IN_UNLINK2, parent, expect, wflag, NULL);
    818         rc = async_data_write_start(exch, path, str_size(path));
    819        
    820         vfs_exchange_end(exch);
    821        
    822         sysarg_t rc_orig;
    823         async_wait_for(req, &rc_orig);
    824        
    825         if (rc_orig != EOK) {
    826                 return (int) rc_orig;
    827         }
     866        size_t pa_size;
     867        char *pa = vfs_absolutize(path, &pa_size);
     868        if (pa == NULL)
     869                return ENOMEM;
     870       
     871        async_exch_t *exch = vfs_exchange_begin();
     872       
     873        req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL);
     874        rc = async_data_write_start(exch, pa, pa_size);
     875        if (rc != EOK) {
     876                vfs_exchange_end(exch);
     877                free(pa);
     878
     879                sysarg_t rc_orig;
     880                async_wait_for(req, &rc_orig);
     881
     882                if (rc_orig == EOK)
     883                        return (int) rc;
     884                else
     885                        return (int) rc_orig;
     886        }
     887        vfs_exchange_end(exch);
     888        free(pa);
     889        async_wait_for(req, &rc);
    828890        return rc;
    829891}
     
    836898int unlink(const char *path)
    837899{
    838         size_t pa_size;
    839         char *pa = vfs_absolutize(path, &pa_size);
    840         if (!pa) {
    841                 return ENOMEM;
    842         }
    843        
    844         return _vfs_unlink2(-1, pa, -1, 0);
     900        int rc;
     901
     902        rc = _unlink(path, L_NONE);
     903        if (rc != EOK) {
     904                errno = rc;
     905                return -1;
     906        }
     907
     908        return 0;
    845909}
    846910
     
    852916int rmdir(const char *path)
    853917{
    854         size_t pa_size;
    855         char *pa = vfs_absolutize(path, &pa_size);
    856         if (!pa) {
    857                 return ENOMEM;
    858         }
    859        
    860         return _vfs_unlink2(-1, pa, -1, WALK_DIRECTORY);
     918        int rc;
     919
     920        rc = _unlink(path, L_DIRECTORY);
     921        if (rc != EOK) {
     922                errno = rc;
     923                return -1;
     924        }
     925
     926        return 0;
    861927}
    862928
     
    891957        async_exch_t *exch = vfs_exchange_begin();
    892958       
    893         req = async_send_1(exch, VFS_IN_RENAME, -1, NULL);
     959        req = async_send_0(exch, VFS_IN_RENAME, NULL);
    894960        rc = async_data_write_start(exch, olda, olda_size);
    895961        if (rc != EOK) {
     
    9521018        size_t abs_size;
    9531019        char *abs = vfs_absolutize(path, &abs_size);
    954         if (!abs)
    955                 return ENOMEM;
    956        
    957         int fd = _vfs_walk(-1, abs, WALK_DIRECTORY);
    958         if (fd < 0) {
     1020        int fd = -1;
     1021       
     1022        if (abs == NULL) {
     1023                errno = ENOMEM;
     1024                return -1;
     1025        }
     1026       
     1027        int rc = open_internal(abs, abs_size, L_DIRECTORY, O_DESC, &fd);
     1028       
     1029        if (rc != EOK) {
    9591030                free(abs);
    960                 errno = fd;
     1031                errno = rc;
    9611032                return -1;
    9621033        }
  • uspace/lib/c/include/ipc/vfs.h

    r1dff985 r5b46ec8  
    6363
    6464typedef enum {
    65         VFS_IN_READ = IPC_FIRST_USER_METHOD,
     65        VFS_IN_OPEN = IPC_FIRST_USER_METHOD,
     66        VFS_IN_READ,
    6667        VFS_IN_WRITE,
    6768        VFS_IN_SEEK,
     
    7475        VFS_IN_SYNC,
    7576        VFS_IN_REGISTER,
     77        VFS_IN_MKDIR,
    7678        VFS_IN_UNLINK,
    7779        VFS_IN_RENAME,
     80        VFS_IN_STAT,
    7881        VFS_IN_DUP,
    7982        VFS_IN_WAIT_HANDLE,
    8083        VFS_IN_MTAB_GET,
    81         VFS_IN_STATFS,
    82         VFS_IN_WALK,
    83         VFS_IN_OPEN2,
    84         VFS_IN_UNLINK2,
     84        VFS_IN_STATFS
    8585} vfs_in_request_t;
    8686
     
    9191        VFS_OUT_TRUNCATE,
    9292        VFS_OUT_CLOSE,
     93        VFS_OUT_MOUNT,
    9394        VFS_OUT_MOUNTED,
     95        VFS_OUT_UNMOUNT,
    9496        VFS_OUT_UNMOUNTED,
    95         VFS_OUT_GET_SIZE,
    96         VFS_OUT_IS_EMPTY,
    9797        VFS_OUT_SYNC,
    9898        VFS_OUT_STAT,
    9999        VFS_OUT_LOOKUP,
    100         VFS_OUT_LINK,
    101100        VFS_OUT_DESTROY,
    102101        VFS_OUT_STATFS,
     
    128127
    129128/**
    130  * Lookup will not cross any mount points.
    131  * If the lookup would have to cross a mount point, it returns EXDEV instead.
     129 * Lookup will succeed only if the object is a root directory. The flag is
     130 * mutually exclusive with L_FILE and L_MP.
    132131 */
    133 #define L_DISABLE_MOUNTS        4
     132#define L_ROOT                  4
    134133
    135134/**
     
    152151
    153152/**
     153 * L_LINK is used for linking to an already existing nodes.
     154 */
     155#define L_LINK                  64
     156
     157/**
    154158 * L_UNLINK is used to remove leaves from the file system namespace. This flag
    155159 * cannot be passed directly by the client, but will be set by VFS during
     
    166170#define L_OPEN                  256
    167171
    168 /*
    169  * Walk flags.
    170  */
    171 enum {
    172         /**
    173          * WALK_PARTIAL requests that if the whole path cannot be traversed,
    174          * the walk() operation should return the last visited file, along
    175          * with an indication of how many directories have been traversed.
    176          */
    177         //WALK_PARTIAL = (1 << 0),
    178        
    179         WALK_MAY_CREATE = (1 << 1),
    180         WALK_MUST_CREATE = (1 << 2),
    181        
    182         WALK_REGULAR = (1 << 3),
    183         WALK_DIRECTORY = (1 << 4),
    184        
    185         WALK_ALL_FLAGS = WALK_MAY_CREATE | WALK_MUST_CREATE | WALK_REGULAR | WALK_DIRECTORY,
    186 };
    187 
    188 enum {
    189         MODE_READ = 1,
    190         MODE_WRITE = 2,
    191         MODE_APPEND = 4,
    192 };
    193 
    194172#endif
    195173
  • uspace/lib/c/include/vfs/vfs.h

    r1dff985 r5b46ec8  
    6464extern void vfs_exchange_end(async_exch_t *);
    6565
    66 extern int _vfs_walk(int parent, const char *path, int flags);
    67 extern int _vfs_open(int file, int mode);
    68 
    6966#endif
    7067
  • uspace/lib/fs/libfs.c

    r1dff985 r5b46ec8  
    3636
    3737#include "libfs.h"
     38#include "../../srv/vfs/vfs.h"
    3839#include <macros.h>
    3940#include <errno.h>
     
    4647#include <sys/statfs.h>
    4748#include <stdlib.h>
    48 #include <fibril_synch.h>
    4949
    5050#define on_error(rc, action) \
     
    6363        } while (0)
    6464
    65 #define DPRINTF(...)
    66 
    67 #define LOG_EXIT(rc) \
    68         DPRINTF("Exiting %s() with rc = %d at line %d\n", __FUNC__, rc, __LINE__);
    69 
    7065static fs_reg_t reg;
    7166
     
    7368static libfs_ops_t *libfs_ops = NULL;
    7469
    75 static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    76     ipc_call_t *);
     70static void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
     71static void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
    7772static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    7873    ipc_call_t *);
     
    109104}
    110105
     106static void vfs_out_mount(ipc_callid_t rid, ipc_call_t *req)
     107{
     108        libfs_mount(libfs_ops, reg.fs_handle, rid, req);
     109}
     110
    111111static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req)
    112112{
     
    119119}
    120120
    121 static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req)
    122 {
    123         libfs_link(libfs_ops, reg.fs_handle, rid, req);
     121static void vfs_out_unmount(ipc_callid_t rid, ipc_call_t *req)
     122{
     123               
     124        libfs_unmount(libfs_ops, rid, req);
    124125}
    125126
     
    192193        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    193194        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
    194 
    195195        int rc;
    196         fs_node_t *node = NULL;
    197         rc = libfs_ops->node_get(&node, service_id, index);
    198         if (rc == EOK && node != NULL) {
    199                 bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
    200                 libfs_ops->node_put(node);
    201                 if (destroy) {
    202                         rc = vfs_out_ops->destroy(service_id, index);
    203                 }
    204         }
     196
     197        rc = vfs_out_ops->destroy(service_id, index);
     198
    205199        async_answer_0(rid, rc);
    206200}
     
    231225        libfs_statfs(libfs_ops, reg.fs_handle, rid, req);
    232226}
    233 
    234 static void vfs_out_get_size(ipc_callid_t rid, ipc_call_t *req)
    235 {
    236         service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    237         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
    238         int rc;
    239 
    240         fs_node_t *node = NULL;
    241         rc = libfs_ops->node_get(&node, service_id, index);
    242         if (rc != EOK) {
    243                 async_answer_0(rid, rc);
    244         }
    245         if (node == NULL) {
    246                 async_answer_0(rid, EINVAL);
    247         }
    248        
    249         uint64_t size = libfs_ops->size_get(node);
    250         libfs_ops->node_put(node);
    251        
    252         async_answer_2(rid, EOK, LOWER32(size), UPPER32(size));
    253 }
    254 
    255 static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req)
    256 {
    257         service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    258         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
    259         int rc;
    260 
    261         fs_node_t *node = NULL;
    262         rc = libfs_ops->node_get(&node, service_id, index);
    263         if (rc != EOK) {
    264                 async_answer_0(rid, rc);
    265         }
    266         if (node == NULL) {
    267                 async_answer_0(rid, EINVAL);
    268         }
    269        
    270         bool children = false;
    271         rc = libfs_ops->has_children(&children, node);
    272         libfs_ops->node_put(node);
    273        
    274         if (rc != EOK) {
    275                 async_answer_0(rid, rc);
    276         }
    277         async_answer_0(rid, children ? ENOTEMPTY : EOK);
    278 }
    279 
    280227static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    281228{
     
    300247                        vfs_out_mounted(callid, &call);
    301248                        break;
     249                case VFS_OUT_MOUNT:
     250                        vfs_out_mount(callid, &call);
     251                        break;
    302252                case VFS_OUT_UNMOUNTED:
    303253                        vfs_out_unmounted(callid, &call);
    304254                        break;
    305                 case VFS_OUT_LINK:
    306                         vfs_out_link(callid, &call);
     255                case VFS_OUT_UNMOUNT:
     256                        vfs_out_unmount(callid, &call);
    307257                        break;
    308258                case VFS_OUT_LOOKUP:
     
    335285                case VFS_OUT_STATFS:
    336286                        vfs_out_statfs(callid, &call);
    337                         break;
    338                 case VFS_OUT_GET_SIZE:
    339                         vfs_out_get_size(callid, &call);
    340                         break;
    341                 case VFS_OUT_IS_EMPTY:
    342                         vfs_out_is_empty(callid, &call);
    343287                        break;
    344288                default:
     
    439383}
    440384
     385void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
     386    ipc_call_t *req)
     387{
     388        service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
     389        fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
     390        fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*req);
     391        service_id_t mr_service_id = (service_id_t) IPC_GET_ARG4(*req);
     392       
     393        async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL);
     394        if (mountee_sess == NULL) {
     395                async_answer_0(rid, EINVAL);
     396                return;
     397        }
     398       
     399        fs_node_t *fn;
     400        int res = ops->node_get(&fn, mp_service_id, mp_fs_index);
     401        if ((res != EOK) || (!fn)) {
     402                async_hangup(mountee_sess);
     403                async_data_write_void(combine_rc(res, ENOENT));
     404                async_answer_0(rid, combine_rc(res, ENOENT));
     405                return;
     406        }
     407       
     408        if (fn->mp_data.mp_active) {
     409                async_hangup(mountee_sess);
     410                (void) ops->node_put(fn);
     411                async_data_write_void(EBUSY);
     412                async_answer_0(rid, EBUSY);
     413                return;
     414        }
     415       
     416        async_exch_t *exch = async_exchange_begin(mountee_sess);
     417        async_sess_t *sess = async_clone_establish(EXCHANGE_PARALLEL, exch);
     418       
     419        if (!sess) {
     420                async_exchange_end(exch);
     421                async_hangup(mountee_sess);
     422                (void) ops->node_put(fn);
     423                async_data_write_void(errno);
     424                async_answer_0(rid, errno);
     425                return;
     426        }
     427       
     428        ipc_call_t answer;
     429        int rc = async_data_write_forward_1_1(exch, VFS_OUT_MOUNTED,
     430            mr_service_id, &answer);
     431        async_exchange_end(exch);
     432       
     433        if (rc == EOK) {
     434                fn->mp_data.mp_active = true;
     435                fn->mp_data.fs_handle = mr_fs_handle;
     436                fn->mp_data.service_id = mr_service_id;
     437                fn->mp_data.sess = mountee_sess;
     438        }
     439       
     440        /*
     441         * Do not release the FS node so that it stays in memory.
     442         */
     443        async_answer_4(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
     444            IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
     445}
     446
     447void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *req)
     448{
     449        service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
     450        fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
     451        fs_node_t *fn;
     452        int res;
     453
     454        res = ops->node_get(&fn, mp_service_id, mp_fs_index);
     455        if ((res != EOK) || (!fn)) {
     456                async_answer_0(rid, combine_rc(res, ENOENT));
     457                return;
     458        }
     459
     460        /*
     461         * We are clearly expecting to find the mount point active.
     462         */
     463        if (!fn->mp_data.mp_active) {
     464                (void) ops->node_put(fn);
     465                async_answer_0(rid, EINVAL);
     466                return;
     467        }
     468
     469        /*
     470         * Tell the mounted file system to unmount.
     471         */
     472        async_exch_t *exch = async_exchange_begin(fn->mp_data.sess);
     473        res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.service_id);
     474        async_exchange_end(exch);
     475
     476        /*
     477         * If everything went well, perform the clean-up on our side.
     478         */
     479        if (res == EOK) {
     480                async_hangup(fn->mp_data.sess);
     481                fn->mp_data.mp_active = false;
     482                fn->mp_data.fs_handle = 0;
     483                fn->mp_data.service_id = 0;
     484                fn->mp_data.sess = NULL;
     485               
     486                /* Drop the reference created in libfs_mount(). */
     487                (void) ops->node_put(fn);
     488        }
     489
     490        (void) ops->node_put(fn);
     491        async_answer_0(rid, res);
     492}
     493
    441494static char plb_get_char(unsigned pos)
    442495{
    443496        return reg.plb_ro[pos % PLB_SIZE];
    444 }
    445 
    446 static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos, unsigned last)
    447 {
    448         unsigned pos = *ppos;
    449         unsigned size = 0;
    450        
    451         if (pos == last) {
    452                 *sz = 0;
    453                 return ERANGE;
    454         }
    455 
    456         char c = plb_get_char(pos);
    457         if (c == '/') {
    458                 pos++;
    459         }
    460        
    461         for (int i = 0; i <= NAME_MAX; i++) {
    462                 c = plb_get_char(pos);
    463                 if (pos == last || c == '/') {
    464                         dest[i] = 0;
    465                         *ppos = pos;
    466                         *sz = size;
    467                         return EOK;
    468                 }
    469                 dest[i] = c;
    470                 pos++;
    471                 size++;
    472         }
    473         return ENAMETOOLONG;
    474 }
    475 
    476 static int receive_fname(char *buffer)
    477 {
    478         size_t size;
    479         ipc_callid_t wcall;
    480        
    481         if (!async_data_write_receive(&wcall, &size)) {
    482                 return ENOENT;
    483         }
    484         if (size > NAME_MAX + 1) {
    485                 async_answer_0(wcall, ERANGE);
    486                 return ERANGE;
    487         }
    488         return async_data_write_finalize(wcall, buffer, size);
    489 }
    490 
    491 /** Link a file at a path.
    492  */
    493 void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, ipc_call_t *req)
    494 {
    495         service_id_t parent_sid = IPC_GET_ARG1(*req);
    496         fs_index_t parent_index = IPC_GET_ARG2(*req);
    497         fs_index_t child_index = IPC_GET_ARG3(*req);
    498        
    499         char component[NAME_MAX + 1];
    500         int rc = receive_fname(component);
    501         if (rc != EOK) {
    502                 async_answer_0(rid, rc);
    503                 return;
    504         }
    505 
    506         fs_node_t *parent = NULL;
    507         rc = ops->node_get(&parent, parent_sid, parent_index);
    508         if (parent == NULL) {
    509                 async_answer_0(rid, rc == EOK ? EBADF : rc);
    510                 return;
    511         }
    512        
    513         fs_node_t *child = NULL;
    514         rc = ops->node_get(&child, parent_sid, child_index);
    515         if (child == NULL) {
    516                 async_answer_0(rid, rc == EOK ? EBADF : rc);
    517                 ops->node_put(parent);
    518                 return;
    519         }
    520        
    521         rc = ops->link(parent, child, component);
    522         ops->node_put(parent);
    523         ops->node_put(child);
    524         async_answer_0(rid, rc);
    525497}
    526498
     
    541513    ipc_call_t *req)
    542514{
    543         unsigned first = IPC_GET_ARG1(*req);
    544         unsigned len = IPC_GET_ARG2(*req);
     515        unsigned int first = IPC_GET_ARG1(*req);
     516        unsigned int last = IPC_GET_ARG2(*req);
     517        unsigned int next = first;
    545518        service_id_t service_id = IPC_GET_ARG3(*req);
    546         fs_index_t index = IPC_GET_ARG4(*req);
    547         int lflag = IPC_GET_ARG5(*req);
    548        
    549         assert((int) index != -1);
    550        
    551         DPRINTF("Entered libfs_lookup()\n");
    552        
    553         // TODO: Validate flags.
    554        
    555         unsigned next = first;
    556         unsigned last = first + len;
    557        
     519        int lflag = IPC_GET_ARG4(*req);
     520        fs_index_t index = IPC_GET_ARG5(*req);
    558521        char component[NAME_MAX + 1];
     522        int len;
    559523        int rc;
     524       
     525        if (last < next)
     526                last += PLB_SIZE;
    560527       
    561528        fs_node_t *par = NULL;
    562529        fs_node_t *cur = NULL;
    563530        fs_node_t *tmp = NULL;
    564         unsigned clen = 0;
    565        
    566         rc = ops->node_get(&cur, service_id, index);
    567         if (rc != EOK) {
    568                 async_answer_0(rid, rc);
    569                 LOG_EXIT(rc);
    570                 goto out;
    571         }
    572        
    573         assert(cur != NULL);
    574        
    575         /* Find the file and its parent. */
    576        
    577         unsigned last_next = 0;
    578        
    579         while (next != last) {
    580                 if (cur == NULL) {
    581                         assert(par != NULL);
    582                         goto out1;
     531       
     532        rc = ops->root_get(&cur, service_id);
     533        on_error(rc, goto out_with_answer);
     534       
     535        if (cur->mp_data.mp_active) {
     536                async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
     537                async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
     538                    cur->mp_data.service_id, lflag, index,
     539                    IPC_FF_ROUTE_FROM_ME);
     540                async_exchange_end(exch);
     541               
     542                (void) ops->node_put(cur);
     543                return;
     544        }
     545       
     546        /* Eat slash */
     547        if (plb_get_char(next) == '/')
     548                next++;
     549       
     550        while (next <= last) {
     551                bool has_children;
     552               
     553                rc = ops->has_children(&has_children, cur);
     554                on_error(rc, goto out_with_answer);
     555                if (!has_children)
     556                        break;
     557               
     558                /* Collect the component */
     559                len = 0;
     560                while ((next <= last) && (plb_get_char(next) != '/')) {
     561                        if (len + 1 == NAME_MAX) {
     562                                /* Component length overflow */
     563                                async_answer_0(rid, ENAMETOOLONG);
     564                                goto out;
     565                        }
     566                        component[len++] = plb_get_char(next);
     567                        /* Process next character */
     568                        next++;
    583569                }
    584 
    585                 if (!ops->is_directory(cur)) {
    586                         async_answer_0(rid, ENOTDIR);
    587                         LOG_EXIT(ENOTDIR);
     570               
     571                assert(len);
     572                component[len] = '\0';
     573                /* Eat slash */
     574                next++;
     575               
     576                /* Match the component */
     577                rc = ops->match(&tmp, cur, component);
     578                on_error(rc, goto out_with_answer);
     579               
     580                /*
     581                 * If the matching component is a mount point, there are two
     582                 * legitimate semantics of the lookup operation. The first is
     583                 * the commonly used one in which the lookup crosses each mount
     584                 * point into the mounted file system. The second semantics is
     585                 * used mostly during unmount() and differs from the first one
     586                 * only in that the last mount point in the looked up path,
     587                 * which is also its last component, is not crossed.
     588                 */
     589
     590                if ((tmp) && (tmp->mp_data.mp_active) &&
     591                    (!(lflag & L_MP) || (next <= last))) {
     592                        if (next > last)
     593                                next = last = first;
     594                        else
     595                                next--;
     596                       
     597                        async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
     598                        async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
     599                            last, tmp->mp_data.service_id, lflag, index,
     600                            IPC_FF_ROUTE_FROM_ME);
     601                        async_exchange_end(exch);
     602                       
     603                        (void) ops->node_put(cur);
     604                        (void) ops->node_put(tmp);
     605                        if (par)
     606                                (void) ops->node_put(par);
     607                        return;
     608                }
     609               
     610                /* Handle miss: match amongst siblings */
     611                if (!tmp) {
     612                        if (next <= last) {
     613                                /* There are unprocessed components */
     614                                async_answer_0(rid, ENOENT);
     615                                goto out;
     616                        }
     617                       
     618                        /* Miss in the last component */
     619                        if (lflag & (L_CREATE | L_LINK)) {
     620                                /* Request to create a new link */
     621                                if (!ops->is_directory(cur)) {
     622                                        async_answer_0(rid, ENOTDIR);
     623                                        goto out;
     624                                }
     625                               
     626                                fs_node_t *fn;
     627                                if (lflag & L_CREATE)
     628                                        rc = ops->create(&fn, service_id,
     629                                            lflag);
     630                                else
     631                                        rc = ops->node_get(&fn, service_id,
     632                                            index);
     633                                on_error(rc, goto out_with_answer);
     634                               
     635                                if (fn) {
     636                                        rc = ops->link(cur, fn, component);
     637                                        if (rc != EOK) {
     638                                                if (lflag & L_CREATE)
     639                                                        (void) ops->destroy(fn);
     640                                                else
     641                                                        (void) ops->node_put(fn);
     642                                                async_answer_0(rid, rc);
     643                                        } else {
     644                                                (void) ops->node_put(cur);
     645                                                cur = fn;
     646                                                goto out_with_answer;
     647                                        }
     648                                } else
     649                                        async_answer_0(rid, ENOSPC);
     650                               
     651                                goto out;
     652                        }
     653                       
     654                        async_answer_0(rid, ENOENT);
    588655                        goto out;
    589656                }
    590657               
    591                 last_next = next;
    592                 /* Collect the component */
    593                 rc = plb_get_component(component, &clen, &next, last);
    594                 assert(rc != ERANGE);
    595                 if (rc != EOK) {
    596                         async_answer_0(rid, rc);
    597                         LOG_EXIT(rc);
    598                         goto out;
    599                 }
    600                
    601                 if (clen == 0) {
    602                         /* The path is just "/". */
    603                         break;
    604                 }
    605                
    606                 assert(component[clen] == 0);
    607                
    608                 /* Match the component */
    609                 rc = ops->match(&tmp, cur, component);
    610                 if (rc != EOK) {
    611                         async_answer_0(rid, rc);
    612                         LOG_EXIT(rc);
    613                         goto out;
    614                 }
    615                
    616                 /* Descend one level */
    617658                if (par) {
    618659                        rc = ops->node_put(par);
    619                         if (rc != EOK) {
    620                                 async_answer_0(rid, rc);
    621                                 LOG_EXIT(rc);
    622                                 goto out;
    623                         }
     660                        on_error(rc, goto out_with_answer);
    624661                }
    625662               
     663                /* Descend one level */
    626664                par = cur;
    627665                cur = tmp;
     
    629667        }
    630668       
    631         /* At this point, par is either NULL or a directory.
    632          * If cur is NULL, the looked up file does not exist yet.
    633          */
    634          
    635         assert(par == NULL || ops->is_directory(par));
    636         assert(par != NULL || cur != NULL);
    637        
    638         /* Check for some error conditions. */
    639        
    640         if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
    641                 async_answer_0(rid, EISDIR);
    642                 LOG_EXIT(EISDIR);
    643                 goto out;
    644         }
    645        
    646         if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
    647                 async_answer_0(rid, ENOTDIR);
    648                 LOG_EXIT(ENOTDIR);
    649                 goto out;
    650         }
    651        
    652         /* Unlink. */
    653        
    654         if (lflag & L_UNLINK) {
    655                 if (!cur) {
    656                         async_answer_0(rid, ENOENT);
    657                         LOG_EXIT(ENOENT);
    658                         goto out;
    659                 }
    660                 if (!par) {
    661                         async_answer_0(rid, EINVAL);
    662                         LOG_EXIT(EINVAL);
    663                         goto out;
    664                 }
    665                
    666                 rc = ops->unlink(par, cur, component);
    667                 if (rc == EOK) {
    668                         int64_t size = ops->size_get(cur);
    669                         int32_t lsize = LOWER32(size);
    670                         if (lsize != size) {
    671                                 lsize = -1;
    672                         }
    673                        
    674                         async_answer_5(rid, fs_handle, service_id,
    675                             ops->index_get(cur), last, lsize,
    676                             ops->is_directory(cur));
    677                         LOG_EXIT(EOK);
    678                 } else {
    679                         async_answer_0(rid, rc);
    680                         LOG_EXIT(rc);
    681                 }
    682                 goto out;
    683         }
    684        
    685         /* Create. */
    686        
    687         if (lflag & L_CREATE) {
    688                 if (cur && (lflag & L_EXCLUSIVE)) {
    689                         async_answer_0(rid, EEXIST);
    690                         LOG_EXIT(EEXIST);
    691                         goto out;
    692                 }
    693        
    694                 if (!cur) {
    695                         rc = ops->create(&cur, service_id, lflag & (L_FILE|L_DIRECTORY));
    696                         if (rc != EOK) {
    697                                 async_answer_0(rid, rc);
    698                                 LOG_EXIT(rc);
    699                                 goto out;
    700                         }
    701                         if (!cur) {
    702                                 async_answer_0(rid, ENOSPC);
    703                                 LOG_EXIT(ENOSPC);
     669        /* Handle miss: excessive components */
     670        if (next <= last) {
     671                bool has_children;
     672                rc = ops->has_children(&has_children, cur);
     673                on_error(rc, goto out_with_answer);
     674               
     675                if (has_children)
     676                        goto skip_miss;
     677               
     678                if (lflag & (L_CREATE | L_LINK)) {
     679                        if (!ops->is_directory(cur)) {
     680                                async_answer_0(rid, ENOTDIR);
    704681                                goto out;
    705682                        }
    706683                       
    707                         rc = ops->link(par, cur, component);
    708                         if (rc != EOK) {
    709                                 (void) ops->destroy(cur);
    710                                 cur = NULL;
    711                                 async_answer_0(rid, rc);
    712                                 LOG_EXIT(rc);
    713                                 goto out;
     684                        /* Collect next component */
     685                        len = 0;
     686                        while (next <= last) {
     687                                if (plb_get_char(next) == '/') {
     688                                        /* More than one component */
     689                                        async_answer_0(rid, ENOENT);
     690                                        goto out;
     691                                }
     692                               
     693                                if (len + 1 == NAME_MAX) {
     694                                        /* Component length overflow */
     695                                        async_answer_0(rid, ENAMETOOLONG);
     696                                        goto out;
     697                                }
     698                               
     699                                component[len++] = plb_get_char(next);
     700                                /* Process next character */
     701                                next++;
    714702                        }
    715                 }
    716         }
    717        
    718         /* Return. */
    719 out1:
    720         if (!cur) {
    721                 async_answer_5(rid, fs_handle, service_id,
    722                         ops->index_get(par), last_next, -1, true);
    723                 LOG_EXIT(EOK);
    724                 goto out;
    725         }
    726        
    727         if (lflag & L_OPEN) {
    728                 rc = ops->node_open(cur);
    729                 if (rc != EOK) {
    730                         async_answer_0(rid, rc);
    731                         LOG_EXIT(rc);
     703                       
     704                        assert(len);
     705                        component[len] = '\0';
     706                       
     707                        fs_node_t *fn;
     708                        if (lflag & L_CREATE)
     709                                rc = ops->create(&fn, service_id, lflag);
     710                        else
     711                                rc = ops->node_get(&fn, service_id, index);
     712                        on_error(rc, goto out_with_answer);
     713                       
     714                        if (fn) {
     715                                rc = ops->link(cur, fn, component);
     716                                if (rc != EOK) {
     717                                        if (lflag & L_CREATE)
     718                                                (void) ops->destroy(fn);
     719                                        else
     720                                                (void) ops->node_put(fn);
     721                                        async_answer_0(rid, rc);
     722                                } else {
     723                                        (void) ops->node_put(cur);
     724                                        cur = fn;
     725                                        goto out_with_answer;
     726                                }
     727                        } else
     728                                async_answer_0(rid, ENOSPC);
     729                       
    732730                        goto out;
    733731                }
    734         }
    735        
    736         int64_t size = ops->size_get(cur);
    737         int32_t lsize = LOWER32(size);
    738         if (lsize != size) {
    739                 lsize = -1;
    740         }
    741        
    742         async_answer_5(rid, fs_handle, service_id, ops->index_get(cur), last,
    743             lsize, ops->is_directory(cur));
    744        
    745         LOG_EXIT(EOK);
     732               
     733                async_answer_0(rid, ENOENT);
     734                goto out;
     735        }
     736       
     737skip_miss:
     738       
     739        /* Handle hit */
     740        if (lflag & L_UNLINK) {
     741                unsigned int old_lnkcnt = ops->lnkcnt_get(cur);
     742                rc = ops->unlink(par, cur, component);
     743               
     744                if (rc == EOK) {
     745                        aoff64_t size = ops->size_get(cur);
     746                        async_answer_5(rid, fs_handle, service_id,
     747                            ops->index_get(cur), LOWER32(size), UPPER32(size),
     748                            old_lnkcnt);
     749                } else
     750                        async_answer_0(rid, rc);
     751               
     752                goto out;
     753        }
     754       
     755        if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
     756            (lflag & L_LINK)) {
     757                async_answer_0(rid, EEXIST);
     758                goto out;
     759        }
     760       
     761        if ((lflag & L_FILE) && (ops->is_directory(cur))) {
     762                async_answer_0(rid, EISDIR);
     763                goto out;
     764        }
     765       
     766        if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
     767                async_answer_0(rid, ENOTDIR);
     768                goto out;
     769        }
     770
     771        if ((lflag & L_ROOT) && par) {
     772                async_answer_0(rid, EINVAL);
     773                goto out;
     774        }
     775       
     776out_with_answer:
     777       
     778        if (rc == EOK) {
     779                if (lflag & L_OPEN)
     780                        rc = ops->node_open(cur);
     781               
     782                if (rc == EOK) {
     783                        aoff64_t size = ops->size_get(cur);
     784                        async_answer_5(rid, fs_handle, service_id,
     785                            ops->index_get(cur), LOWER32(size), UPPER32(size),
     786                            ops->lnkcnt_get(cur));
     787                } else
     788                        async_answer_0(rid, rc);
     789               
     790        } else
     791                async_answer_0(rid, rc);
     792       
    746793out:
    747         if (par) {
     794       
     795        if (par)
    748796                (void) ops->node_put(par);
    749         }
    750        
    751         if (cur) {
     797       
     798        if (cur)
    752799                (void) ops->node_put(cur);
    753         }
    754        
    755         if (tmp) {
     800       
     801        if (tmp)
    756802                (void) ops->node_put(tmp);
    757         }
    758803}
    759804
  • uspace/lib/fs/libfs.h

    r1dff985 r5b46ec8  
    5656
    5757typedef struct {
     58        bool mp_active;
     59        async_sess_t *sess;
     60        fs_handle_t fs_handle;
     61        service_id_t service_id;
     62} mp_data_t;
     63
     64typedef struct {
     65        mp_data_t mp_data;  /**< Mount point info. */
    5866        void *data;         /**< Data of the file system implementation. */
    5967} fs_node_t;
  • uspace/srv/vfs/vfs.c

    r1dff985 r5b46ec8  
    104104                        vfs_unmount_srv(callid, &call);
    105105                        break;
    106                 case VFS_IN_WALK:
    107                         vfs_walk(callid, &call);
    108                         break;
    109                 case VFS_IN_OPEN2:
    110                         vfs_open2(callid, &call);
     106                case VFS_IN_OPEN:
     107                        vfs_open(callid, &call);
    111108                        break;
    112109                case VFS_IN_CLOSE:
     
    128125                        vfs_fstat(callid, &call);
    129126                        break;
    130                 case VFS_IN_UNLINK2:
    131                         vfs_unlink2(callid, &call);
     127                case VFS_IN_STAT:
     128                        vfs_stat(callid, &call);
     129                        break;
     130                case VFS_IN_MKDIR:
     131                        vfs_mkdir(callid, &call);
     132                        break;
     133                case VFS_IN_UNLINK:
     134                        vfs_unlink(callid, &call);
    132135                        break;
    133136                case VFS_IN_RENAME:
  • uspace/srv/vfs/vfs.h

    r1dff985 r5b46ec8  
    9494        vfs_node_type_t type;
    9595        aoff64_t size;
     96        unsigned int lnkcnt;
    9697} vfs_lookup_res_t;
    9798
     
    100101 * which may be associated with it.
    101102 */
    102 typedef struct _vfs_node {
     103typedef struct {
    103104        VFS_TRIPLET;            /**< Identity of the node. */
    104105
     
    109110        unsigned refcnt;
    110111       
     112        /** Number of names this node has in the file system namespace. */
     113        unsigned lnkcnt;
     114
    111115        ht_link_t nh_link;              /**< Node hash-table link. */
    112116
    113117        vfs_node_type_t type;   /**< Partial info about the node type. */
    114118
    115         int64_t size;           /**< Cached size if the node is a file. */
     119        aoff64_t size;          /**< Cached size if the node is a file. */
    116120
    117121        /**
     
    119123         */
    120124        fibril_rwlock_t contents_rwlock;
    121        
    122         struct _vfs_node *mount;
    123125} vfs_node_t;
    124126
     
    136138        unsigned refcnt;
    137139
    138         int permissions;
    139         bool open_read;
    140         bool open_write;
    141 
    142140        /** Append on write. */
    143141        bool append;
     
    178176extern vfs_info_t *fs_handle_to_info(fs_handle_t);
    179177
    180 extern int vfs_lookup_internal(vfs_node_t *, char *, int, vfs_lookup_res_t *);
    181 extern int vfs_link_internal(vfs_node_t *, char *, vfs_triplet_t *);
     178extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *,
     179    vfs_pair_t *, ...);
    182180
    183181extern bool vfs_nodes_init(void);
    184182extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *);
    185 extern vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result);
    186183extern void vfs_node_put(vfs_node_t *);
    187184extern void vfs_node_forget(vfs_node_t *);
    188185extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t);
    189186
    190 extern int64_t vfs_node_get_size(vfs_node_t *node);
    191 extern bool vfs_node_has_children(vfs_node_t *node);
    192187
    193188#define MAX_OPEN_FILES  128
     
    212207extern void vfs_mount_srv(ipc_callid_t, ipc_call_t *);
    213208extern void vfs_unmount_srv(ipc_callid_t, ipc_call_t *);
     209extern void vfs_open(ipc_callid_t, ipc_call_t *);
    214210extern void vfs_sync(ipc_callid_t, ipc_call_t *);
    215211extern void vfs_dup(ipc_callid_t, ipc_call_t *);
     
    220216extern void vfs_truncate(ipc_callid_t, ipc_call_t *);
    221217extern void vfs_fstat(ipc_callid_t, ipc_call_t *);
     218extern void vfs_stat(ipc_callid_t, ipc_call_t *);
     219extern void vfs_mkdir(ipc_callid_t, ipc_call_t *);
     220extern void vfs_unlink(ipc_callid_t, ipc_call_t *);
    222221extern void vfs_rename(ipc_callid_t, ipc_call_t *);
    223222extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *);
     
    234233extern int vfs_rdwr_internal(int, bool, rdwr_io_chunk_t *);
    235234
    236 extern void vfs_walk(ipc_callid_t, ipc_call_t *);
    237 extern void vfs_open2(ipc_callid_t, ipc_call_t *);
    238 extern void vfs_unlink2(ipc_callid_t, ipc_call_t *);
    239 
    240235#endif
    241236
  • uspace/srv/vfs/vfs_file.c

    r1dff985 r5b46ec8  
    177177                 * endpoint FS and drop our reference to the underlying VFS node.
    178178                 */
    179                 if (file->open_read || file->open_write) {
    180                         rc = vfs_file_close_remote(file);
    181                 }
     179                rc = vfs_file_close_remote(file);
    182180                vfs_node_delref(file->node);
    183181                free(file);
     
    395393         */
    396394        acceptor_file->node = donor_file->node;
    397         acceptor_file->permissions = donor_file->permissions;
    398        
    399         // TODO: The file should not inherit its open status, but clients depend on this.
     395        acceptor_file->append = donor_file->append;
    400396        acceptor_file->pos = donor_file->pos;
    401         acceptor_file->append = donor_file->append;
    402         acceptor_file->open_read = donor_file->open_read;
    403         acceptor_file->open_write = donor_file->open_write;
    404397
    405398out:
  • uspace/srv/vfs/vfs_lookup.c

    r1dff985 r5b46ec8  
    4646#include <adt/list.h>
    4747#include <vfs/canonify.h>
    48 #include <dirent.h>
    49 #include <assert.h>
    50 
    51 #define DPRINTF(...)
    5248
    5349#define min(a, b)  ((a) < (b) ? (a) : (b))
     
    5753uint8_t *plb = NULL;
    5854
    59 static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start, size_t len)
     55/** Perform a path lookup.
     56 *
     57 * @param path    Path to be resolved; it must be a NULL-terminated
     58 *                string.
     59 * @param lflag   Flags to be used during lookup.
     60 * @param result  Empty structure where the lookup result will be stored.
     61 *                Can be NULL.
     62 * @param altroot If non-empty, will be used instead of rootfs as the root
     63 *                of the whole VFS tree.
     64 *
     65 * @return EOK on success or an error code from errno.h.
     66 *
     67 */
     68int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
     69    vfs_pair_t *altroot, ...)
    6070{
     71        vfs_pair_t *root;
     72
     73        if (altroot)
     74                root = altroot;
     75        else
     76                root = &rootfs;
     77
     78        if (!root->fs_handle)
     79                return ENOENT;
     80       
     81        size_t len;
     82        path = canonify(path, &len);
     83        if (!path)
     84                return EINVAL;
     85       
     86        fs_index_t index = 0;
     87        if (lflag & L_LINK) {
     88                va_list ap;
     89
     90                va_start(ap, altroot);
     91                index = va_arg(ap, fs_index_t);
     92                va_end(ap);
     93        }
     94       
    6195        fibril_mutex_lock(&plb_mutex);
    6296
    63         link_initialize(&entry->plb_link);
    64         entry->len = len;
     97        plb_entry_t entry;
     98        link_initialize(&entry.plb_link);
     99        entry.len = len;
    65100
    66101        size_t first;   /* the first free index */
     
    103138         */
    104139
    105         entry->index = first;
    106         entry->len = len;
     140        entry.index = first;
     141        entry.len = len;
    107142
    108143        /*
     
    110145         * buffer.
    111146         */
    112         list_append(&entry->plb_link, &plb_entries);
     147        list_append(&entry.plb_link, &plb_entries);
    113148       
    114149        fibril_mutex_unlock(&plb_mutex);
     
    123158        memcpy(plb, &path[cnt1], cnt2);
    124159
    125         *start = first;
    126         return EOK;
    127 }
    128 
    129 static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
    130 {
     160        ipc_call_t answer;
     161        async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
     162        aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first,
     163            (sysarg_t) (first + len - 1) % PLB_SIZE,
     164            (sysarg_t) root->service_id, (sysarg_t) lflag, (sysarg_t) index,
     165            &answer);
     166       
     167        sysarg_t rc;
     168        async_wait_for(req, &rc);
     169        vfs_exchange_release(exch);
     170       
    131171        fibril_mutex_lock(&plb_mutex);
    132         list_remove(&entry->plb_link);
     172        list_remove(&entry.plb_link);
    133173        /*
    134174         * Erasing the path from PLB will come handy for debugging purposes.
    135175         */
    136         size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
    137         size_t cnt2 = len - cnt1;
    138176        memset(&plb[first], 0, cnt1);
    139177        memset(plb, 0, cnt2);
    140178        fibril_mutex_unlock(&plb_mutex);
    141 }
    142 
    143 static char *_strrchr(char *path, int c)
    144 {
    145         char *res = NULL;
    146         while (*path != 0) {
    147                 if (*path == c) {
    148                         res = path;
    149                 }
    150                 path++;
    151         }
    152         return res;
    153 }
    154 
    155 int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
    156 {
    157         assert(base != NULL);
    158         assert(child != NULL);
    159         assert(base->fs_handle);
    160         assert(child->fs_handle);
    161         assert(path != NULL);
    162        
    163         vfs_lookup_res_t res;
    164         char component[NAME_MAX + 1];
    165         int rc;
    166        
    167         size_t len;
    168         char *npath = canonify(path, &len);
    169         if (!npath) {
    170                 rc = EINVAL;
    171                 goto out;
    172         }
    173         path = npath;
    174        
    175         vfs_triplet_t *triplet;
    176        
    177         char *slash = _strrchr(path, '/');
    178         if (slash && slash != path) {
    179                 if (slash[1] == 0) {
    180                         rc = EINVAL;
    181                         goto out;
    182                 }
    183                
    184                 memcpy(component, slash + 1, str_size(slash));
    185                 *slash = 0;
    186                
    187                 rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
    188                 if (rc != EOK) {
    189                         goto out;
    190                 }
    191                 triplet = &res.triplet;
    192                
    193                 *slash = '/';
    194         } else {
    195                 if (base->mount != NULL) {
    196                         rc = EINVAL;
    197                         goto out;
    198                 }
    199                
    200                 memcpy(component, path + 1, str_size(path));
    201                 triplet = (vfs_triplet_t *) base;
    202         }
    203        
    204         if (triplet->fs_handle != child->fs_handle || triplet->service_id != child->service_id) {
    205                 rc = EXDEV;
    206                 goto out;
    207         }
    208        
    209         async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
    210         aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id, triplet->index, child->index, NULL);
    211        
    212         rc = async_data_write_start(exch, component, str_size(component) + 1);
    213         sysarg_t orig_rc;
    214         async_wait_for(req, &orig_rc);
    215         vfs_exchange_release(exch);
    216         if (orig_rc != EOK) {
    217                 rc = orig_rc;
    218         }
    219        
    220 out:
    221         DPRINTF("vfs_link_internal() with path '%s' returns %d\n", path, rc);
    222         return rc;
    223 }
    224 
    225 static int out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
    226         int lflag, vfs_lookup_res_t *result)
    227 {
    228         assert(base);
    229         assert(result);
    230        
    231         sysarg_t rc;
    232         ipc_call_t answer;
    233         async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
    234         aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst, (sysarg_t) *plen,
    235             (sysarg_t) base->service_id, (sysarg_t) base->index, (sysarg_t) lflag, &answer);
    236         async_wait_for(req, &rc);
    237         vfs_exchange_release(exch);
    238        
    239         if ((int) rc < 0) {
     179       
     180        if ((int) rc < EOK)
    240181                return (int) rc;
    241         }
    242        
    243         unsigned last = *pfirst + *plen;
    244         *pfirst = IPC_GET_ARG3(answer);
    245         *plen = last - *pfirst;
     182
     183        if (!result)
     184                return EOK;
    246185       
    247186        result->triplet.fs_handle = (fs_handle_t) rc;
    248187        result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
    249188        result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
    250         result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer);
    251         result->type = IPC_GET_ARG5(answer) ? VFS_NODE_DIRECTORY : VFS_NODE_FILE;
     189        result->size =
     190            (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
     191        result->lnkcnt = (unsigned int) IPC_GET_ARG5(answer);
     192       
     193        if (lflag & L_FILE)
     194                result->type = VFS_NODE_FILE;
     195        else if (lflag & L_DIRECTORY)
     196                result->type = VFS_NODE_DIRECTORY;
     197        else
     198                result->type = VFS_NODE_UNKNOWN;
     199       
    252200        return EOK;
    253201}
    254202
    255 /** Perform a path lookup.
    256  *
    257  * @param base    The file from which to perform the lookup.
    258  * @param path    Path to be resolved; it must be a NULL-terminated
    259  *                string.
    260  * @param lflag   Flags to be used during lookup.
    261  * @param result  Empty structure where the lookup result will be stored.
    262  *                Can be NULL.
    263  *
    264  * @return EOK on success or an error code from errno.h.
    265  *
    266  */
    267 int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag, vfs_lookup_res_t *result)
    268 {
    269         assert(base != NULL);
    270         assert(path != NULL);
    271        
    272         size_t len;
    273         int rc;
    274         char *npath = canonify(path, &len);
    275         if (!npath) {
    276                 DPRINTF("vfs_lookup_internal() can't canonify path: %s\n", path);
    277                 rc = EINVAL;
    278                 return rc;
    279         }
    280         path = npath;
    281        
    282         assert(path[0] == '/');
    283        
    284         size_t first;
    285        
    286         plb_entry_t entry;
    287         rc = plb_insert_entry(&entry, path, &first, len);
    288         if (rc != EOK) {
    289                 DPRINTF("vfs_lookup_internal() can't insert entry into PLB: %d\n", rc);
    290                 return rc;
    291         }
    292        
    293         size_t next = first;
    294         size_t nlen = len;
    295        
    296         vfs_lookup_res_t res;
    297        
    298         /* Resolve path as long as there are mount points to cross. */
    299         while (nlen > 0) {
    300                 while (base->mount != NULL) {
    301                         if (lflag & L_DISABLE_MOUNTS) {
    302                                 rc = EXDEV;
    303                                 goto out;
    304                         }
    305                        
    306                         base = base->mount;
    307                 }
    308                
    309                 rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag, &res);
    310                 if (rc != EOK) {
    311                         goto out;
    312                 }
    313                
    314                 if (nlen > 0) {
    315                         base = vfs_node_peek(&res);
    316                         if (base == NULL || base->mount == NULL) {
    317                                 rc = ENOENT;
    318                                 goto out;
    319                         }
    320                         if (lflag & L_DISABLE_MOUNTS) {
    321                                 rc = EXDEV;
    322                                 goto out;
    323                         }
    324                 }
    325         }
    326        
    327         assert(nlen == 0);
    328         rc = EOK;
    329        
    330         if (result != NULL) {
    331                 /* The found file may be a mount point. Try to cross it. */
    332                 if (!(lflag & L_MP)) {
    333                         base = vfs_node_peek(&res);
    334                         if (base != NULL && base->mount != NULL) {
    335                                 while (base->mount != NULL) {
    336                                         base = base->mount;
    337                                 }
    338                                
    339                                 result->triplet = *(vfs_triplet_t *)base;
    340                                 result->type = base->type;
    341                                 result->size = base->size;                             
    342                                 goto out;
    343                         }
    344                 }
    345 
    346                 memcpy(result, &res, sizeof(vfs_lookup_res_t));
    347         }
    348        
    349 out:
    350         plb_clear_entry(&entry, first, len);
    351         DPRINTF("vfs_lookup_internal() with path '%s' returns %d\n", path, rc);
    352         return rc;
    353 }
    354 
    355203/**
    356204 * @}
  • uspace/srv/vfs/vfs_node.c

    r1dff985 r5b46ec8  
    4545#include <async.h>
    4646#include <errno.h>
    47 #include <macros.h>
    4847
    4948/** Mutex protecting the VFS node hash table. */
     
    107106void vfs_node_delref(vfs_node_t *node)
    108107{
    109         bool free_node = false;
    110        
    111         fibril_mutex_lock(&nodes_mutex);
    112        
    113         node->refcnt--;
    114         if (node->refcnt == 0) {
     108        bool free_vfs_node = false;
     109        bool free_fs_node = false;
     110       
     111        fibril_mutex_lock(&nodes_mutex);
     112       
     113        if (node->refcnt-- == 1) {
    115114               
    116115                /*
     
    120119               
    121120                hash_table_remove_item(&nodes, &node->nh_link);
    122                 free_node = true;
     121                free_vfs_node = true;
     122               
     123                if (!node->lnkcnt)
     124                        free_fs_node = true;
    123125        }
    124126       
    125127        fibril_mutex_unlock(&nodes_mutex);
    126128       
    127         if (free_node) {
     129        if (free_fs_node) {
     130               
    128131                /*
    129                  * DESTROY will free up the file's resources if there are no more hard links.
     132                 * The node is not visible in the file system namespace.
     133                 * Free up its resources.
    130134                 */
    131135               
    132136                async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    133                 async_msg_2(exch, VFS_OUT_DESTROY,
    134                         (sysarg_t) node->service_id, (sysarg_t)node->index);
     137                sysarg_t rc = async_req_2_0(exch, VFS_OUT_DESTROY,
     138                    (sysarg_t) node->service_id, (sysarg_t)node->index);
     139               
     140                assert(rc == EOK);
    135141                vfs_exchange_release(exch);
    136 
     142        }
     143       
     144        if (free_vfs_node)
    137145                free(node);
    138         }
    139146}
    140147
     
    183190                node->index = result->triplet.index;
    184191                node->size = result->size;
     192                node->lnkcnt = result->lnkcnt;
    185193                node->type = result->type;
    186194                fibril_rwlock_initialize(&node->contents_rwlock);
     
    188196        } else {
    189197                node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
     198                if (node->type == VFS_NODE_UNKNOWN &&
     199                    result->type != VFS_NODE_UNKNOWN) {
     200                        /* Upgrade the node type. */
     201                        node->type = result->type;
     202                }
    190203        }
    191204
     205        assert(node->size == result->size || node->type != VFS_NODE_FILE);
     206        assert(node->lnkcnt == result->lnkcnt);
     207        assert(node->type == result->type || result->type == VFS_NODE_UNKNOWN);
     208
    192209        _vfs_node_addref(node);
    193         fibril_mutex_unlock(&nodes_mutex);
    194 
    195         return node;
    196 }
    197 
    198 vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result)
    199 {
    200         vfs_node_t *node = NULL;
    201 
    202         fibril_mutex_lock(&nodes_mutex);
    203         ht_link_t *tmp = hash_table_find(&nodes, &result->triplet);
    204         if (tmp) {
    205                 node = hash_table_get_inst(tmp, vfs_node_t, nh_link);
    206         }
    207210        fibril_mutex_unlock(&nodes_mutex);
    208211
     
    315318}
    316319
    317 int64_t vfs_node_get_size(vfs_node_t *node)
    318 {
    319         if (node->size == -1) {
    320                 sysarg_t sz1 = 0;
    321                 sysarg_t sz2 = 0;
    322                
    323                 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    324                 (void) async_req_2_2(exch, VFS_OUT_GET_SIZE,
    325                         node->service_id, node->index, &sz1, &sz2);
    326                 vfs_exchange_release(exch);
    327                
    328                 node->size = MERGE_LOUP32(sz1, sz2);
    329         }
    330         return node->size;
    331 }
    332 
    333 bool vfs_node_has_children(vfs_node_t *node)
    334 {
    335         async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    336         int rc = async_req_2_0(exch, VFS_OUT_IS_EMPTY, node->service_id, node->index);
    337         vfs_exchange_release(exch);
    338         return rc == ENOTEMPTY;
    339 }
    340 
    341320/**
    342321 * @}
  • uspace/srv/vfs/vfs_ops.c

    r1dff985 r5b46ec8  
    6868FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
    6969
    70 vfs_node_t *root = NULL;
    71 
    72 static int vfs_connect_internal(service_id_t service_id, unsigned flags, unsigned instance,
    73         char *options, char *fsname, vfs_node_t **root)
    74 {
    75         fs_handle_t fs_handle = 0;
    76        
    77         fibril_mutex_lock(&fs_list_lock);
    78         while (1) {
    79                 fs_handle = fs_name_to_handle(instance, fsname, false);
    80                
    81                 if (fs_handle != 0 || !(flags & IPC_FLAG_BLOCKING)) {
    82                         break;
    83                 }
    84                
    85                 fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
    86         }
    87         fibril_mutex_unlock(&fs_list_lock);
    88 
    89         if (fs_handle == 0) {
    90                 return ENOENT;
    91         }
    92        
    93         /* Tell the mountee that it is being mounted. */
     70vfs_pair_t rootfs = {
     71        .fs_handle = 0,
     72        .service_id = 0
     73};
     74
     75static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
     76    fs_handle_t fs_handle, char *mp, char *opts)
     77{
     78        vfs_lookup_res_t mp_res;
     79        vfs_lookup_res_t mr_res;
     80        vfs_node_t *mp_node = NULL;
     81        vfs_node_t *mr_node;
     82        fs_index_t rindex;
     83        aoff64_t rsize;
     84        unsigned rlnkcnt;
     85        async_exch_t *exch;
     86        sysarg_t rc;
     87        aid_t msg;
    9488        ipc_call_t answer;
    95         async_exch_t *exch = vfs_exchange_grab(fs_handle);
    96         aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, &answer);
    97         /* Send the mount options */
    98         sysarg_t rc = async_data_write_start(exch, options, str_size(options));
    99         if (rc != EOK) {
    100                 async_forget(msg);
    101                 vfs_exchange_release(exch);
    102                 return rc;
    103         }
    104         async_wait_for(msg, &rc);
    105         vfs_exchange_release(exch);
    106        
    107         if (rc != EOK) {
    108                 return rc;
    109         }
    110        
    111         vfs_lookup_res_t res;
    112         res.triplet.fs_handle = fs_handle;
    113         res.triplet.service_id = service_id;
    114         res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer);
    115         res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
    116         res.type = VFS_NODE_DIRECTORY;
    117        
    118         /* Add reference to the mounted root. */
    119         *root = vfs_node_get(&res);
    120         assert(*root);
     89       
     90        /* Resolve the path to the mountpoint. */
     91        fibril_rwlock_write_lock(&namespace_rwlock);
     92        if (rootfs.fs_handle) {
     93                /* We already have the root FS. */
     94                if (str_cmp(mp, "/") == 0) {
     95                        /* Trying to mount root FS over root FS */
     96                        fibril_rwlock_write_unlock(&namespace_rwlock);
     97                        async_answer_0(rid, EBUSY);
     98                        return EBUSY;
     99                }
     100               
     101                rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
     102                if (rc != EOK) {
     103                        /* The lookup failed for some reason. */
     104                        fibril_rwlock_write_unlock(&namespace_rwlock);
     105                        async_answer_0(rid, rc);
     106                        return rc;
     107                }
     108               
     109                mp_node = vfs_node_get(&mp_res);
     110                if (!mp_node) {
     111                        fibril_rwlock_write_unlock(&namespace_rwlock);
     112                        async_answer_0(rid, ENOMEM);
     113                        return ENOMEM;
     114                }
     115               
     116                /*
     117                 * Now we hold a reference to mp_node.
     118                 * It will be dropped upon the corresponding VFS_IN_UNMOUNT.
     119                 * This prevents the mount point from being deleted.
     120                 */
     121        } else {
     122                /* We still don't have the root file system mounted. */
     123                if (str_cmp(mp, "/") == 0) {
     124                        /*
     125                         * For this simple, but important case,
     126                         * we are almost done.
     127                         */
    121128                       
    122         return EOK;
    123 }
    124 
    125 static int vfs_mount_internal(service_id_t service_id, unsigned flags, unsigned instance,
    126         char *opts, char *fs_name, char *mp)
    127 {
    128         /* Resolve the path to the mountpoint. */
    129        
    130         if (root == NULL) {
    131                 /* We still don't have the root file system mounted. */
    132                 if (str_cmp(mp, "/") != 0) {
     129                        /* Tell the mountee that it is being mounted. */
     130                        exch = vfs_exchange_grab(fs_handle);
     131                        msg = async_send_1(exch, VFS_OUT_MOUNTED,
     132                            (sysarg_t) service_id, &answer);
     133                        /* Send the mount options */
     134                        rc = async_data_write_start(exch, (void *)opts,
     135                            str_size(opts));
     136                        vfs_exchange_release(exch);
     137                       
     138                        if (rc != EOK) {
     139                                async_forget(msg);
     140                                fibril_rwlock_write_unlock(&namespace_rwlock);
     141                                async_answer_0(rid, rc);
     142                                return rc;
     143                        }
     144                        async_wait_for(msg, &rc);
     145                       
     146                        if (rc != EOK) {
     147                                fibril_rwlock_write_unlock(&namespace_rwlock);
     148                                async_answer_0(rid, rc);
     149                                return rc;
     150                        }
     151
     152                        rindex = (fs_index_t) IPC_GET_ARG1(answer);
     153                        rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
     154                            IPC_GET_ARG3(answer));
     155                        rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
     156                       
     157                        mr_res.triplet.fs_handle = fs_handle;
     158                        mr_res.triplet.service_id = service_id;
     159                        mr_res.triplet.index = rindex;
     160                        mr_res.size = rsize;
     161                        mr_res.lnkcnt = rlnkcnt;
     162                        mr_res.type = VFS_NODE_DIRECTORY;
     163                       
     164                        rootfs.fs_handle = fs_handle;
     165                        rootfs.service_id = service_id;
     166                       
     167                        /* Add reference to the mounted root. */
     168                        mr_node = vfs_node_get(&mr_res);
     169                        assert(mr_node);
     170                       
     171                        fibril_rwlock_write_unlock(&namespace_rwlock);
     172                        async_answer_0(rid, rc);
     173                        return rc;
     174                } else {
    133175                        /*
    134176                         * We can't resolve this without the root filesystem
    135177                         * being mounted first.
    136178                         */
     179                        fibril_rwlock_write_unlock(&namespace_rwlock);
     180                        async_answer_0(rid, ENOENT);
    137181                        return ENOENT;
    138182                }
    139                
    140                 return vfs_connect_internal(service_id, flags, instance, opts, fs_name, &root);
    141         }
    142        
    143         /* We already have the root FS. */
    144         if (str_cmp(mp, "/") == 0) {
    145                 /* Trying to mount root FS over root FS */
    146                 return EBUSY;
    147         }
    148        
    149         vfs_lookup_res_t mp_res;
    150         int rc = vfs_lookup_internal(root, mp, L_DIRECTORY, &mp_res);
    151         if (rc != EOK) {
    152                 /* The lookup failed. */
     183        }
     184       
     185        /*
     186         * At this point, we have all necessary pieces: file system handle
     187         * and service ID, and we know the mount point VFS node.
     188         */
     189       
     190        async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle);
     191        assert(mountee_exch);
     192       
     193        exch = vfs_exchange_grab(mp_res.triplet.fs_handle);
     194        msg = async_send_4(exch, VFS_OUT_MOUNT,
     195            (sysarg_t) mp_res.triplet.service_id,
     196            (sysarg_t) mp_res.triplet.index,
     197            (sysarg_t) fs_handle,
     198            (sysarg_t) service_id, &answer);
     199       
     200        /* Send connection */
     201        rc = async_exchange_clone(exch, mountee_exch);
     202        vfs_exchange_release(mountee_exch);
     203       
     204        if (rc != EOK) {
     205                vfs_exchange_release(exch);
     206                async_forget(msg);
     207               
     208                /* Mount failed, drop reference to mp_node. */
     209                if (mp_node)
     210                        vfs_node_put(mp_node);
     211               
     212                async_answer_0(rid, rc);
     213                fibril_rwlock_write_unlock(&namespace_rwlock);
    153214                return rc;
    154215        }
    155216       
    156         vfs_node_t *mp_node;
    157         mp_node = vfs_node_get(&mp_res);
    158         if (!mp_node) {
    159                 return ENOMEM;
    160         }
    161        
    162         if (mp_node->mount != NULL) {
    163                 return EBUSY;
    164         }
    165        
    166         if (mp_node->type != VFS_NODE_DIRECTORY) {
    167                 printf("%s node not a directory, type=%d\n", mp, mp_node->type);
    168                 return ENOTDIR;
    169         }
    170        
    171         if (vfs_node_has_children(mp_node)) {
    172                 return ENOTEMPTY;
    173         }
    174        
    175         vfs_node_t *mountee;
    176        
    177         rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, &mountee);
    178         if (rc != EOK) {
    179                 vfs_node_put(mp_node);
    180                 return ENOMEM;
    181         }
    182        
    183         mp_node->mount = mountee;
    184         /* The two references to nodes are held by the mount so that they cannot be freed.
    185          * They are removed in detach_internal().
    186          */
    187         return EOK;
     217        /* send the mount options */
     218        rc = async_data_write_start(exch, (void *) opts, str_size(opts));
     219        if (rc != EOK) {
     220                vfs_exchange_release(exch);
     221                async_forget(msg);
     222               
     223                /* Mount failed, drop reference to mp_node. */
     224                if (mp_node)
     225                        vfs_node_put(mp_node);
     226               
     227                fibril_rwlock_write_unlock(&namespace_rwlock);
     228                async_answer_0(rid, rc);
     229                return rc;
     230        }
     231       
     232        /*
     233         * Wait for the answer before releasing the exchange to avoid deadlock
     234         * in case the answer depends on further calls to the same file system.
     235         * Think of a case when mounting a FS on a file_bd backed by a file on
     236         * the same FS.
     237         */
     238        async_wait_for(msg, &rc);
     239        vfs_exchange_release(exch);
     240       
     241        if (rc == EOK) {
     242                rindex = (fs_index_t) IPC_GET_ARG1(answer);
     243                rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
     244                    IPC_GET_ARG3(answer));
     245                rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
     246               
     247                mr_res.triplet.fs_handle = fs_handle;
     248                mr_res.triplet.service_id = service_id;
     249                mr_res.triplet.index = rindex;
     250                mr_res.size = rsize;
     251                mr_res.lnkcnt = rlnkcnt;
     252                mr_res.type = VFS_NODE_DIRECTORY;
     253               
     254                /* Add reference to the mounted root. */
     255                mr_node = vfs_node_get(&mr_res);
     256                assert(mr_node);
     257        } else {
     258                /* Mount failed, drop reference to mp_node. */
     259                if (mp_node)
     260                        vfs_node_put(mp_node);
     261        }
     262       
     263        async_answer_0(rid, rc);
     264        fibril_rwlock_write_unlock(&namespace_rwlock);
     265        return rc;
    188266}
    189267
    190268void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request)
    191269{
     270        service_id_t service_id;
     271
    192272        /*
    193273         * We expect the library to do the device-name to device-handle
     
    195275         * in the request.
    196276         */
    197         service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
     277        service_id = (service_id_t) IPC_GET_ARG1(*request);
    198278       
    199279        /*
     
    221301            0, NULL);
    222302        if (rc != EOK) {
    223                 async_answer_0(rid, rc);
    224303                free(mp);
     304                async_answer_0(rid, rc);
    225305                return;
    226306        }
     
    234314            FS_NAME_MAXLEN, 0, NULL);
    235315        if (rc != EOK) {
    236                 async_answer_0(rid, rc);
    237316                free(mp);
    238317                free(opts);
    239                 return;
    240         }
    241        
     318                async_answer_0(rid, rc);
     319                return;
     320        }
     321       
     322        /*
     323         * Wait for VFS_IN_PING so that we can return an error if we don't know
     324         * fs_name.
     325         */
     326        ipc_call_t data;
     327        ipc_callid_t callid = async_get_call(&data);
     328        if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
     329                async_answer_0(callid, ENOTSUP);
     330                async_answer_0(rid, ENOTSUP);
     331                free(mp);
     332                free(opts);
     333                free(fs_name);
     334                return;
     335        }
     336
     337        /*
     338         * Check if we know a file system with the same name as is in fs_name.
     339         * This will also give us its file system handle.
     340         */
     341        fibril_mutex_lock(&fs_list_lock);
     342        fs_handle_t fs_handle;
     343recheck:
     344        fs_handle = fs_name_to_handle(instance, fs_name, false);
     345        if (!fs_handle) {
     346                if (flags & IPC_FLAG_BLOCKING) {
     347                        fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
     348                        goto recheck;
     349                }
     350               
     351                fibril_mutex_unlock(&fs_list_lock);
     352                async_answer_0(callid, ENOENT);
     353                async_answer_0(rid, ENOENT);
     354                free(mp);
     355                free(fs_name);
     356                free(opts);
     357                return;
     358        }
     359        fibril_mutex_unlock(&fs_list_lock);
     360
    242361        /* Add the filesystem info to the list of mounted filesystems */
    243362        mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t));
    244363        if (!mtab_ent) {
     364                async_answer_0(callid, ENOMEM);
    245365                async_answer_0(rid, ENOMEM);
    246366                free(mp);
     
    249369                return;
    250370        }
    251        
    252         /* Mount the filesystem. */
    253         fibril_rwlock_write_lock(&namespace_rwlock);
    254         rc = vfs_mount_internal(service_id, flags, instance, opts, fs_name, mp);
    255         fibril_rwlock_write_unlock(&namespace_rwlock);
     371
     372        /* Do the mount */
     373        rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
     374        if (rc != EOK) {
     375                async_answer_0(callid, ENOTSUP);
     376                async_answer_0(rid, ENOTSUP);
     377                free(mtab_ent);
     378                free(mp);
     379                free(opts);
     380                free(fs_name);
     381                return;
     382        }
    256383
    257384        /* Add the filesystem info to the list of mounted filesystems */
    258         if (rc == EOK) {
    259                 str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp);
    260                 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
    261                 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
    262                 mtab_ent->instance = instance;
    263                 mtab_ent->service_id = service_id;
    264 
    265                 link_initialize(&mtab_ent->link);
    266 
    267                 fibril_mutex_lock(&mtab_list_lock);
    268                 list_append(&mtab_ent->link, &mtab_list);
    269                 mtab_size++;
    270                 fibril_mutex_unlock(&mtab_list_lock);
    271         }
    272        
    273         async_answer_0(rid, rc);
     385
     386        str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp);
     387        str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
     388        str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
     389        mtab_ent->instance = instance;
     390        mtab_ent->service_id = service_id;
     391
     392        link_initialize(&mtab_ent->link);
     393
     394        fibril_mutex_lock(&mtab_list_lock);
     395        list_append(&mtab_ent->link, &mtab_list);
     396        mtab_size++;
     397        fibril_mutex_unlock(&mtab_list_lock);
    274398
    275399        free(mp);
    276400        free(fs_name);
    277401        free(opts);
     402
     403        /* Acknowledge that we know fs_name. */
     404        async_answer_0(callid, EOK);
    278405}
    279406
    280407void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request)
    281408{
     409        int rc;
     410        char *mp;
     411        vfs_lookup_res_t mp_res;
     412        vfs_lookup_res_t mr_res;
     413        vfs_node_t *mr_node;
     414        async_exch_t *exch;
     415       
    282416        /*
    283417         * Receive the mount point path.
    284418         */
    285         char *mp;
    286         int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
     419        rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
    287420            0, NULL);
    288421        if (rc != EOK)
     
    298431         */
    299432        fibril_rwlock_write_lock(&namespace_rwlock);
    300                
     433       
     434        /*
     435         * Lookup the mounted root and instantiate it.
     436         */
     437        rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);
     438        if (rc != EOK) {
     439                fibril_rwlock_write_unlock(&namespace_rwlock);
     440                free(mp);
     441                async_answer_0(rid, rc);
     442                return;
     443        }
     444        mr_node = vfs_node_get(&mr_res);
     445        if (!mr_node) {
     446                fibril_rwlock_write_unlock(&namespace_rwlock);
     447                free(mp);
     448                async_answer_0(rid, ENOMEM);
     449                return;
     450        }
     451       
     452        /*
     453         * Count the total number of references for the mounted file system. We
     454         * are expecting at least two. One which we got above and one which we
     455         * got when the file system was mounted. If we find more, it means that
     456         * the file system cannot be gracefully unmounted at the moment because
     457         * someone is working with it.
     458         */
     459        if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
     460            mr_node->service_id) != 2) {
     461                fibril_rwlock_write_unlock(&namespace_rwlock);
     462                vfs_node_put(mr_node);
     463                free(mp);
     464                async_answer_0(rid, EBUSY);
     465                return;
     466        }
     467       
    301468        if (str_cmp(mp, "/") == 0) {
    302                 free(mp);
    303469               
    304470                /*
     
    309475                 */
    310476               
    311                 if (!root) {
     477                exch = vfs_exchange_grab(mr_node->fs_handle);
     478                rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
     479                    mr_node->service_id);
     480                vfs_exchange_release(exch);
     481               
     482                if (rc != EOK) {
    312483                        fibril_rwlock_write_unlock(&namespace_rwlock);
    313                         async_answer_0(rid, ENOENT);
     484                        free(mp);
     485                        vfs_node_put(mr_node);
     486                        async_answer_0(rid, rc);
    314487                        return;
    315488                }
    316489               
     490                rootfs.fs_handle = 0;
     491                rootfs.service_id = 0;
     492        } else {
     493               
    317494                /*
    318                  * Count the total number of references for the mounted file system. We
    319                  * are expecting at least one, which we got when the file system was mounted.
    320                  * If we find more, it means that
    321                  * the file system cannot be gracefully unmounted at the moment because
    322                  * someone is working with it.
     495                 * Unmounting a non-root file system.
     496                 *
     497                 * We have a regular mount point node representing the parent
     498                 * file system, so we delegate the operation to it.
    323499                 */
    324                 if (vfs_nodes_refcount_sum_get(root->fs_handle, root->service_id) != 1) {
     500               
     501                rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
     502                if (rc != EOK) {
    325503                        fibril_rwlock_write_unlock(&namespace_rwlock);
    326                         async_answer_0(rid, EBUSY);
     504                        free(mp);
     505                        vfs_node_put(mr_node);
     506                        async_answer_0(rid, rc);
    327507                        return;
    328508                }
    329509               
    330                 async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
    331                 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, root->service_id);
     510                vfs_node_t *mp_node = vfs_node_get(&mp_res);
     511                if (!mp_node) {
     512                        fibril_rwlock_write_unlock(&namespace_rwlock);
     513                        free(mp);
     514                        vfs_node_put(mr_node);
     515                        async_answer_0(rid, ENOMEM);
     516                        return;
     517                }
     518               
     519                exch = vfs_exchange_grab(mp_node->fs_handle);
     520                rc = async_req_2_0(exch, VFS_OUT_UNMOUNT,
     521                    mp_node->service_id, mp_node->index);
    332522                vfs_exchange_release(exch);
    333523               
    334                 fibril_rwlock_write_unlock(&namespace_rwlock);
    335                 if (rc == EOK) {
    336                         vfs_node_forget(root);
    337                         root = NULL;
    338                 }
    339                 async_answer_0(rid, rc);
    340                 return;
    341         }
    342        
    343         /*
    344          * Lookup the mounted root and instantiate it.
    345          */
    346         vfs_lookup_res_t mp_res;
    347         rc = vfs_lookup_internal(root, mp, L_MP, &mp_res);
    348         if (rc != EOK) {
    349                 fibril_rwlock_write_unlock(&namespace_rwlock);
    350                 free(mp);
    351                 async_answer_0(rid, rc);
    352                 return;
    353         }
    354         vfs_node_t *mp_node = vfs_node_get(&mp_res);
    355         if (!mp_node) {
    356                 fibril_rwlock_write_unlock(&namespace_rwlock);
    357                 free(mp);
    358                 async_answer_0(rid, ENOMEM);
    359                 return;
    360         }
    361        
    362         if (mp_node->mount == NULL) {
    363                 fibril_rwlock_write_unlock(&namespace_rwlock);
     524                if (rc != EOK) {
     525                        fibril_rwlock_write_unlock(&namespace_rwlock);
     526                        free(mp);
     527                        vfs_node_put(mp_node);
     528                        vfs_node_put(mr_node);
     529                        async_answer_0(rid, rc);
     530                        return;
     531                }
     532               
     533                /* Drop the reference we got above. */
    364534                vfs_node_put(mp_node);
    365                 free(mp);
    366                 async_answer_0(rid, ENOENT);
    367                 return;
    368         }
    369        
    370         /*
    371          * Count the total number of references for the mounted file system. We
    372          * are expecting at least one, which we got when the file system was mounted.
    373          * If we find more, it means that
    374          * the file system cannot be gracefully unmounted at the moment because
    375          * someone is working with it.
    376          */
    377         if (vfs_nodes_refcount_sum_get(mp_node->mount->fs_handle, mp_node->mount->service_id) != 1) {
    378                 fibril_rwlock_write_unlock(&namespace_rwlock);
     535                /* Drop the reference from when the file system was mounted. */
    379536                vfs_node_put(mp_node);
    380                 free(mp);
    381                 async_answer_0(rid, EBUSY);
    382                 return;
    383         }
    384        
    385         /* Unmount the filesystem. */
    386         async_exch_t *exch = vfs_exchange_grab(mp_node->mount->fs_handle);
    387         rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, mp_node->mount->service_id);
    388         vfs_exchange_release(exch);
    389        
    390         vfs_node_forget(mp_node->mount);
    391         mp_node->mount = NULL;
    392        
    393         vfs_node_put(mp_node);
     537        }
     538       
     539        /*
     540         * All went well, the mounted file system was successfully unmounted.
     541         * The only thing left is to forget the unmounted root VFS node.
     542         */
     543        vfs_node_forget(mr_node);
    394544        fibril_rwlock_write_unlock(&namespace_rwlock);
    395        
     545
    396546        fibril_mutex_lock(&mtab_list_lock);
     547
    397548        int found = 0;
    398549
     
    409560        fibril_mutex_unlock(&mtab_list_lock);
    410561
    411         free(mp);       
    412        
     562        free(mp);
     563
    413564        async_answer_0(rid, EOK);
    414         return;
    415 }
    416 
    417 static inline bool walk_flags_valid(int flags)
    418 {
    419         if ((flags&~WALK_ALL_FLAGS) != 0) {
    420                 return false;
    421         }
    422         if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) {
    423                 return false;
    424         }
    425         if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) {
    426                 return false;
    427         }
    428         if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) {
    429                 if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) {
    430                         return false;
    431                 }
    432         }
    433         return true;
    434 }
    435 
    436 static inline int walk_lookup_flags(int flags)
    437 {
    438         int lflags = 0;
    439         if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) {
    440                 lflags |= L_CREATE;
    441         }
    442         if (flags&WALK_MUST_CREATE) {
    443                 lflags |= L_EXCLUSIVE;
    444         }
    445         if (flags&WALK_REGULAR) {
    446                 lflags |= L_FILE;
    447         }
    448         if (flags&WALK_DIRECTORY) {
    449                 lflags |= L_DIRECTORY;
    450         }
    451         return lflags;
    452 }
    453 
    454 void vfs_walk(ipc_callid_t rid, ipc_call_t *request)
    455 {
    456         /*
    457          * Parent is our relative root for file lookup.
    458          * For defined flags, see <ipc/vfs.h>.
    459          */
    460         int parentfd = IPC_GET_ARG1(*request);
    461         int flags = IPC_GET_ARG2(*request);
    462        
    463         if (!walk_flags_valid(flags)) {
     565}
     566
     567void vfs_open(ipc_callid_t rid, ipc_call_t *request)
     568{
     569        /*
     570         * The POSIX interface is open(path, oflag, mode).
     571         * We can receive oflags and mode along with the VFS_IN_OPEN call;
     572         * the path will need to arrive in another call.
     573         *
     574         * We also receive one private, non-POSIX set of flags called lflag
     575         * used to pass information to vfs_lookup_internal().
     576         */
     577        int lflag = IPC_GET_ARG1(*request);
     578        int oflag = IPC_GET_ARG2(*request);
     579        int mode = IPC_GET_ARG3(*request);
     580
     581        /* Ignore mode for now. */
     582        (void) mode;
     583       
     584        /*
     585         * Make sure that we are called with exactly one of L_FILE and
     586         * L_DIRECTORY. Make sure that the user does not pass L_OPEN,
     587         * L_ROOT or L_MP.
     588         */
     589        if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
     590            ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
     591            (lflag & (L_OPEN | L_ROOT | L_MP))) {
    464592                async_answer_0(rid, EINVAL);
    465593                return;
    466594        }
    467595       
     596        if (oflag & O_CREAT)
     597                lflag |= L_CREATE;
     598        if (oflag & O_EXCL)
     599                lflag |= L_EXCLUSIVE;
     600       
    468601        char *path;
    469         int rc = async_data_write_accept((void **)&path, true, 0, 0, 0, NULL);
    470        
    471         /* Lookup the file structure corresponding to the file descriptor. */
    472         vfs_file_t *parent = NULL;
    473         vfs_node_t *parent_node = root;
    474         // TODO: Client-side root.
    475         if (parentfd != -1) {
    476                 parent = vfs_file_get(parentfd);
    477                 if (!parent) {
    478                         free(path);
    479                         async_answer_0(rid, EBADF);
    480                         return;
    481                 }
    482                 parent_node = parent->node;
    483         }
    484        
    485         fibril_rwlock_read_lock(&namespace_rwlock);
    486        
     602        int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
     603        if (rc != EOK) {
     604                async_answer_0(rid, rc);
     605                return;
     606        }
     607       
     608        /*
     609         * Avoid the race condition in which the file can be deleted before we
     610         * find/create-and-lock the VFS node corresponding to the looked-up
     611         * triplet.
     612         */
     613        if (lflag & L_CREATE)
     614                fibril_rwlock_write_lock(&namespace_rwlock);
     615        else
     616                fibril_rwlock_read_lock(&namespace_rwlock);
     617       
     618        /* The path is now populated and we can call vfs_lookup_internal(). */
    487619        vfs_lookup_res_t lr;
    488         rc = vfs_lookup_internal(parent_node, path, walk_lookup_flags(flags), &lr);
     620        rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);
     621        if (rc != EOK) {
     622                if (lflag & L_CREATE)
     623                        fibril_rwlock_write_unlock(&namespace_rwlock);
     624                else
     625                        fibril_rwlock_read_unlock(&namespace_rwlock);
     626                async_answer_0(rid, rc);
     627                free(path);
     628                return;
     629        }
     630       
     631        /* Path is no longer needed. */
    489632        free(path);
    490 
    491         if (rc != EOK) {
     633       
     634        vfs_node_t *node = vfs_node_get(&lr);
     635        if (lflag & L_CREATE)
     636                fibril_rwlock_write_unlock(&namespace_rwlock);
     637        else
    492638                fibril_rwlock_read_unlock(&namespace_rwlock);
    493                 if (parent) {
    494                         vfs_file_put(parent);
    495                 }
    496                 async_answer_0(rid, rc);
    497                 return;
    498         }
    499        
    500         vfs_node_t *node = vfs_node_get(&lr);
    501        
    502         int fd = vfs_fd_alloc(false);
     639
     640        if (!node) {
     641                async_answer_0(rid, ENOMEM);
     642                return;
     643        }
     644       
     645        /* Truncate the file if requested and if necessary. */
     646        if (oflag & O_TRUNC) {
     647                fibril_rwlock_write_lock(&node->contents_rwlock);
     648                if (node->size) {
     649                        rc = vfs_truncate_internal(node->fs_handle,
     650                            node->service_id, node->index, 0);
     651                        if (rc) {
     652                                fibril_rwlock_write_unlock(&node->contents_rwlock);
     653                                vfs_node_put(node);
     654                                async_answer_0(rid, rc);
     655                                return;
     656                        }
     657                        node->size = 0;
     658                }
     659                fibril_rwlock_write_unlock(&node->contents_rwlock);
     660        }
     661       
     662        /*
     663         * Get ourselves a file descriptor and the corresponding vfs_file_t
     664         * structure.
     665         */
     666        int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
    503667        if (fd < 0) {
    504668                vfs_node_put(node);
    505                 if (parent) {
    506                         vfs_file_put(parent);
    507                 }
    508669                async_answer_0(rid, fd);
    509670                return;
    510671        }
    511        
    512672        vfs_file_t *file = vfs_file_get(fd);
    513         assert(file != NULL);
    514        
     673        assert(file);
    515674        file->node = node;
    516         if (parent) {
    517                 file->permissions = parent->permissions;
    518         } else {
    519                 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
    520         }
    521         file->open_read = false;
    522         file->open_write = false;
    523        
     675        if (oflag & O_APPEND)
     676                file->append = true;
     677       
     678        /*
     679         * The following increase in reference count is for the fact that the
     680         * file is being opened and that a file structure is pointing to it.
     681         * It is necessary so that the file will not disappear when
     682         * vfs_node_put() is called. The reference will be dropped by the
     683         * respective VFS_IN_CLOSE.
     684         */
     685        vfs_node_addref(node);
     686        vfs_node_put(node);
    524687        vfs_file_put(file);
    525         if (parent) {
    526                 vfs_file_put(parent);
    527         }
    528        
    529         fibril_rwlock_read_unlock(&namespace_rwlock);
    530 
     688       
     689        /* Success! Return the new file descriptor to the client. */
    531690        async_answer_1(rid, EOK, fd);
    532 }
    533 
    534 void vfs_open2(ipc_callid_t rid, ipc_call_t *request)
    535 {
    536         int fd = IPC_GET_ARG1(*request);
    537         int flags = IPC_GET_ARG2(*request);
    538 
    539         if (flags == 0) {
    540                 async_answer_0(rid, EINVAL);
    541                 return;
    542         }
    543 
    544         vfs_file_t *file = vfs_file_get(fd);
    545         if (!file) {
    546                 async_answer_0(rid, EBADF);
    547                 return;
    548         }
    549        
    550         if ((flags & ~file->permissions) != 0) {
    551                 vfs_file_put(file);
    552                 async_answer_0(rid, EPERM);
    553                 return;
    554         }
    555        
    556         file->open_read = (flags & MODE_READ) != 0;
    557         file->open_write = (flags & (MODE_WRITE | MODE_APPEND)) != 0;
    558         file->append = (flags & MODE_APPEND) != 0;
    559        
    560         if (!file->open_read && !file->open_write) {
    561                 vfs_file_put(file);
    562                 async_answer_0(rid, EINVAL);
    563                 return;
    564         }
    565        
    566         if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) {
    567                 file->open_read = file->open_write = false;
    568                 vfs_file_put(file);
    569                 async_answer_0(rid, EINVAL);
    570                 return;
    571         }
    572        
    573         int rc = vfs_open_node_remote(file->node);
    574         if (rc != EOK) {
    575                 file->open_read = file->open_write = false;
    576                 vfs_file_put(file);
    577                 async_answer_0(rid, rc);
    578                 return;
    579         }
    580        
    581         vfs_file_put(file);
    582         async_answer_0(rid, EOK);
    583691}
    584692
     
    708816        fibril_mutex_lock(&file->lock);
    709817       
    710         if ((read && !file->open_read) || (!read && !file->open_write)) {
    711                 fibril_mutex_unlock(&file->lock);
    712                 return EINVAL;
    713         }
    714        
    715818        vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
    716819        assert(fs_info);
     
    751854        size_t bytes = IPC_GET_ARG1(answer);
    752855       
    753         if (file->node->type == VFS_NODE_DIRECTORY) {
     856        if (file->node->type == VFS_NODE_DIRECTORY)
    754857                fibril_rwlock_read_unlock(&namespace_rwlock);
    755         }
    756858       
    757859        /* Unlock the VFS node. */
     
    851953        case SEEK_END:
    852954                fibril_rwlock_read_lock(&file->node->contents_rwlock);
    853                 aoff64_t size = vfs_node_get_size(file->node);
     955                aoff64_t size = file->node->size;
    854956               
    855957                if ((off >= 0) && (size + off < size)) {
     
    9591061}
    9601062
    961 static void out_destroy(vfs_triplet_t *file)
    962 {
    963         async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
    964         async_msg_2(exch, VFS_OUT_DESTROY,
    965                 (sysarg_t) file->service_id, (sysarg_t) file->index);
     1063void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
     1064{
     1065        char *path;
     1066        int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
     1067        if (rc != EOK) {
     1068                async_answer_0(rid, rc);
     1069                return;
     1070        }
     1071       
     1072        ipc_callid_t callid;
     1073        if (!async_data_read_receive(&callid, NULL)) {
     1074                free(path);
     1075                async_answer_0(callid, EINVAL);
     1076                async_answer_0(rid, EINVAL);
     1077                return;
     1078        }
     1079
     1080        vfs_lookup_res_t lr;
     1081        fibril_rwlock_read_lock(&namespace_rwlock);
     1082        rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
     1083        free(path);
     1084        if (rc != EOK) {
     1085                fibril_rwlock_read_unlock(&namespace_rwlock);
     1086                async_answer_0(callid, rc);
     1087                async_answer_0(rid, rc);
     1088                return;
     1089        }
     1090        vfs_node_t *node = vfs_node_get(&lr);
     1091        if (!node) {
     1092                fibril_rwlock_read_unlock(&namespace_rwlock);
     1093                async_answer_0(callid, ENOMEM);
     1094                async_answer_0(rid, ENOMEM);
     1095                return;
     1096        }
     1097
     1098        fibril_rwlock_read_unlock(&namespace_rwlock);
     1099
     1100        async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
     1101       
     1102        aid_t msg;
     1103        msg = async_send_3(exch, VFS_OUT_STAT, node->service_id,
     1104            node->index, false, NULL);
     1105        async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
     1106       
    9661107        vfs_exchange_release(exch);
    967 }
    968 
    969 void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request)
    970 {
    971         int rc;
     1108       
     1109        sysarg_t rv;
     1110        async_wait_for(msg, &rv);
     1111
     1112        async_answer_0(rid, rv);
     1113
     1114        vfs_node_put(node);
     1115}
     1116
     1117void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
     1118{
     1119        int mode = IPC_GET_ARG1(*request);
     1120       
    9721121        char *path;
    973         vfs_file_t *parent = NULL;
    974         vfs_file_t *expect = NULL;
    975         vfs_node_t *parent_node = root;
    976        
    977         int parentfd = IPC_GET_ARG1(*request);
    978         int expectfd = IPC_GET_ARG2(*request);
    979         int wflag = IPC_GET_ARG3(*request);
    980        
    981         rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    982         if (rc != EOK) {
    983                 async_answer_0(rid, rc);
    984                 return;
    985         }
     1122        int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
     1123        if (rc != EOK) {
     1124                async_answer_0(rid, rc);
     1125                return;
     1126        }
     1127       
     1128        /* Ignore mode for now. */
     1129        (void) mode;
    9861130       
    9871131        fibril_rwlock_write_lock(&namespace_rwlock);
    988        
    989         int lflag = (wflag&WALK_DIRECTORY) ? L_DIRECTORY: 0;
    990 
    991         if (parentfd >= 0) {
    992                 parent = vfs_file_get(parentfd);
    993                 if (!parent) {
    994                         rc = ENOENT;
    995                         goto exit;
    996                 }
    997                 parent_node = parent->node;
    998         }
    999        
    1000         if (expectfd >= 0) {
    1001                 expect = vfs_file_get(expectfd);
    1002                 if (!expect) {
    1003                         rc = ENOENT;
    1004                         goto exit;
    1005                 }
    1006                
    1007                 vfs_lookup_res_t lr;
    1008                 rc = vfs_lookup_internal(parent_node, path, lflag, &lr);
    1009                 if (rc != EOK) {
    1010                         goto exit;
    1011                 }
    1012                
    1013                 if (__builtin_memcmp(&lr.triplet, expect->node, sizeof(vfs_triplet_t)) != 0) {
    1014                         rc = ENOENT;
    1015                         goto exit;
    1016                 }
    1017                
    1018                 vfs_file_put(expect);
    1019                 expect = NULL;
    1020         }
    1021        
     1132        int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
     1133        rc = vfs_lookup_internal(path, lflag, NULL, NULL);
     1134        fibril_rwlock_write_unlock(&namespace_rwlock);
     1135        free(path);
     1136        async_answer_0(rid, rc);
     1137}
     1138
     1139void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
     1140{
     1141        int lflag = IPC_GET_ARG1(*request);
     1142       
     1143        char *path;
     1144        int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
     1145        if (rc != EOK) {
     1146                async_answer_0(rid, rc);
     1147                return;
     1148        }
     1149       
     1150        fibril_rwlock_write_lock(&namespace_rwlock);
     1151        lflag &= L_DIRECTORY;   /* sanitize lflag */
    10221152        vfs_lookup_res_t lr;
    1023         rc = vfs_lookup_internal(parent_node, path, lflag | L_UNLINK, &lr);
    1024         if (rc != EOK) {
    1025                 goto exit;
    1026         }
    1027 
    1028         /* If the node is not held by anyone, try to destroy it. */
    1029         if (vfs_node_peek(&lr) == NULL) {
    1030                 out_destroy(&lr.triplet);
    1031         }
    1032 
    1033 exit:
    1034         if (path) {
    1035                 free(path);
    1036         }
    1037         if (parent) {
    1038                 vfs_file_put(parent);
    1039         }
    1040         if (expect) {
    1041                 vfs_file_put(expect);
    1042         }
     1153        rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
     1154        free(path);
     1155        if (rc != EOK) {
     1156                fibril_rwlock_write_unlock(&namespace_rwlock);
     1157                async_answer_0(rid, rc);
     1158                return;
     1159        }
     1160
     1161        /*
     1162         * The name has already been unlinked by vfs_lookup_internal().
     1163         * We have to get and put the VFS node to ensure that it is
     1164         * VFS_OUT_DESTROY'ed after the last reference to it is dropped.
     1165         */
     1166        vfs_node_t *node = vfs_node_get(&lr);
     1167        fibril_mutex_lock(&nodes_mutex);
     1168        node->lnkcnt--;
     1169        fibril_mutex_unlock(&nodes_mutex);
    10431170        fibril_rwlock_write_unlock(&namespace_rwlock);
    1044         async_answer_0(rid, rc);
    1045 }
    1046 
    1047 static size_t shared_path(char *a, char *b)
    1048 {
    1049         size_t res = 0;
    1050        
    1051         while (a[res] == b[res] && a[res] != 0) {
    1052                 res++;
    1053         }
    1054        
    1055         if (a[res] == b[res]) {
    1056                 return res;
    1057         }
    1058        
    1059         res--;
    1060         while (a[res] != '/') {
    1061                 res--;
    1062         }
    1063         return res;
    1064 }
    1065 
    1066 static int vfs_rename_internal(vfs_node_t *base, char *old, char *new)
    1067 {
    1068         assert(base != NULL);
    1069         assert(old != NULL);
    1070         assert(new != NULL);
    1071        
    1072         vfs_lookup_res_t base_lr;
    1073         vfs_lookup_res_t old_lr;
    1074         vfs_lookup_res_t new_lr_orig;
    1075         bool orig_unlinked = false;
    1076        
    1077         int rc;
    1078        
    1079         size_t shared = shared_path(old, new);
    1080        
    1081         /* Do not allow one path to be a prefix of the other. */
    1082         if (old[shared] == 0 || new[shared] == 0) {
    1083                 return EINVAL;
    1084         }
    1085         assert(old[shared] == '/');
    1086         assert(new[shared] == '/');
    1087        
    1088         fibril_rwlock_write_lock(&namespace_rwlock);
    1089        
    1090         /* Resolve the shared portion of the path first. */
    1091         if (shared != 0) {
    1092                 old[shared] = 0;
    1093                 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
    1094                 if (rc != EOK) {
    1095                         fibril_rwlock_write_unlock(&namespace_rwlock);
    1096                         return rc;
    1097                 }
    1098                
    1099                 base = vfs_node_get(&base_lr);
    1100                 old[shared] = '/';
    1101                 old += shared;
    1102                 new += shared;
    1103         } else {
    1104                 vfs_node_addref(base);
    1105         }
    1106        
    1107        
    1108         rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, &new_lr_orig);
    1109         if (rc == EOK) {
    1110                 orig_unlinked = true;
    1111         } else if (rc != ENOENT) {
    1112                 vfs_node_put(base);
    1113                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1114                 return rc;
    1115         }
    1116        
    1117         rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, &old_lr);
    1118         if (rc != EOK) {
    1119                 if (orig_unlinked) {
    1120                         vfs_link_internal(base, new, &new_lr_orig.triplet);
    1121                 }
    1122                 vfs_node_put(base);
    1123                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1124                 return rc;
    1125         }
    1126        
    1127         rc = vfs_link_internal(base, new, &old_lr.triplet);
    1128         if (rc != EOK) {
    1129                 vfs_link_internal(base, old, &old_lr.triplet);
    1130                 if (orig_unlinked) {
    1131                         vfs_link_internal(base, new, &new_lr_orig.triplet);
    1132                 }
    1133                 vfs_node_put(base);
    1134                 fibril_rwlock_write_unlock(&namespace_rwlock);
    1135                 return rc;
    1136         }
    1137        
    1138         /* If the node is not held by anyone, try to destroy it. */
    1139         if (orig_unlinked && vfs_node_peek(&new_lr_orig) == NULL) {
    1140                 out_destroy(&new_lr_orig.triplet);
    1141         }
    1142        
    1143         vfs_node_put(base);
    1144         fibril_rwlock_write_unlock(&namespace_rwlock);
    1145         return EOK;
     1171        vfs_node_put(node);
     1172        async_answer_0(rid, EOK);
    11461173}
    11471174
    11481175void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
    11491176{
    1150         /* The common base directory. */
    1151         int basefd;
    1152         char *old = NULL;
    1153         char *new = NULL;
    1154         vfs_file_t *base = NULL;
    1155         int rc;
    1156        
    1157         basefd = IPC_GET_ARG1(*request);
    1158        
    11591177        /* Retrieve the old path. */
    1160         rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
    1161         if (rc != EOK) {
    1162                 goto out;
     1178        char *old;
     1179        int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
     1180        if (rc != EOK) {
     1181                async_answer_0(rid, rc);
     1182                return;
    11631183        }
    11641184       
    11651185        /* Retrieve the new path. */
     1186        char *new;
    11661187        rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
    11671188        if (rc != EOK) {
    1168                 goto out;
     1189                free(old);
     1190                async_answer_0(rid, rc);
     1191                return;
    11691192        }
    11701193       
     
    11751198       
    11761199        if ((!oldc) || (!newc)) {
    1177                 rc = EINVAL;
    1178                 goto out;
    1179         }
    1180        
    1181         assert(oldc[olen] == '\0');
    1182         assert(newc[nlen] == '\0');
    1183        
    1184         /* Lookup the file structure corresponding to the file descriptor. */
    1185         vfs_node_t *base_node = root;
    1186         // TODO: Client-side root.
    1187         if (basefd != -1) {
    1188                 base = vfs_file_get(basefd);
    1189                 if (!base) {
    1190                         rc = EBADF;
    1191                         goto out;
    1192                 }
    1193                 base_node = base->node;
    1194         }
    1195        
    1196         rc = vfs_rename_internal(base_node, oldc, newc);
    1197 
    1198 out:
    1199         async_answer_0(rid, rc);
    1200 
    1201         if (old) {
     1200                async_answer_0(rid, EINVAL);
    12021201                free(old);
    1203         }
    1204         if (new) {
    12051202                free(new);
    1206         }
    1207         if (base) {
    1208                 vfs_file_put(base);
    1209         }
     1203                return;
     1204        }
     1205       
     1206        oldc[olen] = '\0';
     1207        newc[nlen] = '\0';
     1208       
     1209        if ((!str_lcmp(newc, oldc, str_length(oldc))) &&
     1210            ((newc[str_length(oldc)] == '/') ||
     1211            (str_length(oldc) == 1) ||
     1212            (str_length(oldc) == str_length(newc)))) {
     1213                /*
     1214                 * oldc is a prefix of newc and either
     1215                 * - newc continues with a / where oldc ends, or
     1216                 * - oldc was / itself, or
     1217                 * - oldc and newc are equal.
     1218                 */
     1219                async_answer_0(rid, EINVAL);
     1220                free(old);
     1221                free(new);
     1222                return;
     1223        }
     1224       
     1225        vfs_lookup_res_t old_lr;
     1226        vfs_lookup_res_t new_lr;
     1227        vfs_lookup_res_t new_par_lr;
     1228        fibril_rwlock_write_lock(&namespace_rwlock);
     1229       
     1230        /* Lookup the node belonging to the old file name. */
     1231        rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
     1232        if (rc != EOK) {
     1233                fibril_rwlock_write_unlock(&namespace_rwlock);
     1234                async_answer_0(rid, rc);
     1235                free(old);
     1236                free(new);
     1237                return;
     1238        }
     1239       
     1240        vfs_node_t *old_node = vfs_node_get(&old_lr);
     1241        if (!old_node) {
     1242                fibril_rwlock_write_unlock(&namespace_rwlock);
     1243                async_answer_0(rid, ENOMEM);
     1244                free(old);
     1245                free(new);
     1246                return;
     1247        }
     1248       
     1249        /* Determine the path to the parent of the node with the new name. */
     1250        char *parentc = str_dup(newc);
     1251        if (!parentc) {
     1252                fibril_rwlock_write_unlock(&namespace_rwlock);
     1253                vfs_node_put(old_node);
     1254                async_answer_0(rid, rc);
     1255                free(old);
     1256                free(new);
     1257                return;
     1258        }
     1259       
     1260        char *lastsl = str_rchr(parentc + 1, '/');
     1261        if (lastsl)
     1262                *lastsl = '\0';
     1263        else
     1264                parentc[1] = '\0';
     1265       
     1266        /* Lookup parent of the new file name. */
     1267        rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
     1268        free(parentc);  /* not needed anymore */
     1269        if (rc != EOK) {
     1270                fibril_rwlock_write_unlock(&namespace_rwlock);
     1271                vfs_node_put(old_node);
     1272                async_answer_0(rid, rc);
     1273                free(old);
     1274                free(new);
     1275                return;
     1276        }
     1277       
     1278        /* Check whether linking to the same file system instance. */
     1279        if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
     1280            (old_node->service_id != new_par_lr.triplet.service_id)) {
     1281                fibril_rwlock_write_unlock(&namespace_rwlock);
     1282                vfs_node_put(old_node);
     1283                async_answer_0(rid, EXDEV);     /* different file systems */
     1284                free(old);
     1285                free(new);
     1286                return;
     1287        }
     1288       
     1289        /* Destroy the old link for the new name. */
     1290        vfs_node_t *new_node = NULL;
     1291        rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
     1292       
     1293        switch (rc) {
     1294        case ENOENT:
     1295                /* simply not in our way */
     1296                break;
     1297        case EOK:
     1298                new_node = vfs_node_get(&new_lr);
     1299                if (!new_node) {
     1300                        fibril_rwlock_write_unlock(&namespace_rwlock);
     1301                        vfs_node_put(old_node);
     1302                        async_answer_0(rid, ENOMEM);
     1303                        free(old);
     1304                        free(new);
     1305                        return;
     1306                }
     1307                fibril_mutex_lock(&nodes_mutex);
     1308                new_node->lnkcnt--;
     1309                fibril_mutex_unlock(&nodes_mutex);
     1310                break;
     1311        default:
     1312                fibril_rwlock_write_unlock(&namespace_rwlock);
     1313                vfs_node_put(old_node);
     1314                async_answer_0(rid, ENOTEMPTY);
     1315                free(old);
     1316                free(new);
     1317                return;
     1318        }
     1319       
     1320        /* Create the new link for the new name. */
     1321        rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
     1322        if (rc != EOK) {
     1323                fibril_rwlock_write_unlock(&namespace_rwlock);
     1324                vfs_node_put(old_node);
     1325                if (new_node)
     1326                        vfs_node_put(new_node);
     1327                async_answer_0(rid, rc);
     1328                free(old);
     1329                free(new);
     1330                return;
     1331        }
     1332       
     1333        fibril_mutex_lock(&nodes_mutex);
     1334        old_node->lnkcnt++;
     1335        fibril_mutex_unlock(&nodes_mutex);
     1336       
     1337        /* Destroy the link for the old name. */
     1338        rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
     1339        if (rc != EOK) {
     1340                fibril_rwlock_write_unlock(&namespace_rwlock);
     1341                vfs_node_put(old_node);
     1342                if (new_node)
     1343                        vfs_node_put(new_node);
     1344                async_answer_0(rid, rc);
     1345                free(old);
     1346                free(new);
     1347                return;
     1348        }
     1349       
     1350        fibril_mutex_lock(&nodes_mutex);
     1351        old_node->lnkcnt--;
     1352        fibril_mutex_unlock(&nodes_mutex);
     1353        fibril_rwlock_write_unlock(&namespace_rwlock);
     1354        vfs_node_put(old_node);
     1355       
     1356        if (new_node)
     1357                vfs_node_put(new_node);
     1358       
     1359        free(old);
     1360        free(new);
     1361        async_answer_0(rid, EOK);
    12101362}
    12111363
     
    13351487        vfs_lookup_res_t lr;
    13361488        fibril_rwlock_read_lock(&namespace_rwlock);
    1337         rc = vfs_lookup_internal(root, path, L_NONE, &lr);
     1489        rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
    13381490        free(path);
    13391491        if (rc != EOK) {
Note: See TracChangeset for help on using the changeset viewer.