Changeset 0d35511 in mainline for uspace/srv/vfs/vfs_ops.c


Ignore:
Timestamp:
2017-03-08T18:27:40Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4809715
Parents:
5126f80
git-author:
Jiri Zarevucky <zarevucky.jiri@…> (2017-03-08 18:27:40)
git-committer:
Jakub Jermar <jakub@…> (2017-03-08 18:27:40)
Message:

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5/ revisions 1948-1965

Original commit messages:

1965: Jiri Zarevucky 2013-08-07 Split vfs_walk().
1964: Jiri Zarevucky 2013-08-07 Split vfs_wait_handle().
1963: Jiri Zarevucky 2013-08-07 Split vfs_unmount().
1962: Jiri Zarevucky 2013-08-07 Split vfs_unlink2().
1961: Jiri Zarevucky 2013-08-07 Split vfs_truncate().
1960: Jiri Zarevucky 2013-08-07 Split vfs_sync().
1959: Jiri Zarevucky 2013-08-07 Split vfs_seek().
1958: Jiri Zarevucky 2013-08-07 Split vfs_rename().
1957: Jiri Zarevucky 2013-08-07 Split vfs_read() and vfs_write().
1956: Jiri Zarevucky 2013-08-07 Split vfs_open2().
1955: Jiri Zarevucky 2013-08-07 Split vfs_mtab_get().
1954: Jiri Zarevucky 2013-08-07 Split fstat().
1953: Jiri Zarevucky 2013-08-07 Split vfs_dup().
1952: Jiri Zarevucky 2013-08-07 Split vfs_in_dname().
1951: Jiri Zarevucky 2013-08-07 Split vfs_close().
1950: Jiri Zarevucky 2013-08-07 Split vfs_clone().
1949: Jiri Zarevucky 2013-08-07 Order IPC calls lexicographically.
1948: Jiri Zarevucky 2013-08-07 Start splitting off the IPC boilerplate parts. vfs_mount().

Modifications:

  • Removed debug name changes
  • Split vfs_statfs
  • vfs_in_*() call vfs_op_*() according to future changes in the branch
  • Keep the common code for handling read/write
File:
1 edited

Legend:

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

    r5126f80 r0d35511  
    6868FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
    6969
    70 static int vfs_connect_internal(service_id_t service_id, unsigned flags, unsigned instance,
    71     char *options, char *fsname, vfs_node_t **root)
     70static size_t shared_path(char *a, char *b)
     71{
     72        size_t res = 0;
     73       
     74        while (a[res] == b[res] && a[res] != 0) {
     75                res++;
     76        }
     77       
     78        if (a[res] == b[res]) {
     79                return res;
     80        }
     81       
     82        res--;
     83        while (a[res] != '/') {
     84                res--;
     85        }
     86        return res;
     87}
     88
     89/* This call destroys the file if and only if there are no hard links left. */
     90static void out_destroy(vfs_triplet_t *file)
     91{
     92        async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
     93        async_msg_2(exch, VFS_OUT_DESTROY,
     94                (sysarg_t) file->service_id, (sysarg_t) file->index);
     95        vfs_exchange_release(exch);
     96}
     97
     98int vfs_op_clone(int oldfd, bool desc)
     99{
     100        /* Lookup the file structure corresponding to fd. */
     101        vfs_file_t *oldfile = vfs_file_get(oldfd);
     102        if (oldfile == NULL) {
     103                return EBADF;
     104        }
     105        assert(oldfile->node != NULL);
     106       
     107        vfs_file_t *newfile;
     108        int newfd = vfs_fd_alloc(&newfile, desc);
     109        if (newfd >= 0) {
     110                newfile->node = oldfile->node;
     111                newfile->permissions = oldfile->permissions;
     112                vfs_node_addref(newfile->node);
     113       
     114                vfs_file_put(newfile);
     115        }
     116        vfs_file_put(oldfile);
     117       
     118        return newfd;
     119}
     120
     121int vfs_op_close(int fd)
     122{
     123        return vfs_fd_free(fd);
     124}
     125
     126int vfs_op_dup(int oldfd, int newfd)
     127{
     128        /* If the file descriptors are the same, do nothing. */
     129        if (oldfd == newfd) {
     130                return EOK;
     131        }
     132       
     133        /* Lookup the file structure corresponding to oldfd. */
     134        vfs_file_t *oldfile = vfs_file_get(oldfd);
     135        if (!oldfile) {
     136                return EBADF;
     137        }
     138       
     139        /* Make sure newfd is closed. */
     140        (void) vfs_fd_free(newfd);
     141       
     142        /* Assign the old file to newfd. */
     143        int ret = vfs_fd_assign(oldfile, newfd);
     144        vfs_file_put(oldfile);
     145       
     146        return ret;
     147}
     148
     149int vfs_op_fstat_forward(int fd)
     150{
     151        vfs_file_t *file = vfs_file_get(fd);
     152        if (!file) {
     153                return EBADF;
     154        }
     155        assert(file->node);
     156       
     157        ipc_callid_t callid;
     158        if (!async_data_read_receive(&callid, NULL)) {
     159                vfs_file_put(file);
     160                async_answer_0(callid, EINVAL);
     161                return EINVAL;
     162        }
     163
     164        async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
     165        assert(exch);
     166       
     167        aid_t msg;
     168        msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id,
     169            file->node->index, true, NULL);
     170        assert(msg);
     171        async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
     172       
     173        vfs_exchange_release(exch);
     174       
     175        sysarg_t rc;
     176        async_wait_for(msg, &rc);
     177       
     178        vfs_file_put(file);
     179        return rc;
     180}
     181
     182static int vfs_connect_internal(service_id_t service_id, unsigned flags,
     183    unsigned instance, const char *options, const char *fsname,
     184    vfs_node_t **root)
    72185{
    73186        fs_handle_t fs_handle = 0;
     
    92205        ipc_call_t answer;
    93206        async_exch_t *exch = vfs_exchange_grab(fs_handle);
    94         aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, &answer);
     207        aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id,
     208            &answer);
    95209        /* Send the mount options */
    96210        sysarg_t rc = async_data_write_start(exch, options, str_size(options));
     
    111225        res.triplet.service_id = service_id;
    112226        res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer);
    113         res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
     227        res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
     228            IPC_GET_ARG3(answer));
    114229        res.type = VFS_NODE_DIRECTORY;
    115230       
     
    121236}
    122237
    123 void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request)
    124 {
    125         int mpfd = IPC_GET_ARG1(*request);
    126        
    127         /*
    128          * We expect the library to do the device-name to device-handle
    129          * translation for us, thus the device handle will arrive as ARG1
    130          * in the request.
    131          */
    132         service_id_t service_id = (service_id_t) IPC_GET_ARG2(*request);
    133        
    134         /*
    135          * Mount flags are passed as ARG2.
    136          */
    137         unsigned int flags = (unsigned int) IPC_GET_ARG3(*request);
    138        
    139         /*
    140          * Instance number is passed as ARG3.
    141          */
    142         unsigned int instance = IPC_GET_ARG4(*request);
    143        
    144         char *opts = NULL;
    145         char *fs_name = NULL;
     238int vfs_op_mount(int mpfd, unsigned service_id, unsigned flags,
     239    unsigned instance, const char *opts, const char *fs_name, int *outfd)
     240{
     241        int rc;
    146242        vfs_file_t *mp = NULL;
    147243        vfs_file_t *file = NULL;
    148244        int fd = -1;
    149245        mtab_ent_t *mtab_ent = NULL;
    150 
    151         /* Now we expect to receive the mount options. */
    152         int rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,
    153             0, NULL);
    154         if (rc != EOK) {
    155                 async_data_write_void(rc);
    156                 goto out;
    157         }
    158        
    159         /*
    160          * Now, we expect the client to send us data with the name of the file
    161          * system.
    162          */
    163         rc = async_data_write_accept((void **) &fs_name, true, 0,
    164             FS_NAME_MAXLEN, 0, NULL);
    165         if (rc != EOK) {
    166                 goto out;
    167         }
    168246       
    169247        if (!(flags & VFS_MOUNT_CONNECT_ONLY)) {
     
    209287        fibril_rwlock_write_lock(&namespace_rwlock);
    210288
    211         rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, &root);
     289        rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name,
     290             &root);
    212291        if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) {
    213292                vfs_node_addref(mp->node);
     
    235314       
    236315        /* Add the filesystem info to the list of mounted filesystems */
    237         if (rc == EOK) {
    238                 str_cpy(mtab_ent->mp, MAX_PATH_LEN, "fixme");
    239                 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
    240                 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
    241                 mtab_ent->instance = instance;
    242                 mtab_ent->service_id = service_id;
    243 
    244                 link_initialize(&mtab_ent->link);
    245 
    246                 fibril_mutex_lock(&mtab_list_lock);
    247                 list_append(&mtab_ent->link, &mtab_list);
    248                 mtab_size++;
    249                 fibril_mutex_unlock(&mtab_list_lock);
    250         }       
    251        
    252         rc = EOK;
     316        str_cpy(mtab_ent->mp, MAX_PATH_LEN, "fixme");
     317        str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
     318        str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
     319        mtab_ent->instance = instance;
     320        mtab_ent->service_id = service_id;
     321
     322        link_initialize(&mtab_ent->link);
     323
     324        fibril_mutex_lock(&mtab_list_lock);
     325        list_append(&mtab_ent->link, &mtab_list);
     326        mtab_size++;
     327        fibril_mutex_unlock(&mtab_list_lock);   
    253328
    254329out:
    255         async_answer_1(rid, rc, rc == EOK ? fd : 0);
    256 
    257         if (opts) {
    258                 free(opts);
    259         }
    260         if (fs_name) {
    261                 free(fs_name);
    262         }
    263330        if (mp) {
    264331                vfs_file_put(mp);
     
    269336        if (rc != EOK && fd >= 0) {
    270337                vfs_fd_free(fd);
    271         }
    272 }
    273 
    274 void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request)
    275 {
    276         int mpfd = IPC_GET_ARG1(*request);
    277        
    278         vfs_file_t *mp = vfs_file_get(mpfd);
    279         if (mp == NULL) {
    280                 async_answer_0(rid, EBADF);
    281                 return;
    282         }
    283        
    284         if (mp->node->mount == NULL) {
    285                 async_answer_0(rid, ENOENT);
    286                 vfs_file_put(mp);
    287                 return;
    288         }
    289        
    290         fibril_rwlock_write_lock(&namespace_rwlock);
    291        
    292         /*
    293          * Count the total number of references for the mounted file system. We
    294          * are expecting at least one, which is held by the mount point.
    295          * If we find more, it means that
    296          * the file system cannot be gracefully unmounted at the moment because
    297          * someone is working with it.
    298          */
    299         if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle, mp->node->mount->service_id) != 1) {
    300                 async_answer_0(rid, EBUSY);
    301                 vfs_file_put(mp);
    302                 fibril_rwlock_write_unlock(&namespace_rwlock);
    303                 return;
    304         }
    305        
    306         async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
    307         int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, mp->node->mount->service_id);
    308         vfs_exchange_release(exch);
    309        
    310         if (rc != EOK) {
    311                 async_answer_0(rid, rc);
    312                 vfs_file_put(mp);
    313                 fibril_rwlock_write_unlock(&namespace_rwlock);
    314                 return;
    315         }
    316        
    317         vfs_node_forget(mp->node->mount);
    318         vfs_node_put(mp->node);
    319         mp->node->mount = NULL;
    320        
    321         fibril_rwlock_write_unlock(&namespace_rwlock);
    322        
     338                fd = 0;
     339        }
     340       
     341        *outfd = fd;
     342        return rc;
     343}
     344
     345int vfs_op_mtab_get(void)
     346{
     347        ipc_callid_t callid;
     348        ipc_call_t data;
     349        sysarg_t rc = EOK;
     350        size_t len;
     351
    323352        fibril_mutex_lock(&mtab_list_lock);
    324         int found = 0;
     353
     354        /* Send to the caller the number of mounted filesystems */
     355        callid = async_get_call(&data);
     356        if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
     357                rc = ENOTSUP;
     358                async_answer_0(callid, rc);
     359                goto exit;
     360        }
     361        async_answer_1(callid, EOK, mtab_size);
    325362
    326363        list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
    327                 // FIXME: mp name
    328                 if (str_cmp(mtab_ent->mp, "fixme") == 0) {
    329                         list_remove(&mtab_ent->link);
    330                         mtab_size--;
    331                         free(mtab_ent);
    332                         found = 1;
    333                         break;
    334                 }
    335         }
    336         assert(found);
     364                rc = ENOTSUP;
     365
     366                if (!async_data_read_receive(&callid, &len)) {
     367                        async_answer_0(callid, rc);
     368                        goto exit;
     369                }
     370
     371                (void) async_data_read_finalize(callid, mtab_ent->mp,
     372                    str_size(mtab_ent->mp));
     373
     374                if (!async_data_read_receive(&callid, &len)) {
     375                        async_answer_0(callid, rc);
     376                        goto exit;
     377                }
     378
     379                (void) async_data_read_finalize(callid, mtab_ent->opts,
     380                    str_size(mtab_ent->opts));
     381
     382                if (!async_data_read_receive(&callid, &len)) {
     383                        async_answer_0(callid, rc);
     384                        goto exit;
     385                }
     386
     387                (void) async_data_read_finalize(callid, mtab_ent->fs_name,
     388                    str_size(mtab_ent->fs_name));
     389
     390                callid = async_get_call(&data);
     391
     392                if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
     393                        async_answer_0(callid, rc);
     394                        goto exit;
     395                }
     396
     397                rc = EOK;
     398                async_answer_2(callid, rc, mtab_ent->instance,
     399                    mtab_ent->service_id);
     400        }
     401
     402exit:
    337403        fibril_mutex_unlock(&mtab_list_lock);
    338        
    339         vfs_file_put(mp);
    340         async_answer_0(rid, EOK);
    341 }
    342 
    343 static inline bool walk_flags_valid(int flags)
    344 {
    345         if ((flags&~WALK_ALL_FLAGS) != 0) {
    346                 return false;
    347         }
    348         if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) {
    349                 return false;
    350         }
    351         if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) {
    352                 return false;
    353         }
    354         if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) {
    355                 if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) {
    356                         return false;
    357                 }
    358         }
    359         return true;
    360 }
    361 
    362 static inline int walk_lookup_flags(int flags)
    363 {
    364         int lflags = 0;
    365         if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) {
    366                 lflags |= L_CREATE;
    367         }
    368         if (flags&WALK_MUST_CREATE) {
    369                 lflags |= L_EXCLUSIVE;
    370         }
    371         if (flags&WALK_REGULAR) {
    372                 lflags |= L_FILE;
    373         }
    374         if (flags&WALK_DIRECTORY) {
    375                 lflags |= L_DIRECTORY;
    376         }
    377         if (flags&WALK_MOUNT_POINT) {
    378                 lflags |= L_MP;
    379         }
    380         return lflags;
    381 }
    382 
    383 void vfs_walk(ipc_callid_t rid, ipc_call_t *request)
    384 {
    385         /*
    386          * Parent is our relative root for file lookup.
    387          * For defined flags, see <ipc/vfs.h>.
    388          */
    389         int parentfd = IPC_GET_ARG1(*request);
    390         int flags = IPC_GET_ARG2(*request);
    391        
    392         if (!walk_flags_valid(flags)) {
    393                 async_answer_0(rid, EINVAL);
    394                 return;
    395         }
    396        
    397         char *path;
    398         int rc = async_data_write_accept((void **)&path, true, 0, 0, 0, NULL);
    399        
    400         /* Lookup the file structure corresponding to the file descriptor. */
    401         vfs_file_t *parent = vfs_file_get(parentfd);
    402         if (!parent) {
    403                 free(path);
    404                 async_answer_0(rid, EBADF);
    405                 return;
    406         }
    407        
    408         fibril_rwlock_read_lock(&namespace_rwlock);
    409        
    410         vfs_lookup_res_t lr;
    411         rc = vfs_lookup_internal(parent->node, path, walk_lookup_flags(flags), &lr);
    412         free(path);
    413 
    414         if (rc != EOK) {
    415                 fibril_rwlock_read_unlock(&namespace_rwlock);
    416                 if (parent) {
    417                         vfs_file_put(parent);
    418                 }
    419                 async_answer_0(rid, rc);
    420                 return;
    421         }
    422        
    423         vfs_node_t *node = vfs_node_get(&lr);
    424        
    425         vfs_file_t *file;
    426         int fd = vfs_fd_alloc(&file, false);
    427         if (fd < 0) {
    428                 vfs_node_put(node);
    429                 if (parent) {
    430                         vfs_file_put(parent);
    431                 }
    432                 async_answer_0(rid, fd);
    433                 return;
    434         }
    435         assert(file != NULL);
    436        
    437         file->node = node;
    438         if (parent) {
    439                 file->permissions = parent->permissions;
    440         } else {
    441                 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
    442         }
    443         file->open_read = false;
    444         file->open_write = false;
    445        
    446         vfs_file_put(file);
    447         if (parent) {
    448                 vfs_file_put(parent);
    449         }
    450        
    451         fibril_rwlock_read_unlock(&namespace_rwlock);
    452 
    453         async_answer_1(rid, EOK, fd);
    454 }
    455 
    456 void vfs_open2(ipc_callid_t rid, ipc_call_t *request)
    457 {
    458         int fd = IPC_GET_ARG1(*request);
    459         int flags = IPC_GET_ARG2(*request);
    460 
     404        return rc;
     405}
     406
     407int vfs_op_open2(int fd, int flags)
     408{
    461409        if (flags == 0) {
    462                 async_answer_0(rid, EINVAL);
    463                 return;
     410                return EINVAL;
    464411        }
    465412
    466413        vfs_file_t *file = vfs_file_get(fd);
    467414        if (!file) {
    468                 async_answer_0(rid, EBADF);
    469                 return;
     415                return EBADF;
    470416        }
    471417       
    472418        if ((flags & ~file->permissions) != 0) {
    473419                vfs_file_put(file);
    474                 async_answer_0(rid, EPERM);
    475                 return;
     420                return EPERM;
     421        }
     422       
     423        if (file->open_read || file->open_write) {
     424                vfs_file_put(file);
     425                return EBUSY;
    476426        }
    477427       
     
    482432        if (!file->open_read && !file->open_write) {
    483433                vfs_file_put(file);
    484                 async_answer_0(rid, EINVAL);
    485                 return;
     434                return EINVAL;
    486435        }
    487436       
     
    489438                file->open_read = file->open_write = false;
    490439                vfs_file_put(file);
    491                 async_answer_0(rid, EINVAL);
    492                 return;
     440                return EINVAL;
    493441        }
    494442       
     
    497445                file->open_read = file->open_write = false;
    498446                vfs_file_put(file);
    499                 async_answer_0(rid, rc);
    500                 return;
     447                return rc;
    501448        }
    502449       
    503450        vfs_file_put(file);
    504         async_answer_0(rid, EOK);
    505 }
    506 
    507 void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
    508 {
    509         int fd = IPC_GET_ARG1(*request);
    510        
    511         /* Lookup the file structure corresponding to the file descriptor. */
    512         vfs_file_t *file = vfs_file_get(fd);
    513         if (!file) {
    514                 async_answer_0(rid, ENOENT);
    515                 return;
    516         }
    517        
    518         /*
    519          * Lock the open file structure so that no other thread can manipulate
    520          * the same open file at a time.
    521          */
    522         async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
    523        
    524         /* Make a VFS_OUT_SYMC request at the destination FS server. */
    525         aid_t msg;
    526         ipc_call_t answer;
    527         msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
    528             file->node->index, &answer);
    529        
    530         vfs_exchange_release(fs_exch);
    531        
    532         /* Wait for reply from the FS server. */
    533         sysarg_t rc;
    534         async_wait_for(msg, &rc);
    535        
    536         vfs_file_put(file);
    537         async_answer_0(rid, rc);
    538 }
    539 
    540 void vfs_close(ipc_callid_t rid, ipc_call_t *request)
    541 {
    542         int fd = IPC_GET_ARG1(*request);
    543         int ret = vfs_fd_free(fd);
    544         async_answer_0(rid, ret);
     451        return EOK;
    545452}
    546453
     
    629536        assert(fs_info);
    630537       
    631         bool rlock = read || ((fs_info->concurrent_read_write) && (fs_info->write_retains_size));
     538        bool rlock = read ||
     539            (fs_info->concurrent_read_write && fs_info->write_retains_size);
    632540       
    633541        /*
     
    650558                if (!read) {
    651559                        if (rlock) {
    652                                 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
     560                                fibril_rwlock_read_unlock(
     561                                    &file->node->contents_rwlock);
    653562                        } else {
    654                                 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
     563                                fibril_rwlock_write_unlock(
     564                                    &file->node->contents_rwlock);
    655565                        }
    656566                        vfs_file_put(file);
     
    700610        return rc;
    701611}
    702        
    703 static void vfs_rdwr_client(ipc_callid_t rid, ipc_call_t *request, bool read)
    704 {
    705         size_t bytes = 0;       
    706         int rc = vfs_rdwr(IPC_GET_ARG1(*request), read, rdwr_ipc_client,
    707             &bytes);
    708         async_answer_1(rid, rc, bytes);
    709 }
    710612
    711613int vfs_rdwr_internal(int fd, bool read, rdwr_io_chunk_t *chunk)
     
    714616}
    715617
    716 void vfs_read(ipc_callid_t rid, ipc_call_t *request)
    717 {
    718         vfs_rdwr_client(rid, request, true);
    719 }
    720 
    721 void vfs_write(ipc_callid_t rid, ipc_call_t *request)
    722 {
    723         vfs_rdwr_client(rid, request, false);
    724 }
    725 
    726 void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
    727 {
    728         int fd = (int) IPC_GET_ARG1(*request);
    729         off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
    730             IPC_GET_ARG3(*request));
    731         int whence = (int) IPC_GET_ARG4(*request);
    732        
    733         /* Lookup the file structure corresponding to the file descriptor. */
    734         vfs_file_t *file = vfs_file_get(fd);
    735         if (!file) {
    736                 async_answer_0(rid, ENOENT);
    737                 return;
    738         }
    739        
    740         off64_t newoff;
    741         switch (whence) {
    742         case SEEK_SET:
    743                 if (off >= 0) {
    744                         file->pos = (aoff64_t) off;
    745                         vfs_file_put(file);
    746                         async_answer_1(rid, EOK, off);
    747                         return;
    748                 }
    749                 break;
    750         case SEEK_CUR:
    751                 if ((off >= 0) && (file->pos + off < file->pos)) {
    752                         vfs_file_put(file);
    753                         async_answer_0(rid, EOVERFLOW);
    754                         return;
    755                 }
    756                
    757                 if ((off < 0) && (file->pos < (aoff64_t) -off)) {
    758                         vfs_file_put(file);
    759                         async_answer_0(rid, EOVERFLOW);
    760                         return;
    761                 }
    762                
    763                 file->pos += off;
    764                 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos;
    765                
    766                 vfs_file_put(file);
    767                 async_answer_2(rid, EOK, LOWER32(newoff),
    768                     UPPER32(newoff));
    769                 return;
    770         case SEEK_END:
    771                 fibril_rwlock_read_lock(&file->node->contents_rwlock);
    772                 aoff64_t size = vfs_node_get_size(file->node);
    773                
    774                 if ((off >= 0) && (size + off < size)) {
    775                         fibril_rwlock_read_unlock(&file->node->contents_rwlock);
    776                         vfs_file_put(file);
    777                         async_answer_0(rid, EOVERFLOW);
    778                         return;
    779                 }
    780                
    781                 if ((off < 0) && (size < (aoff64_t) -off)) {
    782                         fibril_rwlock_read_unlock(&file->node->contents_rwlock);
    783                         vfs_file_put(file);
    784                         async_answer_0(rid, EOVERFLOW);
    785                         return;
    786                 }
    787                
    788                 file->pos = size + off;
    789                 newoff = (file->pos > OFF64_MAX) ?  OFF64_MAX : file->pos;
    790                
    791                 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
    792                 vfs_file_put(file);
    793                 async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff));
    794                 return;
    795         }
    796        
    797         vfs_file_put(file);
    798         async_answer_0(rid, EINVAL);
    799 }
    800 
    801 int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
    802     fs_index_t index, aoff64_t size)
    803 {
    804         async_exch_t *exch = vfs_exchange_grab(fs_handle);
    805         sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
    806             (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
    807             UPPER32(size));
    808         vfs_exchange_release(exch);
    809        
    810         return (int) rc;
    811 }
    812 
    813 void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
    814 {
    815         int fd = IPC_GET_ARG1(*request);
    816         aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
    817             IPC_GET_ARG3(*request));
    818         int rc;
    819 
    820         vfs_file_t *file = vfs_file_get(fd);
    821         if (!file) {
    822                 async_answer_0(rid, ENOENT);
    823                 return;
    824         }
    825 
    826         fibril_rwlock_write_lock(&file->node->contents_rwlock);
    827         rc = vfs_truncate_internal(file->node->fs_handle,
    828             file->node->service_id, file->node->index, size);
    829         if (rc == EOK)
    830                 file->node->size = size;
    831         fibril_rwlock_write_unlock(&file->node->contents_rwlock);
    832 
    833         vfs_file_put(file);
    834         async_answer_0(rid, (sysarg_t)rc);
    835 }
    836 
    837 void vfs_fstat(ipc_callid_t rid, ipc_call_t *request)
    838 {
    839         int fd = IPC_GET_ARG1(*request);
    840         sysarg_t rc;
    841 
    842         vfs_file_t *file = vfs_file_get(fd);
    843         if (!file) {
    844                 async_answer_0(rid, ENOENT);
    845                 return;
    846         }
    847         assert(file->node);
    848 
    849         ipc_callid_t callid;
    850         if (!async_data_read_receive(&callid, NULL)) {
    851                 vfs_file_put(file);
    852                 async_answer_0(callid, EINVAL);
    853                 async_answer_0(rid, EINVAL);
    854                 return;
    855         }
    856 
    857         async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
    858         assert(exch);
    859        
    860         aid_t msg;
    861         msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id,
    862             file->node->index, true, NULL);
    863         assert(msg);
    864         async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
    865        
    866         vfs_exchange_release(exch);
    867        
    868         async_wait_for(msg, &rc);
    869        
    870         vfs_file_put(file);
    871         async_answer_0(rid, rc);
    872 }
    873 
    874 static void out_destroy(vfs_triplet_t *file)
    875 {
    876         async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
    877         async_msg_2(exch, VFS_OUT_DESTROY,
    878                 (sysarg_t) file->service_id, (sysarg_t) file->index);
    879         vfs_exchange_release(exch);
    880 }
    881 
    882 void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request)
    883 {
    884         int rc;
    885         char *path;
    886         vfs_file_t *parent = NULL;
    887         vfs_file_t *expect = NULL;
    888        
    889         int parentfd = IPC_GET_ARG1(*request);
    890         int expectfd = IPC_GET_ARG2(*request);
    891         int wflag = IPC_GET_ARG3(*request);
    892        
    893         rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
    894         if (rc != EOK) {
    895                 async_answer_0(rid, rc);
    896                 return;
    897         }
    898         if (parentfd == expectfd) {
    899                 async_answer_0(rid, EINVAL);
    900                 return;
    901         }
    902        
    903         fibril_rwlock_write_lock(&namespace_rwlock);
    904        
    905         int lflag = (wflag&WALK_DIRECTORY) ? L_DIRECTORY: 0;
    906 
    907         /* Files are retrieved in order of file descriptors, to prevent deadlock. */
    908         if (parentfd < expectfd) {
    909                 parent = vfs_file_get(parentfd);
    910                 if (!parent) {
    911                         rc = EBADF;
    912                         goto exit;
    913                 }
    914         }
    915        
    916         if (expectfd >= 0) {
    917                 expect = vfs_file_get(expectfd);
    918                 if (!expect) {
    919                         rc = ENOENT;
    920                         goto exit;
    921                 }
    922         }
    923        
    924         if (parentfd > expectfd) {
    925                 parent = vfs_file_get(parentfd);
    926                 if (!parent) {
    927                         rc = EBADF;
    928                         goto exit;
    929                 }
    930         }
    931        
    932         assert(parent != NULL);
    933        
    934         if (expectfd >= 0) {
    935                 vfs_lookup_res_t lr;
    936                 rc = vfs_lookup_internal(parent->node, path, lflag, &lr);
    937                 if (rc != EOK) {
    938                         goto exit;
    939                 }
    940                
    941                 vfs_node_t *found_node = vfs_node_peek(&lr);           
    942                 if (expect->node != found_node) {
    943                         rc = ENOENT;
    944                         goto exit;
    945                 }
    946                
    947                 vfs_file_put(expect);
    948                 expect = NULL;
    949         }
    950        
    951         vfs_lookup_res_t lr;
    952         rc = vfs_lookup_internal(parent->node, path, lflag | L_UNLINK, &lr);
    953         if (rc != EOK) {
    954                 goto exit;
    955         }
    956 
    957         /* If the node is not held by anyone, try to destroy it. */
    958         if (vfs_node_peek(&lr) == NULL) {
    959                 out_destroy(&lr.triplet);
    960         }
    961 
    962 exit:
    963         if (path) {
    964                 free(path);
    965         }
    966         if (parent) {
    967                 vfs_file_put(parent);
    968         }
    969         if (expect) {
    970                 vfs_file_put(expect);
    971         }
    972         fibril_rwlock_write_unlock(&namespace_rwlock);
    973         async_answer_0(rid, rc);
    974 }
    975 
    976 static size_t shared_path(char *a, char *b)
    977 {
    978         size_t res = 0;
    979        
    980         while (a[res] == b[res] && a[res] != 0) {
    981                 res++;
    982         }
    983        
    984         if (a[res] == b[res]) {
    985                 return res;
    986         }
    987        
    988         res--;
    989         while (a[res] != '/') {
    990                 res--;
    991         }
    992         return res;
    993 }
    994 
    995 static int vfs_rename_internal(vfs_node_t *base, char *old, char *new)
    996 {
    997         assert(base != NULL);
    998         assert(old != NULL);
    999         assert(new != NULL);
     618int vfs_op_read(int fd, size_t *out_bytes)
     619{
     620        return vfs_rdwr(fd, true, rdwr_ipc_client, out_bytes);
     621}
     622
     623int vfs_op_rename(int basefd, char *old, char *new)
     624{
     625        vfs_file_t *base_file = vfs_file_get(basefd);
     626        if (!base_file) {
     627                return EBADF;
     628        }
     629        vfs_node_t *base = base_file->node;
     630        vfs_node_addref(base);
     631        vfs_file_put(base_file);
    1000632       
    1001633        vfs_lookup_res_t base_lr;
     
    1026658                }
    1027659               
     660                vfs_node_put(base);
    1028661                base = vfs_node_get(&base_lr);
    1029662                old[shared] = '/';
    1030663                old += shared;
    1031664                new += shared;
    1032         } else {
    1033                 vfs_node_addref(base);
    1034         }
    1035        
    1036        
    1037         rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, &new_lr_orig);
     665        }
     666               
     667        rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS,
     668            &new_lr_orig);
    1038669        if (rc == EOK) {
    1039670                orig_unlinked = true;
     
    1044675        }
    1045676       
    1046         rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, &old_lr);
     677        rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS,
     678            &old_lr);
    1047679        if (rc != EOK) {
    1048680                if (orig_unlinked) {
     
    1075707}
    1076708
    1077 void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
    1078 {
    1079         /* The common base directory. */
    1080         int basefd;
    1081         char *old = NULL;
    1082         char *new = NULL;
    1083         vfs_file_t *base = NULL;
    1084         int rc;
    1085        
    1086         basefd = IPC_GET_ARG1(*request);
    1087        
    1088         /* Retrieve the old path. */
    1089         rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
    1090         if (rc != EOK) {
    1091                 goto out;
    1092         }
    1093        
    1094         /* Retrieve the new path. */
    1095         rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
    1096         if (rc != EOK) {
    1097                 goto out;
    1098         }
    1099        
    1100         size_t olen;
    1101         size_t nlen;
    1102         char *oldc = canonify(old, &olen);
    1103         char *newc = canonify(new, &nlen);
    1104        
    1105         if ((!oldc) || (!newc)) {
    1106                 rc = EINVAL;
    1107                 goto out;
    1108         }
    1109        
    1110         assert(oldc[olen] == '\0');
    1111         assert(newc[nlen] == '\0');
    1112        
    1113         /* Lookup the file structure corresponding to the file descriptor. */
    1114         base = vfs_file_get(basefd);
    1115         if (!base) {
    1116                 rc = EBADF;
    1117                 goto out;
    1118         }
    1119        
    1120         rc = vfs_rename_internal(base->node, oldc, newc);
    1121 
    1122 out:
    1123         async_answer_0(rid, rc);
    1124 
    1125         if (old) {
    1126                 free(old);
    1127         }
    1128         if (new) {
    1129                 free(new);
    1130         }
    1131         if (base) {
    1132                 vfs_file_put(base);
    1133         }
    1134 }
    1135 
    1136 void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
    1137 {
    1138         int oldfd = IPC_GET_ARG1(*request);
    1139         int newfd = IPC_GET_ARG2(*request);
    1140        
    1141         /* If the file descriptors are the same, do nothing. */
    1142         if (oldfd == newfd) {
    1143                 async_answer_1(rid, EOK, newfd);
    1144                 return;
    1145         }
    1146        
    1147         /* Lookup the file structure corresponding to oldfd. */
    1148         vfs_file_t *oldfile = vfs_file_get(oldfd);
    1149         if (!oldfile) {
    1150                 async_answer_0(rid, EBADF);
    1151                 return;
    1152         }
    1153        
    1154         /* Make sure newfd is closed. */
    1155         (void) vfs_fd_free(newfd);
    1156        
    1157         /* Assign the old file to newfd. */
    1158         int ret = vfs_fd_assign(oldfile, newfd);
    1159         vfs_file_put(oldfile);
    1160        
    1161         if (ret != EOK)
    1162                 async_answer_0(rid, ret);
    1163         else
    1164                 async_answer_1(rid, EOK, newfd);
    1165 }
    1166 
    1167 void vfs_wait_handle(ipc_callid_t rid, ipc_call_t *request)
    1168 {
    1169         bool high_fd = IPC_GET_ARG1(*request);
    1170         int fd = vfs_wait_handle_internal(high_fd);
    1171         async_answer_1(rid, EOK, fd);
    1172 }
    1173 
    1174 void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request)
     709int vfs_op_seek(int fd, int64_t offset, int whence, int64_t *out_offset)
     710{
     711        vfs_file_t *file = vfs_file_get(fd);
     712        if (!file) {
     713                return EBADF;
     714        }
     715       
     716        switch (whence) {
     717        case SEEK_SET:
     718                if (offset < 0) {
     719                        vfs_file_put(file);
     720                        return EINVAL;
     721                }
     722                file->pos = offset;
     723                *out_offset = offset;
     724                vfs_file_put(file);
     725                return EOK;
     726        case SEEK_CUR:
     727                if (offset > 0 && file->pos > (INT64_MAX - offset)) {
     728                        vfs_file_put(file);
     729                        return EOVERFLOW;
     730                }
     731               
     732                if (offset < 0 && -file->pos > offset) {
     733                        vfs_file_put(file);
     734                        return EOVERFLOW;
     735                }
     736               
     737                file->pos += offset;
     738                *out_offset = file->pos;
     739                vfs_file_put(file);
     740                return EOK;
     741        case SEEK_END:
     742                fibril_rwlock_read_lock(&file->node->contents_rwlock);
     743                int64_t size = vfs_node_get_size(file->node);
     744                fibril_rwlock_read_unlock(&file->node->contents_rwlock);
     745               
     746                if (offset > 0 && size > (INT64_MAX - offset)) {
     747                        vfs_file_put(file);
     748                        return EOVERFLOW;
     749                }
     750               
     751                if (offset < 0 && -size > offset) {
     752                        vfs_file_put(file);
     753                        return EOVERFLOW;
     754                }
     755               
     756                file->pos = size + offset;
     757                *out_offset = file->pos;
     758                vfs_file_put(file);
     759                return EOK;
     760        }
     761       
     762        vfs_file_put(file);
     763        return EINVAL;
     764}
     765
     766int vfs_op_statfs(int fd)
    1175767{
    1176768        ipc_callid_t callid;
    1177         ipc_call_t data;
    1178         sysarg_t rc = EOK;
    1179         size_t len;
    1180 
    1181         fibril_mutex_lock(&mtab_list_lock);
    1182 
    1183         /* Send to the caller the number of mounted filesystems */
    1184         callid = async_get_call(&data);
    1185         if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
    1186                 rc = ENOTSUP;
    1187                 async_answer_0(callid, rc);
    1188                 goto exit;
    1189         }
    1190         async_answer_1(callid, EOK, mtab_size);
    1191 
    1192         list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
    1193                 rc = ENOTSUP;
    1194 
    1195                 if (!async_data_read_receive(&callid, &len)) {
    1196                         async_answer_0(callid, rc);
    1197                         goto exit;
    1198                 }
    1199 
    1200                 (void) async_data_read_finalize(callid, mtab_ent->mp,
    1201                     str_size(mtab_ent->mp));
    1202 
    1203                 if (!async_data_read_receive(&callid, &len)) {
    1204                         async_answer_0(callid, rc);
    1205                         goto exit;
    1206                 }
    1207 
    1208                 (void) async_data_read_finalize(callid, mtab_ent->opts,
    1209                     str_size(mtab_ent->opts));
    1210 
    1211                 if (!async_data_read_receive(&callid, &len)) {
    1212                         async_answer_0(callid, rc);
    1213                         goto exit;
    1214                 }
    1215 
    1216                 (void) async_data_read_finalize(callid, mtab_ent->fs_name,
    1217                     str_size(mtab_ent->fs_name));
    1218 
    1219                 callid = async_get_call(&data);
    1220 
    1221                 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
    1222                         async_answer_0(callid, rc);
    1223                         goto exit;
    1224                 }
    1225 
    1226                 rc = EOK;
    1227                 async_answer_2(callid, rc, mtab_ent->instance,
    1228                     mtab_ent->service_id);
    1229         }
    1230 
    1231 exit:
    1232         fibril_mutex_unlock(&mtab_list_lock);
    1233         async_answer_0(rid, rc);
    1234 }
    1235 
    1236 void vfs_statfs(ipc_callid_t rid, ipc_call_t *request)
    1237 {
    1238         int fd = IPC_GET_ARG1(*request);
    1239        
    1240         ipc_callid_t callid;
     769       
    1241770        if (!async_data_read_receive(&callid, NULL)) {
    1242771                async_answer_0(callid, EINVAL);
    1243                 async_answer_0(rid, EINVAL);
    1244                 return;
     772                return EINVAL;
    1245773        }
    1246774
     
    1248776        if (!file) {
    1249777                async_answer_0(callid, EBADF);
    1250                 async_answer_0(rid, EBADF);
     778                return EBADF;
    1251779        }
    1252780
     
    1254782
    1255783        async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
    1256        
     784                                                               
    1257785        aid_t msg;
    1258786        msg = async_send_3(exch, VFS_OUT_STATFS, node->service_id,
    1259             node->index, false, NULL);
     787        node->index, false, NULL);
    1260788        async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
    1261        
     789
    1262790        vfs_exchange_release(exch);
    1263        
     791
    1264792        sysarg_t rv;
    1265793        async_wait_for(msg, &rv);
    1266794
    1267795        vfs_file_put(file);
    1268 
    1269         async_answer_0(rid, rv);
    1270 }
    1271 
    1272 void vfs_op_clone(ipc_callid_t rid, ipc_call_t *request)
    1273 {
    1274         int oldfd = IPC_GET_ARG1(*request);
    1275         bool desc = IPC_GET_ARG2(*request);
    1276        
    1277         /* Lookup the file structure corresponding to fd. */
    1278         vfs_file_t *oldfile = vfs_file_get(oldfd);
    1279         if (oldfile == NULL) {
    1280                 async_answer_0(rid, EBADF);
    1281                 return;
    1282         }
    1283        
    1284         vfs_file_t *newfile;
    1285         int newfd = vfs_fd_alloc(&newfile, desc);
    1286         async_answer_0(rid, newfd);
    1287        
    1288         if (newfd < 0) {
    1289                 vfs_file_put(oldfile);
    1290                 return;
    1291         }
    1292        
    1293         assert(oldfile->node != NULL);
    1294        
    1295         newfile->node = oldfile->node;
    1296         newfile->permissions = oldfile->permissions;
    1297         vfs_node_addref(newfile->node);
    1298 
    1299         vfs_file_put(oldfile);
    1300         vfs_file_put(newfile);
     796        return rv;
     797}
     798
     799int vfs_op_sync(int fd)
     800{
     801        vfs_file_t *file = vfs_file_get(fd);
     802        if (!file) {
     803                return EBADF;
     804        }
     805       
     806        async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
     807       
     808        aid_t msg;
     809        ipc_call_t answer;
     810        msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
     811                file->node->index, &answer);
     812       
     813        vfs_exchange_release(fs_exch);
     814       
     815        sysarg_t rc;
     816        async_wait_for(msg, &rc);
     817       
     818        vfs_file_put(file);
     819        return rc;
     820       
     821}
     822
     823static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
     824    fs_index_t index, aoff64_t size)
     825{
     826        async_exch_t *exch = vfs_exchange_grab(fs_handle);
     827        sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
     828            (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
     829            UPPER32(size));
     830        vfs_exchange_release(exch);
     831       
     832        return (int) rc;
     833}
     834
     835int vfs_op_truncate(int fd, int64_t size)
     836{
     837        vfs_file_t *file = vfs_file_get(fd);
     838        if (!file) {
     839                return EBADF;
     840        }
     841
     842        fibril_rwlock_write_lock(&file->node->contents_rwlock);
     843       
     844        int rc = vfs_truncate_internal(file->node->fs_handle,
     845                file->node->service_id, file->node->index, size);
     846        if (rc == EOK) {
     847                file->node->size = size;
     848        }
     849       
     850        fibril_rwlock_write_unlock(&file->node->contents_rwlock);
     851        vfs_file_put(file);
     852        return rc;
     853}
     854
     855int vfs_op_unlink2(int parentfd, int expectfd, int wflag, char *path)
     856{
     857        int rc = EOK;
     858        vfs_file_t *parent = NULL;
     859        vfs_file_t *expect = NULL;
     860       
     861        if (parentfd == expectfd) {
     862                return EINVAL;
     863        }
     864       
     865        fibril_rwlock_write_lock(&namespace_rwlock);
     866       
     867        int lflag = (wflag&WALK_DIRECTORY) ? L_DIRECTORY: 0;
     868
     869        /*
     870         * Files are retrieved in order of file descriptors, to prevent
     871         * deadlock.
     872         */
     873        if (parentfd < expectfd) {
     874                parent = vfs_file_get(parentfd);
     875                if (!parent) {
     876                        rc = EBADF;
     877                        goto exit;
     878                }
     879        }
     880       
     881        if (expectfd >= 0) {
     882                expect = vfs_file_get(expectfd);
     883                if (!expect) {
     884                        rc = EBADF;
     885                        goto exit;
     886                }
     887        }
     888       
     889        if (parentfd > expectfd) {
     890                parent = vfs_file_get(parentfd);
     891                if (!parent) {
     892                        rc = EBADF;
     893                        goto exit;
     894                }
     895        }
     896       
     897        assert(parent != NULL);
     898       
     899        if (expectfd >= 0) {
     900                vfs_lookup_res_t lr;
     901                rc = vfs_lookup_internal(parent->node, path, lflag, &lr);
     902                if (rc != EOK) {
     903                        goto exit;
     904                }
     905               
     906                vfs_node_t *found_node = vfs_node_peek(&lr);           
     907                if (expect->node != found_node) {
     908                        rc = ENOENT;
     909                        goto exit;
     910                }
     911               
     912                vfs_file_put(expect);
     913                expect = NULL;
     914        }
     915       
     916        vfs_lookup_res_t lr;
     917        rc = vfs_lookup_internal(parent->node, path, lflag | L_UNLINK, &lr);
     918        if (rc != EOK) {
     919                goto exit;
     920        }
     921
     922        /* If the node is not held by anyone, try to destroy it. */
     923        if (vfs_node_peek(&lr) == NULL) {
     924                out_destroy(&lr.triplet);
     925        }
     926
     927exit:
     928        if (path) {
     929                free(path);
     930        }
     931        if (parent) {
     932                vfs_file_put(parent);
     933        }
     934        if (expect) {
     935                vfs_file_put(expect);
     936        }
     937        fibril_rwlock_write_unlock(&namespace_rwlock);
     938        return rc;
     939}
     940
     941int vfs_op_unmount(int mpfd)
     942{
     943        vfs_file_t *mp = vfs_file_get(mpfd);
     944        if (mp == NULL) {
     945                return EBADF;
     946        }
     947       
     948        if (mp->node->mount == NULL) {
     949                vfs_file_put(mp);
     950                return ENOENT;
     951        }
     952       
     953        fibril_rwlock_write_lock(&namespace_rwlock);
     954       
     955        /*
     956         * Count the total number of references for the mounted file system. We
     957         * are expecting at least one, which is held by the mount point.
     958         * If we find more, it means that
     959         * the file system cannot be gracefully unmounted at the moment because
     960         * someone is working with it.
     961         */
     962        if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle,
     963            mp->node->mount->service_id) != 1) {
     964                vfs_file_put(mp);
     965                fibril_rwlock_write_unlock(&namespace_rwlock);
     966                return EBUSY;
     967        }
     968       
     969        async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
     970        int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
     971            mp->node->mount->service_id);
     972        vfs_exchange_release(exch);
     973       
     974        if (rc != EOK) {
     975                vfs_file_put(mp);
     976                fibril_rwlock_write_unlock(&namespace_rwlock);
     977                return rc;
     978        }
     979       
     980        vfs_node_forget(mp->node->mount);
     981        vfs_node_put(mp->node);
     982        mp->node->mount = NULL;
     983       
     984        fibril_rwlock_write_unlock(&namespace_rwlock);
     985       
     986        fibril_mutex_lock(&mtab_list_lock);
     987        int found = 0;
     988
     989        list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
     990                // FIXME: mp name
     991                if (str_cmp(mtab_ent->mp, "fixme") == 0) {
     992                        list_remove(&mtab_ent->link);
     993                        mtab_size--;
     994                        free(mtab_ent);
     995                        found = 1;
     996                        break;
     997                }
     998        }
     999        assert(found);
     1000        fibril_mutex_unlock(&mtab_list_lock);
     1001       
     1002        vfs_file_put(mp);
     1003        return EOK;
     1004}
     1005
     1006int vfs_op_wait_handle(bool high_fd)
     1007{
     1008        return vfs_wait_handle_internal(high_fd);
     1009}
     1010
     1011static inline bool walk_flags_valid(int flags)
     1012{
     1013        if ((flags&~WALK_ALL_FLAGS) != 0) {
     1014                return false;
     1015        }
     1016        if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) {
     1017                return false;
     1018        }
     1019        if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) {
     1020                return false;
     1021        }
     1022        if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) {
     1023                if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) {
     1024                        return false;
     1025                }
     1026        }
     1027        return true;
     1028}
     1029
     1030static inline int walk_lookup_flags(int flags)
     1031{
     1032        int lflags = 0;
     1033        if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) {
     1034                lflags |= L_CREATE;
     1035        }
     1036        if (flags&WALK_MUST_CREATE) {
     1037                lflags |= L_EXCLUSIVE;
     1038        }
     1039        if (flags&WALK_REGULAR) {
     1040                lflags |= L_FILE;
     1041        }
     1042        if (flags&WALK_DIRECTORY) {
     1043                lflags |= L_DIRECTORY;
     1044        }
     1045        if (flags&WALK_MOUNT_POINT) {
     1046                lflags |= L_MP;
     1047        }
     1048        return lflags;
     1049}
     1050
     1051int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd)
     1052{
     1053        if (!walk_flags_valid(flags)) {
     1054                return EINVAL;
     1055        }
     1056       
     1057        vfs_file_t *parent = vfs_file_get(parentfd);
     1058        if (!parent) {
     1059                return EBADF;
     1060        }
     1061       
     1062        fibril_rwlock_read_lock(&namespace_rwlock);
     1063       
     1064        vfs_lookup_res_t lr;
     1065        int rc = vfs_lookup_internal(parent->node, path,
     1066            walk_lookup_flags(flags), &lr);
     1067
     1068        if (rc != EOK) {
     1069                fibril_rwlock_read_unlock(&namespace_rwlock);
     1070                vfs_file_put(parent);
     1071                return rc;
     1072        }
     1073       
     1074        vfs_node_t *node = vfs_node_get(&lr);
     1075       
     1076        vfs_file_t *file;
     1077        int fd = vfs_fd_alloc(&file, false);
     1078        if (fd < 0) {
     1079                vfs_node_put(node);
     1080                vfs_file_put(parent);
     1081                return fd;
     1082        }
     1083        assert(file != NULL);
     1084       
     1085        file->node = node;
     1086        file->permissions = parent->permissions;
     1087        file->open_read = false;
     1088        file->open_write = false;
     1089       
     1090        vfs_file_put(file);
     1091        vfs_file_put(parent);
     1092       
     1093        fibril_rwlock_read_unlock(&namespace_rwlock);
     1094
     1095        *out_fd = fd;
     1096        return EOK;
     1097}
     1098
     1099int vfs_op_write(int fd, size_t *out_bytes)
     1100{
     1101        return vfs_rdwr(fd, false, rdwr_ipc_client, out_bytes);
    13011102}
    13021103
Note: See TracChangeset for help on using the changeset viewer.