Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/vfs/vfs_lookup.c

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