Ignore:
File:
1 edited

Legend:

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

    ra6fc88a r6afc9d7  
    3333 */
    3434
     35#include <vfs/canonify.h>
    3536#include <vfs/vfs.h>
    36 #include <vfs/canonify.h>
    37 #include <vfs/vfs_mtab.h>
    3837#include <vfs/vfs_sess.h>
    3938#include <macros.h>
    4039#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>
    4146#include <sys/types.h>
    4247#include <ipc/services.h>
     
    5156#include <ipc/loc.h>
    5257
    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 
    11658static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
    11759static async_sess_t *vfs_sess = NULL;
     
    12365static size_t cwd_size = 0;
    12466
    125 static FIBRIL_MUTEX_INITIALIZE(root_mutex);
    126 static int root_fd = -1;
    127 
    128 static 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  */
     67/** Start an async exchange on the VFS session.
     68 *
     69 * @return New exchange.
     70 *
     71 */
     72async_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 */
     90void vfs_exchange_end(async_exch_t *exch)
     91{
     92        async_exchange_end(exch);
     93}
     94
    17095char *vfs_absolutize(const char *path, size_t *retlen)
    17196{
     
    218143}
    219144
    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  */
    233 int 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  */
    249 int 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  */
    270 int 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  */
    303 async_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  */
    321 void 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  */
    337 async_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  */
    365 int 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  */
    395 int 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  */
    417 int 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  */
    444 int 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  */
    471 int 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  */
    515 int vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
     145int vfs_mount(const char *fs_name, const char *mp, const char *fqsn,
    516146    const char *opts, unsigned int flags, unsigned int instance)
    517147{
     
    520150       
    521151        if (str_cmp(fqsn, "") == 0) {
    522                 /*
    523                  * No device specified, create a fresh null/%d device instead.
    524                 */
     152                /* No device specified, create a fresh
     153                   null/%d device instead */
    525154                null_id = loc_null_create();
    526155               
     
    531160                fqsn = null;
    532161        }
    533        
    534         if (flags & IPC_FLAG_BLOCKING)
    535                 flags = VFS_MOUNT_BLOCKING;
    536         else
    537                 flags = 0;
    538162       
    539163        service_id_t service_id;
     
    555179        }
    556180       
    557         fibril_mutex_lock(&root_mutex);
    558        
    559         int rc;
    560        
    561         if (str_cmp(mpa, "/") == 0) {
    562                 /* Mounting root. */
    563                
    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                 }
    570                
    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                 }
    583                
    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);
     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);
     191               
     192                if (null_id != -1)
     193                        loc_null_destroy(null_id);
     194               
     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);
     206               
     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);
    595250       
    596251        if ((rc != EOK) && (null_id != -1))
     
    600255}
    601256
    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  */
    610 int 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  */
    627 int 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  */
    639 int 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  */
    655 int 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 
     257int 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 */
     301static 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       
     325        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 */
     341int 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 */
     368int 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.
     385 *
     386 * Read up to @a nbyte bytes from file. The actual number of bytes read
     387 * may be lower, but greater than zero if there are any bytes available.
     388 * If there are no bytes available for reading, then the function will
     389 * return success with zero bytes read.
     390 *
     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 */
     398static int _read_short(int fildes, void *buf, size_t nbyte, ssize_t *nread)
     399{
     400        sysarg_t rc;
     401        ipc_call_t answer;
     402        aid_t req;
     403       
     404        if (nbyte > DATA_XFER_LIMIT)
     405                nbyte = DATA_XFER_LIMIT;
     406       
     407        async_exch_t *exch = vfs_exchange_begin();
     408       
     409        req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
     410        rc = async_data_read_start(exch, (void *) buf, nbyte);
     411        if (rc != EOK) {
     412                vfs_exchange_end(exch);
     413               
     414                sysarg_t rc_orig;
     415                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       
    672426        if (rc != EOK)
    673427                return rc;
    674         return ret;
    675 }
    676 
    677 /** Read data
     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 */
     445static 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);
     459        if (rc != EOK) {
     460                vfs_exchange_end(exch);
     461               
     462                sysarg_t rc_orig;
     463                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);
     472        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.
    678482 *
    679483 * Read up to @a nbytes bytes from file if available. This function always reads
    680484 * all the available bytes up to @a nbytes.
    681485 *
    682  * @param file          File handle to read from
    683  * @param[inout] pos    Position to read from, updated by the actual bytes read
     486 * @param fildes        File descriptor
    684487 * @param buf           Buffer, @a nbytes bytes long
    685488 * @param nbytes        Number of bytes to read
    686489 *
    687  * @return              On success, non-negative number of bytes read
    688  * @return              On failure, a negative error code
    689  */
    690 ssize_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte)
     490 * @return              On success, nonnegative number of bytes read.
     491 *                      On failure, -1 and sets errno.
     492 */
     493ssize_t read(int fildes, void *buf, size_t nbyte)
    691494{
    692495        ssize_t cnt = 0;
     
    698501                bp += cnt;
    699502                nread += cnt;
    700                 *pos += cnt;
    701                 rc = vfs_read_short(file, *pos, bp, nbyte - nread, &cnt);
     503                rc = _read_short(fildes, bp, nbyte - nread, &cnt);
    702504        } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
    703505       
    704         if (rc != EOK)
    705                 return rc;
    706        
    707         *pos += cnt;
     506        if (rc != EOK) {
     507                errno = rc;
     508                return -1;
     509        }
     510       
    708511        return nread + cnt;
    709512}
    710513
    711 /** Read bytes from a file
    712  *
    713  * Read up to @a nbyte bytes from file. The actual number of bytes read
    714  * may be lower, but greater than zero if there are any bytes available.
    715  * If there are no bytes available for reading, then the function will
    716  * return success with zero bytes read.
    717  *
    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  */
    726 int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
    727     ssize_t *nread)
     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 */
     525ssize_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 */
     551int 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 */
     574off64_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 */
     603int ftruncate(int fildes, aoff64_t length)
    728604{
    729605        sysarg_t rc;
    730         ipc_call_t answer;
     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 */
     627int fstat(int fildes, struct stat *stat)
     628{
     629        sysarg_t rc;
    731630        aid_t req;
    732631       
    733         if (nbyte > DATA_XFER_LIMIT)
    734                 nbyte = DATA_XFER_LIMIT;
    735        
    736         async_exch_t *exch = vfs_exchange_begin();
    737        
    738         req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos),
    739             UPPER32(pos), &answer);
    740         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  */
    768 int vfs_rename_path(const char *old, const char *new)
     632        async_exch_t *exch = vfs_exchange_begin();
     633       
     634        req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
     635        rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
     636        if (rc != EOK) {
     637                vfs_exchange_end(exch);
     638               
     639                sysarg_t rc_orig;
     640                async_wait_for(req, &rc_orig);
     641               
     642                if (rc_orig != EOK)
     643                        rc = rc_orig;
     644                if (rc != EOK) {
     645                        errno = rc;
     646                        return -1;
     647                }
     648               
     649                return 0;
     650        }
     651       
     652        vfs_exchange_end(exch);
     653        async_wait_for(req, &rc);
     654       
     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 */
     670int stat(const char *path, struct stat *stat)
    769671{
    770672        sysarg_t rc;
     
    772674        aid_t req;
    773675       
     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 */
     726DIR *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 */
     763struct 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 */
     782void 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 */
     792int 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 */
     809int mkdir(const char *path, mode_t mode)
     810{
     811        sysarg_t rc;
     812        aid_t req;
     813       
     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);
     828               
     829                sysarg_t rc_orig;
     830                async_wait_for(req, &rc_orig);
     831               
     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 */
     861static int _unlink(const char *path, int lflag)
     862{
     863        sysarg_t rc;
     864        aid_t req;
     865       
     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 */
     898int 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 */
     916int 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 */
     936int rename(const char *old, const char *new)
     937{
     938        sysarg_t rc;
     939        sysarg_t rc_orig;
     940        aid_t req;
     941       
    774942        size_t olda_size;
    775943        char *olda = vfs_absolutize(old, &olda_size);
    776         if (olda == NULL)
    777                 return ENOMEM;
     944        if (olda == NULL) {
     945                errno = ENOMEM;
     946                return -1;
     947        }
    778948
    779949        size_t newa_size;
     
    781951        if (newa == NULL) {
    782952                free(olda);
    783                 return ENOMEM;
    784         }
    785        
    786         async_exch_t *exch = vfs_exchange_begin();
    787         int root = vfs_root();
    788         if (root < 0) {
     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);
    789963                free(olda);
    790964                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);
     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);
    796975        if (rc != EOK) {
    797976                vfs_exchange_end(exch);
    798977                free(olda);
    799978                free(newa);
    800                 vfs_put(root);
    801979                async_wait_for(req, &rc_orig);
    802980                if (rc_orig != EOK)
    803981                        rc = rc_orig;
    804                 return rc;
    805         }
    806         rc = async_data_write_start(exch, newa, newa_size);
    807         if (rc != EOK) {
    808                 vfs_exchange_end(exch);
    809                 free(olda);
    810                 free(newa);
    811                 vfs_put(root);
    812                 async_wait_for(req, &rc_orig);
    813                 if (rc_orig != EOK)
    814                         rc = rc_orig;
    815                 return rc;
     982                if (rc != EOK) {
     983                        errno = rc;
     984                        return -1;
     985                }
     986                return 0;
    816987        }
    817988        vfs_exchange_end(exch);
    818989        free(olda);
    819990        free(newa);
    820         vfs_put(root);
    821991        async_wait_for(req, &rc);
    822992
    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  */
    835 int 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  */
    849 int 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  */
    869 void 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  */
    885 int vfs_stat(int file, struct stat *stat)
     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 */
     1006int 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 */
     1016int 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 */
     1057char *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 */
     1087async_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 */
     1108int 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);
     1114       
     1115        vfs_exchange_end(exch);
     1116       
     1117        if (rc == EOK)
     1118                rc = ret;
     1119       
     1120        if (rc != EOK) {
     1121                errno = rc;
     1122                return -1;
     1123        }
     1124       
     1125        return 0;
     1126}
     1127
     1128int 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
     1143int vfs_get_mtab_list(list_t *mtab_list)
    8861144{
    8871145        sysarg_t rc;
    8881146        aid_t req;
    889        
    890         async_exch_t *exch = vfs_exchange_begin();
    891        
    892         req = async_send_1(exch, VFS_IN_STAT, file, NULL);
    893         rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
    894         if (rc != EOK) {
    895                 vfs_exchange_end(exch);
    896                
    897                 sysarg_t rc_orig;
    898                 async_wait_for(req, &rc_orig);
    899                
    900                 if (rc_orig != EOK)
    901                         rc = rc_orig;
    902                
    903                 return rc;
    904         }
    905        
    906         vfs_exchange_end(exch);
     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);
     1156        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
     1198exit:
    9071199        async_wait_for(req, &rc);
    908        
     1200        vfs_exchange_end(exch);
    9091201        return rc;
    9101202}
    9111203
    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  */
    919 int 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  */
    939 int vfs_statfs(int file, struct statfs *st)
    940 {
    941         sysarg_t rc, ret;
     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 */
     1210int statfs(const char *path, struct statfs *st)
     1211{
     1212        sysarg_t rc, rc_orig;
    9421213        aid_t req;
    943 
    944         async_exch_t *exch = vfs_exchange_begin();
    945 
    946         req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
     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
    9471229        rc = async_data_read_start(exch, (void *) st, sizeof(*st));
    9481230
    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  */
    964 int 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  */
    983 int 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  */
    1005 int vfs_unlink(int parent, const char *child, int expect)
    1006 {
    1007         sysarg_t rc;
    1008         aid_t req;
    1009        
    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;
     1231exit:
     1232        vfs_exchange_end(exch);
     1233        free(pa);
    10181234        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  */
    1034 int 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  */
    1061 int 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  */
    1075 int 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  */
    1095 int 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);
    1103                
    1104         sysarg_t rc_orig;
    1105         async_wait_for(req, &rc_orig);
    1106 
    1107         if (rc_orig != EOK)
    1108                 return (int) rc_orig;
    1109                
    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  */
    1129 ssize_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  */
    1163 int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte,
    1164     ssize_t *nwritten)
    1165 {
    1166         sysarg_t rc;
    1167         ipc_call_t answer;
    1168         aid_t req;
    1169        
    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);
    1178        
    1179         vfs_exchange_end(exch);
    1180        
    1181         if (rc == EOK)
    1182                 async_wait_for(req, &rc);
    1183         else
    1184                 async_forget(req);
    1185 
    1186         if (rc != EOK)
    1187                 return rc;
    1188        
    1189         *nwritten = (ssize_t) IPC_GET_ARG1(answer);
    1190         return EOK;
     1235        rc = (rc_orig != EOK ? rc_orig : rc);
     1236
     1237        if (rc != EOK) {
     1238                errno = rc;
     1239                return -1;
     1240        }
     1241
     1242        return 0;
    11911243}
    11921244
Note: See TracChangeset for help on using the changeset viewer.