Ignore:
File:
1 edited

Legend:

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

    r3e6a98c5 r5bcd5b7  
    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, 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) {
    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);
    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                __builtin_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
Note: See TracChangeset for help on using the changeset viewer.