Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/vfs/vfs.c

    r6afc9d7 ra6fc88a  
    3333 */
    3434
     35#include <vfs/vfs.h>
    3536#include <vfs/canonify.h>
    36 #include <vfs/vfs.h>
     37#include <vfs/vfs_mtab.h>
    3738#include <vfs/vfs_sess.h>
    3839#include <macros.h>
    3940#include <stdlib.h>
    40 #include <unistd.h>
    41 #include <dirent.h>
    42 #include <fcntl.h>
    43 #include <stdio.h>
    44 #include <sys/stat.h>
    45 #include <sys/statfs.h>
    4641#include <sys/types.h>
    4742#include <ipc/services.h>
     
    5651#include <ipc/loc.h>
    5752
     53/*
     54 * This file contains the implementation of the native HelenOS file system API.
     55 *
     56 * The API supports client-side file system roots, client-side IO cursors and
     57 * uses file handles as a primary means to refer to files. In order to call the
     58 * API functions, one just includes vfs/vfs.h.
     59 *
     60 * The API functions come in two main flavors:
     61 *
     62 * - functions that operate on integer file handles, such as:
     63 *   vfs_walk(), vfs_open(), vfs_read(), vfs_link(), ...
     64 * 
     65 * - functions that operate on paths, such as:
     66 *   vfs_lookup(), vfs_link_path(), vfs_unlink_path(), vfs_rename_path(), ...
     67 *
     68 * There is usually a corresponding path function for each file handle function
     69 * that exists mostly as a convenience wrapper, except for cases when only a
     70 * path version exists due to file system consistency considerations (see
     71 * vfs_rename_path()). Sometimes one of the versions does not make sense, in
     72 * which case it is also omitted.
     73 *
     74 * Besides of that, the API provides some convenience wrappers for frequently
     75 * performed pairs of operations, for example there is a combo API for
     76 * vfs_lookup() and vfs_open(): vfs_lookup_open().
     77 *
     78 * Some of the functions here return a file handle that can be passed to other
     79 * functions. Note that a file handle does not automatically represent a file
     80 * from which one can read or to which one can write. In order to do so, the
     81 * file handle must be opened first for reading/writing using vfs_open().
     82 *
     83 * All file handles, no matter whether opened or not, must be eventually
     84 * returned to the system using vfs_put(). Non-returned file handles are in use
     85 * and consume system resources.
     86 *
     87 * Functions that return int return a negative error code on error and do not
     88 * set errno. Depending on function, success is signalled by returning either
     89 * EOK or a non-negative file handle.
     90 *
     91 * An example life-cycle of a file handle is as follows:
     92 *
     93 *      #include <vfs/vfs.h>
     94 *
     95 *      int file = vfs_lookup("/foo/bar/foobar", WALK_REGULAR);
     96 *      if (file < 0)
     97 *              return file;
     98 *      int rc = vfs_open(file, MODE_READ);
     99 *      if (rc != EOK) {
     100 *              (void) vfs_put(file);
     101 *              return rc;
     102 *      }
     103 *      aoff64_t pos = 42;
     104 *      char buf[512];
     105 *      ssize_t size = vfs_read(file, &pos, buf, sizeof(buf));
     106 *      if (size < 0) {
     107 *              vfs_put(file);
     108 *              return size;
     109 *      }
     110 *
     111 *      // buf is now filled with data from file
     112 *
     113 *      vfs_put(file);
     114 */
     115
    58116static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
    59117static async_sess_t *vfs_sess = NULL;
     
    65123static size_t cwd_size = 0;
    66124
    67 /** Start an async exchange on the VFS session.
    68  *
    69  * @return New exchange.
    70  *
    71  */
    72 async_exch_t *vfs_exchange_begin(void)
    73 {
    74         fibril_mutex_lock(&vfs_mutex);
    75        
    76         while (vfs_sess == NULL)
    77                 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
    78                     0);
    79        
    80         fibril_mutex_unlock(&vfs_mutex);
    81        
    82         return async_exchange_begin(vfs_sess);
    83 }
    84 
    85 /** Finish an async exchange on the VFS session.
    86  *
    87  * @param exch Exchange to be finished.
    88  *
    89  */
    90 void vfs_exchange_end(async_exch_t *exch)
    91 {
    92         async_exchange_end(exch);
    93 }
    94 
     125static FIBRIL_MUTEX_INITIALIZE(root_mutex);
     126static int root_fd = -1;
     127
     128static int get_parent_and_child(const char *path, char **child)
     129{
     130        size_t size;
     131        char *apath = vfs_absolutize(path, &size);
     132        if (!apath)
     133                return ENOMEM;
     134
     135        char *slash = str_rchr(apath, L'/');
     136        int parent;
     137        if (slash == apath) {
     138                parent = vfs_root();
     139                *child = apath;
     140        } else {
     141                *slash = '\0';
     142                parent = vfs_lookup(apath, WALK_DIRECTORY);
     143                if (parent < 0) {
     144                        free(apath);
     145                        return parent;
     146                }
     147                *slash = '/';
     148                *child = str_dup(slash);
     149                free(apath);
     150                if (!*child) {
     151                        vfs_put(parent);
     152                        return ENOMEM;
     153                }
     154        }
     155
     156        return parent;
     157}
     158
     159/** Make a potentially relative path absolute
     160 *
     161 * This function coverts a current-working-directory-relative path into a
     162 * well-formed, absolute path. The caller is responsible for deallocating the
     163 * returned buffer.
     164 *
     165 * @param[in] path      Path to be absolutized
     166 * @param[out] retlen   Length of the absolutized path
     167 *
     168 * @return              New buffer holding the absolutized path or NULL
     169 */
    95170char *vfs_absolutize(const char *path, size_t *retlen)
    96171{
     
    143218}
    144219
    145 int vfs_mount(const char *fs_name, const char *mp, const char *fqsn,
     220/** Clone a file handle
     221 *
     222 * The caller can choose whether to clone an existing file handle into another
     223 * already existing file handle (in which case it is first closed) or to a new
     224 * file handle allocated either from low or high indices.
     225 *
     226 * @param file_from     Source file handle
     227 * @param file_to       Destination file handle or -1
     228 * @param high          If file_to is -1, high controls whether the new file
     229 *                      handle will be allocated from high indices
     230 *
     231 * @return              New file handle on success or a negative error code
     232 */
     233int vfs_clone(int file_from, int file_to, bool high)
     234{
     235        async_exch_t *vfs_exch = vfs_exchange_begin();
     236        int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
     237            (sysarg_t) file_to, (sysarg_t) high);
     238        vfs_exchange_end(vfs_exch);
     239        return rc;
     240}
     241
     242/** Get current working directory path
     243 *
     244 * @param[out] buf      Buffer
     245 * @param size          Size of @a buf
     246 *
     247 * @return              EOK on success or a non-negative error code
     248 */
     249int vfs_cwd_get(char *buf, size_t size)
     250{
     251        fibril_mutex_lock(&cwd_mutex);
     252       
     253        if ((cwd_size == 0) || (size < cwd_size + 1)) {
     254                fibril_mutex_unlock(&cwd_mutex);
     255                return ERANGE;
     256        }
     257       
     258        str_cpy(buf, size, cwd_path);
     259        fibril_mutex_unlock(&cwd_mutex);
     260       
     261        return EOK;
     262}
     263
     264/** Change working directory
     265 *
     266 * @param path  Path of the new working directory
     267 *
     268 * @return      EOK on success or a negative error code
     269 */
     270int vfs_cwd_set(const char *path)
     271{
     272        size_t abs_size;
     273        char *abs = vfs_absolutize(path, &abs_size);
     274        if (!abs)
     275                return ENOMEM;
     276       
     277        int fd = vfs_lookup(abs, WALK_DIRECTORY);
     278        if (fd < 0) {
     279                free(abs);
     280                return fd;
     281        }
     282       
     283        fibril_mutex_lock(&cwd_mutex);
     284       
     285        if (cwd_fd >= 0)
     286                vfs_put(cwd_fd);
     287       
     288        if (cwd_path)
     289                free(cwd_path);
     290       
     291        cwd_fd = fd;
     292        cwd_path = abs;
     293        cwd_size = abs_size;
     294       
     295        fibril_mutex_unlock(&cwd_mutex);
     296        return EOK;
     297}
     298
     299/** Start an async exchange on the VFS session
     300 *
     301 * @return      New exchange
     302 */
     303async_exch_t *vfs_exchange_begin(void)
     304{
     305        fibril_mutex_lock(&vfs_mutex);
     306       
     307        while (vfs_sess == NULL) {
     308                vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
     309                    0);
     310        }
     311       
     312        fibril_mutex_unlock(&vfs_mutex);
     313       
     314        return async_exchange_begin(vfs_sess);
     315}
     316
     317/** Finish an async exchange on the VFS session
     318 *
     319 * @param exch  Exchange to be finished
     320 */
     321void vfs_exchange_end(async_exch_t *exch)
     322{
     323        async_exchange_end(exch);
     324}
     325
     326/** Open session to service represented by a special file
     327 *
     328 * Given that the file referred to by @a file represents a service,
     329 * open a session to that service.
     330 *
     331 * @param file  File handle representing a service
     332 * @param iface Interface to connect to (XXX Should be automatic)
     333 *
     334 * @return      Session pointer on success.
     335 * @return      @c NULL or error.
     336 */
     337async_sess_t *vfs_fd_session(int file, iface_t iface)
     338{
     339        struct stat stat;
     340        int rc = vfs_stat(file, &stat);
     341        if (rc != 0)
     342                return NULL;
     343       
     344        if (stat.service == 0)
     345                return NULL;
     346       
     347        return loc_service_connect(stat.service, iface, 0);
     348}
     349
     350/** Link a file or directory
     351 *
     352 * Create a new name and an empty file or an empty directory in a parent
     353 * directory. If child with the same name already exists, the function returns
     354 * a failure, the existing file remains untouched and no file system object
     355 * is created.
     356 *
     357 * @param parent        File handle of the parent directory node
     358 * @param child         New name to be linked
     359 * @param kind          Kind of the object to be created: KIND_FILE or
     360 *                      KIND_DIRECTORY
     361 * @param[out] linkedfd If not NULL, will receive a file handle to the linked
     362 *                      child
     363 * @return              EOK on success or a negative error code
     364 */
     365int vfs_link(int parent, const char *child, vfs_file_kind_t kind, int *linkedfd)
     366{
     367        int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR;
     368        int file = vfs_walk(parent, child, WALK_MUST_CREATE | flags);
     369
     370        if (file < 0)
     371                return file;
     372
     373        if (linkedfd)
     374                *linkedfd = file;
     375        else
     376                vfs_put(file);
     377
     378        return EOK;
     379}
     380
     381/** Link a file or directory
     382 *
     383 * Create a new name and an empty file or an empty directory at given path.
     384 * If a link with the same name already exists, the function returns
     385 * a failure, the existing file remains untouched and no file system object
     386 * is created.
     387 *
     388 * @param path          New path to be linked
     389 * @param kind          Kind of the object to be created: KIND_FILE or
     390 *                      KIND_DIRECTORY
     391 * @param[out] linkedfd If not NULL, will receive a file handle to the linked
     392 *                      child
     393 * @return              EOK on success or a negative error code
     394 */
     395int vfs_link_path(const char *path, vfs_file_kind_t kind, int *linkedfd)
     396{
     397        char *child;
     398        int parent = get_parent_and_child(path, &child);
     399        if (parent < 0)
     400                return parent;
     401
     402        int rc = vfs_link(parent, child, kind, linkedfd);
     403
     404        free(child);
     405        vfs_put(parent);
     406        return rc;
     407}       
     408
     409/** Lookup a path relative to the local root
     410 *
     411 * @param path  Path to be looked up
     412 * @param flags Walk flags
     413 *
     414 * @return      File handle representing the result on success or a negative
     415 *              error code on error
     416 */
     417int vfs_lookup(const char *path, int flags)
     418{
     419        size_t size;
     420        char *p = vfs_absolutize(path, &size);
     421        if (!p)
     422                return ENOMEM;
     423        int root = vfs_root();
     424        if (root < 0) {
     425                free(p);
     426                return ENOENT;
     427        }
     428        int rc = vfs_walk(root, p, flags);
     429        vfs_put(root);
     430        free(p);
     431        return rc;
     432}
     433
     434/** Lookup a path relative to the local root and open the result
     435 *
     436 * This function is a convenience combo for vfs_lookup() and vfs_open().
     437 *
     438 * @param path  Path to be looked up
     439 * @param flags Walk flags
     440 * @param mode  Mode in which to open file in
     441 *
     442 * @return      EOK on success or a negative error code
     443 */
     444int vfs_lookup_open(const char *path, int flags, int mode)
     445{
     446        int file = vfs_lookup(path, flags);
     447        if (file < 0)
     448                return file;
     449
     450        int rc = vfs_open(file, mode);
     451        if (rc != EOK) {
     452                vfs_put(file);
     453                return rc;
     454        }
     455       
     456        return file;
     457}
     458
     459/** Mount a file system
     460 *
     461 * @param[in] mp                File handle representing the mount-point
     462 * @param[in] fs_name           File system name
     463 * @param[in] serv              Service representing the mountee
     464 * @param[in] opts              Mount options for the endpoint file system
     465 * @param[in] flags             Mount flags
     466 * @param[in] instance          Instance number of the file system server
     467 * @param[out] mountedfd        File handle of the mounted root if not NULL
     468 *
     469 * @return                      EOK on success or a negative error code
     470 */
     471int vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
     472    unsigned int flags, unsigned int instance, int *mountedfd)
     473{
     474        sysarg_t rc, rc1;
     475       
     476        if (!mountedfd)
     477                flags |= VFS_MOUNT_NO_REF;
     478        if (mp < 0)
     479                flags |= VFS_MOUNT_CONNECT_ONLY;
     480       
     481        ipc_call_t answer;
     482        async_exch_t *exch = vfs_exchange_begin();
     483        aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance,
     484            &answer);
     485
     486        rc1 = async_data_write_start(exch, (void *) opts, str_size(opts));
     487        if (rc1 == EOK) {
     488                rc1 = async_data_write_start(exch, (void *) fs_name,
     489                    str_size(fs_name));
     490        }
     491
     492        vfs_exchange_end(exch);
     493
     494        async_wait_for(req, &rc);
     495
     496        if (mountedfd)
     497                *mountedfd = (int) IPC_GET_ARG1(answer);
     498       
     499        if (rc != EOK)
     500                return rc;
     501        return rc1;
     502}
     503
     504/** Mount a file system
     505 *
     506 * @param[in] mp                Path representing the mount-point
     507 * @param[in] fs_name           File system name
     508 * @param[in] fqsn              Fully qualified service name of the mountee
     509 * @param[in] opts              Mount options for the endpoint file system
     510 * @param[in] flags             Mount flags
     511 * @param[in] instance          Instance number of the file system server
     512 *
     513 * @return                      EOK on success or a negative error code
     514 */
     515int vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
    146516    const char *opts, unsigned int flags, unsigned int instance)
    147517{
     
    150520       
    151521        if (str_cmp(fqsn, "") == 0) {
    152                 /* No device specified, create a fresh
    153                    null/%d device instead */
     522                /*
     523                 * No device specified, create a fresh null/%d device instead.
     524                */
    154525                null_id = loc_null_create();
    155526               
     
    161532        }
    162533       
     534        if (flags & IPC_FLAG_BLOCKING)
     535                flags = VFS_MOUNT_BLOCKING;
     536        else
     537                flags = 0;
     538       
    163539        service_id_t service_id;
    164540        int res = loc_service_get_id(fqsn, &service_id, flags);
     
    179555        }
    180556       
    181         async_exch_t *exch = vfs_exchange_begin();
    182 
    183         sysarg_t rc_orig;
    184         aid_t req = async_send_3(exch, VFS_IN_MOUNT, service_id, flags,
    185             instance, NULL);
    186         sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size);
    187         if (rc != EOK) {
    188                 vfs_exchange_end(exch);
    189                 free(mpa);
    190                 async_wait_for(req, &rc_orig);
     557        fibril_mutex_lock(&root_mutex);
     558       
     559        int rc;
     560       
     561        if (str_cmp(mpa, "/") == 0) {
     562                /* Mounting root. */
    191563               
    192                 if (null_id != -1)
    193                         loc_null_destroy(null_id);
     564                if (root_fd >= 0) {
     565                        fibril_mutex_unlock(&root_mutex);
     566                        if (null_id != -1)
     567                                loc_null_destroy(null_id);
     568                        return EBUSY;
     569                }
    194570               
    195                 if (rc_orig == EOK)
    196                         return (int) rc;
    197                 else
    198                         return (int) rc_orig;
    199         }
    200        
    201         rc = async_data_write_start(exch, (void *) opts, str_size(opts));
    202         if (rc != EOK) {
    203                 vfs_exchange_end(exch);
    204                 free(mpa);
    205                 async_wait_for(req, &rc_orig);
     571                int root;
     572                rc = vfs_mount(-1, fs_name, service_id, opts, flags, instance,
     573                    &root);
     574                if (rc == EOK)
     575                        root_fd = root;
     576        } else {
     577                if (root_fd < 0) {
     578                        fibril_mutex_unlock(&root_mutex);
     579                        if (null_id != -1)
     580                                loc_null_destroy(null_id);
     581                        return EINVAL;
     582                }
    206583               
    207                 if (null_id != -1)
    208                         loc_null_destroy(null_id);
    209                
    210                 if (rc_orig == EOK)
    211                         return (int) rc;
    212                 else
    213                         return (int) rc_orig;
    214         }
    215        
    216         rc = async_data_write_start(exch, (void *) fs_name, str_size(fs_name));
    217         if (rc != EOK) {
    218                 vfs_exchange_end(exch);
    219                 free(mpa);
    220                 async_wait_for(req, &rc_orig);
    221                
    222                 if (null_id != -1)
    223                         loc_null_destroy(null_id);
    224                
    225                 if (rc_orig == EOK)
    226                         return (int) rc;
    227                 else
    228                         return (int) rc_orig;
    229         }
    230        
    231         /* Ask VFS whether it likes fs_name. */
    232         rc = async_req_0_0(exch, VFS_IN_PING);
    233         if (rc != EOK) {
    234                 vfs_exchange_end(exch);
    235                 free(mpa);
    236                 async_wait_for(req, &rc_orig);
    237                
    238                 if (null_id != -1)
    239                         loc_null_destroy(null_id);
    240                
    241                 if (rc_orig == EOK)
    242                         return (int) rc;
    243                 else
    244                         return (int) rc_orig;
    245         }
    246        
    247         vfs_exchange_end(exch);
    248         free(mpa);
    249         async_wait_for(req, &rc);
     584                int mpfd = vfs_walk(root_fd, mpa, WALK_DIRECTORY);
     585                if (mpfd >= 0) {
     586                        rc = vfs_mount(mpfd, fs_name, service_id, opts, flags,
     587                            instance, NULL);
     588                        vfs_put(mpfd);
     589                } else {
     590                        rc = mpfd;
     591                }
     592        }
     593       
     594        fibril_mutex_unlock(&root_mutex);
    250595       
    251596        if ((rc != EOK) && (null_id != -1))
     
    255600}
    256601
    257 int vfs_unmount(const char *mp)
    258 {
    259         sysarg_t rc;
    260         sysarg_t rc_orig;
    261         aid_t req;
    262         size_t mpa_size;
    263         char *mpa;
    264        
    265         mpa = vfs_absolutize(mp, &mpa_size);
    266         if (mpa == NULL)
    267                 return ENOMEM;
    268        
    269         async_exch_t *exch = vfs_exchange_begin();
    270        
    271         req = async_send_0(exch, VFS_IN_UNMOUNT, NULL);
    272         rc = async_data_write_start(exch, (void *) mpa, mpa_size);
    273         if (rc != EOK) {
    274                 vfs_exchange_end(exch);
    275                 free(mpa);
    276                 async_wait_for(req, &rc_orig);
    277                 if (rc_orig == EOK)
    278                         return (int) rc;
    279                 else
    280                         return (int) rc_orig;
    281         }
    282        
    283 
    284         vfs_exchange_end(exch);
    285         free(mpa);
    286         async_wait_for(req, &rc);
    287        
    288         return (int) rc;
    289 }
    290 
    291 /** Open file (internal).
    292  *
    293  * @param abs Absolute path to file
    294  * @param abs_size Size of @a abs string
    295  * @param lflag L_xxx flags
    296  * @param oflag O_xxx flags
    297  * @param fd Place to store new file descriptor
    298  *
    299  * @return EOK on success, non-zero error code on error
    300  */
    301 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag,
    302     int *fd)
    303 {
    304         async_exch_t *exch = vfs_exchange_begin();
    305        
    306         ipc_call_t answer;
    307         aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer);
    308         sysarg_t rc = async_data_write_start(exch, abs, abs_size);
    309        
    310         if (rc != EOK) {
    311                 vfs_exchange_end(exch);
    312 
    313                 sysarg_t rc_orig;
    314                 async_wait_for(req, &rc_orig);
    315                
    316                 if (rc_orig == EOK)
    317                         return (int) rc;
    318                 else
    319                         return (int) rc_orig;
    320         }
    321        
    322         vfs_exchange_end(exch);
    323         async_wait_for(req, &rc);
    324        
     602
     603/** Open a file handle for I/O
     604 *
     605 * @param file  File handle to enable I/O on
     606 * @param mode  Mode in which to open file in
     607 *
     608 * @return      EOK on success or a negative error code
     609 */
     610int vfs_open(int file, int mode)
     611{
     612        async_exch_t *exch = vfs_exchange_begin();
     613        int rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode);
     614        vfs_exchange_end(exch);
     615       
     616        return rc;
     617}
     618
     619/** Pass a file handle to another VFS client
     620 *
     621 * @param vfs_exch      Donor's VFS exchange
     622 * @param file          Donor's file handle to pass
     623 * @param exch          Exchange to the acceptor
     624 *
     625 * @return              EOK on success or a negative error code
     626 */
     627int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
     628{
     629        return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
     630            0, vfs_exch);
     631}
     632
     633/** Stop working with a file handle
     634 *
     635 * @param file  File handle to put
     636 *
     637 * @return      EOK on success or a negative error code
     638 */
     639int vfs_put(int file)
     640{
     641        async_exch_t *exch = vfs_exchange_begin();
     642        int rc = async_req_1_0(exch, VFS_IN_PUT, file);
     643        vfs_exchange_end(exch);
     644       
     645        return rc;
     646}
     647
     648/** Receive a file handle from another VFS client
     649 *
     650 * @param high   If true, the received file handle will be allocated from high
     651 *               indices
     652 *
     653 * @return       EOK on success or a negative error code
     654 */
     655int vfs_receive_handle(bool high)
     656{
     657        ipc_callid_t callid;
     658        if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
     659                async_answer_0(callid, EINVAL);
     660                return EINVAL;
     661        }
     662
     663        async_exch_t *vfs_exch = vfs_exchange_begin();
     664
     665        async_state_change_finalize(callid, vfs_exch);
     666
     667        sysarg_t ret;
     668        sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret);
     669
     670        async_exchange_end(vfs_exch);
     671
    325672        if (rc != EOK)
    326             return (int) rc;
    327        
    328         *fd = (int) IPC_GET_ARG1(answer);
    329         return EOK;
    330 }
    331 
    332 /** Open file.
    333  *
    334  * @param path File path
    335  * @param oflag O_xxx flags
    336  * @param mode File mode (only with O_CREAT)
    337  *
    338  * @return Nonnegative file descriptor on success. On error -1 is returned
    339  *         and errno is set.
    340  */
    341 int open(const char *path, int oflag, ...)
    342 {
    343         size_t abs_size;
    344         char *abs = vfs_absolutize(path, &abs_size);
    345         int fd = -1;
    346        
    347         if (abs == NULL) {
    348                 errno = ENOMEM;
    349                 return -1;
    350         }
    351        
    352         int rc = open_internal(abs, abs_size, L_FILE, oflag, &fd);
    353         free(abs);
    354        
    355         if (rc != EOK) {
    356                 errno = rc;
    357                 return -1;
    358         }
    359        
    360         return fd;
    361 }
    362 
    363 /** Close file.
    364  *
    365  * @param fildes File descriptor
    366  * @return Zero on success. On error -1 is returned and errno is set.
    367  */
    368 int close(int fildes)
    369 {
    370         sysarg_t rc;
    371        
    372         async_exch_t *exch = vfs_exchange_begin();
    373         rc = async_req_1_0(exch, VFS_IN_CLOSE, fildes);
    374         vfs_exchange_end(exch);
    375        
    376         if (rc != EOK) {
    377                 errno = rc;
    378                 return -1;
    379         }
    380        
    381         return 0;
    382 }
    383 
    384 /** Read bytes from file.
     673                return rc;
     674        return ret;
     675}
     676
     677/** Read data
     678 *
     679 * Read up to @a nbytes bytes from file if available. This function always reads
     680 * all the available bytes up to @a nbytes.
     681 *
     682 * @param file          File handle to read from
     683 * @param[inout] pos    Position to read from, updated by the actual bytes read
     684 * @param buf           Buffer, @a nbytes bytes long
     685 * @param nbytes        Number of bytes to read
     686 *
     687 * @return              On success, non-negative number of bytes read
     688 * @return              On failure, a negative error code
     689 */
     690ssize_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte)
     691{
     692        ssize_t cnt = 0;
     693        size_t nread = 0;
     694        uint8_t *bp = (uint8_t *) buf;
     695        int rc;
     696       
     697        do {
     698                bp += cnt;
     699                nread += cnt;
     700                *pos += cnt;
     701                rc = vfs_read_short(file, *pos, bp, nbyte - nread, &cnt);
     702        } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
     703       
     704        if (rc != EOK)
     705                return rc;
     706       
     707        *pos += cnt;
     708        return nread + cnt;
     709}
     710
     711/** Read bytes from a file
    385712 *
    386713 * Read up to @a nbyte bytes from file. The actual number of bytes read
     
    389716 * return success with zero bytes read.
    390717 *
    391  * @param fildes File descriptor
    392  * @param buf Buffer
    393  * @param nbyte Maximum number of bytes to read
    394  * @param nread Place to store actual number of bytes read (0 or more)
    395  *
    396  * @return EOK on success, non-zero error code on error.
    397  */
    398 static int _read_short(int fildes, void *buf, size_t nbyte, ssize_t *nread)
     718 * @param file          File handle to read from
     719 * @param[in] pos       Position to read from
     720 * @param buf           Buffer to read from
     721 * @param nbyte         Maximum number of bytes to read
     722 * @param[out] nread    Actual number of bytes read (0 or more)
     723 *
     724 * @return              EOK on success or a negative error code
     725 */
     726int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
     727    ssize_t *nread)
    399728{
    400729        sysarg_t rc;
     
    407736        async_exch_t *exch = vfs_exchange_begin();
    408737       
    409         req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
     738        req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos),
     739            UPPER32(pos), &answer);
    410740        rc = async_data_read_start(exch, (void *) buf, nbyte);
     741
     742        vfs_exchange_end(exch);
     743       
     744        if (rc == EOK)
     745                async_wait_for(req, &rc);
     746        else
     747                async_forget(req);
     748       
     749        if (rc != EOK)
     750                return rc;
     751       
     752        *nread = (ssize_t) IPC_GET_ARG1(answer);
     753        return EOK;
     754}
     755
     756/** Rename a file or directory
     757 *
     758 * There is no file-handle-based variant to disallow attempts to introduce loops
     759 * and breakage in the directory tree when relinking eg. a node under its own
     760 * descendant.  The path-based variant is not susceptible because the VFS can
     761 * prevent this lexically by comparing the paths.
     762 *
     763 * @param old   Old path
     764 * @param new   New path
     765 *
     766 * @return      EOK on success or a negative error code
     767 */
     768int vfs_rename_path(const char *old, const char *new)
     769{
     770        sysarg_t rc;
     771        sysarg_t rc_orig;
     772        aid_t req;
     773       
     774        size_t olda_size;
     775        char *olda = vfs_absolutize(old, &olda_size);
     776        if (olda == NULL)
     777                return ENOMEM;
     778
     779        size_t newa_size;
     780        char *newa = vfs_absolutize(new, &newa_size);
     781        if (newa == NULL) {
     782                free(olda);
     783                return ENOMEM;
     784        }
     785       
     786        async_exch_t *exch = vfs_exchange_begin();
     787        int root = vfs_root();
     788        if (root < 0) {
     789                free(olda);
     790                free(newa);
     791                return ENOENT;
     792        }
     793       
     794        req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
     795        rc = async_data_write_start(exch, olda, olda_size);
    411796        if (rc != EOK) {
    412797                vfs_exchange_end(exch);
    413                
    414                 sysarg_t rc_orig;
     798                free(olda);
     799                free(newa);
     800                vfs_put(root);
    415801                async_wait_for(req, &rc_orig);
    416                
    417                 if (rc_orig == EOK)
    418                         return rc;
    419                 else
    420                         return rc_orig;
    421         }
    422        
    423         vfs_exchange_end(exch);
    424         async_wait_for(req, &rc);
    425        
    426         if (rc != EOK)
     802                if (rc_orig != EOK)
     803                        rc = rc_orig;
    427804                return rc;
    428        
    429         *nread = (ssize_t) IPC_GET_ARG1(answer);
    430         return EOK;
    431 }
    432 
    433 /** Write bytes to file.
    434  *
    435  * Write up to @a nbyte bytes from file. The actual number of bytes written
    436  * may be lower, but greater than zero.
    437  *
    438  * @param fildes File descriptor
    439  * @param buf Buffer
    440  * @param nbyte Maximum number of bytes to write
    441  * @param nread Place to store actual number of bytes written (0 or more)
    442  *
    443  * @return EOK on success, non-zero error code on error.
    444  */
    445 static int _write_short(int fildes, const void *buf, size_t nbyte,
    446     ssize_t *nwritten)
    447 {
    448         sysarg_t rc;
    449         ipc_call_t answer;
    450         aid_t req;
    451        
    452         if (nbyte > DATA_XFER_LIMIT)
    453                 nbyte = DATA_XFER_LIMIT;
    454        
    455         async_exch_t *exch = vfs_exchange_begin();
    456        
    457         req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
    458         rc = async_data_write_start(exch, (void *) buf, nbyte);
     805        }
     806        rc = async_data_write_start(exch, newa, newa_size);
    459807        if (rc != EOK) {
    460808                vfs_exchange_end(exch);
    461                
    462                 sysarg_t rc_orig;
     809                free(olda);
     810                free(newa);
     811                vfs_put(root);
    463812                async_wait_for(req, &rc_orig);
    464                
    465                 if (rc_orig == EOK)
    466                         return rc;
    467                 else
    468                         return rc_orig;
    469         }
    470        
    471         vfs_exchange_end(exch);
     813                if (rc_orig != EOK)
     814                        rc = rc_orig;
     815                return rc;
     816        }
     817        vfs_exchange_end(exch);
     818        free(olda);
     819        free(newa);
     820        vfs_put(root);
    472821        async_wait_for(req, &rc);
    473        
    474         if (rc != EOK)
    475                 return rc;
    476        
    477         *nwritten = (ssize_t) IPC_GET_ARG1(answer);
    478         return EOK;
    479 }
    480 
    481 /** Read data.
    482  *
    483  * Read up to @a nbytes bytes from file if available. This function always reads
    484  * all the available bytes up to @a nbytes.
    485  *
    486  * @param fildes        File descriptor
    487  * @param buf           Buffer, @a nbytes bytes long
    488  * @param nbytes        Number of bytes to read
    489  *
    490  * @return              On success, nonnegative number of bytes read.
    491  *                      On failure, -1 and sets errno.
    492  */
    493 ssize_t read(int fildes, void *buf, size_t nbyte)
    494 {
    495         ssize_t cnt = 0;
    496         size_t nread = 0;
    497         uint8_t *bp = (uint8_t *) buf;
    498         int rc;
    499        
    500         do {
    501                 bp += cnt;
    502                 nread += cnt;
    503                 rc = _read_short(fildes, bp, nbyte - nread, &cnt);
    504         } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
    505        
    506         if (rc != EOK) {
    507                 errno = rc;
    508                 return -1;
    509         }
    510        
    511         return nread + cnt;
    512 }
    513 
    514 /** Write data.
    515  *
    516  * This function fails if it cannot write exactly @a len bytes to the file.
    517  *
    518  * @param fildes        File descriptor
    519  * @param buf           Data, @a nbytes bytes long
    520  * @param nbytes        Number of bytes to write
    521  *
    522  * @return              On success, nonnegative number of bytes written.
    523  *                      On failure, -1 and sets errno.
    524  */
    525 ssize_t write(int fildes, const void *buf, size_t nbyte)
    526 {
    527         ssize_t cnt = 0;
    528         ssize_t nwritten = 0;
    529         const uint8_t *bp = (uint8_t *) buf;
    530         int rc;
    531 
    532         do {
    533                 bp += cnt;
    534                 nwritten += cnt;
    535                 rc = _write_short(fildes, bp, nbyte - nwritten, &cnt);
    536         } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
    537 
    538         if (rc != EOK) {
    539                 errno = rc;
    540                 return -1;
    541         }
    542 
    543         return nbyte;
    544 }
    545 
    546 /** Synchronize file.
    547  *
    548  * @param fildes File descriptor
    549  * @return 0 on success. On error returns -1 and sets errno.
    550  */
    551 int fsync(int fildes)
    552 {
    553         async_exch_t *exch = vfs_exchange_begin();
    554         sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes);
    555         vfs_exchange_end(exch);
    556        
    557         if (rc != EOK) {
    558                 errno = rc;
    559                 return -1;
    560         }
    561        
    562         return 0;
    563 }
    564 
    565 /** Seek to a position.
    566  *
    567  * @param fildes File descriptor
    568  * @param offset Offset
    569  * @param whence SEEK_SET, SEEK_CUR or SEEK_END
    570  *
    571  * @return On success the nonnegative offset from start of file. On error
    572  *         returns (off64_t)-1 and sets errno.
    573  */
    574 off64_t lseek(int fildes, off64_t offset, int whence)
    575 {
    576         async_exch_t *exch = vfs_exchange_begin();
    577        
    578         sysarg_t newoff_lo;
    579         sysarg_t newoff_hi;
    580         sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes,
    581             LOWER32(offset), UPPER32(offset), whence,
    582             &newoff_lo, &newoff_hi);
    583        
    584         vfs_exchange_end(exch);
    585        
    586         if (rc != EOK) {
    587                 errno = rc;
    588                 return (off64_t) -1;
    589         }
    590        
    591         return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
    592 }
    593 
    594 /** Truncate file to a specified length.
    595  *
    596  * Truncate file so that its size is exactly @a length
    597  *
    598  * @param fildes File descriptor
    599  * @param length Length
    600  *
    601  * @return 0 on success, -1 on error and sets errno.
    602  */
    603 int ftruncate(int fildes, aoff64_t length)
    604 {
    605         sysarg_t rc;
    606        
    607         async_exch_t *exch = vfs_exchange_begin();
    608         rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes,
    609             LOWER32(length), UPPER32(length));
    610         vfs_exchange_end(exch);
    611        
    612         if (rc != EOK) {
    613                 errno = rc;
    614                 return -1;
    615         }
    616        
    617         return 0;
    618 }
    619 
    620 /** Get file status.
    621  *
    622  * @param fildes File descriptor
    623  * @param stat Place to store file information
    624  *
    625  * @return 0 on success, -1 on error and sets errno.
    626  */
    627 int fstat(int fildes, struct stat *stat)
     822
     823        return rc;
     824}
     825
     826/** Resize file to a specified length
     827 *
     828 * Resize file so that its size is exactly @a length.
     829 *
     830 * @param file          File handle to resize
     831 * @param length        New length
     832 *
     833 * @return              EOK on success or a negative error code
     834 */
     835int vfs_resize(int file, aoff64_t length)
     836{
     837        async_exch_t *exch = vfs_exchange_begin();
     838        int rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
     839            UPPER32(length));
     840        vfs_exchange_end(exch);
     841       
     842        return rc;
     843}
     844
     845/** Return a new file handle representing the local root
     846 *
     847 * @return      A clone of the local root file handle or a negative error code
     848 */
     849int vfs_root(void)
     850{
     851        fibril_mutex_lock(&root_mutex);
     852        int r;
     853        if (root_fd < 0)
     854                r = ENOENT;
     855        else
     856                r = vfs_clone(root_fd, -1, true);
     857        fibril_mutex_unlock(&root_mutex);
     858        return r;
     859}
     860
     861/** Set a new local root
     862 *
     863 * Note that it is still possible to have file handles for other roots and pass
     864 * them to the API functions. Functions like vfs_root() and vfs_lookup() will
     865 * however consider the file set by this function to be the root.
     866 *
     867 * @param nroot The new local root file handle
     868 */
     869void vfs_root_set(int nroot)
     870{
     871        fibril_mutex_lock(&root_mutex);
     872        if (root_fd >= 0)
     873                vfs_put(root_fd);
     874        root_fd = vfs_clone(nroot, -1, true);
     875        fibril_mutex_unlock(&root_mutex);
     876}
     877
     878/** Get file information
     879 *
     880 * @param file          File handle to get information about
     881 * @param[out] stat     Place to store file information
     882 *
     883 * @return              EOK on success or a negative error code
     884 */
     885int vfs_stat(int file, struct stat *stat)
    628886{
    629887        sysarg_t rc;
     
    632890        async_exch_t *exch = vfs_exchange_begin();
    633891       
    634         req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
     892        req = async_send_1(exch, VFS_IN_STAT, file, NULL);
    635893        rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
    636894        if (rc != EOK) {
     
    642900                if (rc_orig != EOK)
    643901                        rc = rc_orig;
    644                 if (rc != EOK) {
    645                         errno = rc;
    646                         return -1;
    647                 }
    648902               
    649                 return 0;
     903                return rc;
    650904        }
    651905       
     
    653907        async_wait_for(req, &rc);
    654908       
    655         if (rc != EOK) {
    656                 errno = rc;
    657                 return -1;
    658         }
    659        
    660         return 0;
    661 }
    662 
    663 /** Get file status.
    664  *
    665  * @param path Path to file
    666  * @param stat Place to store file information
    667  *
    668  * @return 0 on success, -1 on error and sets errno.
    669  */
    670 int stat(const char *path, struct stat *stat)
    671 {
    672         sysarg_t rc;
    673         sysarg_t rc_orig;
     909        return rc;
     910}
     911
     912/** Get file information
     913 *
     914 * @param path          File path to get information about
     915 * @param[out] stat     Place to store file information
     916 *
     917 * @return              EOK on success or a negative error code
     918 */
     919int vfs_stat_path(const char *path, struct stat *stat)
     920{
     921        int file = vfs_lookup(path, 0);
     922        if (file < 0)
     923                return file;
     924       
     925        int rc = vfs_stat(file, stat);
     926
     927        vfs_put(file);
     928
     929        return rc;
     930}
     931
     932/** Get filesystem statistics
     933 *
     934 * @param file          File located on the queried file system
     935 * @param[out] st       Buffer for storing information
     936 *
     937 * @return              EOK on success or a negative error code
     938 */
     939int vfs_statfs(int file, struct statfs *st)
     940{
     941        sysarg_t rc, ret;
    674942        aid_t req;
    675        
    676         size_t pa_size;
    677         char *pa = vfs_absolutize(path, &pa_size);
    678         if (pa == NULL) {
    679                 errno = ENOMEM;
    680                 return -1;
    681         }
    682        
    683         async_exch_t *exch = vfs_exchange_begin();
    684        
    685         req = async_send_0(exch, VFS_IN_STAT, NULL);
    686         rc = async_data_write_start(exch, pa, pa_size);
    687         if (rc != EOK) {
    688                 vfs_exchange_end(exch);
    689                 free(pa);
    690                 async_wait_for(req, &rc_orig);
    691                 if (rc_orig != EOK)
    692                         rc = rc_orig;
    693                 if (rc != EOK) {
    694                         errno = rc;
    695                         return -1;
    696                 }
    697         }
    698         rc = async_data_read_start(exch, stat, sizeof(struct stat));
    699         if (rc != EOK) {
    700                 vfs_exchange_end(exch);
    701                 free(pa);
    702                 async_wait_for(req, &rc_orig);
    703                 if (rc_orig != EOK)
    704                         rc = rc_orig;
    705                 if (rc != EOK) {
    706                         errno = rc;
    707                         return -1;
    708                 }
    709         }
    710         vfs_exchange_end(exch);
    711         free(pa);
    712         async_wait_for(req, &rc);
    713         if (rc != EOK) {
    714                 errno = rc;
    715                 return -1;
    716         }
    717         return 0;
    718 }
    719 
    720 /** Open directory.
    721  *
    722  * @param dirname Directory pathname
    723  *
    724  * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
    725  */
    726 DIR *opendir(const char *dirname)
    727 {
    728         DIR *dirp = malloc(sizeof(DIR));
    729         int fd = -1;
    730        
    731         if (dirp == NULL) {
    732                 errno = ENOMEM;
    733                 return NULL;
    734         }
    735        
    736         size_t abs_size;
    737         char *abs = vfs_absolutize(dirname, &abs_size);
    738         if (abs == NULL) {
    739                 free(dirp);
    740                 errno = ENOMEM;
    741                 return NULL;
    742         }
    743        
    744         int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd);
    745         free(abs);
    746        
    747         if (rc != EOK) {
    748                 free(dirp);
    749                 errno = rc;
    750                 return NULL;
    751         }
    752        
    753         dirp->fd = fd;
    754         return dirp;
    755 }
    756 
    757 /** Read directory entry.
    758  *
    759  * @param dirp Open directory
    760  * @return Non-NULL pointer to directory entry on success. On error returns
    761  *         @c NULL and sets errno.
    762  */
    763 struct dirent *readdir(DIR *dirp)
    764 {
    765         int rc;
    766         ssize_t len;
    767        
    768         rc = _read_short(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1, &len);
    769         if (rc != EOK) {
    770                 errno = rc;
    771                 return NULL;
    772         }
    773        
    774         (void) len;
    775         return &dirp->res;
    776 }
    777 
    778 /** Rewind directory position to the beginning.
    779  *
    780  * @param dirp Open directory
    781  */
    782 void rewinddir(DIR *dirp)
    783 {
    784         (void) lseek(dirp->fd, 0, SEEK_SET);
    785 }
    786 
    787 /** Close directory.
    788  *
    789  * @param dirp Open directory
    790  * @return 0 on success. On error returns -1 and sets errno.
    791  */
    792 int closedir(DIR *dirp)
    793 {
    794         int rc;
    795        
    796         rc = close(dirp->fd);
    797         free(dirp);
    798 
    799         /* On error errno was set by close() */
    800         return rc;
    801 }
    802 
    803 /** Create directory.
    804  *
    805  * @param path Path
    806  * @param mode File mode
    807  * @return 0 on success. On error returns -1 and sets errno.
    808  */
    809 int mkdir(const char *path, mode_t mode)
     943
     944        async_exch_t *exch = vfs_exchange_begin();
     945
     946        req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
     947        rc = async_data_read_start(exch, (void *) st, sizeof(*st));
     948
     949        vfs_exchange_end(exch);
     950        async_wait_for(req, &ret);
     951
     952        rc = (ret != EOK ? ret : rc);
     953
     954        return rc;
     955}
     956
     957/** Get filesystem statistics
     958 *
     959 * @param file          Path pointing to the queried file system
     960 * @param[out] st       Buffer for storing information
     961 *
     962 * @return              EOK on success or a negative error code
     963 */
     964int vfs_statfs_path(const char *path, struct statfs *st)
     965{
     966        int file = vfs_lookup(path, 0);
     967        if (file < 0)
     968                return file;
     969       
     970        int rc = vfs_statfs(file, st);
     971
     972        vfs_put(file);
     973
     974        return rc;
     975}
     976
     977/** Synchronize file
     978 *
     979 * @param file  File handle to synchronize
     980 *
     981 * @return      EOK on success or a negative error code
     982 */
     983int vfs_sync(int file)
     984{
     985        async_exch_t *exch = vfs_exchange_begin();
     986        int rc = async_req_1_0(exch, VFS_IN_SYNC, file);
     987        vfs_exchange_end(exch);
     988       
     989        return rc;
     990}
     991
     992/** Unlink a file or directory
     993 *
     994 * Unlink a name from a parent directory. The caller can supply the file handle
     995 * of the unlinked child in order to detect a possible race with vfs_link() and
     996 * avoid unlinking a wrong file. If the last link for a file or directory is
     997 * removed, the FS implementation will deallocate its resources.
     998 *
     999 * @param parent        File handle of the parent directory node
     1000 * @param child         Old name to be unlinked
     1001 * @param expect        File handle of the unlinked child
     1002 *
     1003 * @return              EOK on success or a negative error code
     1004 */
     1005int vfs_unlink(int parent, const char *child, int expect)
    8101006{
    8111007        sysarg_t rc;
    8121008        aid_t req;
    8131009       
    814         size_t pa_size;
    815         char *pa = vfs_absolutize(path, &pa_size);
    816         if (pa == NULL) {
    817                 errno = ENOMEM;
    818                 return -1;
    819         }
    820        
    821         async_exch_t *exch = vfs_exchange_begin();
    822        
    823         req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
    824         rc = async_data_write_start(exch, pa, pa_size);
    825         if (rc != EOK) {
    826                 vfs_exchange_end(exch);
    827                 free(pa);
     1010        async_exch_t *exch = vfs_exchange_begin();
     1011       
     1012        req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
     1013        rc = async_data_write_start(exch, child, str_size(child));
     1014       
     1015        vfs_exchange_end(exch);
     1016       
     1017        sysarg_t rc_orig;
     1018        async_wait_for(req, &rc_orig);
     1019       
     1020        if (rc_orig != EOK)
     1021                return (int) rc_orig;
     1022        return rc;
     1023}
     1024
     1025/** Unlink a file or directory
     1026 *
     1027 * Unlink a path. If the last link for a file or directory is removed, the FS
     1028 * implementation will deallocate its resources.
     1029 *
     1030 * @param path          Old path to be unlinked
     1031 *
     1032 * @return              EOK on success or a negative error code
     1033 */
     1034int vfs_unlink_path(const char *path)
     1035{
     1036        int expect = vfs_lookup(path, 0);
     1037        if (expect < 0)
     1038                return expect;
     1039
     1040        char *child;
     1041        int parent = get_parent_and_child(path, &child);
     1042        if (parent < 0) {
     1043                vfs_put(expect);
     1044                return parent;
     1045        }
     1046
     1047        int rc = vfs_unlink(parent, child, expect);
     1048       
     1049        free(child);
     1050        vfs_put(parent);
     1051        vfs_put(expect);
     1052        return rc;
     1053}
     1054
     1055/** Unmount a file system
     1056 *
     1057 * @param mp    File handle representing the mount-point
     1058 *
     1059 * @return      EOK on success or a negative error code
     1060 */
     1061int vfs_unmount(int mp)
     1062{
     1063        async_exch_t *exch = vfs_exchange_begin();
     1064        int rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp);
     1065        vfs_exchange_end(exch);
     1066        return rc;
     1067}
     1068
     1069/** Unmount a file system
     1070 *
     1071 * @param mpp   Mount-point path
     1072 *
     1073 * @return      EOK on success or a negative error code
     1074 */
     1075int vfs_unmount_path(const char *mpp)
     1076{
     1077        int mp = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY);
     1078        if (mp < 0)
     1079                return mp;
     1080       
     1081        int rc = vfs_unmount(mp);
     1082        vfs_put(mp);
     1083        return rc;
     1084}
     1085
     1086/** Walk a path starting in a parent node
     1087 *
     1088 * @param parent        File handle of the parent node where the walk starts
     1089 * @param path          Parent-relative path to be walked
     1090 * @param flags         Flags influencing the walk
     1091 *
     1092 * @retrun              File handle representing the result on success or
     1093 *                      a negative error code on error
     1094 */
     1095int vfs_walk(int parent, const char *path, int flags)
     1096{
     1097        async_exch_t *exch = vfs_exchange_begin();
     1098       
     1099        ipc_call_t answer;
     1100        aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
     1101        sysarg_t rc = async_data_write_start(exch, path, str_size(path));
     1102        vfs_exchange_end(exch);
    8281103               
    829                 sysarg_t rc_orig;
    830                 async_wait_for(req, &rc_orig);
     1104        sysarg_t rc_orig;
     1105        async_wait_for(req, &rc_orig);
     1106
     1107        if (rc_orig != EOK)
     1108                return (int) rc_orig;
    8311109               
    832                 if (rc_orig != EOK)
    833                         rc = rc_orig;
    834                
    835                 if (rc != EOK) {
    836                         errno = rc;
    837                         return -1;
    838                 }
    839                
    840                 return 0;
    841         }
    842        
    843         vfs_exchange_end(exch);
    844         free(pa);
    845         async_wait_for(req, &rc);
    846        
    847         if (rc != EOK) {
    848                 errno = rc;
    849                 return -1;
    850         }
    851        
    852         return 0;
    853 }
    854 
    855 /** Unlink a file or directory.
    856  *
    857  * @param path Path to file or empty directory
    858  * @param lflag L_xxx flag (L_NONE, L_FILE or L_DIRECTORY)
    859  * @return EOK on success, non-zero error code on error
    860  */
    861 static int _unlink(const char *path, int lflag)
     1110        if (rc != EOK)
     1111                return (int) rc;
     1112       
     1113        return (int) IPC_GET_ARG1(answer);
     1114}
     1115
     1116/** Write data
     1117 *
     1118 * This function fails if it cannot write exactly @a len bytes to the file.
     1119 *
     1120 * @param file          File handle to write to
     1121 * @param[inout] pos    Position to write to, updated by the actual bytes
     1122 *                      written
     1123 * @param buf           Data, @a nbytes bytes long
     1124 * @param nbytes        Number of bytes to write
     1125 *
     1126 * @return              On success, non-negative number of bytes written
     1127 * @return              On failure, a negative error code
     1128 */
     1129ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte)
     1130{
     1131        ssize_t cnt = 0;
     1132        ssize_t nwritten = 0;
     1133        const uint8_t *bp = (uint8_t *) buf;
     1134        int rc;
     1135
     1136        do {
     1137                bp += cnt;
     1138                nwritten += cnt;
     1139                *pos += cnt;
     1140                rc = vfs_write_short(file, *pos, bp, nbyte - nwritten, &cnt);
     1141        } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
     1142
     1143        if (rc != EOK)
     1144                return rc;
     1145
     1146        *pos += cnt;
     1147        return nbyte;
     1148}
     1149
     1150/** Write bytes to a file
     1151 *
     1152 * Write up to @a nbyte bytes from file. The actual number of bytes written
     1153 * may be lower, but greater than zero.
     1154 *
     1155 * @param file          File handle to write to
     1156 * @param[in] pos       Position to write to
     1157 * @param buf           Buffer to write to
     1158 * @param nbyte         Maximum number of bytes to write
     1159 * @param[out] nread    Actual number of bytes written (0 or more)
     1160 *
     1161 * @return              EOK on success or a negative error code
     1162 */
     1163int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte,
     1164    ssize_t *nwritten)
    8621165{
    8631166        sysarg_t rc;
     1167        ipc_call_t answer;
    8641168        aid_t req;
    8651169       
    866         size_t pa_size;
    867         char *pa = vfs_absolutize(path, &pa_size);
    868         if (pa == NULL)
    869                 return ENOMEM;
    870        
    871         async_exch_t *exch = vfs_exchange_begin();
    872        
    873         req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL);
    874         rc = async_data_write_start(exch, pa, pa_size);
    875         if (rc != EOK) {
    876                 vfs_exchange_end(exch);
    877                 free(pa);
    878 
    879                 sysarg_t rc_orig;
    880                 async_wait_for(req, &rc_orig);
    881 
    882                 if (rc_orig == EOK)
    883                         return (int) rc;
    884                 else
    885                         return (int) rc_orig;
    886         }
    887         vfs_exchange_end(exch);
    888         free(pa);
    889         async_wait_for(req, &rc);
    890         return rc;
    891 }
    892 
    893 /** Unlink file or directory.
    894  *
    895  * @param path Path
    896  * @return EOk on success, error code on error
    897  */
    898 int unlink(const char *path)
    899 {
    900         int rc;
    901 
    902         rc = _unlink(path, L_NONE);
    903         if (rc != EOK) {
    904                 errno = rc;
    905                 return -1;
    906         }
    907 
    908         return 0;
    909 }
    910 
    911 /** Remove empty directory.
    912  *
    913  * @param path Path
    914  * @return 0 on success. On error returns -1 and sets errno.
    915  */
    916 int rmdir(const char *path)
    917 {
    918         int rc;
    919 
    920         rc = _unlink(path, L_DIRECTORY);
    921         if (rc != EOK) {
    922                 errno = rc;
    923                 return -1;
    924         }
    925 
    926         return 0;
    927 }
    928 
    929 /** Rename directory entry.
    930  *
    931  * @param old Old name
    932  * @param new New name
    933  *
    934  * @return 0 on success. On error returns -1 and sets errno.
    935  */
    936 int rename(const char *old, const char *new)
    937 {
    938         sysarg_t rc;
    939         sysarg_t rc_orig;
    940         aid_t req;
    941        
    942         size_t olda_size;
    943         char *olda = vfs_absolutize(old, &olda_size);
    944         if (olda == NULL) {
    945                 errno = ENOMEM;
    946                 return -1;
    947         }
    948 
    949         size_t newa_size;
    950         char *newa = vfs_absolutize(new, &newa_size);
    951         if (newa == NULL) {
    952                 free(olda);
    953                 errno = ENOMEM;
    954                 return -1;
    955         }
    956        
    957         async_exch_t *exch = vfs_exchange_begin();
    958        
    959         req = async_send_0(exch, VFS_IN_RENAME, NULL);
    960         rc = async_data_write_start(exch, olda, olda_size);
    961         if (rc != EOK) {
    962                 vfs_exchange_end(exch);
    963                 free(olda);
    964                 free(newa);
    965                 async_wait_for(req, &rc_orig);
    966                 if (rc_orig != EOK)
    967                         rc = rc_orig;
    968                 if (rc != EOK) {
    969                         errno = rc;
    970                         return -1;
    971                 }
    972                 return 0;
    973         }
    974         rc = async_data_write_start(exch, newa, newa_size);
    975         if (rc != EOK) {
    976                 vfs_exchange_end(exch);
    977                 free(olda);
    978                 free(newa);
    979                 async_wait_for(req, &rc_orig);
    980                 if (rc_orig != EOK)
    981                         rc = rc_orig;
    982                 if (rc != EOK) {
    983                         errno = rc;
    984                         return -1;
    985                 }
    986                 return 0;
    987         }
    988         vfs_exchange_end(exch);
    989         free(olda);
    990         free(newa);
    991         async_wait_for(req, &rc);
    992 
    993         if (rc != EOK) {
    994                 errno = rc;
    995                 return -1;
    996         }
    997 
    998         return 0;
    999 }
    1000 
    1001 /** Remove directory entry.
    1002  *
    1003  * @param path Path
    1004  * @return 0 on success. On error returns -1 and sets errno.
    1005  */
    1006 int remove(const char *path)
    1007 {
    1008         return unlink(path);
    1009 }
    1010 
    1011 /** Change working directory.
    1012  *
    1013  * @param path Path
    1014  * @return 0 on success. On error returns -1 and sets errno.
    1015  */
    1016 int chdir(const char *path)
    1017 {
    1018         size_t abs_size;
    1019         char *abs = vfs_absolutize(path, &abs_size);
    1020         int fd = -1;
    1021        
    1022         if (abs == NULL) {
    1023                 errno = ENOMEM;
    1024                 return -1;
    1025         }
    1026        
    1027         int rc = open_internal(abs, abs_size, L_DIRECTORY, O_DESC, &fd);
    1028        
    1029         if (rc != EOK) {
    1030                 free(abs);
    1031                 errno = rc;
    1032                 return -1;
    1033         }
    1034        
    1035         fibril_mutex_lock(&cwd_mutex);
    1036        
    1037         if (cwd_fd >= 0)
    1038                 close(cwd_fd);
    1039        
    1040         if (cwd_path)
    1041                 free(cwd_path);
    1042        
    1043         cwd_fd = fd;
    1044         cwd_path = abs;
    1045         cwd_size = abs_size;
    1046        
    1047         fibril_mutex_unlock(&cwd_mutex);
    1048         return 0;
    1049 }
    1050 
    1051 /** Get current working directory path.
    1052  *
    1053  * @param buf Buffer
    1054  * @param size Size of @a buf
    1055  * @return On success returns @a buf. On failure returns @c NULL and sets errno.
    1056  */
    1057 char *getcwd(char *buf, size_t size)
    1058 {
    1059         if (size == 0) {
    1060                 errno = EINVAL;
    1061                 return NULL;
    1062         }
    1063        
    1064         fibril_mutex_lock(&cwd_mutex);
    1065        
    1066         if ((cwd_size == 0) || (size < cwd_size + 1)) {
    1067                 fibril_mutex_unlock(&cwd_mutex);
    1068                 errno = ERANGE;
    1069                 return NULL;
    1070         }
    1071        
    1072         str_cpy(buf, size, cwd_path);
    1073         fibril_mutex_unlock(&cwd_mutex);
    1074        
    1075         return buf;
    1076 }
    1077 
    1078 /** Open session to service represented by a special file.
    1079  *
    1080  * Given that the file referred to by @a fildes represents a service,
    1081  * open a session to that service.
    1082  *
    1083  * @param fildes File descriptor
    1084  * @param iface Interface to connect to (XXX Should be automatic)
    1085  * @return On success returns session pointer. On error returns @c NULL.
    1086  */
    1087 async_sess_t *vfs_fd_session(int fildes, iface_t iface)
    1088 {
    1089         struct stat stat;
    1090         int rc = fstat(fildes, &stat);
    1091         if (rc != 0)
    1092                 return NULL;
    1093        
    1094         if (stat.service == 0)
    1095                 return NULL;
    1096        
    1097         return loc_service_connect(stat.service, iface, 0);
    1098 }
    1099 
    1100 /** Duplicate open file.
    1101  *
    1102  * Duplicate open file under a new file descriptor.
    1103  *
    1104  * @param oldfd Old file descriptor
    1105  * @param newfd New file descriptor
    1106  * @return 0 on success. On error -1 is returned and errno is set
    1107  */
    1108 int dup2(int oldfd, int newfd)
    1109 {
    1110         async_exch_t *exch = vfs_exchange_begin();
    1111        
    1112         sysarg_t ret;
    1113         sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret);
     1170        if (nbyte > DATA_XFER_LIMIT)
     1171                nbyte = DATA_XFER_LIMIT;
     1172       
     1173        async_exch_t *exch = vfs_exchange_begin();
     1174       
     1175        req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos),
     1176            UPPER32(pos), &answer);
     1177        rc = async_data_write_start(exch, (void *) buf, nbyte);
    11141178       
    11151179        vfs_exchange_end(exch);
    11161180       
    11171181        if (rc == EOK)
    1118                 rc = ret;
    1119        
    1120         if (rc != EOK) {
    1121                 errno = rc;
    1122                 return -1;
    1123         }
    1124        
    1125         return 0;
    1126 }
    1127 
    1128 int vfs_fd_wait(void)
    1129 {
    1130         async_exch_t *exch = vfs_exchange_begin();
    1131        
    1132         sysarg_t ret;
    1133         sysarg_t rc = async_req_0_1(exch, VFS_IN_WAIT_HANDLE, &ret);
    1134        
    1135         vfs_exchange_end(exch);
    1136        
    1137         if (rc == EOK)
    1138                 return (int) ret;
    1139        
    1140         return (int) rc;
    1141 }
    1142 
    1143 int vfs_get_mtab_list(list_t *mtab_list)
    1144 {
    1145         sysarg_t rc;
    1146         aid_t req;
    1147         size_t i;
    1148         sysarg_t num_mounted_fs;
    1149        
    1150         async_exch_t *exch = vfs_exchange_begin();
    1151 
    1152         req = async_send_0(exch, VFS_IN_MTAB_GET, NULL);
    1153 
    1154         /* Ask VFS how many filesystems are mounted */
    1155         rc = async_req_0_1(exch, VFS_IN_PING, &num_mounted_fs);
     1182                async_wait_for(req, &rc);
     1183        else
     1184                async_forget(req);
     1185
    11561186        if (rc != EOK)
    1157                 goto exit;
    1158 
    1159         for (i = 0; i < num_mounted_fs; ++i) {
    1160                 mtab_ent_t *mtab_ent;
    1161 
    1162                 mtab_ent = malloc(sizeof(mtab_ent_t));
    1163                 if (mtab_ent == NULL) {
    1164                         rc = ENOMEM;
    1165                         goto exit;
    1166                 }
    1167 
    1168                 memset(mtab_ent, 0, sizeof(mtab_ent_t));
    1169 
    1170                 rc = async_data_read_start(exch, (void *) mtab_ent->mp,
    1171                     MAX_PATH_LEN);
    1172                 if (rc != EOK)
    1173                         goto exit;
    1174 
    1175                 rc = async_data_read_start(exch, (void *) mtab_ent->opts,
    1176                         MAX_MNTOPTS_LEN);
    1177                 if (rc != EOK)
    1178                         goto exit;
    1179 
    1180                 rc = async_data_read_start(exch, (void *) mtab_ent->fs_name,
    1181                         FS_NAME_MAXLEN);
    1182                 if (rc != EOK)
    1183                         goto exit;
    1184 
    1185                 sysarg_t p[2];
    1186 
    1187                 rc = async_req_0_2(exch, VFS_IN_PING, &p[0], &p[1]);
    1188                 if (rc != EOK)
    1189                         goto exit;
    1190 
    1191                 mtab_ent->instance = p[0];
    1192                 mtab_ent->service_id = p[1];
    1193 
    1194                 link_initialize(&mtab_ent->link);
    1195                 list_append(&mtab_ent->link, mtab_list);
    1196         }
    1197 
    1198 exit:
    1199         async_wait_for(req, &rc);
    1200         vfs_exchange_end(exch);
    1201         return rc;
    1202 }
    1203 
    1204 /** Get filesystem statistics.
    1205  *
    1206  * @param path Mount point path
    1207  * @param st Buffer for storing information
    1208  * @return 0 on success. On error -1 is returned and errno is set.
    1209  */
    1210 int statfs(const char *path, struct statfs *st)
    1211 {
    1212         sysarg_t rc, rc_orig;
    1213         aid_t req;
    1214         size_t pa_size;
    1215 
    1216         char *pa = vfs_absolutize(path, &pa_size);
    1217         if (pa == NULL) {
    1218                 errno = ENOMEM;
    1219                 return -1;
    1220         }
    1221 
    1222         async_exch_t *exch = vfs_exchange_begin();
    1223 
    1224         req = async_send_0(exch, VFS_IN_STATFS, NULL);
    1225         rc = async_data_write_start(exch, pa, pa_size);
    1226         if (rc != EOK)
    1227                 goto exit;
    1228 
    1229         rc = async_data_read_start(exch, (void *) st, sizeof(*st));
    1230 
    1231 exit:
    1232         vfs_exchange_end(exch);
    1233         free(pa);
    1234         async_wait_for(req, &rc_orig);
    1235         rc = (rc_orig != EOK ? rc_orig : rc);
    1236 
    1237         if (rc != EOK) {
    1238                 errno = rc;
    1239                 return -1;
    1240         }
    1241 
    1242         return 0;
     1187                return rc;
     1188       
     1189        *nwritten = (ssize_t) IPC_GET_ARG1(answer);
     1190        return EOK;
    12431191}
    12441192
Note: See TracChangeset for help on using the changeset viewer.