Ignore:
File:
1 edited

Legend:

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

    r3e6a98c5 r51774cd  
    4646#include <adt/list.h>
    4747#include <vfs/canonify.h>
    48 
    49 #define min(a, b)  ((a) < (b) ? (a) : (b))
     48#include <dirent.h>
     49#include <assert.h>
    5050
    5151FIBRIL_MUTEX_INITIALIZE(plb_mutex);
     
    5353uint8_t *plb = NULL;
    5454
    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        
     55static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start,
     56    size_t len)
     57{
    9558        fibril_mutex_lock(&plb_mutex);
    9659
    97         plb_entry_t entry;
    98         link_initialize(&entry.plb_link);
    99         entry.len = len;
     60        link_initialize(&entry->plb_link);
     61        entry->len = len;
    10062
    10163        size_t first;   /* the first free index */
     
    138100         */
    139101
    140         entry.index = first;
    141         entry.len = len;
     102        entry->index = first;
     103        entry->len = len;
    142104
    143105        /*
     
    145107         * buffer.
    146108         */
    147         list_append(&entry.plb_link, &plb_entries);
     109        list_append(&entry->plb_link, &plb_entries);
    148110       
    149111        fibril_mutex_unlock(&plb_mutex);
     
    158120        memcpy(plb, &path[cnt1], cnt2);
    159121
    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        
     122        *start = first;
     123        return EOK;
     124}
     125
     126static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
     127{
    171128        fibril_mutex_lock(&plb_mutex);
    172         list_remove(&entry.plb_link);
     129        list_remove(&entry->plb_link);
    173130        /*
    174131         * Erasing the path from PLB will come handy for debugging purposes.
    175132         */
     133        size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
     134        size_t cnt2 = len - cnt1;
    176135        memset(&plb[first], 0, cnt1);
    177136        memset(plb, 0, cnt2);
    178137        fibril_mutex_unlock(&plb_mutex);
    179        
    180         if ((int) rc < EOK)
     138}
     139
     140int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
     141{
     142        assert(base != NULL);
     143        assert(child != NULL);
     144        assert(base->fs_handle);
     145        assert(child->fs_handle);
     146        assert(path != NULL);
     147       
     148        vfs_lookup_res_t res;
     149        char component[NAME_MAX + 1];
     150        int rc;
     151       
     152        size_t len;
     153        char *npath = canonify(path, &len);
     154        if (!npath) {
     155                rc = EINVAL;
     156                goto out;
     157        }
     158        path = npath;
     159       
     160        vfs_triplet_t *triplet;
     161       
     162        char *slash = str_rchr(path, L'/');
     163        if (slash && slash != path) {
     164                if (slash[1] == 0) {
     165                        rc = EINVAL;
     166                        goto out;
     167                }
     168               
     169                memcpy(component, slash + 1, str_size(slash));
     170                *slash = 0;
     171               
     172                rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
     173                if (rc != EOK)
     174                        goto out;
     175                triplet = &res.triplet;
     176               
     177                *slash = '/';
     178        } else {
     179                if (base->mount != NULL) {
     180                        rc = EINVAL;
     181                        goto out;
     182                }
     183               
     184                memcpy(component, path + 1, str_size(path));
     185                triplet = (vfs_triplet_t *) base;
     186        }
     187       
     188        if (triplet->fs_handle != child->fs_handle ||
     189            triplet->service_id != child->service_id) {
     190                rc = EXDEV;
     191                goto out;
     192        }
     193       
     194        async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
     195        aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id,
     196            triplet->index, child->index, NULL);
     197       
     198        rc = async_data_write_start(exch, component, str_size(component) + 1);
     199        sysarg_t orig_rc;
     200        async_wait_for(req, &orig_rc);
     201        vfs_exchange_release(exch);
     202        if (orig_rc != EOK)
     203                rc = orig_rc;
     204       
     205out:
     206        return rc;
     207}
     208
     209static int out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
     210    int lflag, vfs_lookup_res_t *result)
     211{
     212        assert(base);
     213        assert(result);
     214       
     215        sysarg_t rc;
     216        ipc_call_t answer;
     217        async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
     218        aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst,
     219            (sysarg_t) *plen, (sysarg_t) base->service_id,
     220            (sysarg_t) base->index, (sysarg_t) lflag, &answer);
     221        async_wait_for(req, &rc);
     222        vfs_exchange_release(exch);
     223       
     224        if ((int) rc < 0)
    181225                return (int) rc;
    182 
    183         if (!result)
    184                 return EOK;
     226       
     227        unsigned last = *pfirst + *plen;
     228        *pfirst = IPC_GET_ARG3(answer) & 0xffff;
     229        *plen = last - *pfirst;
    185230       
    186231        result->triplet.fs_handle = (fs_handle_t) rc;
    187232        result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
    188233        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        
     234        result->size = MERGE_LOUP32(IPC_GET_ARG4(answer), IPC_GET_ARG5(answer));
     235        result->type = (IPC_GET_ARG3(answer) >> 16) ?
     236            VFS_NODE_DIRECTORY : VFS_NODE_FILE;
    200237        return EOK;
     238}
     239
     240static int _vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
     241    vfs_lookup_res_t *result, size_t len)
     242{
     243        size_t first;
     244        int rc;
     245
     246        plb_entry_t entry;
     247        rc = plb_insert_entry(&entry, path, &first, len);
     248        if (rc != EOK)
     249                return rc;
     250       
     251        size_t next = first;
     252        size_t nlen = len;
     253       
     254        vfs_lookup_res_t res;
     255       
     256        /* Resolve path as long as there are mount points to cross. */
     257        while (nlen > 0) {
     258                while (base->mount) {
     259                        if (lflag & L_DISABLE_MOUNTS) {
     260                                rc = EXDEV;
     261                                goto out;
     262                        }
     263                       
     264                        base = base->mount;
     265                }
     266               
     267                rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag,
     268                    &res);
     269                if (rc != EOK)
     270                        goto out;
     271               
     272                if (nlen > 0) {
     273                        base = vfs_node_peek(&res);
     274                        if (!base) {
     275                                rc = ENOENT;
     276                                goto out;
     277                        }
     278                        if (!base->mount) {
     279                                vfs_node_put(base);
     280                                rc = ENOENT;
     281                                goto out;
     282                        }
     283                        vfs_node_put(base);
     284                        if (lflag & L_DISABLE_MOUNTS) {
     285                                rc = EXDEV;
     286                                goto out;
     287                        }
     288                }
     289        }
     290       
     291        assert(nlen == 0);
     292        rc = EOK;
     293       
     294        if (result != NULL) {
     295                /* The found file may be a mount point. Try to cross it. */
     296                if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
     297                        base = vfs_node_peek(&res);
     298                        if (base && base->mount) {
     299                                while (base->mount) {
     300                                        vfs_node_addref(base->mount);
     301                                        vfs_node_t *nbase = base->mount;
     302                                        vfs_node_put(base);
     303                                        base = nbase;
     304                                }
     305                               
     306                                result->triplet = *((vfs_triplet_t *) base);
     307                                result->type = base->type;
     308                                result->size = base->size;
     309                                vfs_node_put(base);
     310                                goto out;
     311                        }
     312                        if (base)
     313                                vfs_node_put(base);
     314                }
     315
     316                *result = res;
     317        }
     318       
     319out:
     320        plb_clear_entry(&entry, first, len);
     321        return rc;
     322}
     323
     324/** Perform a path lookup.
     325 *
     326 * @param base    The file from which to perform the lookup.
     327 * @param path    Path to be resolved; it must be a NULL-terminated
     328 *                string.
     329 * @param lflag   Flags to be used during lookup.
     330 * @param result  Empty structure where the lookup result will be stored.
     331 *                Can be NULL.
     332 *
     333 * @return EOK on success or an error code from errno.h.
     334 *
     335 */
     336int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
     337    vfs_lookup_res_t *result)
     338{
     339        assert(base != NULL);
     340        assert(path != NULL);
     341       
     342        size_t len;
     343        int rc;
     344        char *npath = canonify(path, &len);
     345        if (!npath) {
     346                rc = EINVAL;
     347                return rc;
     348        }
     349        path = npath;
     350       
     351        assert(path[0] == '/');
     352
     353
     354        if (lflag & (L_CREATE | L_UNLINK)) {
     355
     356                /*
     357                 * Creation and destruction of names must be done in two
     358                 * separate steps: lookup of the parent node and the name
     359                 * link/unlink operation itself.  Otherwise the parent
     360                 * filesystem would not be able to tell when a mountpoint is
     361                 * crossed. It would attempt to perform the link/unlink in
     362                 * itself instead of letting the mounted filesystem do it,
     363                 * resulting in wrong behavior. This is the wages of server-side
     364                 * mountpoints.
     365                 */
     366
     367                char *slash = str_rchr(path, L'/');
     368                vfs_node_t *parent = base;
     369               
     370                if (slash != path) {
     371                        int tflag = lflag;
     372                        vfs_lookup_res_t tres;
     373
     374                        tflag &= ~(L_CREATE | L_EXCLUSIVE | L_UNLINK | L_FILE);
     375                        tflag |= L_DIRECTORY;
     376                        rc = _vfs_lookup_internal(base, path, tflag, &tres,
     377                            slash - path);
     378                        if (rc != EOK)
     379                                return rc;
     380                        parent = vfs_node_get(&tres);
     381                        if (!parent)
     382                                return ENOMEM;
     383                } else
     384                        vfs_node_addref(parent);
     385
     386                rc = _vfs_lookup_internal(parent, slash, lflag, result,
     387                    len - (slash - path));
     388
     389                vfs_node_put(parent);
     390
     391        } else {
     392                rc = _vfs_lookup_internal(base, path, lflag, result, len);
     393        }
     394       
     395        return rc;
    201396}
    202397
Note: See TracChangeset for help on using the changeset viewer.