Changeset 1dff985 in mainline


Ignore:
Timestamp:
2017-03-03T21:32:38Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c577a9a
Parents:
5b46ec8 (diff), b8dbe2f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5 up to revision 1926

Location:
uspace
Files:
12 edited

Legend:

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

    r5b46ec8 r1dff985  
    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);
    700698        o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def);
    701699        proto_add_oper(p, VFS_IN_READ, o);
     
    716714        o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def);
    717715        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);
    722716        o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
    723717        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);
    726718        o = oper_new("statfs", 0, arg_def, V_ERRNO, 0, resp_def);
    727719        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);
    728726
    729727        proto_register(SERVICE_VFS, p);
  • uspace/lib/c/generic/vfs/vfs.c

    r5b46ec8 r1dff985  
    9393}
    9494
     95int _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
     118int _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
    95127char *vfs_absolutize(const char *path, size_t *retlen)
    96128{
     
    229261        }
    230262       
    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        
    247263        vfs_exchange_end(exch);
    248264        free(mpa);
     
    289305}
    290306
    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  */
    301 static 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;
     307static 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;
    330318}
    331319
     
    341329int open(const char *path, int oflag, ...)
    342330{
     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       
    343338        size_t abs_size;
    344339        char *abs = vfs_absolutize(path, &abs_size);
    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;
     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;
    361371}
    362372
     
    670680int stat(const char *path, struct stat *stat)
    671681{
    672         sysarg_t rc;
    673         sysarg_t rc_orig;
    674         aid_t req;
    675        
    676682        size_t pa_size;
    677683        char *pa = vfs_absolutize(path, &pa_size);
    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;
     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;
    718696}
    719697
     
    727705{
    728706        DIR *dirp = malloc(sizeof(DIR));
    729         int fd = -1;
    730        
    731         if (dirp == NULL) {
     707        if (!dirp) {
    732708                errno = ENOMEM;
    733709                return NULL;
     
    742718        }
    743719       
    744         int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd);
     720        int ret = _vfs_walk(-1, abs, WALK_DIRECTORY);
    745721        free(abs);
    746722       
    747         if (rc != EOK) {
     723        if (ret < EOK) {
    748724                free(dirp);
     725                errno = ret;
     726                return NULL;
     727        }
     728       
     729        int rc = _vfs_open(ret, MODE_READ);
     730        if (rc < 0) {
     731                free(dirp);
     732                close(ret);
    749733                errno = rc;
    750734                return NULL;
    751735        }
    752736       
    753         dirp->fd = fd;
     737        dirp->fd = ret;
    754738        return dirp;
    755739}
     
    809793int mkdir(const char *path, mode_t mode)
    810794{
     795        size_t pa_size;
     796        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
     810static int _vfs_unlink2(int parent, const char *path, int expect, int wflag)
     811{
    811812        sysarg_t rc;
    812813        aid_t req;
    813814       
     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        }
     828        return rc;
     829}
     830
     831/** Unlink file or directory.
     832 *
     833 * @param path Path
     834 * @return EOk on success, error code on error
     835 */
     836int unlink(const char *path)
     837{
    814838        size_t pa_size;
    815839        char *pa = vfs_absolutize(path, &pa_size);
    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  */
    861 static int _unlink(const char *path, int lflag)
    862 {
    863         sysarg_t rc;
    864         aid_t req;
    865        
     840        if (!pa) {
     841                return ENOMEM;
     842        }
     843       
     844        return _vfs_unlink2(-1, pa, -1, 0);
     845}
     846
     847/** Remove empty directory.
     848 *
     849 * @param path Path
     850 * @return 0 on success. On error returns -1 and sets errno.
     851 */
     852int rmdir(const char *path)
     853{
    866854        size_t pa_size;
    867855        char *pa = vfs_absolutize(path, &pa_size);
    868         if (pa == NULL)
     856        if (!pa) {
    869857                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);
    890         return rc;
    891 }
    892 
    893 /** Unlink file or directory.
    894  *
    895  * @param path Path
    896  * @return EOk on success, error code on error
    897  */
    898 int unlink(const char *path)
    899 {
    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;
    909 }
    910 
    911 /** Remove empty directory.
    912  *
    913  * @param path Path
    914  * @return 0 on success. On error returns -1 and sets errno.
    915  */
    916 int rmdir(const char *path)
    917 {
    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;
     858        }
     859       
     860        return _vfs_unlink2(-1, pa, -1, WALK_DIRECTORY);
    927861}
    928862
     
    957891        async_exch_t *exch = vfs_exchange_begin();
    958892       
    959         req = async_send_0(exch, VFS_IN_RENAME, NULL);
     893        req = async_send_1(exch, VFS_IN_RENAME, -1, NULL);
    960894        rc = async_data_write_start(exch, olda, olda_size);
    961895        if (rc != EOK) {
     
    1018952        size_t abs_size;
    1019953        char *abs = vfs_absolutize(path, &abs_size);
    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) {
     954        if (!abs)
     955                return ENOMEM;
     956       
     957        int fd = _vfs_walk(-1, abs, WALK_DIRECTORY);
     958        if (fd < 0) {
    1030959                free(abs);
    1031                 errno = rc;
     960                errno = fd;
    1032961                return -1;
    1033962        }
  • uspace/lib/c/include/ipc/vfs.h

    r5b46ec8 r1dff985  
    6363
    6464typedef enum {
    65         VFS_IN_OPEN = IPC_FIRST_USER_METHOD,
    66         VFS_IN_READ,
     65        VFS_IN_READ = IPC_FIRST_USER_METHOD,
    6766        VFS_IN_WRITE,
    6867        VFS_IN_SEEK,
     
    7574        VFS_IN_SYNC,
    7675        VFS_IN_REGISTER,
    77         VFS_IN_MKDIR,
    7876        VFS_IN_UNLINK,
    7977        VFS_IN_RENAME,
    80         VFS_IN_STAT,
    8178        VFS_IN_DUP,
    8279        VFS_IN_WAIT_HANDLE,
    8380        VFS_IN_MTAB_GET,
    84         VFS_IN_STATFS
     81        VFS_IN_STATFS,
     82        VFS_IN_WALK,
     83        VFS_IN_OPEN2,
     84        VFS_IN_UNLINK2,
    8585} vfs_in_request_t;
    8686
     
    9191        VFS_OUT_TRUNCATE,
    9292        VFS_OUT_CLOSE,
    93         VFS_OUT_MOUNT,
    9493        VFS_OUT_MOUNTED,
    95         VFS_OUT_UNMOUNT,
    9694        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,
    100101        VFS_OUT_DESTROY,
    101102        VFS_OUT_STATFS,
     
    127128
    128129/**
    129  * Lookup will succeed only if the object is a root directory. The flag is
    130  * mutually exclusive with L_FILE and L_MP.
     130 * Lookup will not cross any mount points.
     131 * If the lookup would have to cross a mount point, it returns EXDEV instead.
    131132 */
    132 #define L_ROOT                  4
     133#define L_DISABLE_MOUNTS        4
    133134
    134135/**
     
    151152
    152153/**
    153  * L_LINK is used for linking to an already existing nodes.
    154  */
    155 #define L_LINK                  64
    156 
    157 /**
    158154 * L_UNLINK is used to remove leaves from the file system namespace. This flag
    159155 * cannot be passed directly by the client, but will be set by VFS during
     
    170166#define L_OPEN                  256
    171167
     168/*
     169 * Walk flags.
     170 */
     171enum {
     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
     188enum {
     189        MODE_READ = 1,
     190        MODE_WRITE = 2,
     191        MODE_APPEND = 4,
     192};
     193
    172194#endif
    173195
  • uspace/lib/c/include/vfs/vfs.h

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

    r5b46ec8 r1dff985  
    3636
    3737#include "libfs.h"
    38 #include "../../srv/vfs/vfs.h"
    3938#include <macros.h>
    4039#include <errno.h>
     
    4746#include <sys/statfs.h>
    4847#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
    6570static fs_reg_t reg;
    6671
     
    6873static libfs_ops_t *libfs_ops = NULL;
    6974
    70 static void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
    71 static void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
     75static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t,
     76    ipc_call_t *);
    7277static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    7378    ipc_call_t *);
     
    104109}
    105110
    106 static 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_unmount(ipc_callid_t rid, ipc_call_t *req)
    122 {
    123                
    124         libfs_unmount(libfs_ops, rid, req);
     121static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req)
     122{
     123        libfs_link(libfs_ops, reg.fs_handle, rid, req);
    125124}
    126125
     
    193192        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    194193        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
     194
    195195        int rc;
    196 
    197         rc = vfs_out_ops->destroy(service_id, index);
    198 
     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        }
    199205        async_answer_0(rid, rc);
    200206}
     
    225231        libfs_statfs(libfs_ops, reg.fs_handle, rid, req);
    226232}
     233
     234static 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
     255static 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
    227280static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    228281{
     
    247300                        vfs_out_mounted(callid, &call);
    248301                        break;
    249                 case VFS_OUT_MOUNT:
    250                         vfs_out_mount(callid, &call);
    251                         break;
    252302                case VFS_OUT_UNMOUNTED:
    253303                        vfs_out_unmounted(callid, &call);
    254304                        break;
    255                 case VFS_OUT_UNMOUNT:
    256                         vfs_out_unmount(callid, &call);
     305                case VFS_OUT_LINK:
     306                        vfs_out_link(callid, &call);
    257307                        break;
    258308                case VFS_OUT_LOOKUP:
     
    285335                case VFS_OUT_STATFS:
    286336                        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);
    287343                        break;
    288344                default:
     
    383439}
    384440
    385 void 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);
     441static char plb_get_char(unsigned pos)
     442{
     443        return reg.plb_ro[pos % PLB_SIZE];
     444}
     445
     446static 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
     476static 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 */
     493void 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);
    396503                return;
    397504        }
    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));
     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);
    405510                return;
    406511        }
    407512       
    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);
     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);
    413518                return;
    414519        }
    415520       
    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 
    447 void 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 
    494 static char plb_get_char(unsigned pos)
    495 {
    496         return reg.plb_ro[pos % PLB_SIZE];
     521        rc = ops->link(parent, child, component);
     522        ops->node_put(parent);
     523        ops->node_put(child);
     524        async_answer_0(rid, rc);
    497525}
    498526
     
    513541    ipc_call_t *req)
    514542{
    515         unsigned int first = IPC_GET_ARG1(*req);
    516         unsigned int last = IPC_GET_ARG2(*req);
    517         unsigned int next = first;
     543        unsigned first = IPC_GET_ARG1(*req);
     544        unsigned len = IPC_GET_ARG2(*req);
    518545        service_id_t service_id = IPC_GET_ARG3(*req);
    519         int lflag = IPC_GET_ARG4(*req);
    520         fs_index_t index = IPC_GET_ARG5(*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       
    521558        char component[NAME_MAX + 1];
    522         int len;
    523559        int rc;
    524        
    525         if (last < next)
    526                 last += PLB_SIZE;
    527560       
    528561        fs_node_t *par = NULL;
    529562        fs_node_t *cur = NULL;
    530563        fs_node_t *tmp = NULL;
    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);
     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;
     583                }
     584
     585                if (!ops->is_directory(cur)) {
     586                        async_answer_0(rid, ENOTDIR);
     587                        LOG_EXIT(ENOTDIR);
     588                        goto out;
     589                }
    541590               
    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;
     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                }
    552600               
    553                 rc = ops->has_children(&has_children, cur);
    554                 on_error(rc, goto out_with_answer);
    555                 if (!has_children)
    556                         break;
     601                if (clen == 0) {
     602                        /* The path is just "/". */
     603                        break;
     604                }
    557605               
    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++;
    569                 }
    570                
    571                 assert(len);
    572                 component[len] = '\0';
    573                 /* Eat slash */
    574                 next++;
     606                assert(component[clen] == 0);
    575607               
    576608                /* Match the component */
    577609                rc = ops->match(&tmp, cur, component);
    578                 on_error(rc, goto out_with_answer);
     610                if (rc != EOK) {
     611                        async_answer_0(rid, rc);
     612                        LOG_EXIT(rc);
     613                        goto out;
     614                }
    579615               
    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--;
     616                /* Descend one level */
     617                if (par) {
     618                        rc = ops->node_put(par);
     619                        if (rc != EOK) {
     620                                async_answer_0(rid, rc);
     621                                LOG_EXIT(rc);
     622                                goto out;
     623                        }
     624                }
     625               
     626                par = cur;
     627                cur = tmp;
     628                tmp = NULL;
     629        }
     630       
     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                        }
    596673                       
    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);
     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);
    615704                                goto out;
    616705                        }
    617706                       
    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                                
     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);
    651713                                goto out;
    652714                        }
    653                        
    654                         async_answer_0(rid, ENOENT);
     715                }
     716        }
     717       
     718        /* Return. */
     719out1:
     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);
    655732                        goto out;
    656733                }
    657                
    658                 if (par) {
    659                         rc = ops->node_put(par);
    660                         on_error(rc, goto out_with_answer);
    661                 }
    662                
    663                 /* Descend one level */
    664                 par = cur;
    665                 cur = tmp;
    666                 tmp = NULL;
    667         }
    668        
    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);
    681                                 goto out;
    682                         }
    683                        
    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++;
    702                         }
    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                        
    730                         goto out;
    731                 }
    732                
    733                 async_answer_0(rid, ENOENT);
    734                 goto out;
    735         }
    736        
    737 skip_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        
    776 out_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        
     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);
    793746out:
    794        
    795         if (par)
     747        if (par) {
    796748                (void) ops->node_put(par);
    797        
    798         if (cur)
     749        }
     750       
     751        if (cur) {
    799752                (void) ops->node_put(cur);
    800        
    801         if (tmp)
     753        }
     754       
     755        if (tmp) {
    802756                (void) ops->node_put(tmp);
     757        }
    803758}
    804759
  • uspace/lib/fs/libfs.h

    r5b46ec8 r1dff985  
    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 
    64 typedef struct {
    65         mp_data_t mp_data;  /**< Mount point info. */
    6658        void *data;         /**< Data of the file system implementation. */
    6759} fs_node_t;
  • uspace/srv/vfs/vfs.c

    r5b46ec8 r1dff985  
    104104                        vfs_unmount_srv(callid, &call);
    105105                        break;
    106                 case VFS_IN_OPEN:
    107                         vfs_open(callid, &call);
     106                case VFS_IN_WALK:
     107                        vfs_walk(callid, &call);
     108                        break;
     109                case VFS_IN_OPEN2:
     110                        vfs_open2(callid, &call);
    108111                        break;
    109112                case VFS_IN_CLOSE:
     
    125128                        vfs_fstat(callid, &call);
    126129                        break;
    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);
     130                case VFS_IN_UNLINK2:
     131                        vfs_unlink2(callid, &call);
    135132                        break;
    136133                case VFS_IN_RENAME:
  • uspace/srv/vfs/vfs.h

    r5b46ec8 r1dff985  
    9494        vfs_node_type_t type;
    9595        aoff64_t size;
    96         unsigned int lnkcnt;
    9796} vfs_lookup_res_t;
    9897
     
    101100 * which may be associated with it.
    102101 */
    103 typedef struct {
     102typedef struct _vfs_node {
    104103        VFS_TRIPLET;            /**< Identity of the node. */
    105104
     
    110109        unsigned refcnt;
    111110       
    112         /** Number of names this node has in the file system namespace. */
    113         unsigned lnkcnt;
    114 
    115111        ht_link_t nh_link;              /**< Node hash-table link. */
    116112
    117113        vfs_node_type_t type;   /**< Partial info about the node type. */
    118114
    119         aoff64_t size;          /**< Cached size if the node is a file. */
     115        int64_t size;           /**< Cached size if the node is a file. */
    120116
    121117        /**
     
    123119         */
    124120        fibril_rwlock_t contents_rwlock;
     121       
     122        struct _vfs_node *mount;
    125123} vfs_node_t;
    126124
     
    138136        unsigned refcnt;
    139137
     138        int permissions;
     139        bool open_read;
     140        bool open_write;
     141
    140142        /** Append on write. */
    141143        bool append;
     
    176178extern vfs_info_t *fs_handle_to_info(fs_handle_t);
    177179
    178 extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *,
    179     vfs_pair_t *, ...);
     180extern int vfs_lookup_internal(vfs_node_t *, char *, int, vfs_lookup_res_t *);
     181extern int vfs_link_internal(vfs_node_t *, char *, vfs_triplet_t *);
    180182
    181183extern bool vfs_nodes_init(void);
    182184extern vfs_node_t *vfs_node_get(vfs_lookup_res_t *);
     185extern vfs_node_t *vfs_node_peek(vfs_lookup_res_t *result);
    183186extern void vfs_node_put(vfs_node_t *);
    184187extern void vfs_node_forget(vfs_node_t *);
    185188extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t);
    186189
     190extern int64_t vfs_node_get_size(vfs_node_t *node);
     191extern bool vfs_node_has_children(vfs_node_t *node);
    187192
    188193#define MAX_OPEN_FILES  128
     
    207212extern void vfs_mount_srv(ipc_callid_t, ipc_call_t *);
    208213extern void vfs_unmount_srv(ipc_callid_t, ipc_call_t *);
    209 extern void vfs_open(ipc_callid_t, ipc_call_t *);
    210214extern void vfs_sync(ipc_callid_t, ipc_call_t *);
    211215extern void vfs_dup(ipc_callid_t, ipc_call_t *);
     
    216220extern void vfs_truncate(ipc_callid_t, ipc_call_t *);
    217221extern void vfs_fstat(ipc_callid_t, ipc_call_t *);
    218 extern void vfs_stat(ipc_callid_t, ipc_call_t *);
    219 extern void vfs_mkdir(ipc_callid_t, ipc_call_t *);
    220 extern void vfs_unlink(ipc_callid_t, ipc_call_t *);
    221222extern void vfs_rename(ipc_callid_t, ipc_call_t *);
    222223extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *);
     
    233234extern int vfs_rdwr_internal(int, bool, rdwr_io_chunk_t *);
    234235
     236extern void vfs_walk(ipc_callid_t, ipc_call_t *);
     237extern void vfs_open2(ipc_callid_t, ipc_call_t *);
     238extern void vfs_unlink2(ipc_callid_t, ipc_call_t *);
     239
    235240#endif
    236241
  • uspace/srv/vfs/vfs_file.c

    r5b46ec8 r1dff985  
    177177                 * endpoint FS and drop our reference to the underlying VFS node.
    178178                 */
    179                 rc = vfs_file_close_remote(file);
     179                if (file->open_read || file->open_write) {
     180                        rc = vfs_file_close_remote(file);
     181                }
    180182                vfs_node_delref(file->node);
    181183                free(file);
     
    393395         */
    394396        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.
     400        acceptor_file->pos = donor_file->pos;
    395401        acceptor_file->append = donor_file->append;
    396         acceptor_file->pos = donor_file->pos;
     402        acceptor_file->open_read = donor_file->open_read;
     403        acceptor_file->open_write = donor_file->open_write;
    397404
    398405out:
  • uspace/srv/vfs/vfs_lookup.c

    r5b46ec8 r1dff985  
    4646#include <adt/list.h>
    4747#include <vfs/canonify.h>
     48#include <dirent.h>
     49#include <assert.h>
     50
     51#define DPRINTF(...)
    4852
    4953#define min(a, b)  ((a) < (b) ? (a) : (b))
     
    5357uint8_t *plb = NULL;
    5458
    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  */
    68 int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
    69     vfs_pair_t *altroot, ...)
    70 {
    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        
     59static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start, size_t len)
     60{
    9561        fibril_mutex_lock(&plb_mutex);
    9662
    97         plb_entry_t entry;
    98         link_initialize(&entry.plb_link);
    99         entry.len = len;
     63        link_initialize(&entry->plb_link);
     64        entry->len = len;
    10065
    10166        size_t first;   /* the first free index */
     
    138103         */
    139104
    140         entry.index = first;
    141         entry.len = len;
     105        entry->index = first;
     106        entry->len = len;
    142107
    143108        /*
     
    145110         * buffer.
    146111         */
    147         list_append(&entry.plb_link, &plb_entries);
     112        list_append(&entry->plb_link, &plb_entries);
    148113       
    149114        fibril_mutex_unlock(&plb_mutex);
     
    158123        memcpy(plb, &path[cnt1], cnt2);
    159124
    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        
     125        *start = first;
     126        return EOK;
     127}
     128
     129static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
     130{
    171131        fibril_mutex_lock(&plb_mutex);
    172         list_remove(&entry.plb_link);
     132        list_remove(&entry->plb_link);
    173133        /*
    174134         * Erasing the path from PLB will come handy for debugging purposes.
    175135         */
     136        size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
     137        size_t cnt2 = len - cnt1;
    176138        memset(&plb[first], 0, cnt1);
    177139        memset(plb, 0, cnt2);
    178140        fibril_mutex_unlock(&plb_mutex);
    179        
    180         if ((int) rc < EOK)
     141}
     142
     143static 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
     155int 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       
     220out:
     221        DPRINTF("vfs_link_internal() with path '%s' returns %d\n", path, rc);
     222        return rc;
     223}
     224
     225static 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) {
    181240                return (int) rc;
    182 
    183         if (!result)
    184                 return EOK;
     241        }
     242       
     243        unsigned last = *pfirst + *plen;
     244        *pfirst = IPC_GET_ARG3(answer);
     245        *plen = last - *pfirst;
    185246       
    186247        result->triplet.fs_handle = (fs_handle_t) rc;
    187248        result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
    188249        result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
    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        
     250        result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer);
     251        result->type = IPC_GET_ARG5(answer) ? VFS_NODE_DIRECTORY : VFS_NODE_FILE;
    200252        return EOK;
     253}
     254
     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 */
     267int 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       
     349out:
     350        plb_clear_entry(&entry, first, len);
     351        DPRINTF("vfs_lookup_internal() with path '%s' returns %d\n", path, rc);
     352        return rc;
    201353}
    202354
  • uspace/srv/vfs/vfs_node.c

    r5b46ec8 r1dff985  
    4545#include <async.h>
    4646#include <errno.h>
     47#include <macros.h>
    4748
    4849/** Mutex protecting the VFS node hash table. */
     
    106107void vfs_node_delref(vfs_node_t *node)
    107108{
    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) {
     109        bool free_node = false;
     110       
     111        fibril_mutex_lock(&nodes_mutex);
     112       
     113        node->refcnt--;
     114        if (node->refcnt == 0) {
    114115               
    115116                /*
     
    119120               
    120121                hash_table_remove_item(&nodes, &node->nh_link);
    121                 free_vfs_node = true;
    122                
    123                 if (!node->lnkcnt)
    124                         free_fs_node = true;
    125         }
    126        
    127         fibril_mutex_unlock(&nodes_mutex);
    128        
    129         if (free_fs_node) {
    130                
     122                free_node = true;
     123        }
     124       
     125        fibril_mutex_unlock(&nodes_mutex);
     126       
     127        if (free_node) {
    131128                /*
    132                  * The node is not visible in the file system namespace.
    133                  * Free up its resources.
     129                 * DESTROY will free up the file's resources if there are no more hard links.
    134130                 */
    135131               
    136132                async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    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);
     133                async_msg_2(exch, VFS_OUT_DESTROY,
     134                        (sysarg_t) node->service_id, (sysarg_t)node->index);
    141135                vfs_exchange_release(exch);
    142         }
    143        
    144         if (free_vfs_node)
     136
    145137                free(node);
     138        }
    146139}
    147140
     
    190183                node->index = result->triplet.index;
    191184                node->size = result->size;
    192                 node->lnkcnt = result->lnkcnt;
    193185                node->type = result->type;
    194186                fibril_rwlock_initialize(&node->contents_rwlock);
     
    196188        } else {
    197189                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                 }
    203         }
    204 
    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);
     190        }
    208191
    209192        _vfs_node_addref(node);
     193        fibril_mutex_unlock(&nodes_mutex);
     194
     195        return node;
     196}
     197
     198vfs_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        }
    210207        fibril_mutex_unlock(&nodes_mutex);
    211208
     
    318315}
    319316
     317int64_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
     333bool 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
    320341/**
    321342 * @}
  • uspace/srv/vfs/vfs_ops.c

    r5b46ec8 r1dff985  
    6868FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
    6969
    70 vfs_pair_t rootfs = {
    71         .fs_handle = 0,
    72         .service_id = 0
    73 };
    74 
    75 static 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;
     70vfs_node_t *root = NULL;
     71
     72static 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. */
    8894        ipc_call_t answer;
    89        
     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);
     121                       
     122        return EOK;
     123}
     124
     125static int vfs_mount_internal(service_id_t service_id, unsigned flags, unsigned instance,
     126        char *opts, char *fs_name, char *mp)
     127{
    90128        /* 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 {
     129       
     130        if (root == NULL) {
    122131                /* 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                          */
    128                        
    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 {
     132                if (str_cmp(mp, "/") != 0) {
    175133                        /*
    176134                         * We can't resolve this without the root filesystem
    177135                         * being mounted first.
    178136                         */
    179                         fibril_rwlock_write_unlock(&namespace_rwlock);
    180                         async_answer_0(rid, ENOENT);
    181137                        return ENOENT;
    182138                }
    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);
     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. */
    214153                return rc;
    215154        }
    216155       
    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;
     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;
    266188}
    267189
    268190void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request)
    269191{
    270         service_id_t service_id;
    271 
    272192        /*
    273193         * We expect the library to do the device-name to device-handle
     
    275195         * in the request.
    276196         */
    277         service_id = (service_id_t) IPC_GET_ARG1(*request);
     197        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
    278198       
    279199        /*
     
    301221            0, NULL);
    302222        if (rc != EOK) {
     223                async_answer_0(rid, rc);
    303224                free(mp);
    304                 async_answer_0(rid, rc);
    305225                return;
    306226        }
     
    314234            FS_NAME_MAXLEN, 0, NULL);
    315235        if (rc != EOK) {
     236                async_answer_0(rid, rc);
    316237                free(mp);
    317238                free(opts);
    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;
    343 recheck:
    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 
     239                return;
     240        }
     241       
    361242        /* Add the filesystem info to the list of mounted filesystems */
    362243        mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t));
    363244        if (!mtab_ent) {
    364                 async_answer_0(callid, ENOMEM);
    365245                async_answer_0(rid, ENOMEM);
    366246                free(mp);
     
    369249                return;
    370250        }
    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         }
     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);
    383256
    384257        /* Add the filesystem info to the list of mounted filesystems */
    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);
     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);
    398274
    399275        free(mp);
    400276        free(fs_name);
    401277        free(opts);
    402 
    403         /* Acknowledge that we know fs_name. */
    404         async_answer_0(callid, EOK);
    405278}
    406279
    407280void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request)
    408281{
    409         int rc;
     282        /*
     283         * Receive the mount point path.
     284         */
    410285        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        
    416         /*
    417          * Receive the mount point path.
    418          */
    419         rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
     286        int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
    420287            0, NULL);
    421288        if (rc != EOK)
     
    431298         */
    432299        fibril_rwlock_write_lock(&namespace_rwlock);
    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);
     300               
     301        if (str_cmp(mp, "/") == 0) {
    440302                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        
    468         if (str_cmp(mp, "/") == 0) {
    469303               
    470304                /*
     
    475309                 */
    476310               
    477                 exch = vfs_exchange_grab(mr_node->fs_handle);
    478                 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
    479                     mr_node->service_id);
     311                if (!root) {
     312                        fibril_rwlock_write_unlock(&namespace_rwlock);
     313                        async_answer_0(rid, ENOENT);
     314                        return;
     315                }
     316               
     317                /*
     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.
     323                 */
     324                if (vfs_nodes_refcount_sum_get(root->fs_handle, root->service_id) != 1) {
     325                        fibril_rwlock_write_unlock(&namespace_rwlock);
     326                        async_answer_0(rid, EBUSY);
     327                        return;
     328                }
     329               
     330                async_exch_t *exch = vfs_exchange_grab(root->fs_handle);
     331                rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, root->service_id);
    480332                vfs_exchange_release(exch);
    481333               
    482                 if (rc != EOK) {
    483                         fibril_rwlock_write_unlock(&namespace_rwlock);
    484                         free(mp);
    485                         vfs_node_put(mr_node);
    486                         async_answer_0(rid, rc);
    487                         return;
    488                 }
    489                
    490                 rootfs.fs_handle = 0;
    491                 rootfs.service_id = 0;
    492         } else {
    493                
    494                 /*
    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.
    499                  */
    500                
    501                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
    502                 if (rc != EOK) {
    503                         fibril_rwlock_write_unlock(&namespace_rwlock);
    504                         free(mp);
    505                         vfs_node_put(mr_node);
    506                         async_answer_0(rid, rc);
    507                         return;
    508                 }
    509                
    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);
    522                 vfs_exchange_release(exch);
    523                
    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. */
     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);
    534364                vfs_node_put(mp_node);
    535                 /* Drop the reference from when the file system was mounted. */
     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);
    536379                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);
     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);
    544394        fibril_rwlock_write_unlock(&namespace_rwlock);
    545 
     395       
    546396        fibril_mutex_lock(&mtab_list_lock);
    547 
    548397        int found = 0;
    549398
     
    560409        fibril_mutex_unlock(&mtab_list_lock);
    561410
    562         free(mp);
    563 
     411        free(mp);       
     412       
    564413        async_answer_0(rid, EOK);
    565 }
    566 
    567 void 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))) {
     414        return;
     415}
     416
     417static 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
     436static 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
     454void 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)) {
    592464                async_answer_0(rid, EINVAL);
    593465                return;
    594466        }
    595467       
    596         if (oflag & O_CREAT)
    597                 lflag |= L_CREATE;
    598         if (oflag & O_EXCL)
    599                 lflag |= L_EXCLUSIVE;
    600        
    601468        char *path;
    602         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    603         if (rc != EOK) {
     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       
     487        vfs_lookup_res_t lr;
     488        rc = vfs_lookup_internal(parent_node, path, walk_lookup_flags(flags), &lr);
     489        free(path);
     490
     491        if (rc != EOK) {
     492                fibril_rwlock_read_unlock(&namespace_rwlock);
     493                if (parent) {
     494                        vfs_file_put(parent);
     495                }
    604496                async_answer_0(rid, rc);
    605497                return;
    606498        }
    607499       
    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(). */
    619         vfs_lookup_res_t 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. */
    632         free(path);
    633        
    634500        vfs_node_t *node = vfs_node_get(&lr);
    635         if (lflag & L_CREATE)
    636                 fibril_rwlock_write_unlock(&namespace_rwlock);
    637         else
    638                 fibril_rwlock_read_unlock(&namespace_rwlock);
    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);
     501       
     502        int fd = vfs_fd_alloc(false);
    667503        if (fd < 0) {
    668504                vfs_node_put(node);
     505                if (parent) {
     506                        vfs_file_put(parent);
     507                }
    669508                async_answer_0(rid, fd);
    670509                return;
    671510        }
     511       
    672512        vfs_file_t *file = vfs_file_get(fd);
    673         assert(file);
     513        assert(file != NULL);
     514       
    674515        file->node = node;
    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);
     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       
    687524        vfs_file_put(file);
    688        
    689         /* Success! Return the new file descriptor to the client. */
     525        if (parent) {
     526                vfs_file_put(parent);
     527        }
     528       
     529        fibril_rwlock_read_unlock(&namespace_rwlock);
     530
    690531        async_answer_1(rid, EOK, fd);
     532}
     533
     534void 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);
    691583}
    692584
     
    816708        fibril_mutex_lock(&file->lock);
    817709       
     710        if ((read && !file->open_read) || (!read && !file->open_write)) {
     711                fibril_mutex_unlock(&file->lock);
     712                return EINVAL;
     713        }
     714       
    818715        vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
    819716        assert(fs_info);
     
    854751        size_t bytes = IPC_GET_ARG1(answer);
    855752       
    856         if (file->node->type == VFS_NODE_DIRECTORY)
     753        if (file->node->type == VFS_NODE_DIRECTORY) {
    857754                fibril_rwlock_read_unlock(&namespace_rwlock);
     755        }
    858756       
    859757        /* Unlock the VFS node. */
     
    953851        case SEEK_END:
    954852                fibril_rwlock_read_lock(&file->node->contents_rwlock);
    955                 aoff64_t size = file->node->size;
     853                aoff64_t size = vfs_node_get_size(file->node);
    956854               
    957855                if ((off >= 0) && (size + off < size)) {
     
    1061959}
    1062960
    1063 void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
    1064 {
     961static 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);
     966        vfs_exchange_release(exch);
     967}
     968
     969void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request)
     970{
     971        int rc;
    1065972        char *path;
    1066         int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
     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);
    1067982        if (rc != EOK) {
    1068983                async_answer_0(rid, rc);
     
    1070985        }
    1071986       
    1072         ipc_callid_t callid;
    1073         if (!async_data_read_receive(&callid, NULL)) {
     987        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       
     1022        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
     1033exit:
     1034        if (path) {
    10741035                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        
    1107         vfs_exchange_release(exch);
    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 
    1117 void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
    1118 {
    1119         int mode = IPC_GET_ARG1(*request);
    1120        
    1121         char *path;
    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;
     1036        }
     1037        if (parent) {
     1038                vfs_file_put(parent);
     1039        }
     1040        if (expect) {
     1041                vfs_file_put(expect);
     1042        }
     1043        fibril_rwlock_write_unlock(&namespace_rwlock);
     1044        async_answer_0(rid, rc);
     1045}
     1046
     1047static 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
     1066static 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] == '/');
    11301087       
    11311088        fibril_rwlock_write_lock(&namespace_rwlock);
    1132         int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
    1133         rc = vfs_lookup_internal(path, lflag, NULL, NULL);
     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);
    11341144        fibril_rwlock_write_unlock(&namespace_rwlock);
    1135         free(path);
    1136         async_answer_0(rid, rc);
    1137 }
    1138 
    1139 void 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 */
    1152         vfs_lookup_res_t lr;
    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);
    1170         fibril_rwlock_write_unlock(&namespace_rwlock);
    1171         vfs_node_put(node);
    1172         async_answer_0(rid, EOK);
     1145        return EOK;
    11731146}
    11741147
    11751148void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
    11761149{
     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       
    11771159        /* Retrieve the old path. */
    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;
     1160        rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
     1161        if (rc != EOK) {
     1162                goto out;
    11831163        }
    11841164       
    11851165        /* Retrieve the new path. */
    1186         char *new;
    11871166        rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
    11881167        if (rc != EOK) {
    1189                 free(old);
    1190                 async_answer_0(rid, rc);
    1191                 return;
     1168                goto out;
    11921169        }
    11931170       
     
    11981175       
    11991176        if ((!oldc) || (!newc)) {
    1200                 async_answer_0(rid, EINVAL);
     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
     1198out:
     1199        async_answer_0(rid, rc);
     1200
     1201        if (old) {
    12011202                free(old);
     1203        }
     1204        if (new) {
    12021205                free(new);
    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);
     1206        }
     1207        if (base) {
     1208                vfs_file_put(base);
     1209        }
    13621210}
    13631211
     
    14871335        vfs_lookup_res_t lr;
    14881336        fibril_rwlock_read_lock(&namespace_rwlock);
    1489         rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
     1337        rc = vfs_lookup_internal(root, path, L_NONE, &lr);
    14901338        free(path);
    14911339        if (rc != EOK) {
Note: See TracChangeset for help on using the changeset viewer.