Changes in uspace/lib/fs/libfs.c [b8dbe2f:f9b2cb4c] in mainline


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/fs/libfs.c

    rb8dbe2f rf9b2cb4c  
    3636
    3737#include "libfs.h"
     38#include "../../srv/vfs/vfs.h"
    3839#include <macros.h>
    3940#include <errno.h>
     
    4445#include <mem.h>
    4546#include <sys/stat.h>
     47#include <sys/statfs.h>
    4648#include <stdlib.h>
    47 #include <fibril_synch.h>
    4849
    4950#define on_error(rc, action) \
     
    6263        } while (0)
    6364
    64 #define DPRINTF(...)
    65 
    66 #define LOG_EXIT(rc) \
    67         DPRINTF("Exiting %s() with rc = %d at line %d\n", __FUNC__, rc, __LINE__);
    68 
    6965static fs_reg_t reg;
    7066
     
    7268static libfs_ops_t *libfs_ops = NULL;
    7369
    74 static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    75     ipc_call_t *);
     70static void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
     71static void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
    7672static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    7773    ipc_call_t *);
     
    7975static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    8076    ipc_call_t *);
     77static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
    8178
    8279static void vfs_out_mounted(ipc_callid_t rid, ipc_call_t *req)
     
    107104}
    108105
     106static void vfs_out_mount(ipc_callid_t rid, ipc_call_t *req)
     107{
     108        libfs_mount(libfs_ops, reg.fs_handle, rid, req);
     109}
     110
    109111static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req)
    110112{
     
    117119}
    118120
    119 static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req)
    120 {
    121         libfs_link(libfs_ops, reg.fs_handle, rid, req);
     121static void vfs_out_unmount(ipc_callid_t rid, ipc_call_t *req)
     122{
     123               
     124        libfs_unmount(libfs_ops, rid, req);
    122125}
    123126
     
    190193        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    191194        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
    192 
    193195        int rc;
    194         fs_node_t *node = NULL;
    195         rc = libfs_ops->node_get(&node, service_id, index);
    196         if (rc == EOK && node != NULL) {
    197                 bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
    198                 libfs_ops->node_put(node);
    199                 if (destroy) {
    200                         rc = vfs_out_ops->destroy(service_id, index);
    201                 }
    202         }
     196
     197        rc = vfs_out_ops->destroy(service_id, index);
     198
    203199        async_answer_0(rid, rc);
    204200}
     
    225221}
    226222
    227 static void vfs_out_get_size(ipc_callid_t rid, ipc_call_t *req)
    228 {
    229         service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    230         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
    231         int rc;
    232 
    233         fs_node_t *node = NULL;
    234         rc = libfs_ops->node_get(&node, service_id, index);
    235         if (rc != EOK) {
    236                 async_answer_0(rid, rc);
    237         }
    238         if (node == NULL) {
    239                 async_answer_0(rid, EINVAL);
    240         }
    241        
    242         uint64_t size = libfs_ops->size_get(node);
    243         libfs_ops->node_put(node);
    244        
    245         async_answer_2(rid, EOK, LOWER32(size), UPPER32(size));
    246 }
    247 
    248 static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req)
    249 {
    250         service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    251         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
    252         int rc;
    253 
    254         fs_node_t *node = NULL;
    255         rc = libfs_ops->node_get(&node, service_id, index);
    256         if (rc != EOK) {
    257                 async_answer_0(rid, rc);
    258         }
    259         if (node == NULL) {
    260                 async_answer_0(rid, EINVAL);
    261         }
    262        
    263         bool children = false;
    264         rc = libfs_ops->has_children(&children, node);
    265         libfs_ops->node_put(node);
    266        
    267         if (rc != EOK) {
    268                 async_answer_0(rid, rc);
    269         }
    270         async_answer_0(rid, children ? ENOTEMPTY : EOK);
    271 }
    272 
     223static void vfs_out_statfs(ipc_callid_t rid, ipc_call_t *req)
     224{
     225        libfs_statfs(libfs_ops, reg.fs_handle, rid, req);
     226}
    273227static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    274228{
     
    293247                        vfs_out_mounted(callid, &call);
    294248                        break;
     249                case VFS_OUT_MOUNT:
     250                        vfs_out_mount(callid, &call);
     251                        break;
    295252                case VFS_OUT_UNMOUNTED:
    296253                        vfs_out_unmounted(callid, &call);
    297254                        break;
    298                 case VFS_OUT_LINK:
    299                         vfs_out_link(callid, &call);
     255                case VFS_OUT_UNMOUNT:
     256                        vfs_out_unmount(callid, &call);
    300257                        break;
    301258                case VFS_OUT_LOOKUP:
     
    326283                        vfs_out_sync(callid, &call);
    327284                        break;
    328                 case VFS_OUT_GET_SIZE:
    329                         vfs_out_get_size(callid, &call);
    330                         break;
    331                 case VFS_OUT_IS_EMPTY:
    332                         vfs_out_is_empty(callid, &call);
     285                case VFS_OUT_STATFS:
     286                        vfs_out_statfs(callid, &call);
    333287                        break;
    334288                default:
     
    388342         * Ask VFS for callback connection.
    389343         */
    390         async_connect_to_me(exch, 0, 0, 0, vfs_connection, NULL);
     344        port_id_t port;
     345        rc = async_create_callback_port(exch, INTERFACE_VFS_DRIVER_CB, 0, 0,
     346            vfs_connection, NULL, &port);
    391347       
    392348        /*
     
    417373         * the same connection fibril as well.
    418374         */
    419         async_set_client_connection(vfs_connection);
     375        async_set_fallback_port_handler(vfs_connection, NULL);
    420376       
    421377        return IPC_GET_RETVAL(answer);
     
    427383}
    428384
     385void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
     386    ipc_call_t *req)
     387{
     388        service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
     389        fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
     390        fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*req);
     391        service_id_t mr_service_id = (service_id_t) IPC_GET_ARG4(*req);
     392       
     393        async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL);
     394        if (mountee_sess == NULL) {
     395                async_answer_0(rid, EINVAL);
     396                return;
     397        }
     398       
     399        fs_node_t *fn;
     400        int res = ops->node_get(&fn, mp_service_id, mp_fs_index);
     401        if ((res != EOK) || (!fn)) {
     402                async_hangup(mountee_sess);
     403                async_data_write_void(combine_rc(res, ENOENT));
     404                async_answer_0(rid, combine_rc(res, ENOENT));
     405                return;
     406        }
     407       
     408        if (fn->mp_data.mp_active) {
     409                async_hangup(mountee_sess);
     410                (void) ops->node_put(fn);
     411                async_data_write_void(EBUSY);
     412                async_answer_0(rid, EBUSY);
     413                return;
     414        }
     415       
     416        async_exch_t *exch = async_exchange_begin(mountee_sess);
     417        async_sess_t *sess = async_clone_establish(EXCHANGE_PARALLEL, exch);
     418       
     419        if (!sess) {
     420                async_exchange_end(exch);
     421                async_hangup(mountee_sess);
     422                (void) ops->node_put(fn);
     423                async_data_write_void(errno);
     424                async_answer_0(rid, errno);
     425                return;
     426        }
     427       
     428        ipc_call_t answer;
     429        int rc = async_data_write_forward_1_1(exch, VFS_OUT_MOUNTED,
     430            mr_service_id, &answer);
     431        async_exchange_end(exch);
     432       
     433        if (rc == EOK) {
     434                fn->mp_data.mp_active = true;
     435                fn->mp_data.fs_handle = mr_fs_handle;
     436                fn->mp_data.service_id = mr_service_id;
     437                fn->mp_data.sess = mountee_sess;
     438        }
     439       
     440        /*
     441         * Do not release the FS node so that it stays in memory.
     442         */
     443        async_answer_4(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
     444            IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
     445}
     446
     447void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *req)
     448{
     449        service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
     450        fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
     451        fs_node_t *fn;
     452        int res;
     453
     454        res = ops->node_get(&fn, mp_service_id, mp_fs_index);
     455        if ((res != EOK) || (!fn)) {
     456                async_answer_0(rid, combine_rc(res, ENOENT));
     457                return;
     458        }
     459
     460        /*
     461         * We are clearly expecting to find the mount point active.
     462         */
     463        if (!fn->mp_data.mp_active) {
     464                (void) ops->node_put(fn);
     465                async_answer_0(rid, EINVAL);
     466                return;
     467        }
     468
     469        /*
     470         * Tell the mounted file system to unmount.
     471         */
     472        async_exch_t *exch = async_exchange_begin(fn->mp_data.sess);
     473        res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.service_id);
     474        async_exchange_end(exch);
     475
     476        /*
     477         * If everything went well, perform the clean-up on our side.
     478         */
     479        if (res == EOK) {
     480                async_hangup(fn->mp_data.sess);
     481                fn->mp_data.mp_active = false;
     482                fn->mp_data.fs_handle = 0;
     483                fn->mp_data.service_id = 0;
     484                fn->mp_data.sess = NULL;
     485               
     486                /* Drop the reference created in libfs_mount(). */
     487                (void) ops->node_put(fn);
     488        }
     489
     490        (void) ops->node_put(fn);
     491        async_answer_0(rid, res);
     492}
     493
    429494static char plb_get_char(unsigned pos)
    430495{
    431496        return reg.plb_ro[pos % PLB_SIZE];
    432 }
    433 
    434 static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos, unsigned last)
    435 {
    436         unsigned pos = *ppos;
    437         unsigned size = 0;
    438        
    439         if (pos == last) {
    440                 *sz = 0;
    441                 return ERANGE;
    442         }
    443 
    444         char c = plb_get_char(pos);
    445         if (c == '/') {
    446                 pos++;
    447         }
    448        
    449         for (int i = 0; i <= NAME_MAX; i++) {
    450                 c = plb_get_char(pos);
    451                 if (pos == last || c == '/') {
    452                         dest[i] = 0;
    453                         *ppos = pos;
    454                         *sz = size;
    455                         return EOK;
    456                 }
    457                 dest[i] = c;
    458                 pos++;
    459                 size++;
    460         }
    461         return ENAMETOOLONG;
    462 }
    463 
    464 static int receive_fname(char *buffer)
    465 {
    466         size_t size;
    467         ipc_callid_t wcall;
    468        
    469         if (!async_data_write_receive(&wcall, &size)) {
    470                 return ENOENT;
    471         }
    472         if (size > NAME_MAX + 1) {
    473                 async_answer_0(wcall, ERANGE);
    474                 return ERANGE;
    475         }
    476         return async_data_write_finalize(wcall, buffer, size);
    477 }
    478 
    479 /** Link a file at a path.
    480  */
    481 void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, ipc_call_t *req)
    482 {
    483         service_id_t parent_sid = IPC_GET_ARG1(*req);
    484         fs_index_t parent_index = IPC_GET_ARG2(*req);
    485         fs_index_t child_index = IPC_GET_ARG3(*req);
    486        
    487         char component[NAME_MAX + 1];
    488         int rc = receive_fname(component);
    489         if (rc != EOK) {
    490                 async_answer_0(rid, rc);
    491                 return;
    492         }
    493 
    494         fs_node_t *parent = NULL;
    495         rc = ops->node_get(&parent, parent_sid, parent_index);
    496         if (parent == NULL) {
    497                 async_answer_0(rid, rc == EOK ? EBADF : rc);
    498                 return;
    499         }
    500        
    501         fs_node_t *child = NULL;
    502         rc = ops->node_get(&child, parent_sid, child_index);
    503         if (child == NULL) {
    504                 async_answer_0(rid, rc == EOK ? EBADF : rc);
    505                 ops->node_put(parent);
    506                 return;
    507         }
    508        
    509         rc = ops->link(parent, child, component);
    510         ops->node_put(parent);
    511         ops->node_put(child);
    512         async_answer_0(rid, rc);
    513497}
    514498
     
    526510 *
    527511 */
    528 void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, ipc_call_t *req)
    529 {
    530         unsigned first = IPC_GET_ARG1(*req);
    531         unsigned len = IPC_GET_ARG2(*req);
     512void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
     513    ipc_call_t *req)
     514{
     515        unsigned int first = IPC_GET_ARG1(*req);
     516        unsigned int last = IPC_GET_ARG2(*req);
     517        unsigned int next = first;
    532518        service_id_t service_id = IPC_GET_ARG3(*req);
    533         fs_index_t index = IPC_GET_ARG4(*req);
    534         int lflag = IPC_GET_ARG5(*req);
    535        
    536         assert((int) index != -1);
    537        
    538         DPRINTF("Entered libfs_lookup()\n");
    539        
    540         // TODO: Validate flags.
    541        
    542         unsigned next = first;
    543         unsigned last = first + len;
    544        
     519        int lflag = IPC_GET_ARG4(*req);
     520        fs_index_t index = IPC_GET_ARG5(*req);
    545521        char component[NAME_MAX + 1];
     522        int len;
    546523        int rc;
     524       
     525        if (last < next)
     526                last += PLB_SIZE;
    547527       
    548528        fs_node_t *par = NULL;
    549529        fs_node_t *cur = NULL;
    550530        fs_node_t *tmp = NULL;
    551         unsigned clen = 0;
    552        
    553         rc = ops->node_get(&cur, service_id, index);
    554         if (rc != EOK) {
    555                 async_answer_0(rid, rc);
    556                 LOG_EXIT(rc);
    557                 goto out;
    558         }
    559        
    560         assert(cur != NULL);
    561        
    562         /* Find the file and its parent. */
    563        
    564         unsigned last_next = 0;
    565        
    566         while (next != last) {
    567                 if (cur == NULL) {
    568                         assert(par != NULL);
    569                         goto out1;
     531       
     532        rc = ops->root_get(&cur, service_id);
     533        on_error(rc, goto out_with_answer);
     534       
     535        if (cur->mp_data.mp_active) {
     536                async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
     537                async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
     538                    cur->mp_data.service_id, lflag, index,
     539                    IPC_FF_ROUTE_FROM_ME);
     540                async_exchange_end(exch);
     541               
     542                (void) ops->node_put(cur);
     543                return;
     544        }
     545       
     546        /* Eat slash */
     547        if (plb_get_char(next) == '/')
     548                next++;
     549       
     550        while (next <= last) {
     551                bool has_children;
     552               
     553                rc = ops->has_children(&has_children, cur);
     554                on_error(rc, goto out_with_answer);
     555                if (!has_children)
     556                        break;
     557               
     558                /* Collect the component */
     559                len = 0;
     560                while ((next <= last) && (plb_get_char(next) != '/')) {
     561                        if (len + 1 == NAME_MAX) {
     562                                /* Component length overflow */
     563                                async_answer_0(rid, ENAMETOOLONG);
     564                                goto out;
     565                        }
     566                        component[len++] = plb_get_char(next);
     567                        /* Process next character */
     568                        next++;
    570569                }
    571 
    572                 if (!ops->is_directory(cur)) {
    573                         async_answer_0(rid, ENOTDIR);
    574                         LOG_EXIT(ENOTDIR);
     570               
     571                assert(len);
     572                component[len] = '\0';
     573                /* Eat slash */
     574                next++;
     575               
     576                /* Match the component */
     577                rc = ops->match(&tmp, cur, component);
     578                on_error(rc, goto out_with_answer);
     579               
     580                /*
     581                 * If the matching component is a mount point, there are two
     582                 * legitimate semantics of the lookup operation. The first is
     583                 * the commonly used one in which the lookup crosses each mount
     584                 * point into the mounted file system. The second semantics is
     585                 * used mostly during unmount() and differs from the first one
     586                 * only in that the last mount point in the looked up path,
     587                 * which is also its last component, is not crossed.
     588                 */
     589
     590                if ((tmp) && (tmp->mp_data.mp_active) &&
     591                    (!(lflag & L_MP) || (next <= last))) {
     592                        if (next > last)
     593                                next = last = first;
     594                        else
     595                                next--;
     596                       
     597                        async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
     598                        async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
     599                            last, tmp->mp_data.service_id, lflag, index,
     600                            IPC_FF_ROUTE_FROM_ME);
     601                        async_exchange_end(exch);
     602                       
     603                        (void) ops->node_put(cur);
     604                        (void) ops->node_put(tmp);
     605                        if (par)
     606                                (void) ops->node_put(par);
     607                        return;
     608                }
     609               
     610                /* Handle miss: match amongst siblings */
     611                if (!tmp) {
     612                        if (next <= last) {
     613                                /* There are unprocessed components */
     614                                async_answer_0(rid, ENOENT);
     615                                goto out;
     616                        }
     617                       
     618                        /* Miss in the last component */
     619                        if (lflag & (L_CREATE | L_LINK)) {
     620                                /* Request to create a new link */
     621                                if (!ops->is_directory(cur)) {
     622                                        async_answer_0(rid, ENOTDIR);
     623                                        goto out;
     624                                }
     625                               
     626                                fs_node_t *fn;
     627                                if (lflag & L_CREATE)
     628                                        rc = ops->create(&fn, service_id,
     629                                            lflag);
     630                                else
     631                                        rc = ops->node_get(&fn, service_id,
     632                                            index);
     633                                on_error(rc, goto out_with_answer);
     634                               
     635                                if (fn) {
     636                                        rc = ops->link(cur, fn, component);
     637                                        if (rc != EOK) {
     638                                                if (lflag & L_CREATE)
     639                                                        (void) ops->destroy(fn);
     640                                                else
     641                                                        (void) ops->node_put(fn);
     642                                                async_answer_0(rid, rc);
     643                                        } else {
     644                                                (void) ops->node_put(cur);
     645                                                cur = fn;
     646                                                goto out_with_answer;
     647                                        }
     648                                } else
     649                                        async_answer_0(rid, ENOSPC);
     650                               
     651                                goto out;
     652                        }
     653                       
     654                        async_answer_0(rid, ENOENT);
    575655                        goto out;
    576656                }
    577657               
    578                 last_next = next;
    579                 /* Collect the component */
    580                 rc = plb_get_component(component, &clen, &next, last);
    581                 assert(rc != ERANGE);
    582                 if (rc != EOK) {
    583                         async_answer_0(rid, rc);
    584                         LOG_EXIT(rc);
    585                         goto out;
    586                 }
    587                
    588                 if (clen == 0) {
    589                         /* The path is just "/". */
    590                         break;
    591                 }
    592                
    593                 assert(component[clen] == 0);
    594                
    595                 /* Match the component */
    596                 rc = ops->match(&tmp, cur, component);
    597                 if (rc != EOK) {
    598                         async_answer_0(rid, rc);
    599                         LOG_EXIT(rc);
    600                         goto out;
    601                 }
    602                
    603                 /* Descend one level */
    604658                if (par) {
    605659                        rc = ops->node_put(par);
    606                         if (rc != EOK) {
    607                                 async_answer_0(rid, rc);
    608                                 LOG_EXIT(rc);
    609                                 goto out;
    610                         }
     660                        on_error(rc, goto out_with_answer);
    611661                }
    612662               
     663                /* Descend one level */
    613664                par = cur;
    614665                cur = tmp;
     
    616667        }
    617668       
    618         /* At this point, par is either NULL or a directory.
    619          * If cur is NULL, the looked up file does not exist yet.
    620          */
    621          
    622         assert(par == NULL || ops->is_directory(par));
    623         assert(par != NULL || cur != NULL);
    624        
    625         /* Check for some error conditions. */
    626        
    627         if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
    628                 async_answer_0(rid, EISDIR);
    629                 LOG_EXIT(EISDIR);
    630                 goto out;
    631         }
    632        
    633         if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
    634                 async_answer_0(rid, ENOTDIR);
    635                 LOG_EXIT(ENOTDIR);
    636                 goto out;
    637         }
    638        
    639         /* Unlink. */
    640        
    641         if (lflag & L_UNLINK) {
    642                 if (!cur) {
    643                         async_answer_0(rid, ENOENT);
    644                         LOG_EXIT(ENOENT);
    645                         goto out;
    646                 }
    647                 if (!par) {
    648                         async_answer_0(rid, EINVAL);
    649                         LOG_EXIT(EINVAL);
    650                         goto out;
    651                 }
    652                
    653                 rc = ops->unlink(par, cur, component);
    654                 if (rc == EOK) {
    655                         int64_t size = ops->size_get(cur);
    656                         int32_t lsize = LOWER32(size);
    657                         if (lsize != size) {
    658                                 lsize = -1;
    659                         }
    660                        
    661                         async_answer_5(rid, fs_handle, service_id,
    662                             ops->index_get(cur), last, lsize,
    663                             ops->is_directory(cur));
    664                         LOG_EXIT(EOK);
    665                 } else {
    666                         async_answer_0(rid, rc);
    667                         LOG_EXIT(rc);
    668                 }
    669                 goto out;
    670         }
    671        
    672         /* Create. */
    673        
    674         if (lflag & L_CREATE) {
    675                 if (cur && (lflag & L_EXCLUSIVE)) {
    676                         async_answer_0(rid, EEXIST);
    677                         LOG_EXIT(EEXIST);
    678                         goto out;
    679                 }
    680        
    681                 if (!cur) {
    682                         rc = ops->create(&cur, service_id, lflag & (L_FILE|L_DIRECTORY));
    683                         if (rc != EOK) {
    684                                 async_answer_0(rid, rc);
    685                                 LOG_EXIT(rc);
    686                                 goto out;
    687                         }
    688                         if (!cur) {
    689                                 async_answer_0(rid, ENOSPC);
    690                                 LOG_EXIT(ENOSPC);
     669        /* Handle miss: excessive components */
     670        if (next <= last) {
     671                bool has_children;
     672                rc = ops->has_children(&has_children, cur);
     673                on_error(rc, goto out_with_answer);
     674               
     675                if (has_children)
     676                        goto skip_miss;
     677               
     678                if (lflag & (L_CREATE | L_LINK)) {
     679                        if (!ops->is_directory(cur)) {
     680                                async_answer_0(rid, ENOTDIR);
    691681                                goto out;
    692682                        }
    693683                       
    694                         rc = ops->link(par, cur, component);
    695                         if (rc != EOK) {
    696                                 (void) ops->destroy(cur);
    697                                 cur = NULL;
    698                                 async_answer_0(rid, rc);
    699                                 LOG_EXIT(rc);
    700                                 goto out;
     684                        /* Collect next component */
     685                        len = 0;
     686                        while (next <= last) {
     687                                if (plb_get_char(next) == '/') {
     688                                        /* More than one component */
     689                                        async_answer_0(rid, ENOENT);
     690                                        goto out;
     691                                }
     692                               
     693                                if (len + 1 == NAME_MAX) {
     694                                        /* Component length overflow */
     695                                        async_answer_0(rid, ENAMETOOLONG);
     696                                        goto out;
     697                                }
     698                               
     699                                component[len++] = plb_get_char(next);
     700                                /* Process next character */
     701                                next++;
    701702                        }
    702                 }
    703         }
    704        
    705         /* Return. */
    706 out1:
    707         if (!cur) {
    708                 async_answer_5(rid, fs_handle, service_id,
    709                         ops->index_get(par), last_next, -1, true);
    710                 LOG_EXIT(EOK);
    711                 goto out;
    712         }
    713        
    714         if (lflag & L_OPEN) {
    715                 rc = ops->node_open(cur);
    716                 if (rc != EOK) {
    717                         async_answer_0(rid, rc);
    718                         LOG_EXIT(rc);
     703                       
     704                        assert(len);
     705                        component[len] = '\0';
     706                       
     707                        fs_node_t *fn;
     708                        if (lflag & L_CREATE)
     709                                rc = ops->create(&fn, service_id, lflag);
     710                        else
     711                                rc = ops->node_get(&fn, service_id, index);
     712                        on_error(rc, goto out_with_answer);
     713                       
     714                        if (fn) {
     715                                rc = ops->link(cur, fn, component);
     716                                if (rc != EOK) {
     717                                        if (lflag & L_CREATE)
     718                                                (void) ops->destroy(fn);
     719                                        else
     720                                                (void) ops->node_put(fn);
     721                                        async_answer_0(rid, rc);
     722                                } else {
     723                                        (void) ops->node_put(cur);
     724                                        cur = fn;
     725                                        goto out_with_answer;
     726                                }
     727                        } else
     728                                async_answer_0(rid, ENOSPC);
     729                       
    719730                        goto out;
    720731                }
    721         }
    722        
    723         int64_t size = ops->size_get(cur);
    724         int32_t lsize = LOWER32(size);
    725         if (lsize != size) {
    726                 lsize = -1;
    727         }
    728        
    729         async_answer_5(rid, fs_handle, service_id,
    730                 ops->index_get(cur), last, lsize,
    731                 ops->is_directory(cur));
    732        
    733         LOG_EXIT(EOK);
     732               
     733                async_answer_0(rid, ENOENT);
     734                goto out;
     735        }
     736       
     737skip_miss:
     738       
     739        /* Handle hit */
     740        if (lflag & L_UNLINK) {
     741                unsigned int old_lnkcnt = ops->lnkcnt_get(cur);
     742                rc = ops->unlink(par, cur, component);
     743               
     744                if (rc == EOK) {
     745                        aoff64_t size = ops->size_get(cur);
     746                        async_answer_5(rid, fs_handle, service_id,
     747                            ops->index_get(cur), LOWER32(size), UPPER32(size),
     748                            old_lnkcnt);
     749                } else
     750                        async_answer_0(rid, rc);
     751               
     752                goto out;
     753        }
     754       
     755        if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
     756            (lflag & L_LINK)) {
     757                async_answer_0(rid, EEXIST);
     758                goto out;
     759        }
     760       
     761        if ((lflag & L_FILE) && (ops->is_directory(cur))) {
     762                async_answer_0(rid, EISDIR);
     763                goto out;
     764        }
     765       
     766        if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
     767                async_answer_0(rid, ENOTDIR);
     768                goto out;
     769        }
     770
     771        if ((lflag & L_ROOT) && par) {
     772                async_answer_0(rid, EINVAL);
     773                goto out;
     774        }
     775       
     776out_with_answer:
     777       
     778        if (rc == EOK) {
     779                if (lflag & L_OPEN)
     780                        rc = ops->node_open(cur);
     781               
     782                if (rc == EOK) {
     783                        aoff64_t size = ops->size_get(cur);
     784                        async_answer_5(rid, fs_handle, service_id,
     785                            ops->index_get(cur), LOWER32(size), UPPER32(size),
     786                            ops->lnkcnt_get(cur));
     787                } else
     788                        async_answer_0(rid, rc);
     789               
     790        } else
     791                async_answer_0(rid, rc);
     792       
    734793out:
    735         if (par) {
     794       
     795        if (par)
    736796                (void) ops->node_put(par);
    737         }
    738        
    739         if (cur) {
     797       
     798        if (cur)
    740799                (void) ops->node_put(cur);
    741         }
    742        
    743         if (tmp) {
     800       
     801        if (tmp)
    744802                (void) ops->node_put(tmp);
    745         }
    746803}
    747804
     
    751808        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
    752809        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
    753        
     810
    754811        fs_node_t *fn;
    755812        int rc = ops->node_get(&fn, service_id, index);
    756813        on_error(rc, answer_and_return(rid, rc));
    757        
     814
    758815        ipc_callid_t callid;
    759816        size_t size;
     
    765822                return;
    766823        }
    767        
     824
    768825        struct stat stat;
    769826        memset(&stat, 0, sizeof(struct stat));
    770        
     827
    771828        stat.fs_handle = fs_handle;
    772829        stat.service_id = service_id;
     
    777834        stat.size = ops->size_get(fn);
    778835        stat.service = ops->service_get(fn);
    779        
     836
    780837        ops->node_put(fn);
    781        
     838
     839
    782840        async_data_read_finalize(callid, &stat, sizeof(struct stat));
    783841        async_answer_0(rid, EOK);
    784842}
     843
     844void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
     845    ipc_call_t *request)
     846{
     847        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
     848        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
     849
     850        fs_node_t *fn;
     851        int rc = ops->node_get(&fn, service_id, index);
     852        on_error(rc, answer_and_return(rid, rc));
     853
     854        ipc_callid_t callid;
     855        size_t size;
     856        if ((!async_data_read_receive(&callid, &size)) ||
     857            (size != sizeof(struct statfs))) {
     858                goto error;
     859        }
     860
     861        struct statfs st;
     862        memset(&st, 0, sizeof(struct statfs));
     863
     864        if (ops->size_block != NULL) {
     865                rc = ops->size_block(service_id, &st.f_bsize);
     866                if (rc != EOK)
     867                        goto error;
     868        }
     869
     870        if (ops->total_block_count != NULL) {
     871                rc = ops->total_block_count(service_id, &st.f_blocks);
     872                if (rc != EOK)
     873                        goto error;
     874        }
     875
     876        if (ops->free_block_count != NULL) {
     877                rc = ops->free_block_count(service_id, &st.f_bfree);
     878                if (rc != EOK)
     879                        goto error;
     880        }
     881
     882        ops->node_put(fn);
     883        async_data_read_finalize(callid, &st, sizeof(struct statfs));
     884        async_answer_0(rid, EOK);
     885        return;
     886
     887error:
     888        ops->node_put(fn);
     889        async_answer_0(callid, EINVAL);
     890        async_answer_0(rid, EINVAL);
     891}
     892
    785893
    786894/** Open VFS triplet.
     
    836944
    837945        fibril_mutex_lock(&instances_mutex);
    838         list_foreach(instances_list, link) {
    839                 fs_instance_t *cur = list_get_instance(link, fs_instance_t,
    840                     link);
    841 
     946        list_foreach(instances_list, link, fs_instance_t, cur) {
    842947                if (cur->service_id == service_id) {
    843948                        fibril_mutex_unlock(&instances_mutex);
     
    862967{
    863968        fibril_mutex_lock(&instances_mutex);
    864         list_foreach(instances_list, link) {
    865                 fs_instance_t *inst = list_get_instance(link, fs_instance_t,
    866                     link);
    867 
     969        list_foreach(instances_list, link, fs_instance_t, inst) {
    868970                if (inst->service_id == service_id) {
    869971                        *idp = inst->data;
     
    879981{
    880982        fibril_mutex_lock(&instances_mutex);
    881         list_foreach(instances_list, link) {
    882                 fs_instance_t *inst = list_get_instance(link, fs_instance_t,
    883                     link);
    884 
     983        list_foreach(instances_list, link, fs_instance_t, inst) {
    885984                if (inst->service_id == service_id) {
    886985                        list_remove(&inst->link);
Note: See TracChangeset for help on using the changeset viewer.