Changeset bf9dc4e2 in mainline


Ignore:
Timestamp:
2013-07-28T19:32:36Z (11 years ago)
Author:
Jiri Zarevucky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
778d26d
Parents:
d60ce4a
Message:

Relativize and simplify lookup().

Location:
uspace
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/include/ipc/vfs.h

    rd60ce4a rbf9dc4e2  
    9797        VFS_OUT_STAT,
    9898        VFS_OUT_LOOKUP,
     99        VFS_OUT_LINK,
    99100        VFS_OUT_DESTROY,
    100101        VFS_OUT_LAST
     
    125126
    126127/**
    127  * Lookup will succeed only if the object is a root directory. The flag is
    128  * mutually exclusive with L_FILE and L_MP.
    129  */
    130 #define L_ROOT                  4
    131 
    132 /**
    133128 * Lookup will succeed only if the object is a mount point. The flag is mutually
    134129 * exclusive with L_FILE and L_ROOT.
     
    147142 */
    148143#define L_CREATE                32
    149 
    150 /**
    151  * L_LINK is used for linking to an already existing nodes.
    152  */
    153 #define L_LINK                  64
    154144
    155145/**
  • uspace/lib/fs/libfs.c

    rd60ce4a rbf9dc4e2  
    6262        } while (0)
    6363
     64#define DPRINTF(...)
     65
     66#define LOG_EXIT(rc) \
     67        DPRINTF("Exiting %s() with rc = %d at line %d\n", __FUNC__, rc, __LINE__);
     68
    6469static fs_reg_t reg;
    6570
     
    6974static void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
    7075static void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
     76static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t,
     77    ipc_call_t *);
    7178static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    7279    ipc_call_t *);
     
    121128               
    122129        libfs_unmount(libfs_ops, rid, req);
     130}
     131
     132static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req)
     133{
     134        libfs_link(libfs_ops, reg.fs_handle, rid, req);
    123135}
    124136
     
    250262                        vfs_out_unmount(callid, &call);
    251263                        break;
     264                case VFS_OUT_LINK:
     265                        vfs_out_link(callid, &call);
     266                        break;
    252267                case VFS_OUT_LOOKUP:
    253268                        vfs_out_lookup(callid, &call);
     
    486501}
    487502
     503static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos, unsigned last)
     504{
     505        unsigned pos = *ppos;
     506        unsigned size = 0;
     507       
     508        if (pos == last) {
     509                *sz = 0;
     510                return ERANGE;
     511        }
     512
     513        char c = plb_get_char(pos);
     514        if (c == '/') {
     515                pos++;
     516        }
     517       
     518        for (int i = 0; i <= NAME_MAX; i++) {
     519                c = plb_get_char(pos);
     520                if (pos == last || c == '/') {
     521                        dest[i] = 0;
     522                        *ppos = pos;
     523                        *sz = size;
     524                        return EOK;
     525                }
     526                dest[i] = c;
     527                pos++;
     528                size++;
     529        }
     530        return ENAMETOOLONG;
     531}
     532
     533static int receive_fname(char *buffer)
     534{
     535        size_t size;
     536        ipc_callid_t wcall;
     537       
     538        if (!async_data_write_receive(&wcall, &size)) {
     539                return ENOENT;
     540        }
     541        if (size > NAME_MAX + 1) {
     542                async_answer_0(wcall, ERANGE);
     543                return ERANGE;
     544        }
     545        return async_data_write_finalize(wcall, buffer, size);
     546}
     547
     548/** Link a file at a path.
     549 */
     550void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, ipc_call_t *req)
     551{
     552        service_id_t parent_sid = IPC_GET_ARG1(*req);
     553        fs_index_t parent_index = IPC_GET_ARG2(*req);
     554        fs_index_t child_index = IPC_GET_ARG3(*req);
     555       
     556        char component[NAME_MAX + 1];
     557        int rc = receive_fname(component);
     558        if (rc != EOK) {
     559                async_answer_0(rid, rc);
     560                return;
     561        }
     562
     563        fs_node_t *parent = NULL;
     564        rc = ops->node_get(&parent, parent_sid, parent_index);
     565        if (parent == NULL) {
     566                async_answer_0(rid, rc == EOK ? EBADF : rc);
     567                return;
     568        }
     569       
     570        fs_node_t *child = NULL;
     571        rc = ops->node_get(&child, parent_sid, child_index);
     572        if (child == NULL) {
     573                async_answer_0(rid, rc == EOK ? EBADF : rc);
     574                ops->node_put(parent);
     575                return;
     576        }
     577       
     578        rc = ops->link(parent, child, component);
     579        ops->node_put(parent);
     580        ops->node_put(child);
     581        async_answer_0(rid, rc);
     582}
     583
    488584/** Lookup VFS triplet by name in the file system name space.
    489585 *
     
    499595 *
    500596 */
    501 void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
    502     ipc_call_t *req)
    503 {
    504         unsigned int first = IPC_GET_ARG1(*req);
    505         unsigned int last = IPC_GET_ARG2(*req);
    506         unsigned int next = first;
     597void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, ipc_call_t *req)
     598{
     599        unsigned first = IPC_GET_ARG1(*req);
     600        unsigned len = IPC_GET_ARG2(*req);
    507601        service_id_t service_id = IPC_GET_ARG3(*req);
    508         int lflag = IPC_GET_ARG4(*req);
    509         fs_index_t index = IPC_GET_ARG5(*req);
     602        fs_index_t index = IPC_GET_ARG4(*req);
     603        int lflag = IPC_GET_ARG5(*req);
     604       
     605        DPRINTF("Entered libfs_lookup()\n");
     606       
     607        // TODO: Validate flags.
     608       
     609        unsigned next = first;
     610        unsigned last = first + len;
     611       
    510612        char component[NAME_MAX + 1];
    511         int len;
    512613        int rc;
    513        
    514         if (last < next)
    515                 last += PLB_SIZE;
    516614       
    517615        fs_node_t *par = NULL;
    518616        fs_node_t *cur = NULL;
    519617        fs_node_t *tmp = NULL;
    520        
    521         rc = ops->root_get(&cur, service_id);
    522         on_error(rc, goto out_with_answer);
     618        unsigned clen = 0;
     619       
     620        if (index == (fs_index_t)-1) {
     621                rc = ops->root_get(&cur, service_id);
     622        } else {
     623                rc = ops->node_get(&cur, service_id, index);
     624        }
     625        if (rc != EOK) {
     626                async_answer_0(rid, rc);
     627                LOG_EXIT(rc);
     628                goto out;
     629        }
     630       
     631        assert(cur != NULL);
    523632       
    524633        if (cur->mp_data.mp_active) {
    525634                async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
    526                 async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
    527                     cur->mp_data.service_id, lflag, index,
    528                     IPC_FF_ROUTE_FROM_ME);
     635                async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last - next,
     636                    cur->mp_data.service_id, (fs_index_t) -1, lflag, IPC_FF_ROUTE_FROM_ME);
    529637                async_exchange_end(exch);
    530638               
    531639                (void) ops->node_put(cur);
    532                 return;
    533         }
    534        
    535         /* Eat slash */
    536         if (plb_get_char(next) == '/')
    537                 next++;
    538        
    539         while (next <= last) {
    540                 bool has_children;
    541                
    542                 rc = ops->has_children(&has_children, cur);
    543                 on_error(rc, goto out_with_answer);
    544                 if (!has_children)
    545                         break;
     640                DPRINTF("Passing to another filesystem instance.\n");
     641                return;
     642        }
     643       
     644        /* Find the file and its parent. */
     645       
     646        while (next != last) {
     647                if (cur == NULL) {
     648                        async_answer_0(rid, ENOENT);
     649                        LOG_EXIT(ENOENT);
     650                        goto out;
     651                }
     652                if (!ops->is_directory(cur)) {
     653                        async_answer_0(rid, ENOTDIR);
     654                        LOG_EXIT(ENOTDIR);
     655                        goto out;
     656                }
    546657               
    547658                /* Collect the component */
    548                 len = 0;
    549                 while ((next <= last) && (plb_get_char(next) != '/')) {
    550                         if (len + 1 == NAME_MAX) {
    551                                 /* Component length overflow */
    552                                 async_answer_0(rid, ENAMETOOLONG);
    553                                 goto out;
    554                         }
    555                         component[len++] = plb_get_char(next);
    556                         /* Process next character */
    557                         next++;
    558                 }
    559                
    560                 assert(len);
    561                 component[len] = '\0';
    562                 /* Eat slash */
    563                 next++;
     659                rc = plb_get_component(component, &clen, &next, last);
     660                assert(rc != ERANGE);
     661                if (rc != EOK) {
     662                        async_answer_0(rid, rc);
     663                        LOG_EXIT(rc);
     664                        goto out;
     665                }
     666               
     667                if (clen == 0) {
     668                        /* The path is just "/". */
     669                        break;
     670                }
     671               
     672                assert(component[clen] == 0);
    564673               
    565674                /* Match the component */
    566675                rc = ops->match(&tmp, cur, component);
    567                 on_error(rc, goto out_with_answer);
     676                if (rc != EOK) {
     677                        async_answer_0(rid, rc);
     678                        LOG_EXIT(rc);
     679                        goto out;
     680                }
    568681               
    569682                /*
     
    578691
    579692                if ((tmp) && (tmp->mp_data.mp_active) &&
    580                     (!(lflag & L_MP) || (next <= last))) {
    581                         if (next > last)
    582                                 next = last = first;
    583                         else
    584                                 next--;
    585                        
     693                    (!(lflag & L_MP) || (next < last))) {
    586694                        async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
    587695                        async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
    588                             last, tmp->mp_data.service_id, lflag, index,
     696                            last - next, tmp->mp_data.service_id, (fs_index_t) -1, lflag,
    589697                            IPC_FF_ROUTE_FROM_ME);
    590698                        async_exchange_end(exch);
    591                        
    592                         (void) ops->node_put(cur);
    593                         (void) ops->node_put(tmp);
    594                         if (par)
    595                                 (void) ops->node_put(par);
    596                         return;
    597                 }
    598                
    599                 /* Handle miss: match amongst siblings */
    600                 if (!tmp) {
    601                         if (next <= last) {
    602                                 /* There are unprocessed components */
    603                                 async_answer_0(rid, ENOENT);
     699                        DPRINTF("Passing to another filesystem instance.\n");
     700                        goto out;
     701                }
     702               
     703                /* Descend one level */
     704                if (par) {
     705                        rc = ops->node_put(par);
     706                        if (rc != EOK) {
     707                                async_answer_0(rid, rc);
     708                                LOG_EXIT(rc);
    604709                                goto out;
    605710                        }
    606                        
    607                         /* Miss in the last component */
    608                         if (lflag & (L_CREATE | L_LINK)) {
    609                                 /* Request to create a new link */
    610                                 if (!ops->is_directory(cur)) {
    611                                         async_answer_0(rid, ENOTDIR);
    612                                         goto out;
    613                                 }
    614                                
    615                                 fs_node_t *fn;
    616                                 if (lflag & L_CREATE)
    617                                         rc = ops->create(&fn, service_id,
    618                                             lflag);
    619                                 else
    620                                         rc = ops->node_get(&fn, service_id,
    621                                             index);
    622                                 on_error(rc, goto out_with_answer);
    623                                
    624                                 if (fn) {
    625                                         rc = ops->link(cur, fn, component);
    626                                         if (rc != EOK) {
    627                                                 if (lflag & L_CREATE)
    628                                                         (void) ops->destroy(fn);
    629                                                 else
    630                                                         (void) ops->node_put(fn);
    631                                                 async_answer_0(rid, rc);
    632                                         } else {
    633                                                 (void) ops->node_put(cur);
    634                                                 cur = fn;
    635                                                 goto out_with_answer;
    636                                         }
    637                                 } else
    638                                         async_answer_0(rid, ENOSPC);
    639                                
    640                                 goto out;
    641                         }
    642                        
    643                         async_answer_0(rid, ENOENT);
    644                         goto out;
    645                 }
    646                
    647                 if (par) {
    648                         rc = ops->node_put(par);
    649                         on_error(rc, goto out_with_answer);
    650                 }
    651                
    652                 /* Descend one level */
     711                }
     712               
    653713                par = cur;
    654714                cur = tmp;
     
    656716        }
    657717       
    658         /* Handle miss: excessive components */
    659         if (next <= last) {
    660                 bool has_children;
    661                 rc = ops->has_children(&has_children, cur);
    662                 on_error(rc, goto out_with_answer);
    663                
    664                 if (has_children)
    665                         goto skip_miss;
    666                
    667                 if (lflag & (L_CREATE | L_LINK)) {
    668                         if (!ops->is_directory(cur)) {
    669                                 async_answer_0(rid, ENOTDIR);
    670                                 goto out;
    671                         }
    672                        
    673                         /* Collect next component */
    674                         len = 0;
    675                         while (next <= last) {
    676                                 if (plb_get_char(next) == '/') {
    677                                         /* More than one component */
    678                                         async_answer_0(rid, ENOENT);
    679                                         goto out;
    680                                 }
    681                                
    682                                 if (len + 1 == NAME_MAX) {
    683                                         /* Component length overflow */
    684                                         async_answer_0(rid, ENAMETOOLONG);
    685                                         goto out;
    686                                 }
    687                                
    688                                 component[len++] = plb_get_char(next);
    689                                 /* Process next character */
    690                                 next++;
    691                         }
    692                        
    693                         assert(len);
    694                         component[len] = '\0';
    695                        
    696                         fs_node_t *fn;
    697                         if (lflag & L_CREATE)
    698                                 rc = ops->create(&fn, service_id, lflag);
    699                         else
    700                                 rc = ops->node_get(&fn, service_id, index);
    701                         on_error(rc, goto out_with_answer);
    702                        
    703                         if (fn) {
    704                                 rc = ops->link(cur, fn, component);
    705                                 if (rc != EOK) {
    706                                         if (lflag & L_CREATE)
    707                                                 (void) ops->destroy(fn);
    708                                         else
    709                                                 (void) ops->node_put(fn);
    710                                         async_answer_0(rid, rc);
    711                                 } else {
    712                                         (void) ops->node_put(cur);
    713                                         cur = fn;
    714                                         goto out_with_answer;
    715                                 }
    716                         } else
    717                                 async_answer_0(rid, ENOSPC);
    718                        
     718        /* At this point, par is either NULL or a directory.
     719         * If cur is NULL, the looked up file does not exist yet.
     720         */
     721         
     722        assert(par == NULL || ops->is_directory(par));
     723        assert(par != NULL || cur != NULL);
     724       
     725        /* Check for some error conditions. */
     726       
     727        if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
     728                async_answer_0(rid, EISDIR);
     729                LOG_EXIT(EISDIR);
     730                goto out;
     731        }
     732       
     733        if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
     734                async_answer_0(rid, ENOTDIR);
     735                LOG_EXIT(ENOTDIR);
     736                goto out;
     737        }
     738       
     739        /* Unlink. */
     740       
     741        if (lflag & L_UNLINK) {
     742                if (!cur) {
     743                        async_answer_0(rid, ENOENT);
     744                        LOG_EXIT(ENOENT);
    719745                        goto out;
    720746                }
    721                
    722                 async_answer_0(rid, ENOENT);
    723                 goto out;
    724         }
    725        
    726 skip_miss:
    727        
    728         /* Handle hit */
    729         if (lflag & L_UNLINK) {
     747                if (!par) {
     748                        async_answer_0(rid, EINVAL);
     749                        LOG_EXIT(EINVAL);
     750                        goto out;
     751                }
     752               
    730753                unsigned int old_lnkcnt = ops->lnkcnt_get(cur);
    731754                rc = ops->unlink(par, cur, component);
    732                
    733755                if (rc == EOK) {
    734756                        aoff64_t size = ops->size_get(cur);
     
    736758                            ops->index_get(cur), LOWER32(size), UPPER32(size),
    737759                            old_lnkcnt);
    738                 } else
     760                        LOG_EXIT(EOK);
     761                } else {
    739762                        async_answer_0(rid, rc);
    740                
     763                        LOG_EXIT(rc);
     764                }
    741765                goto out;
    742766        }
    743767       
    744         if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
    745             (lflag & L_LINK)) {
    746                 async_answer_0(rid, EEXIST);
     768        /* Create. */
     769       
     770        if (lflag & L_CREATE) {
     771                if (cur && (lflag & L_EXCLUSIVE)) {
     772                        async_answer_0(rid, EEXIST);
     773                        LOG_EXIT(EEXIST);
     774                        goto out;
     775                }
     776       
     777                if (!cur) {
     778                        rc = ops->create(&cur, service_id, lflag & (L_FILE|L_DIRECTORY));
     779                        if (rc != EOK) {
     780                                async_answer_0(rid, rc);
     781                                LOG_EXIT(rc);
     782                                goto out;
     783                        }
     784                        if (!cur) {
     785                                async_answer_0(rid, ENOSPC);
     786                                LOG_EXIT(ENOSPC);
     787                                goto out;
     788                        }
     789                       
     790                        rc = ops->link(par, cur, component);
     791                        if (rc != EOK) {
     792                                (void) ops->destroy(cur);
     793                                cur = NULL;
     794                                async_answer_0(rid, rc);
     795                                LOG_EXIT(rc);
     796                                goto out;
     797                        }
     798                }
     799        }
     800       
     801        /* Return. */
     802       
     803        if (!cur) {
     804                async_answer_0(rid, ENOENT);
     805                LOG_EXIT(ENOENT);
    747806                goto out;
    748807        }
    749808       
    750         if ((lflag & L_FILE) && (ops->is_directory(cur))) {
    751                 async_answer_0(rid, EISDIR);
    752                 goto out;
    753         }
    754        
    755         if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
    756                 async_answer_0(rid, ENOTDIR);
    757                 goto out;
    758         }
    759 
    760         if ((lflag & L_ROOT) && par) {
    761                 async_answer_0(rid, EINVAL);
    762                 goto out;
    763         }
    764        
    765 out_with_answer:
    766        
    767         if (rc == EOK) {
    768                 if (lflag & L_OPEN)
    769                         rc = ops->node_open(cur);
    770                
    771                 if (rc == EOK) {
    772                         aoff64_t size = ops->size_get(cur);
    773                         async_answer_5(rid, fs_handle, service_id,
    774                             ops->index_get(cur), LOWER32(size), UPPER32(size),
    775                             ops->lnkcnt_get(cur));
    776                 } else
     809        if (lflag & L_OPEN) {
     810                rc = ops->node_open(cur);
     811                if (rc != EOK) {
    777812                        async_answer_0(rid, rc);
    778                
    779         } else
    780                 async_answer_0(rid, rc);
    781        
     813                        LOG_EXIT(rc);
     814                        goto out;
     815                }
     816        }
     817       
     818        aoff64_t size = ops->size_get(cur);
     819        async_answer_5(rid, fs_handle, service_id,
     820                ops->index_get(cur), LOWER32(size), UPPER32(size),
     821                ops->lnkcnt_get(cur));
     822       
     823        LOG_EXIT(EOK);
    782824out:
    783        
    784         if (par)
     825        if (par) {
    785826                (void) ops->node_put(par);
    786        
    787         if (cur)
     827        }
     828       
     829        if (cur) {
    788830                (void) ops->node_put(cur);
    789        
    790         if (tmp)
     831        }
     832       
     833        if (tmp) {
    791834                (void) ops->node_put(tmp);
     835        }
    792836}
    793837
  • uspace/srv/vfs/vfs.h

    rd60ce4a rbf9dc4e2  
    180180extern vfs_info_t *fs_handle_to_info(fs_handle_t);
    181181
    182 extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *,
    183     vfs_pair_t *, ...);
     182extern int vfs_lookup_internal(vfs_triplet_t *, char *, int, vfs_lookup_res_t *);
     183extern int vfs_link_internal(vfs_triplet_t *, char *, vfs_triplet_t *);
    184184
    185185extern bool vfs_nodes_init(void);
  • uspace/srv/vfs/vfs_lookup.c

    rd60ce4a rbf9dc4e2  
    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)
    181                 return (int) rc;
    182 
    183         if (!result)
    184                 return 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_triplet_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        char *slash = _strrchr(path, '/');
     176        if (slash && slash != path) {
     177                if (slash[1] == 0) {
     178                        rc = EINVAL;
     179                        goto out;
     180                }
     181               
     182                memcpy(component, slash + 1, str_size(slash));
     183                *slash = 0;
     184               
     185                rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
     186                if (rc != EOK) {
     187                        goto out;
     188                }
     189                base = &res.triplet;
     190               
     191                *slash = '/';
     192        } else {
     193                memcpy(component, path + 1, str_size(path));
     194        }
     195       
     196        if (base->fs_handle != child->fs_handle || base->service_id != child->service_id) {
     197                rc = EXDEV;
     198                goto out;
     199        }
     200       
     201        async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
     202        aid_t req = async_send_3(exch, VFS_OUT_LINK, base->service_id, base->index, child->index, NULL);
     203       
     204        rc = async_data_write_start(exch, component, str_size(component) + 1);
     205        sysarg_t orig_rc;
     206        async_wait_for(req, &orig_rc);
     207        vfs_exchange_release(exch);
     208        if (orig_rc != EOK) {
     209                rc = orig_rc;
     210        }
     211       
     212out:
     213        DPRINTF("vfs_link_internal() with path '%s' returns %d\n", path, rc);
     214        return rc;
     215}
     216
     217/** Perform a path lookup.
     218 *
     219 * @param base    The file from which to perform the lookup.
     220 * @param path    Path to be resolved; it must be a NULL-terminated
     221 *                string.
     222 * @param lflag   Flags to be used during lookup.
     223 * @param result  Empty structure where the lookup result will be stored.
     224 *                Can be NULL.
     225 *
     226 * @return EOK on success or an error code from errno.h.
     227 *
     228 */
     229int vfs_lookup_internal(vfs_triplet_t *base, char *path, int lflag, vfs_lookup_res_t *result)
     230{
     231        assert(base != NULL);
     232        assert(path != NULL);
     233       
     234        sysarg_t rc;
     235       
     236        if (!base->fs_handle) {
     237                rc = ENOENT;
     238                goto out;
     239        }
     240       
     241        size_t len;
     242        char *npath = canonify(path, &len);
     243        if (!npath) {
     244                rc = EINVAL;
     245                goto out;
     246        }
     247        path = npath;
     248       
     249        assert(path[0] == '/');
     250       
     251        size_t first;
     252       
     253        plb_entry_t entry;
     254        rc = plb_insert_entry(&entry, path, &first, len);
     255        if (rc != EOK) {
     256                goto out;
     257        }
     258       
     259        ipc_call_t answer;
     260        async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
     261        aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first, (sysarg_t) len,
     262            (sysarg_t) base->service_id, (sysarg_t) base->index, (sysarg_t) lflag, &answer);
     263        async_wait_for(req, &rc);
     264        vfs_exchange_release(exch);
     265       
     266        plb_clear_entry(&entry, first, len);
     267       
     268        if ((int) rc < 0) {
     269                goto out;
     270        }
     271       
     272        if (!result) {
     273                rc = EOK;
     274                goto out;
     275        }
    185276       
    186277        result->triplet.fs_handle = (fs_handle_t) rc;
     
    197288        else
    198289                result->type = VFS_NODE_UNKNOWN;
    199        
    200         return EOK;
     290
     291        rc = EOK;
     292
     293out:
     294        DPRINTF("vfs_lookup_internal() with path '%s' returns %d\n", path, rc);
     295        return rc;
    201296}
    202297
  • uspace/srv/vfs/vfs_ops.c

    rd60ce4a rbf9dc4e2  
    6868FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
    6969
    70 vfs_pair_t rootfs = {
    71         .fs_handle = 0,
    72         .service_id = 0
    73 };
     70vfs_node_t *root = NULL;
    7471
    7572static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
     
    9087        /* Resolve the path to the mountpoint. */
    9188        fibril_rwlock_write_lock(&namespace_rwlock);
    92         if (rootfs.fs_handle) {
    93                 /* We already have the root FS. */
    94                 if (str_cmp(mp, "/") == 0) {
    95                         /* Trying to mount root FS over root FS */
    96                         fibril_rwlock_write_unlock(&namespace_rwlock);
    97                         async_answer_0(rid, EBUSY);
    98                         return EBUSY;
    99                 }
    100                
    101                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
    102                 if (rc != EOK) {
    103                         /* The lookup failed for some reason. */
    104                         fibril_rwlock_write_unlock(&namespace_rwlock);
    105                         async_answer_0(rid, rc);
    106                         return rc;
    107                 }
    108                
    109                 mp_node = vfs_node_get(&mp_res);
    110                 if (!mp_node) {
    111                         fibril_rwlock_write_unlock(&namespace_rwlock);
    112                         async_answer_0(rid, ENOMEM);
    113                         return ENOMEM;
    114                 }
    115                
    116                 /*
    117                  * Now we hold a reference to mp_node.
    118                  * It will be dropped upon the corresponding VFS_IN_UNMOUNT.
    119                  * This prevents the mount point from being deleted.
    120                  */
    121         } else {
     89        if (root == NULL) {
    12290                /* We still don't have the root file system mounted. */
    123                 if (str_cmp(mp, "/") == 0) {
    124                         /*
    125                          * For this simple, but important case,
    126                          * we are almost done.
    127                          */
    128                        
    129                         /* Tell the mountee that it is being mounted. */
    130                         exch = vfs_exchange_grab(fs_handle);
    131                         msg = async_send_1(exch, VFS_OUT_MOUNTED,
    132                             (sysarg_t) service_id, &answer);
    133                         /* Send the mount options */
    134                         rc = async_data_write_start(exch, (void *)opts,
    135                             str_size(opts));
    136                         vfs_exchange_release(exch);
    137                        
    138                         if (rc != EOK) {
    139                                 async_forget(msg);
    140                                 fibril_rwlock_write_unlock(&namespace_rwlock);
    141                                 async_answer_0(rid, rc);
    142                                 return rc;
    143                         }
    144                         async_wait_for(msg, &rc);
    145                        
    146                         if (rc != EOK) {
    147                                 fibril_rwlock_write_unlock(&namespace_rwlock);
    148                                 async_answer_0(rid, rc);
    149                                 return rc;
    150                         }
    151 
    152                         rindex = (fs_index_t) IPC_GET_ARG1(answer);
    153                         rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
    154                             IPC_GET_ARG3(answer));
    155                         rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
    156                        
    157                         mr_res.triplet.fs_handle = fs_handle;
    158                         mr_res.triplet.service_id = service_id;
    159                         mr_res.triplet.index = rindex;
    160                         mr_res.size = rsize;
    161                         mr_res.lnkcnt = rlnkcnt;
    162                         mr_res.type = VFS_NODE_DIRECTORY;
    163                        
    164                         rootfs.fs_handle = fs_handle;
    165                         rootfs.service_id = service_id;
    166                        
    167                         /* Add reference to the mounted root. */
    168                         mr_node = vfs_node_get(&mr_res);
    169                         assert(mr_node);
    170                        
    171                         fibril_rwlock_write_unlock(&namespace_rwlock);
    172                         async_answer_0(rid, rc);
    173                         return rc;
    174                 } else {
     91                if (str_cmp(mp, "/") != 0) {
    17592                        /*
    17693                         * We can't resolve this without the root filesystem
     
    18198                        return ENOENT;
    18299                }
    183         }
     100               
     101                /*
     102                 * For this simple, but important case,
     103                 * we are almost done.
     104                 */
     105                       
     106                /* Tell the mountee that it is being mounted. */
     107                exch = vfs_exchange_grab(fs_handle);
     108                msg = async_send_1(exch, VFS_OUT_MOUNTED,
     109                    (sysarg_t) service_id, &answer);
     110                /* Send the mount options */
     111                rc = async_data_write_start(exch, (void *)opts,
     112                    str_size(opts));
     113                vfs_exchange_release(exch);
     114                       
     115                if (rc != EOK) {
     116                        async_forget(msg);
     117                        fibril_rwlock_write_unlock(&namespace_rwlock);
     118                        async_answer_0(rid, rc);
     119                        return rc;
     120                }
     121                async_wait_for(msg, &rc);
     122                       
     123                if (rc != EOK) {
     124                        fibril_rwlock_write_unlock(&namespace_rwlock);
     125                        async_answer_0(rid, rc);
     126                        return rc;
     127                }
     128
     129                rindex = (fs_index_t) IPC_GET_ARG1(answer);
     130                rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
     131                    IPC_GET_ARG3(answer));
     132                rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
     133               
     134                mr_res.triplet.fs_handle = fs_handle;
     135                mr_res.triplet.service_id = service_id;
     136                mr_res.triplet.index = rindex;
     137                mr_res.size = rsize;
     138                mr_res.lnkcnt = rlnkcnt;
     139                mr_res.type = VFS_NODE_DIRECTORY;
     140                       
     141                /* Add reference to the mounted root. */
     142                root = vfs_node_get(&mr_res);
     143                assert(root);
     144                       
     145                fibril_rwlock_write_unlock(&namespace_rwlock);
     146                async_answer_0(rid, rc);
     147                return rc;
     148        }
     149       
     150        /* We already have the root FS. */
     151        if (str_cmp(mp, "/") == 0) {
     152                /* Trying to mount root FS over root FS */
     153                fibril_rwlock_write_unlock(&namespace_rwlock);
     154                async_answer_0(rid, EBUSY);
     155                return EBUSY;
     156        }
     157       
     158        rc = vfs_lookup_internal((vfs_triplet_t *) root, mp, L_DIRECTORY, &mp_res);
     159        if (rc != EOK) {
     160                /* The lookup failed. */
     161                fibril_rwlock_write_unlock(&namespace_rwlock);
     162                async_answer_0(rid, rc);
     163                return rc;
     164        }
     165       
     166        mp_node = vfs_node_get(&mp_res);
     167        if (!mp_node) {
     168                fibril_rwlock_write_unlock(&namespace_rwlock);
     169                async_answer_0(rid, ENOMEM);
     170                return ENOMEM;
     171        }
     172       
     173        /*
     174         * Now we hold a reference to mp_node.
     175         * It will be dropped upon the corresponding VFS_IN_UNMOUNT.
     176         * This prevents the mount point from being deleted.
     177         */
    184178       
    185179        /*
     
    435429         * Lookup the mounted root and instantiate it.
    436430         */
    437         rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);
     431        rc = vfs_lookup_internal((vfs_triplet_t *) root, mp, 0, &mr_res);
    438432        if (rc != EOK) {
    439433                fibril_rwlock_write_unlock(&namespace_rwlock);
     
    488482                }
    489483               
    490                 rootfs.fs_handle = 0;
    491                 rootfs.service_id = 0;
     484                root = NULL;
    492485        } else {
    493486               
     
    499492                 */
    500493               
    501                 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
     494                rc = vfs_lookup_internal((vfs_triplet_t *) root, mp, L_MP, &mp_res);
    502495                if (rc != EOK) {
    503496                        fibril_rwlock_write_unlock(&namespace_rwlock);
     
    624617        /* Lookup the file structure corresponding to the file descriptor. */
    625618        vfs_file_t *parent = NULL;
    626         vfs_pair_t *parent_node = NULL;
     619        vfs_node_t *parent_node = root;
    627620        // TODO: Client-side root.
    628621        if (parentfd != -1) {
     
    633626                        return;
    634627                }
    635                 parent_node = (vfs_pair_t *)parent->node;
     628                parent_node = parent->node;
    636629        }
    637630       
     
    639632       
    640633        vfs_lookup_res_t lr;
    641         rc = vfs_lookup_internal(path, walk_lookup_flags(flags), &lr, parent_node);
     634        rc = vfs_lookup_internal((vfs_triplet_t *) parent_node, path, walk_lookup_flags(flags), &lr);
    642635        free(path);
    643636
     
    10691062        vfs_file_t *parent = NULL;
    10701063        vfs_file_t *expect = NULL;
    1071         vfs_pair_t *parent_node = NULL;
     1064        vfs_node_t *parent_node = root;
    10721065       
    10731066        int parentfd = IPC_GET_ARG1(*request);
     
    10911084                        goto exit;
    10921085                }
    1093                 parent_node = (vfs_pair_t *)parent->node;
     1086                parent_node = parent->node;
    10941087        }
    10951088       
     
    11021095               
    11031096                vfs_lookup_res_t lr;
    1104                 rc = vfs_lookup_internal(path, lflag, &lr, parent_node);
     1097                rc = vfs_lookup_internal((vfs_triplet_t *) parent_node, path, lflag, &lr);
    11051098                if (rc != EOK) {
    11061099                        goto exit;
     
    11171110       
    11181111        vfs_lookup_res_t lr;
    1119         rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, parent_node);
     1112        rc = vfs_lookup_internal((vfs_triplet_t *) parent_node, path, lflag | L_UNLINK, &lr);
    11201113        if (rc != EOK) {
    11211114                goto exit;
     
    12011194       
    12021195        /* Lookup the node belonging to the old file name. */
    1203         rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
     1196        rc = vfs_lookup_internal((vfs_triplet_t *) root, oldc, L_NONE, &old_lr);
    12041197        if (rc != EOK) {
    12051198                fibril_rwlock_write_unlock(&namespace_rwlock);
     
    12371230       
    12381231        /* Lookup parent of the new file name. */
    1239         rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
     1232        rc = vfs_lookup_internal((vfs_triplet_t *) root, parentc, L_NONE, &new_par_lr);
    12401233        free(parentc);  /* not needed anymore */
    12411234        if (rc != EOK) {
     
    12611254        /* Destroy the old link for the new name. */
    12621255        vfs_node_t *new_node = NULL;
    1263         rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
     1256        rc = vfs_lookup_internal((vfs_triplet_t *) root, newc, L_UNLINK, &new_lr);
    12641257       
    12651258        switch (rc) {
     
    12911284       
    12921285        /* Create the new link for the new name. */
    1293         rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
     1286        rc = vfs_link_internal((vfs_triplet_t *) root, newc, (vfs_triplet_t *) old_node);
    12941287        if (rc != EOK) {
    12951288                fibril_rwlock_write_unlock(&namespace_rwlock);
     
    13081301       
    13091302        /* Destroy the link for the old name. */
    1310         rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
     1303        rc = vfs_lookup_internal((vfs_triplet_t *) root, oldc, L_UNLINK, NULL);
    13111304        if (rc != EOK) {
    13121305                fibril_rwlock_write_unlock(&namespace_rwlock);
Note: See TracChangeset for help on using the changeset viewer.