Changeset 1dff985 in mainline for uspace/lib


Ignore:
Timestamp:
2017-03-03T21:32:38Z (9 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/lib
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • 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;
Note: See TracChangeset for help on using the changeset viewer.