Changeset bf9dc4e2 in mainline for uspace/lib/fs/libfs.c


Ignore:
Timestamp:
2013-07-28T19:32:36Z (12 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().

File:
1 edited

Legend:

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