Changeset 368ee04 in mainline for uspace/lib


Ignore:
Timestamp:
2017-04-05T18:10:39Z (9 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
93ad8166
Parents:
39f892a9 (diff), 2166728 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from lp:~jakub/helenos/vfs-2.5-cherrypick

This merge cherry-picks some of the changesets from Jiri Zarevucky's:

lp:~zarevucky-jiri/helenos/vfs-2.5

and then continues independently, yet sometime in a similar vein.

Roughly speaking, Jiri's branch is merged entirely up to its revision
1926 and then cherry-picked on and off until its revision 1965. Among
these changes are:

  • relativization of the API,
  • client-side roots,
  • server-side mounts,
  • inbox for passing arbitrary files from parent to child,
  • some streamlining and cleanup.

Additional changes include:

  • addressing issues introduced by the above changes,
  • client-side I/O cursors (file positions),
  • all HelenOS file system APIs begin with the vfs_ prefix and can be used after including vfs/vfs.h,
  • removal of some POSIX-ish headers and definitions,
  • additional cleanup.
Location:
uspace/lib
Files:
2 added
1 deleted
45 edited
2 moved

Legend:

Unmodified
Added
Removed
  • uspace/lib/bithenge/src/failure.c

    r39f892a9 r368ee04  
    4141#include <stdio.h>
    4242#include <stdlib.h>
    43 #include <sys/stat.h>
    4443#include <sys/types.h>
    4544#include <sys/wait.h>
     
    152151                if (null == -1)
    153152                        exit(127);
    154                 dup2(null, STDOUT_FILENO);
    155                 dup2(null, STDERR_FILENO);
    156                 close(null);
     153                vfs_clone(null, STDOUT_FILENO, false);
     154                vfs_clone(null, STDERR_FILENO, false);
     155                vfs_put(null);
    157156                return 1;
    158157        }
  • uspace/lib/bithenge/src/failure.h

    r39f892a9 r368ee04  
    4242#include <stdio.h>
    4343#include <stdlib.h>
    44 #include <sys/stat.h>
    4544#include <sys/types.h>
    4645#include <unistd.h>
  • uspace/lib/bithenge/src/file.c

    r39f892a9 r368ee04  
    3838#include <assert.h>
    3939#include <errno.h>
    40 #include <fcntl.h>
    4140#include <stdio.h>
    4241#include <stdlib.h>
    43 #include <sys/stat.h>
     42#include <vfs/vfs.h>
    4443#include <sys/types.h>
    4544#include <unistd.h>
     
    7877        if (offset > blob->size)
    7978                return ELIMIT;
    80         if (lseek(blob->fd, offset, SEEK_SET) < 0)
    81                 return errno == EINVAL ? EIO : errno;
    8279
    83         ssize_t amount_read;
    84         aoff64_t remaining_size = *size;
    85         *size = 0;
    86         do {
    87                 amount_read = read(blob->fd, buffer, remaining_size);
    88                 if (amount_read < 0)
    89                         return errno;
    90                 buffer += amount_read;
    91                 *size += amount_read;
    92                 remaining_size -= amount_read;
    93         } while (remaining_size && amount_read);
     80        ssize_t amount_read = vfs_read(blob->fd, &offset, buffer, *size);
     81        if (amount_read < 0)
     82                return errno;
     83        *size += amount_read;
    9484        return EOK;
    9585}
     
    9888{
    9989        file_blob_t *blob = blob_as_file(base);
    100         close(blob->fd);
     90        vfs_put(blob->fd);
    10191        free(blob);
    10292}
     
    113103
    114104        struct stat stat;
    115         int rc = fstat(fd, &stat);
    116         if (rc != 0) {
     105        int rc = vfs_stat(fd, &stat);
     106        if (rc != EOK) {
    117107                if (needs_close)
    118                         close(fd);
     108                        vfs_put(fd);
    119109                return rc;
    120110        }
     
    124114        if (!blob) {
    125115                if (needs_close)
    126                         close(fd);
     116                        vfs_put(fd);
    127117                return ENOMEM;
    128118        }
     
    131121                free(blob);
    132122                if (needs_close)
    133                         close(fd);
     123                        vfs_put(fd);
    134124                return rc;
    135125        }
     
    155145        assert(filename);
    156146
    157         int fd = open(filename, O_RDONLY);
     147        int fd = vfs_lookup_open(filename, WALK_REGULAR, MODE_READ);
    158148        if (fd < 0)
    159149                return errno;
  • uspace/lib/c/Makefile

    r39f892a9 r368ee04  
    7373        generic/device/clock_dev.c \
    7474        generic/device/led_dev.c \
     75        generic/dirent.c \
    7576        generic/dhcp.c \
    7677        generic/dnsr.c \
     
    147148        generic/stdlib.c \
    148149        generic/udebug.c \
     150        generic/vfs/canonify.c \
     151        generic/vfs/inbox.c \
     152        generic/vfs/mtab.c \
    149153        generic/vfs/vfs.c \
    150         generic/vfs/canonify.c \
    151154        generic/rcu.c \
    152155        generic/setjmp.c \
  • uspace/lib/c/generic/dirent.c

    r39f892a9 r368ee04  
    3333 */
    3434
    35 #ifndef LIBC_SYS_STAT_H_
    36 #define LIBC_SYS_STAT_H_
     35#include <vfs/vfs.h>
     36#include <stdlib.h>
     37#include <dirent.h>
     38#include <sys/types.h>
     39#include <errno.h>
     40#include <assert.h>
    3741
    38 #include <sys/types.h>
    39 #include <stdbool.h>
    40 #include <ipc/vfs.h>
    41 #include <ipc/loc.h>
     42/** Open directory.
     43 *
     44 * @param dirname Directory pathname
     45 *
     46 * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
     47 */
     48DIR *opendir(const char *dirname)
     49{
     50        DIR *dirp = malloc(sizeof(DIR));
     51        if (!dirp) {
     52                errno = ENOMEM;
     53                return NULL;
     54        }
     55       
     56        int fd = vfs_lookup(dirname, WALK_DIRECTORY);
     57        if (fd < 0) {
     58                free(dirp);
     59                errno = fd;
     60                return NULL;
     61        }
     62       
     63        int rc = vfs_open(fd, MODE_READ);
     64        if (rc < 0) {
     65                free(dirp);
     66                vfs_put(fd);
     67                errno = rc;
     68                return NULL;
     69        }
     70       
     71        dirp->fd = fd;
     72        dirp->pos = 0;
     73        return dirp;
     74}
    4275
    43 struct stat {
    44         fs_handle_t fs_handle;
    45         service_id_t service_id;
    46         fs_index_t index;
    47         unsigned int lnkcnt;
    48         bool is_file;
    49         bool is_directory;
    50         aoff64_t size;
    51         service_id_t service;
    52 };
     76/** Read directory entry.
     77 *
     78 * @param dirp Open directory
     79 * @return Non-NULL pointer to directory entry on success. On error returns
     80 *         @c NULL and sets errno.
     81 */
     82struct dirent *readdir(DIR *dirp)
     83{
     84        int rc;
     85        ssize_t len = 0;
     86       
     87        rc = vfs_read_short(dirp->fd, dirp->pos, &dirp->res.d_name[0],
     88            NAME_MAX + 1, &len);
     89        if (rc != EOK) {
     90                errno = rc;
     91                return NULL;
     92        }
     93       
     94        dirp->pos += len;
     95       
     96        return &dirp->res;
     97}
    5398
    54 extern int fstat(int, struct stat *);
    55 extern int stat(const char *, struct stat *);
    56 extern int mkdir(const char *, mode_t);
     99/** Rewind directory position to the beginning.
     100 *
     101 * @param dirp Open directory
     102 */
     103void rewinddir(DIR *dirp)
     104{
     105        dirp->pos = 0;
     106}
    57107
    58 #endif
     108/** Close directory.
     109 *
     110 * @param dirp Open directory
     111 * @return 0 on success. On error returns -1 and sets errno.
     112 */
     113int closedir(DIR *dirp)
     114{
     115        int rc;
     116       
     117        rc = vfs_put(dirp->fd);
     118        free(dirp);
     119
     120        /* On error errno was set by close() */
     121        return rc;
     122}
    59123
    60124/** @}
  • uspace/lib/c/generic/elf/elf_load.c

    r39f892a9 r368ee04  
    4141#include <stdio.h>
    4242#include <stdlib.h>
     43#include <vfs/vfs.h>
    4344
    4445#ifdef CONFIG_RTLD
     
    5051/** Load ELF program.
    5152 *
    52  * @param file_name File name
     53 * @param file File handle
    5354 * @param info Place to store ELF program information
    5455 * @return EOK on success or non-zero error code
    5556 */
    56 int elf_load(const char *file_name, elf_info_t *info)
     57int elf_load(int file, elf_info_t *info)
    5758{
    5859#ifdef CONFIG_RTLD
     
    6162        int rc;
    6263
    63         rc = elf_load_file(file_name, 0, 0, &info->finfo);
     64        rc = elf_load_file(file, 0, 0, &info->finfo);
    6465        if (rc != EE_OK) {
    6566                DPRINTF("Failed to load executable '%s'.\n", file_name);
  • uspace/lib/c/generic/elf/elf_mod.c

    r39f892a9 r368ee04  
    4444 */
    4545
     46#include <errno.h>
    4647#include <stdio.h>
     48#include <vfs/vfs.h>
    4749#include <sys/types.h>
    4850#include <align.h>
     
    5052#include <as.h>
    5153#include <elf/elf.h>
    52 #include <unistd.h>
    53 #include <fcntl.h>
    5454#include <smc.h>
    5555#include <loader/pcb.h>
    5656#include <entry_point.h>
     57#include <str_error.h>
     58#include <stdlib.h>
    5759
    5860#include <elf/elf_load.h>
     
    8284 * pointed to by @a info.
    8385 *
    84  * @param file_name Path to the ELF file.
     86 * @param file      ELF file.
    8587 * @param so_bias   Bias to use if the file is a shared object.
    8688 * @param info      Pointer to a structure for storing information
     
    9092 *
    9193 */
    92 int elf_load_file(const char *file_name, size_t so_bias, eld_flags_t flags,
    93     elf_finfo_t *info)
     94int elf_load_file(int file, size_t so_bias, eld_flags_t flags, elf_finfo_t *info)
    9495{
    9596        elf_ld_t elf;
    9697
    97         int fd;
    98         int rc;
    99 
    100         fd = open(file_name, O_RDONLY);
    101         if (fd < 0) {
    102                 DPRINTF("failed opening file\n");
    103                 return -1;
    104         }
    105 
    106         elf.fd = fd;
     98        int ofile = vfs_clone(file, -1, true);
     99        int rc = vfs_open(ofile, MODE_READ);
     100        if (rc != EOK) {
     101                return rc;
     102        }
     103
     104        elf.fd = ofile;
    107105        elf.info = info;
    108106        elf.flags = flags;
     
    110108        rc = elf_load_module(&elf, so_bias);
    111109
    112         close(fd);
    113 
     110        vfs_put(ofile);
     111        return rc;
     112}
     113
     114int elf_load_file_name(const char *path, size_t so_bias, eld_flags_t flags,
     115    elf_finfo_t *info)
     116{
     117        int file = vfs_lookup(path, 0);
     118        int rc = elf_load_file(file, so_bias, flags, info);
     119        vfs_put(file);
    114120        return rc;
    115121}
     
    129135        elf_header_t header_buf;
    130136        elf_header_t *header = &header_buf;
     137        aoff64_t pos = 0;
    131138        int i, rc;
    132139
    133         rc = read(elf->fd, header, sizeof(elf_header_t));
     140        rc = vfs_read(elf->fd, &pos, header, sizeof(elf_header_t));
    134141        if (rc != sizeof(elf_header_t)) {
    135142                DPRINTF("Read error.\n");
     
    189196                elf_segment_header_t segment_hdr;
    190197
    191                 /* Seek to start of segment header */
    192                 lseek(elf->fd, header->e_phoff
    193                         + i * sizeof(elf_segment_header_t), SEEK_SET);
    194 
    195                 rc = read(elf->fd, &segment_hdr,
     198                pos = header->e_phoff + i * sizeof(elf_segment_header_t);
     199                rc = vfs_read(elf->fd, &pos, &segment_hdr,
    196200                    sizeof(elf_segment_header_t));
    197201                if (rc != sizeof(elf_segment_header_t)) {
     
    211215                elf_section_header_t section_hdr;
    212216
    213                 /* Seek to start of section header */
    214                 lseek(elf->fd, header->e_shoff
    215                     + i * sizeof(elf_section_header_t), SEEK_SET);
    216 
    217                 rc = read(elf->fd, &section_hdr,
     217                pos = header->e_shoff + i * sizeof(elf_section_header_t);
     218                rc = vfs_read(elf->fd, &pos, &section_hdr,
    218219                    sizeof(elf_section_header_t));
    219220                if (rc != sizeof(elf_section_header_t)) {
     
    327328        uintptr_t seg_addr;
    328329        size_t mem_sz;
     330        aoff64_t pos;
    329331        ssize_t rc;
    330332
     
    384386         * Load segment data
    385387         */
    386         rc = lseek(elf->fd, entry->p_offset, SEEK_SET);
     388        pos = entry->p_offset;
     389        rc = vfs_read(elf->fd, &pos, seg_ptr, entry->p_filesz);
    387390        if (rc < 0) {
    388                 printf("seek error\n");
     391                DPRINTF("read error\n");
    389392                return EE_INVALID;
    390         }
    391 
    392 /*      rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
    393         if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
    394 
    395         /* Long reads are not possible yet. Load segment piecewise. */
    396 
    397         unsigned left, now;
    398         uint8_t *dp;
    399 
    400         left = entry->p_filesz;
    401         dp = seg_ptr;
    402 
    403         while (left > 0) {
    404                 now = 16384;
    405                 if (now > left) now = left;
    406 
    407                 rc = read(elf->fd, dp, now);
    408 
    409                 if (rc != (ssize_t) now) {
    410                         DPRINTF("Read error.\n");
    411                         return EE_INVALID;
    412                 }
    413 
    414                 left -= now;
    415                 dp += now;
    416393        }
    417394
  • uspace/lib/c/generic/io/io.c

    r39f892a9 r368ee04  
    3535#include <stdio.h>
    3636#include <unistd.h>
    37 #include <fcntl.h>
    3837#include <assert.h>
    3938#include <str.h>
     
    4544#include <vfs/vfs.h>
    4645#include <vfs/vfs_sess.h>
     46#include <vfs/inbox.h>
    4747#include <ipc/loc.h>
    4848#include <adt/list.h>
     
    5555static FILE stdin_null = {
    5656        .fd = -1,
     57        .pos = 0,
    5758        .error = true,
    5859        .eof = true,
     
    6970static FILE stdout_kio = {
    7071        .fd = -1,
     72        .pos = 0,
    7173        .error = false,
    7274        .eof = false,
     
    8385static FILE stderr_kio = {
    8486        .fd = -1,
     87        .pos = 0,
    8588        .error = false,
    8689        .eof = false,
     
    101104static LIST_INITIALIZE(files);
    102105
    103 void __stdio_init(int filc)
    104 {
    105         if (filc > 0) {
    106                 stdin = fdopen(0, "r");
     106void __stdio_init(void)
     107{
     108        /* The first three standard file descriptors are assigned for compatibility.
     109         * This will probably be removed later.
     110         */
     111         
     112        int infd = inbox_get("stdin");
     113        if (infd >= 0) {
     114                int stdinfd = vfs_clone(infd, -1, false);
     115                assert(stdinfd == 0);
     116                vfs_open(stdinfd, MODE_READ);
     117                stdin = fdopen(stdinfd, "r");
    107118        } else {
    108119                stdin = &stdin_null;
     
    110121        }
    111122       
    112         if (filc > 1) {
    113                 stdout = fdopen(1, "w");
     123        int outfd = inbox_get("stdout");
     124        if (outfd >= 0) {
     125                int stdoutfd = vfs_clone(outfd, -1, false);
     126                assert(stdoutfd <= 1);
     127                while (stdoutfd < 1)
     128                        stdoutfd = vfs_clone(outfd, -1, false);
     129                vfs_open(stdoutfd, MODE_APPEND);
     130                stdout = fdopen(stdoutfd, "a");
    114131        } else {
    115132                stdout = &stdout_kio;
     
    117134        }
    118135       
    119         if (filc > 2) {
    120                 stderr = fdopen(2, "w");
     136        int errfd = inbox_get("stderr");
     137        if (errfd >= 0) {
     138                int stderrfd = vfs_clone(errfd, -1, false);
     139                assert(stderrfd <= 2);
     140                while (stderrfd < 2)
     141                        stderrfd = vfs_clone(errfd, -1, false);
     142                vfs_open(stderrfd, MODE_APPEND);
     143                stderr = fdopen(stderrfd, "a");
    121144        } else {
    122145                stderr = &stderr_kio;
     
    133156}
    134157
    135 static bool parse_mode(const char *mode, int *flags)
     158static bool parse_mode(const char *fmode, int *mode, bool *create, bool *truncate)
    136159{
    137160        /* Parse mode except first character. */
    138         const char *mp = mode;
     161        const char *mp = fmode;
    139162        if (*mp++ == 0) {
    140163                errno = EINVAL;
     
    156179                return false;
    157180        }
    158        
    159         /* Parse first character of mode and determine flags for open(). */
    160         switch (mode[0]) {
     181
     182        *create = false;
     183        *truncate = false;
     184       
     185        /* Parse first character of fmode and determine mode for vfs_open(). */
     186        switch (fmode[0]) {
    161187        case 'r':
    162                 *flags = plus ? O_RDWR : O_RDONLY;
     188                *mode = plus ? MODE_READ | MODE_WRITE : MODE_READ;
    163189                break;
    164190        case 'w':
    165                 *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
     191                *mode = plus ? MODE_READ | MODE_WRITE : MODE_WRITE;
     192                *create = true;
     193                if (!plus)
     194                        *truncate = true;
    166195                break;
    167196        case 'a':
     
    171200                        return false;
    172201                }
    173                 *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
     202
     203                *mode = MODE_APPEND | (plus ? MODE_READ | MODE_WRITE : MODE_WRITE);
     204                *create = true;
    174205                break;
    175206        default:
     
    245276 *
    246277 */
    247 FILE *fopen(const char *path, const char *mode)
    248 {
    249         int flags;
    250         if (!parse_mode(mode, &flags))
     278FILE *fopen(const char *path, const char *fmode)
     279{
     280        int mode;
     281        bool create;
     282        bool truncate;
     283
     284        if (!parse_mode(fmode, &mode, &create, &truncate))
    251285                return NULL;
    252286       
     
    257291                return NULL;
    258292        }
    259        
    260         stream->fd = open(path, flags, 0666);
    261         if (stream->fd < 0) {
    262                 /* errno was set by open() */
     293
     294        int flags = WALK_REGULAR;
     295        if (create)
     296                flags |= WALK_MAY_CREATE;
     297        int file = vfs_lookup(path, flags);
     298        if (file < 0) {
     299                errno = file;
    263300                free(stream);
    264301                return NULL;
    265302        }
    266        
     303
     304        int rc = vfs_open(file, mode);
     305        if (rc != EOK) {
     306                errno = rc;
     307                vfs_put(file);
     308                free(stream);
     309                return NULL;
     310        }
     311       
     312        if (truncate) {
     313                rc = vfs_resize(file, 0);
     314                if (rc != EOK) {
     315                        errno = rc;
     316                        vfs_put(file);
     317                        free(stream);
     318                        return NULL;
     319                }
     320        }
     321
     322        stream->fd = file;
     323        stream->pos = 0;
    267324        stream->error = false;
    268325        stream->eof = false;
     
    288345       
    289346        stream->fd = fd;
     347        stream->pos = 0;
    290348        stream->error = false;
    291349        stream->eof = false;
     
    312370       
    313371        if (stream->fd >= 0)
    314                 rc = close(stream->fd);
     372                rc = vfs_put(stream->fd);
    315373       
    316374        list_remove(&stream->link);
     
    373431static size_t _fread(void *buf, size_t size, size_t nmemb, FILE *stream)
    374432{
    375         size_t left, done;
    376 
    377433        if (size == 0 || nmemb == 0)
    378434                return 0;
    379435
    380         left = size * nmemb;
    381         done = 0;
    382        
    383         while ((left > 0) && (!stream->error) && (!stream->eof)) {
    384                 ssize_t rd = read(stream->fd, buf + done, left);
    385                
    386                 if (rd < 0) {
    387                         /* errno was set by read() */
    388                         stream->error = true;
    389                 } else if (rd == 0) {
    390                         stream->eof = true;
    391                 } else {
    392                         left -= rd;
    393                         done += rd;
    394                 }
    395         }
    396        
    397         return (done / size);
     436        ssize_t rd = vfs_read(stream->fd, &stream->pos, buf, size * nmemb);
     437        if (rd < 0) {
     438                errno = rd;
     439                stream->error = true;
     440                rd = 0;
     441        } else if (rd == 0) {
     442                stream->eof = true;
     443        }
     444       
     445        return (rd / size);
    398446}
    399447
     
    410458static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
    411459{
    412         size_t left;
    413         size_t done;
    414         int rc;
    415 
    416460        if (size == 0 || nmemb == 0)
    417461                return 0;
    418462
    419         left = size * nmemb;
    420         done = 0;
    421 
    422         while ((left > 0) && (!stream->error)) {
    423                 ssize_t wr;
    424                 size_t uwr;
    425                
    426                 if (stream->kio) {
    427                         uwr = 0;
    428                         rc = kio_write(buf + done, left, &uwr);
    429                         if (rc != EOK)
    430                                 errno = rc;
     463        ssize_t wr;
     464        if (stream->kio) {
     465                size_t nwritten;
     466                wr = kio_write(buf, size * nmemb, &nwritten);
     467                if (wr != EOK) {
     468                        stream->error = true;
     469                        wr = 0;
    431470                } else {
    432                         wr = write(stream->fd, buf + done, left);
    433                         if (wr >= 0) {
    434                                 uwr = (size_t)wr;
    435                                 rc = EOK;
    436                         } else {
    437                                 /* errno was set by write */
    438                                 uwr = 0;
    439                                 rc = errno;
    440                         }
     471                        wr = nwritten;
    441472                }
    442                
    443                 if (rc != EOK) {
    444                         /* errno was set above */
     473        } else {
     474                wr = vfs_write(stream->fd, &stream->pos, buf, size * nmemb);
     475                if (wr < 0) {
     476                        errno = wr;
    445477                        stream->error = true;
    446                 } else {
    447                         left -= uwr;
    448                         done += uwr;
     478                        wr = 0;
    449479                }
    450480        }
    451481
    452         if (done > 0)
     482        if (wr > 0)
    453483                stream->need_sync = true;
    454484       
    455         return (done / size);
     485        return (wr / size);
    456486}
    457487
     
    466496        stream->buf_head = stream->buf_tail = stream->buf;
    467497
    468         rc = read(stream->fd, stream->buf, stream->buf_size);
     498        rc = vfs_read(stream->fd, &stream->pos, stream->buf, stream->buf_size);
    469499        if (rc < 0) {
    470                 /* errno was set by read() */
     500                errno = rc;
    471501                stream->error = true;
    472502                return;
     
    493523
    494524        /* If buffer has prefetched read data, we need to seek back. */
    495         if (bytes_used > 0 && stream->buf_state == _bs_read) {
    496                 off64_t rc;
    497                 rc = lseek(stream->fd, - (ssize_t) bytes_used, SEEK_CUR);
    498                 if (rc == (off64_t)-1) {
    499                         /* errno was set by lseek */
    500                         stream->error = 1;
    501                         return;
    502                 }
    503         }
     525        if (bytes_used > 0 && stream->buf_state == _bs_read)
     526                stream->pos -= bytes_used;
    504527
    505528        /* If buffer has unwritten data, we need to write them out. */
     
    773796int fseek(FILE *stream, off64_t offset, int whence)
    774797{
    775         off64_t rc;
     798        int rc;
    776799
    777800        if (stream->error)
    778                 return EOF;
     801                return -1;
    779802
    780803        _fflushbuf(stream);
    781804        if (stream->error) {
    782805                /* errno was set by _fflushbuf() */
    783                 return EOF;
     806                return -1;
    784807        }
    785808
    786809        stream->ungetc_chars = 0;
    787810
    788         rc = lseek(stream->fd, offset, whence);
    789         if (rc == (off64_t) (-1)) {
    790                 /* errno has been set by lseek() */
    791                 return EOF;
     811        struct stat st;
     812        switch (whence) {
     813        case SEEK_SET:
     814                stream->pos = offset;
     815                break;
     816        case SEEK_CUR:
     817                stream->pos += offset;
     818                break;
     819        case SEEK_END:
     820                rc = vfs_stat(stream->fd, &st);
     821                if (rc != EOK) {
     822                        errno = rc;
     823                        stream->error = true;
     824                        return -1;     
     825                }
     826                stream->pos = st.size + offset;
     827                break;
    792828        }
    793829
     
    798834off64_t ftell(FILE *stream)
    799835{
    800         off64_t pos;
    801        
     836        /* The native position is too large for the C99-ish interface. */
     837        if (stream->pos - stream->ungetc_chars > INT64_MAX)
     838                return EOF;
     839
    802840        if (stream->error)
    803841                return EOF;
     
    809847        }
    810848
    811         pos = lseek(stream->fd, 0, SEEK_CUR);
    812         if (pos == (off64_t) -1) {
    813                 /* errno was set by lseek */
    814                 return (off64_t) -1;
    815         }
    816        
    817         return pos - stream->ungetc_chars;
     849        return stream->pos - stream->ungetc_chars;
    818850}
    819851
     
    840872       
    841873        if ((stream->fd >= 0) && (stream->need_sync)) {
     874                int rc;
     875
    842876                /**
    843877                 * Better than syncing always, but probably still not the
     
    845879                 */
    846880                stream->need_sync = false;
    847                 if (fsync(stream->fd) != 0) {
    848                         /* errno was set by fsync() */
     881                rc = vfs_sync(stream->fd);
     882                if (rc != EOK) {
     883                        errno = rc;
    849884                        return EOF;
    850885                }
  • uspace/lib/c/generic/io/logctl.c

    r39f892a9 r368ee04  
    3939#include <ns.h>
    4040#include <str.h>
     41#include <vfs/vfs.h>
    4142
    4243/** IPC session with the logger service. */
     
    122123}
    123124
     125/** Set logger's VFS root.
     126 *
     127 * @return Error code or EOK on success.
     128 */
     129int logctl_set_root(void)
     130{
     131        async_exch_t *exchange = NULL;
     132        int rc = start_logger_exchange(&exchange);
     133        if (rc != EOK)
     134                return rc;
     135
     136        aid_t reg_msg = async_send_0(exchange, LOGGER_CONTROL_SET_ROOT, NULL);
     137        async_exch_t *vfs_exch = vfs_exchange_begin();
     138        rc = vfs_pass_handle(vfs_exch, vfs_root(), exchange);
     139        vfs_exchange_end(vfs_exch);
     140        sysarg_t reg_msg_rc;
     141        async_wait_for(reg_msg, &reg_msg_rc);
     142
     143        async_exchange_end(exchange);
     144
     145        if (rc != EOK)
     146                return rc;
     147
     148        return (int) reg_msg_rc;
     149}
     150
    124151/** @}
    125152 */
  • uspace/lib/c/generic/libc.c

    r39f892a9 r368ee04  
    4848#include <task.h>
    4949#include <loader/pcb.h>
     50#include <vfs/vfs.h>
     51#include <vfs/inbox.h>
    5052#include "private/libc.h"
    5153#include "private/async.h"
     
    107109                argc = 0;
    108110                argv = NULL;
    109                 __stdio_init(0);
     111                __stdio_init();
    110112        } else {
    111113                argc = __pcb->argc;
    112114                argv = __pcb->argv;
    113                 __stdio_init(__pcb->filc);
    114                 (void) chdir(__pcb->cwd);
     115                __inbox_init(__pcb->inbox, __pcb->inbox_entries);
     116                __stdio_init();
     117                vfs_root_set(inbox_get("root"));
     118                (void) vfs_cwd_set(__pcb->cwd);
    115119        }
    116120       
  • uspace/lib/c/generic/loader.c

    r39f892a9 r368ee04  
    124124                return ENOMEM;
    125125       
    126         if (getcwd(cwd, MAX_PATH_LEN + 1) == NULL)
     126        if (vfs_cwd_get(cwd, MAX_PATH_LEN + 1) != EOK)
    127127                str_cpy(cwd, MAX_PATH_LEN + 1, "/");
    128128       
     
    147147}
    148148
    149 /** Set pathname of the program to load.
    150  *
    151  * Sets the name of the program file to load. The name can be relative
    152  * to the current working directory (it will be absolutized before
    153  * sending to the loader).
     149/** Set the program to load.
    154150 *
    155151 * @param ldr  Loader connection structure.
    156  * @param path Pathname of the program file.
    157  *
    158  * @return Zero on success or negative error code.
    159  *
    160  */
    161 int loader_set_pathname(loader_t *ldr, const char *path)
    162 {
    163         size_t pa_len;
    164         char *pa = vfs_absolutize(path, &pa_len);
    165         if (!pa)
    166                 return ENOMEM;
    167        
    168         /* Send program pathname */
    169         async_exch_t *exch = async_exchange_begin(ldr->sess);
    170        
     152 * @param name Name to set for the spawned program.
     153 * @param file Program file.
     154 *
     155 * @return Zero on success or negative error code.
     156 *
     157 */
     158int loader_set_program(loader_t *ldr, const char *name, int file)
     159{
     160        async_exch_t *exch = async_exchange_begin(ldr->sess);
     161
    171162        ipc_call_t answer;
    172         aid_t req = async_send_0(exch, LOADER_SET_PATHNAME, &answer);
    173         sysarg_t rc = async_data_write_start(exch, (void *) pa, pa_len);
    174        
    175         async_exchange_end(exch);
    176         free(pa);
    177        
     163        aid_t req = async_send_0(exch, LOADER_SET_PROGRAM, &answer);
     164
     165        sysarg_t rc = async_data_write_start(exch, name, str_size(name) + 1);
     166        if (rc == EOK) {
     167                async_exch_t *vfs_exch = vfs_exchange_begin();
     168                rc = vfs_pass_handle(vfs_exch, file, exch);
     169                vfs_exchange_end(vfs_exch);
     170        }
     171
     172        async_exchange_end(exch);
     173
    178174        if (rc != EOK) {
    179175                async_forget(req);
    180176                return (int) rc;
    181177        }
    182        
     178
    183179        async_wait_for(req, &rc);
    184180        return (int) rc;
    185181}
     182
     183/** Set the program to load by path.
     184 *
     185 * @param ldr  Loader connection structure.
     186 * @param path Program path.
     187 *
     188 * @return Zero on success or negative error code.
     189 *
     190 */
     191int loader_set_program_path(loader_t *ldr, const char *path)
     192{
     193        const char *name = str_rchr(path, '/');
     194        if (name == NULL) {
     195                name = path;
     196        } else {
     197                name++;
     198        }
     199       
     200        int fd = vfs_lookup(path, 0);
     201        if (fd < 0) {
     202                return fd;
     203        }
     204       
     205        int rc = loader_set_program(ldr, name, fd);
     206        vfs_put(fd);
     207        return rc;
     208}
     209
    186210
    187211/** Set command-line arguments for the program.
     
    244268}
    245269
    246 /** Set preset files for the program.
    247  *
    248  * Sets the vector of preset files to be passed to the loaded
    249  * program. By convention, the first three files represent stdin,
    250  * stdout and stderr respectively.
    251  *
    252  * @param ldr   Loader connection structure.
    253  * @param files NULL-terminated array of pointers to files.
    254  *
    255  * @return Zero on success or negative error code.
    256  *
    257  */
    258 int loader_set_files(loader_t *ldr, int * const files[])
    259 {
    260         /* Send serialized files to the loader */
     270/** Add a file to the task's inbox.
     271 *
     272 * @param ldr        Loader connection structure.
     273 * @param name       Identification of the file.
     274 * @param file       The file's descriptor.
     275 *
     276 * @return Zero on success or negative error code.
     277 *
     278 */
     279int loader_add_inbox(loader_t *ldr, const char *name, int file)
     280{
    261281        async_exch_t *exch = async_exchange_begin(ldr->sess);
    262282        async_exch_t *vfs_exch = vfs_exchange_begin();
    263283       
    264         int i;
    265         for (i = 0; files[i]; i++);
    266 
    267         ipc_call_t answer;
    268         aid_t req = async_send_1(exch, LOADER_SET_FILES, i, &answer);
    269 
    270         sysarg_t rc = EOK;
    271        
    272         for (i = 0; files[i]; i++) {
    273                 rc = async_state_change_start(exch, VFS_PASS_HANDLE, *files[i],
    274                     0, vfs_exch);
    275                 if (rc != EOK)
    276                         break;
    277         }
    278        
    279         vfs_exchange_end(vfs_exch);
    280         async_exchange_end(exch);
    281 
    282         if (rc != EOK) {
    283                 async_forget(req);
    284                 return (int) rc;
    285         }
    286        
    287         async_wait_for(req, &rc);
     284        aid_t req = async_send_0(exch, LOADER_ADD_INBOX, NULL);
     285       
     286        sysarg_t rc = async_data_write_start(exch, name, str_size(name) + 1);
     287        if (rc == EOK) {
     288                rc = vfs_pass_handle(vfs_exch, file, exch);
     289        }
     290       
     291        async_exchange_end(vfs_exch);
     292        async_exchange_end(exch);
     293       
     294        if (rc == EOK) {
     295                async_wait_for(req, &rc);
     296        } else {
     297                async_forget(req);
     298        }
     299       
    288300        return (int) rc;
    289301}
  • uspace/lib/c/generic/private/io.h

    r39f892a9 r368ee04  
    3636#define LIBC_PRIVATE_IO_H_
    3737
    38 extern void __stdio_init(int);
     38#include <loader/pcb.h>
     39
     40extern void __stdio_init(void);
    3941extern void __stdio_done(void);
     42
     43extern void __inbox_init(struct pcb_inbox_entry *entries, int count);
    4044
    4145#endif
  • uspace/lib/c/generic/private/stdio.h

    r39f892a9 r368ee04  
    4949        /** Underlying file descriptor. */
    5050        int fd;
     51
     52        /** File position. */
     53        aoff64_t pos;
    5154       
    5255        /** Error indicator. */
  • uspace/lib/c/generic/rtld/module.c

    r39f892a9 r368ee04  
    3838#include <elf/elf_load.h>
    3939#include <errno.h>
    40 #include <fcntl.h>
    4140#include <loader/pcb.h>
    4241#include <stdio.h>
     
    196195        DPRINTF("load '%s' at 0x%x\n", name_buf, m->bias);
    197196
    198         rc = elf_load_file(name_buf, m->bias, ELDF_RW, &info);
     197        rc = elf_load_file_name(name_buf, m->bias, ELDF_RW, &info);
    199198        if (rc != EE_OK) {
    200199                printf("Failed to load '%s'\n", name_buf);
  • uspace/lib/c/generic/task.c

    r39f892a9 r368ee04  
    4848#include "private/ns.h"
    4949#include <vfs/vfs.h>
     50#include <unistd.h>
    5051
    5152task_id_t task_get_id(void)
     
    107108{
    108109        /* Send default files */
    109         int *files[4];
    110         int fd_stdin;
    111         int fd_stdout;
    112         int fd_stderr;
    113        
    114         if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK))
    115                 files[0] = &fd_stdin;
    116         else
    117                 files[0] = NULL;
    118        
    119         if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK))
    120                 files[1] = &fd_stdout;
    121         else
    122                 files[1] = NULL;
    123        
    124         if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK))
    125                 files[2] = &fd_stderr;
    126         else
    127                 files[2] = NULL;
    128        
    129         files[3] = NULL;
    130        
    131         return task_spawnvf(id, wait, path, args, files);
     110       
     111        int fd_stdin = -1;
     112        int fd_stdout = -1;
     113        int fd_stderr = -1;
     114       
     115        if (stdin != NULL) {
     116                (void) vfs_fhandle(stdin, &fd_stdin);
     117        }
     118       
     119        if (stdout != NULL) {
     120                (void) vfs_fhandle(stdout, &fd_stdout);
     121        }
     122
     123        if (stderr != NULL) {
     124                (void) vfs_fhandle(stderr, &fd_stderr);
     125        }
     126       
     127        return task_spawnvf(id, wait, path, args, fd_stdin, fd_stdout,
     128            fd_stderr);
    132129}
    133130
     
    138135 * Files are passed as null-terminated array of pointers to fdi_node_t.
    139136 *
    140  * @param id    If not NULL, the ID of the task is stored here on success.
    141  * @param wait  If not NULL, setup waiting for task's return value and store
    142  *              the information necessary for waiting here on success.
    143  * @param path  Pathname of the binary to execute.
    144  * @param argv  Command-line arguments.
    145  * @param files Standard files to use.
     137 * @param id      If not NULL, the ID of the task is stored here on success.
     138 * @param wait    If not NULL, setup waiting for task's return value and store
     139 * @param path    Pathname of the binary to execute.
     140 * @param argv    Command-line arguments.
     141 * @param std_in  File to use as stdin.
     142 * @param std_out File to use as stdout.
     143 * @param std_err File to use as stderr.
    146144 *
    147145 * @return Zero on success or negative error code.
     
    149147 */
    150148int task_spawnvf(task_id_t *id, task_wait_t *wait, const char *path,
    151     const char *const args[], int *const files[])
     149    const char *const args[], int fd_stdin, int fd_stdout, int fd_stderr)
    152150{
    153151        /* Connect to a program loader. */
     
    169167                goto error;
    170168       
    171         /* Send program pathname. */
    172         rc = loader_set_pathname(ldr, path);
     169        /* Send program binary. */
     170        rc = loader_set_program_path(ldr, path);
    173171        if (rc != EOK)
    174172                goto error;
     
    180178       
    181179        /* Send files */
    182         rc = loader_set_files(ldr, files);
    183         if (rc != EOK)
    184                 goto error;
     180        int root = vfs_root();
     181        if (root >= 0) {
     182                rc = loader_add_inbox(ldr, "root", root);
     183                vfs_put(root);
     184                if (rc != EOK)
     185                        goto error;
     186        }
     187       
     188        if (fd_stdin >= 0) {
     189                rc = loader_add_inbox(ldr, "stdin", fd_stdin);
     190                if (rc != EOK)
     191                        goto error;
     192        }
     193       
     194        if (fd_stdout >= 0) {
     195                rc = loader_add_inbox(ldr, "stdout", fd_stdout);
     196                if (rc != EOK)
     197                        goto error;
     198        }
     199       
     200        if (fd_stderr >= 0) {
     201                rc = loader_add_inbox(ldr, "stderr", fd_stderr);
     202                if (rc != EOK)
     203                        goto error;
     204        }               
    185205       
    186206        /* Load the program. */
  • uspace/lib/c/generic/vfs/vfs.c

    r39f892a9 r368ee04  
    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
  • uspace/lib/c/include/dirent.h

    r39f892a9 r368ee04  
    3838#define NAME_MAX  256
    3939
     40#include <sys/types.h>
     41
    4042struct dirent {
    4143        char d_name[NAME_MAX + 1];
     
    4547        int fd;
    4648        struct dirent res;
     49        aoff64_t pos;
    4750} DIR;
    4851
  • uspace/lib/c/include/elf/elf_load.h

    r39f892a9 r368ee04  
    4545} elf_info_t;
    4646
    47 extern int elf_load(const char *, elf_info_t *);
     47extern int elf_load(int, elf_info_t *);
    4848extern void elf_set_pcb(elf_info_t *, pcb_t *);
    4949
  • uspace/lib/c/include/elf/elf_mod.h

    r39f892a9 r368ee04  
    108108
    109109extern const char *elf_error(unsigned int);
    110 extern int elf_load_file(const char *, size_t, eld_flags_t, elf_finfo_t *);
     110extern int elf_load_file(int, size_t, eld_flags_t, elf_finfo_t *);
     111extern int elf_load_file_name(const char *, size_t, eld_flags_t, elf_finfo_t *);
    111112
    112113#endif
  • uspace/lib/c/include/io/logctl.h

    r39f892a9 r368ee04  
    3838extern int logctl_set_default_level(log_level_t);
    3939extern int logctl_set_log_level(const char *, log_level_t);
     40extern int logctl_set_root(void);
    4041
    4142#endif
  • uspace/lib/c/include/ipc/loader.h

    r39f892a9 r368ee04  
    4242        LOADER_GET_TASKID,
    4343        LOADER_SET_CWD,
    44         LOADER_SET_PATHNAME,
     44        LOADER_SET_PROGRAM,
    4545        LOADER_SET_ARGS,
    46         LOADER_SET_FILES,
     46        LOADER_ADD_INBOX,
    4747        LOADER_LOAD,
    4848        LOADER_RUN
  • uspace/lib/c/include/ipc/logger.h

    r39f892a9 r368ee04  
    4949         * Followed by: string with full log name.
    5050         */
    51         LOGGER_CONTROL_SET_LOG_LEVEL
     51        LOGGER_CONTROL_SET_LOG_LEVEL,
     52        /** Set VFS root.
     53         *
     54         * Returns: error code
     55         * Followed by: vfs_pass_handle() request.
     56         */
     57        LOGGER_CONTROL_SET_ROOT
    5258} logger_control_request_t;
    5359
  • uspace/lib/c/include/ipc/vfs.h

    r39f892a9 r368ee04  
    4141
    4242#define FS_NAME_MAXLEN  20
    43 #define MAX_PATH_LEN    (64 * 1024)
     43#define MAX_PATH_LEN    (32 * 1024)
    4444#define MAX_MNTOPTS_LEN 256
    4545#define PLB_SIZE        (2 * MAX_PATH_LEN)
     
    6363
    6464typedef enum {
    65         VFS_IN_OPEN = IPC_FIRST_USER_METHOD,
     65        VFS_IN_CLONE = IPC_FIRST_USER_METHOD,
     66        VFS_IN_MOUNT,
     67        VFS_IN_OPEN,
     68        VFS_IN_PUT,
    6669        VFS_IN_READ,
     70        VFS_IN_REGISTER,
     71        VFS_IN_RENAME,
     72        VFS_IN_RESIZE,
     73        VFS_IN_STAT,
     74        VFS_IN_STATFS,
     75        VFS_IN_SYNC,
     76        VFS_IN_UNLINK,
     77        VFS_IN_UNMOUNT,
     78        VFS_IN_WAIT_HANDLE,
     79        VFS_IN_WALK,
    6780        VFS_IN_WRITE,
    68         VFS_IN_SEEK,
    69         VFS_IN_TRUNCATE,
    70         VFS_IN_FSTAT,
    71         VFS_IN_CLOSE,
    72         VFS_IN_PING,
    73         VFS_IN_MOUNT,
    74         VFS_IN_UNMOUNT,
    75         VFS_IN_SYNC,
    76         VFS_IN_REGISTER,
    77         VFS_IN_MKDIR,
    78         VFS_IN_UNLINK,
    79         VFS_IN_RENAME,
    80         VFS_IN_STAT,
    81         VFS_IN_DUP,
    82         VFS_IN_WAIT_HANDLE,
    83         VFS_IN_MTAB_GET,
    84         VFS_IN_STATFS
    8581} vfs_in_request_t;
    8682
    8783typedef enum {
    88         VFS_OUT_OPEN_NODE = IPC_FIRST_USER_METHOD,
     84        VFS_OUT_CLOSE = IPC_FIRST_USER_METHOD,
     85        VFS_OUT_DESTROY,
     86        VFS_OUT_IS_EMPTY,
     87        VFS_OUT_LINK,
     88        VFS_OUT_LOOKUP,
     89        VFS_OUT_MOUNTED,
     90        VFS_OUT_OPEN_NODE,
    8991        VFS_OUT_READ,
     92        VFS_OUT_STAT,
     93        VFS_OUT_STATFS,
     94        VFS_OUT_SYNC,
     95        VFS_OUT_TRUNCATE,
     96        VFS_OUT_UNMOUNTED,
    9097        VFS_OUT_WRITE,
    91         VFS_OUT_TRUNCATE,
    92         VFS_OUT_CLOSE,
    93         VFS_OUT_MOUNT,
    94         VFS_OUT_MOUNTED,
    95         VFS_OUT_UNMOUNT,
    96         VFS_OUT_UNMOUNTED,
    97         VFS_OUT_SYNC,
    98         VFS_OUT_STAT,
    99         VFS_OUT_LOOKUP,
    100         VFS_OUT_DESTROY,
    101         VFS_OUT_STATFS,
    10298        VFS_OUT_LAST
    10399} vfs_out_request_t;
     
    127123
    128124/**
    129  * Lookup will succeed only if the object is a root directory. The flag is
    130  * mutually exclusive with L_FILE and L_MP.
     125 * Lookup will not cross any mount points.
     126 * If the lookup would have to cross a mount point, it returns EXDEV instead.
    131127 */
    132 #define L_ROOT                  4
     128#define L_DISABLE_MOUNTS        4
    133129
    134130/**
    135131 * Lookup will succeed only if the object is a mount point. The flag is mutually
    136  * exclusive with L_FILE and L_ROOT.
     132 * exclusive with L_FILE.
    137133 */
    138134#define L_MP                    8
     
    151147
    152148/**
    153  * L_LINK is used for linking to an already existing nodes.
    154  */
    155 #define L_LINK                  64
    156 
    157 /**
    158149 * L_UNLINK is used to remove leaves from the file system namespace. This flag
    159150 * cannot be passed directly by the client, but will be set by VFS during
    160151 * VFS_UNLINK.
    161152 */
    162 #define L_UNLINK                128
     153#define L_UNLINK                64
    163154
    164 /**
    165  * L_OPEN is used to indicate that the lookup operation is a part of VFS_IN_OPEN
    166  * call from the client. This means that the server might allocate some
    167  * resources for the opened file. This flag cannot be passed directly by the
    168  * client.
     155/*
     156 * Walk flags.
    169157 */
    170 #define L_OPEN                  256
     158enum {
     159        WALK_MAY_CREATE = (1 << 0),
     160        WALK_MUST_CREATE = (1 << 1),
     161       
     162        WALK_REGULAR = (1 << 2),
     163        WALK_DIRECTORY = (1 << 3),
     164        WALK_MOUNT_POINT = (1 << 4),
     165       
     166        WALK_ALL_FLAGS = WALK_MAY_CREATE | WALK_MUST_CREATE | WALK_REGULAR |
     167            WALK_DIRECTORY | WALK_MOUNT_POINT,
     168};
     169
     170enum {
     171        VFS_MOUNT_BLOCKING = 1,
     172        VFS_MOUNT_CONNECT_ONLY = 2,
     173        VFS_MOUNT_NO_REF = 4,
     174};
     175
     176enum {
     177        MODE_READ = 1,
     178        MODE_WRITE = 2,
     179        MODE_APPEND = 4,
     180};
    171181
    172182#endif
  • uspace/lib/c/include/loader/loader.h

    r39f892a9 r368ee04  
    4747extern int loader_get_task_id(loader_t *, task_id_t *);
    4848extern int loader_set_cwd(loader_t *);
    49 extern int loader_set_pathname(loader_t *, const char *);
     49extern int loader_set_program(loader_t *, const char *, int);
     50extern int loader_set_program_path(loader_t *, const char *);
    5051extern int loader_set_args(loader_t *, const char *const[]);
    51 extern int loader_set_files(loader_t *, int *const[]);
     52extern int loader_add_inbox(loader_t *, const char *, int);
    5253extern int loader_load_program(loader_t *);
    5354extern int loader_run(loader_t *);
  • uspace/lib/c/include/loader/pcb.h

    r39f892a9 r368ee04  
    4141typedef void (*entry_point_t)(void);
    4242
     43struct pcb_inbox_entry {
     44        char *name;
     45        int file;
     46};
     47
    4348/** Program Control Block.
    4449 *
     
    6065        char **argv;
    6166       
    62         /** Number of preset files. */
    63         unsigned int filc;
     67        /** List of inbox files. */
     68        struct pcb_inbox_entry *inbox;
     69        int inbox_entries;
    6470       
    6571        /*
  • uspace/lib/c/include/stdio.h

    r39f892a9 r368ee04  
    4444#define EOF  (-1)
    4545
    46 /** Default size for stream I/O buffers */
    47 #define BUFSIZ  4096
    48 
    49 #define DEBUG(fmt, ...) \
    50         { \
    51                 char _buf[256]; \
    52                 int _n = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__); \
    53                 if (_n > 0) \
    54                         (void) __SYSCALL3(SYS_KIO, KIO_WRITE, (sysarg_t) _buf, str_size(_buf)); \
    55         }
    56 
    5746#ifndef SEEK_SET
    5847        #define SEEK_SET  0
     
    6655        #define SEEK_END  2
    6756#endif
     57
     58/** Default size for stream I/O buffers */
     59#define BUFSIZ  4096
     60
     61#define DEBUG(fmt, ...) \
     62        { \
     63                char _buf[256]; \
     64                int _n = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__); \
     65                if (_n > 0) \
     66                        (void) __SYSCALL3(SYS_KIO, KIO_WRITE, (sysarg_t) _buf, str_size(_buf)); \
     67        }
    6868
    6969enum _buffer_type {
     
    153153extern void setbuf(FILE *, void *);
    154154
    155 /* Misc file functions */
    156 extern int rename(const char *, const char *);
    157 extern int remove(const char *);
    158 
    159155#endif
    160156
  • uspace/lib/c/include/stdlib.h

    r39f892a9 r368ee04  
    4949
    5050extern void abort(void) __attribute__((noreturn));
     51extern void exit(int) __attribute__((noreturn));
    5152
    5253#endif
  • uspace/lib/c/include/sys/types.h

    r39f892a9 r368ee04  
    3838#include <libarch/types.h>
    3939
    40 typedef unsigned int mode_t;
    41 
    4240/** Relative offset */
    4341typedef int64_t off64_t;
  • uspace/lib/c/include/task.h

    r39f892a9 r368ee04  
    5757    const char *const []);
    5858extern int task_spawnvf(task_id_t *, task_wait_t *, const char *path,
    59     const char *const [], int *const []);
     59    const char *const [], int, int, int);
    6060extern int task_spawn(task_id_t *, task_wait_t *, const char *path, int,
    6161    va_list ap);
  • uspace/lib/c/include/unistd.h

    r39f892a9 r368ee04  
    4444#endif
    4545
    46 #ifndef SEEK_SET
    47         #define SEEK_SET  0
    48 #endif
    49 
    50 #ifndef SEEK_CUR
    51         #define SEEK_CUR  1
    52 #endif
    53 
    54 #ifndef SEEK_END
    55         #define SEEK_END  2
    56 #endif
    57 
    5846#define getpagesize()  (PAGE_SIZE)
    5947
    60 extern int dup2(int, int);
    61 
    62 extern ssize_t write(int, const void *, size_t);
    63 extern ssize_t read(int, void *, size_t);
    64 
    65 extern off64_t lseek(int, off64_t, int);
    66 extern int ftruncate(int, aoff64_t);
    67 
    68 extern int close(int);
    69 extern int fsync(int);
    70 extern int unlink(const char *);
    71 
    72 extern char *getcwd(char *, size_t);
    73 extern int rmdir(const char *);
    74 extern int chdir(const char *);
    75 
    76 extern void exit(int) __attribute__((noreturn));
    7748extern int usleep(useconds_t);
    7849extern unsigned int sleep(unsigned int);
  • uspace/lib/c/include/vfs/inbox.h

    r39f892a9 r368ee04  
    11/*
    2  * Copyright (c) 2007 Jakub Jermar
     2 * Copyright (c) 2013 Jiri Zarevucky
    33 * All rights reserved.
    44 *
     
    2727 */
    2828
    29 /** @addtogroup libc
     29/** @addtogroup libc 
    3030 * @{
    31  */
    32 /** @file
     31 */
     32
     33/**
     34 * @file
     35 * @brief
    3336 */
    3437
    35 #ifndef LIBC_FCNTL_H_
    36 #define LIBC_FCNTL_H_
     38#ifndef LIBC_VFS_INBOX_H_
     39#define LIBC_VFS_INBOX_H_
    3740
    38 #define O_CREAT   1
    39 #define O_EXCL    2
    40 #define O_TRUNC   4
    41 #define O_APPEND  8
    42 #define O_RDONLY  16
    43 #define O_RDWR    32
    44 #define O_WRONLY  64
    45 #define O_DESC    128
     41enum {
     42        INBOX_MAX_ENTRIES = 256,
     43};
    4644
    47 extern int open(const char *, int, ...);
     45extern int inbox_set(const char *name, int file);
     46extern int inbox_get(const char *name);
     47
     48extern int inbox_list(const char **names, int capacity);
    4849
    4950#endif
    5051
    51 /** @}
     52/**
     53 * @}
    5254 */
  • uspace/lib/c/include/vfs/vfs.h

    r39f892a9 r368ee04  
    4242#include <stdio.h>
    4343#include <async.h>
    44 #include "vfs_mtab.h"
    4544
     45#define MAX_OPEN_FILES  128
    4646
    4747enum vfs_change_state_type {
     
    4949};
    5050
     51typedef enum {
     52        KIND_FILE,
     53        KIND_DIRECTORY,
     54} vfs_file_kind_t;
    5155
    52 extern char *vfs_absolutize(const char *, size_t *);
    5356
    54 extern int vfs_mount(const char *, const char *, const char *, const char *,
    55     unsigned int, unsigned int);
    56 extern int vfs_unmount(const char *);
     57struct stat {
     58        fs_handle_t fs_handle;
     59        service_id_t service_id;
     60        fs_index_t index;
     61        unsigned int lnkcnt;
     62        bool is_file;
     63        bool is_directory;
     64        aoff64_t size;
     65        service_id_t service;
     66};
     67
     68struct statfs {
     69        char fs_name[FS_NAME_MAXLEN + 1];
     70        uint32_t f_bsize;    /* fundamental file system block size */
     71        uint64_t f_blocks;   /* total data blocks in file system */
     72        uint64_t f_bfree;    /* free blocks in fs */
     73};
    5774
    5875extern int vfs_fhandle(FILE *, int *);
    5976
    60 extern int vfs_fd_wait(void);
    61 extern int vfs_get_mtab_list(list_t *mtab_list);
    62 
     77extern char *vfs_absolutize(const char *, size_t *);
     78extern int vfs_clone(int, int, bool);
     79extern int vfs_cwd_get(char *path, size_t);
     80extern int vfs_cwd_set(const char *path);
    6381extern async_exch_t *vfs_exchange_begin(void);
    6482extern void vfs_exchange_end(async_exch_t *);
     83extern int vfs_link(int, const char *, vfs_file_kind_t, int *);
     84extern int vfs_link_path(const char *, vfs_file_kind_t, int *);
     85extern int vfs_lookup(const char *, int);
     86extern int vfs_lookup_open(const char *, int, int);
     87extern int vfs_mount_path(const char *, const char *, const char *,
     88    const char *, unsigned int, unsigned int);
     89extern int vfs_mount(int, const char *, service_id_t, const char *, unsigned,
     90    unsigned, int *);
     91extern int vfs_open(int, int);
     92extern int vfs_pass_handle(async_exch_t *, int, async_exch_t *);
     93extern int vfs_put(int);
     94extern ssize_t vfs_read(int, aoff64_t *, void *, size_t);
     95extern int vfs_read_short(int, aoff64_t, void *, size_t, ssize_t *);
     96extern int vfs_receive_handle(bool);
     97extern int vfs_rename_path(const char *, const char *);
     98extern int vfs_resize(int, aoff64_t);
     99extern int vfs_root(void);
     100extern void vfs_root_set(int);
     101extern int vfs_stat(int, struct stat *);
     102extern int vfs_stat_path(const char *, struct stat *);
     103extern int vfs_statfs(int, struct statfs *);
     104extern int vfs_statfs_path(const char *, struct statfs *);
     105extern int vfs_sync(int);
     106extern int vfs_unlink(int, const char *, int);
     107extern int vfs_unlink_path(const char *);
     108extern int vfs_unmount(int);
     109extern int vfs_unmount_path(const char *);
     110extern int vfs_walk(int, const char *, int);
     111extern ssize_t vfs_write(int, aoff64_t *, const void *, size_t);
     112extern int vfs_write_short(int, aoff64_t, const void *, size_t, ssize_t *);
    65113
    66114#endif
  • uspace/lib/c/include/vfs/vfs_mtab.h

    r39f892a9 r368ee04  
    4343        link_t link;
    4444        char mp[MAX_PATH_LEN];
    45         char opts[MAX_MNTOPTS_LEN];
    4645        char fs_name[FS_NAME_MAXLEN];
    47         unsigned int instance;
    4846        service_id_t service_id;
    4947} mtab_ent_t;
     48
     49extern int vfs_get_mtab_list(list_t *);
    5050
    5151#endif
  • uspace/lib/fs/libfs.c

    r39f892a9 r368ee04  
    3636
    3737#include "libfs.h"
    38 #include "../../srv/vfs/vfs.h"
    3938#include <macros.h>
    4039#include <errno.h>
     
    4443#include <dirent.h>
    4544#include <mem.h>
    46 #include <sys/stat.h>
    47 #include <sys/statfs.h>
     45#include <str.h>
    4846#include <stdlib.h>
     47#include <fibril_synch.h>
     48#include <ipc/vfs.h>
     49#include <vfs/vfs.h>
    4950
    5051#define on_error(rc, action) \
     
    6869static libfs_ops_t *libfs_ops = NULL;
    6970
    70 static void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
    71 static void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
     71static char fs_name[FS_NAME_MAXLEN + 1];
     72
     73static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t,
     74    ipc_call_t *);
    7275static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    7376    ipc_call_t *);
     
    7578static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t,
    7679    ipc_call_t *);
    77 static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
     80static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_callid_t,
     81    ipc_call_t *);
    7882
    7983static void vfs_out_mounted(ipc_callid_t rid, ipc_call_t *req)
     
    104108}
    105109
    106 static void vfs_out_mount(ipc_callid_t rid, ipc_call_t *req)
    107 {
    108         libfs_mount(libfs_ops, reg.fs_handle, rid, req);
    109 }
    110 
    111110static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req)
    112111{
     
    119118}
    120119
    121 static void vfs_out_unmount(ipc_callid_t rid, ipc_call_t *req)
    122 {
    123                
    124         libfs_unmount(libfs_ops, rid, req);
     120static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req)
     121{
     122        libfs_link(libfs_ops, reg.fs_handle, rid, req);
    125123}
    126124
     
    159157        rc = vfs_out_ops->write(service_id, index, pos, &wbytes, &nsize);
    160158
    161         if (rc == EOK)
    162                 async_answer_3(rid, EOK, wbytes, LOWER32(nsize), UPPER32(nsize));
    163         else
     159        if (rc == EOK) {
     160                async_answer_3(rid, EOK, wbytes, LOWER32(nsize),
     161                    UPPER32(nsize));
     162        } else
    164163                async_answer_0(rid, rc);
    165164}
     
    193192        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
    194193        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
     194
    195195        int rc;
    196 
    197         rc = vfs_out_ops->destroy(service_id, index);
    198 
     196        fs_node_t *node = NULL;
     197        rc = libfs_ops->node_get(&node, service_id, index);
     198        if (rc == EOK && node != NULL) {
     199                bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
     200                libfs_ops->node_put(node);
     201                if (destroy)
     202                        rc = vfs_out_ops->destroy(service_id, index);
     203        }
    199204        async_answer_0(rid, rc);
    200205}
     
    225230        libfs_statfs(libfs_ops, reg.fs_handle, rid, req);
    226231}
     232
     233static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req)
     234{
     235        service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
     236        fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
     237        int rc;
     238
     239        fs_node_t *node = NULL;
     240        rc = libfs_ops->node_get(&node, service_id, index);
     241        if (rc != EOK)
     242                async_answer_0(rid, rc);
     243        if (node == NULL)
     244                async_answer_0(rid, EINVAL);
     245       
     246        bool children = false;
     247        rc = libfs_ops->has_children(&children, node);
     248        libfs_ops->node_put(node);
     249       
     250        if (rc != EOK)
     251                async_answer_0(rid, rc);
     252        async_answer_0(rid, children ? ENOTEMPTY : EOK);
     253}
     254
    227255static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    228256{
     
    247275                        vfs_out_mounted(callid, &call);
    248276                        break;
    249                 case VFS_OUT_MOUNT:
    250                         vfs_out_mount(callid, &call);
    251                         break;
    252277                case VFS_OUT_UNMOUNTED:
    253278                        vfs_out_unmounted(callid, &call);
    254279                        break;
    255                 case VFS_OUT_UNMOUNT:
    256                         vfs_out_unmount(callid, &call);
     280                case VFS_OUT_LINK:
     281                        vfs_out_link(callid, &call);
    257282                        break;
    258283                case VFS_OUT_LOOKUP:
     
    285310                case VFS_OUT_STATFS:
    286311                        vfs_out_statfs(callid, &call);
     312                        break;
     313                case VFS_OUT_IS_EMPTY:
     314                        vfs_out_is_empty(callid, &call);
    287315                        break;
    288316                default:
     
    338366        vfs_out_ops = vops;
    339367        libfs_ops = lops;
     368
     369        str_cpy(fs_name, sizeof(fs_name), info->name);
    340370
    341371        /*
     
    383413}
    384414
    385 void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
     415static char plb_get_char(unsigned pos)
     416{
     417        return reg.plb_ro[pos % PLB_SIZE];
     418}
     419
     420static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos,
     421    unsigned last)
     422{
     423        unsigned pos = *ppos;
     424        unsigned size = 0;
     425       
     426        if (pos == last) {
     427                *sz = 0;
     428                return ERANGE;
     429        }
     430
     431        char c = plb_get_char(pos);
     432        if (c == '/')
     433                pos++;
     434       
     435        for (int i = 0; i <= NAME_MAX; i++) {
     436                c = plb_get_char(pos);
     437                if (pos == last || c == '/') {
     438                        dest[i] = 0;
     439                        *ppos = pos;
     440                        *sz = size;
     441                        return EOK;
     442                }
     443                dest[i] = c;
     444                pos++;
     445                size++;
     446        }
     447        return ENAMETOOLONG;
     448}
     449
     450static int receive_fname(char *buffer)
     451{
     452        size_t size;
     453        ipc_callid_t wcall;
     454       
     455        if (!async_data_write_receive(&wcall, &size))
     456                return ENOENT;
     457        if (size > NAME_MAX + 1) {
     458                async_answer_0(wcall, ERANGE);
     459                return ERANGE;
     460        }
     461        return async_data_write_finalize(wcall, buffer, size);
     462}
     463
     464/** Link a file at a path.
     465 */
     466void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
    386467    ipc_call_t *req)
    387468{
    388         service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
    389         fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
    390         fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*req);
    391         service_id_t mr_service_id = (service_id_t) IPC_GET_ARG4(*req);
    392        
    393         async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL);
    394         if (mountee_sess == NULL) {
    395                 async_answer_0(rid, EINVAL);
     469        service_id_t parent_sid = IPC_GET_ARG1(*req);
     470        fs_index_t parent_index = IPC_GET_ARG2(*req);
     471        fs_index_t child_index = IPC_GET_ARG3(*req);
     472       
     473        char component[NAME_MAX + 1];
     474        int rc = receive_fname(component);
     475        if (rc != EOK) {
     476                async_answer_0(rid, rc);
    396477                return;
    397478        }
    398        
    399         fs_node_t *fn;
    400         int res = ops->node_get(&fn, mp_service_id, mp_fs_index);
    401         if ((res != EOK) || (!fn)) {
    402                 async_hangup(mountee_sess);
    403                 async_data_write_void(combine_rc(res, ENOENT));
    404                 async_answer_0(rid, combine_rc(res, ENOENT));
     479
     480        fs_node_t *parent = NULL;
     481        rc = ops->node_get(&parent, parent_sid, parent_index);
     482        if (parent == NULL) {
     483                async_answer_0(rid, rc == EOK ? EBADF : rc);
    405484                return;
    406485        }
    407486       
    408         if (fn->mp_data.mp_active) {
    409                 async_hangup(mountee_sess);
    410                 (void) ops->node_put(fn);
    411                 async_data_write_void(EBUSY);
    412                 async_answer_0(rid, EBUSY);
     487        fs_node_t *child = NULL;
     488        rc = ops->node_get(&child, parent_sid, child_index);
     489        if (child == NULL) {
     490                async_answer_0(rid, rc == EOK ? EBADF : rc);
     491                ops->node_put(parent);
    413492                return;
    414493        }
    415494       
    416         async_exch_t *exch = async_exchange_begin(mountee_sess);
    417         async_sess_t *sess = async_clone_establish(EXCHANGE_PARALLEL, exch);
    418        
    419         if (!sess) {
    420                 async_exchange_end(exch);
    421                 async_hangup(mountee_sess);
    422                 (void) ops->node_put(fn);
    423                 async_data_write_void(errno);
    424                 async_answer_0(rid, errno);
    425                 return;
    426         }
    427        
    428         ipc_call_t answer;
    429         int rc = async_data_write_forward_1_1(exch, VFS_OUT_MOUNTED,
    430             mr_service_id, &answer);
    431         async_exchange_end(exch);
    432        
    433         if (rc == EOK) {
    434                 fn->mp_data.mp_active = true;
    435                 fn->mp_data.fs_handle = mr_fs_handle;
    436                 fn->mp_data.service_id = mr_service_id;
    437                 fn->mp_data.sess = mountee_sess;
    438         }
    439        
    440         /*
    441          * Do not release the FS node so that it stays in memory.
    442          */
    443         async_answer_4(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
    444             IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
    445 }
    446 
    447 void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *req)
    448 {
    449         service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
    450         fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
    451         fs_node_t *fn;
    452         int res;
    453 
    454         res = ops->node_get(&fn, mp_service_id, mp_fs_index);
    455         if ((res != EOK) || (!fn)) {
    456                 async_answer_0(rid, combine_rc(res, ENOENT));
    457                 return;
    458         }
    459 
    460         /*
    461          * We are clearly expecting to find the mount point active.
    462          */
    463         if (!fn->mp_data.mp_active) {
    464                 (void) ops->node_put(fn);
    465                 async_answer_0(rid, EINVAL);
    466                 return;
    467         }
    468 
    469         /*
    470          * Tell the mounted file system to unmount.
    471          */
    472         async_exch_t *exch = async_exchange_begin(fn->mp_data.sess);
    473         res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.service_id);
    474         async_exchange_end(exch);
    475 
    476         /*
    477          * If everything went well, perform the clean-up on our side.
    478          */
    479         if (res == EOK) {
    480                 async_hangup(fn->mp_data.sess);
    481                 fn->mp_data.mp_active = false;
    482                 fn->mp_data.fs_handle = 0;
    483                 fn->mp_data.service_id = 0;
    484                 fn->mp_data.sess = NULL;
    485                
    486                 /* Drop the reference created in libfs_mount(). */
    487                 (void) ops->node_put(fn);
    488         }
    489 
    490         (void) ops->node_put(fn);
    491         async_answer_0(rid, res);
    492 }
    493 
    494 static char plb_get_char(unsigned pos)
    495 {
    496         return reg.plb_ro[pos % PLB_SIZE];
     495        rc = ops->link(parent, child, component);
     496        ops->node_put(parent);
     497        ops->node_put(child);
     498        async_answer_0(rid, rc);
    497499}
    498500
     
    513515    ipc_call_t *req)
    514516{
    515         unsigned int first = IPC_GET_ARG1(*req);
    516         unsigned int last = IPC_GET_ARG2(*req);
    517         unsigned int next = first;
     517        unsigned first = IPC_GET_ARG1(*req);
     518        unsigned len = IPC_GET_ARG2(*req);
    518519        service_id_t service_id = IPC_GET_ARG3(*req);
    519         int lflag = IPC_GET_ARG4(*req);
    520         fs_index_t index = IPC_GET_ARG5(*req);
     520        fs_index_t index = IPC_GET_ARG4(*req);
     521        int lflag = IPC_GET_ARG5(*req);
     522       
     523        // TODO: Validate flags.
     524       
     525        unsigned next = first;
     526        unsigned last = first + len;
     527       
    521528        char component[NAME_MAX + 1];
    522         int len;
    523529        int rc;
    524        
    525         if (last < next)
    526                 last += PLB_SIZE;
    527530       
    528531        fs_node_t *par = NULL;
    529532        fs_node_t *cur = NULL;
    530533        fs_node_t *tmp = NULL;
    531        
    532         rc = ops->root_get(&cur, service_id);
    533         on_error(rc, goto out_with_answer);
    534        
    535         if (cur->mp_data.mp_active) {
    536                 async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
    537                 async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
    538                     cur->mp_data.service_id, lflag, index,
    539                     IPC_FF_ROUTE_FROM_ME);
    540                 async_exchange_end(exch);
     534        unsigned clen = 0;
     535       
     536        rc = ops->node_get(&cur, service_id, index);
     537        if (rc != EOK) {
     538                async_answer_0(rid, rc);
     539                goto out;
     540        }
     541       
     542        assert(cur != NULL);
     543       
     544        /* Find the file and its parent. */
     545       
     546        unsigned last_next = 0;
     547       
     548        while (next != last) {
     549                if (cur == NULL) {
     550                        assert(par != NULL);
     551                        goto out1;
     552                }
     553
     554                if (!ops->is_directory(cur)) {
     555                        async_answer_0(rid, ENOTDIR);
     556                        goto out;
     557                }
    541558               
    542                 (void) ops->node_put(cur);
    543                 return;
    544         }
    545        
    546         /* Eat slash */
    547         if (plb_get_char(next) == '/')
    548                 next++;
    549        
    550         while (next <= last) {
    551                 bool has_children;
     559                last_next = next;
     560                /* Collect the component */
     561                rc = plb_get_component(component, &clen, &next, last);
     562                assert(rc != ERANGE);
     563                if (rc != EOK) {
     564                        async_answer_0(rid, rc);
     565                        goto out;
     566                }
    552567               
    553                 rc = ops->has_children(&has_children, cur);
    554                 on_error(rc, goto out_with_answer);
    555                 if (!has_children)
    556                         break;
     568                if (clen == 0) {
     569                        /* The path is just "/". */
     570                        break;
     571                }
    557572               
    558                 /* Collect the component */
    559                 len = 0;
    560                 while ((next <= last) && (plb_get_char(next) != '/')) {
    561                         if (len + 1 == NAME_MAX) {
    562                                 /* Component length overflow */
    563                                 async_answer_0(rid, ENAMETOOLONG);
    564                                 goto out;
    565                         }
    566                         component[len++] = plb_get_char(next);
    567                         /* Process next character */
    568                         next++;
    569                 }
    570                
    571                 assert(len);
    572                 component[len] = '\0';
    573                 /* Eat slash */
    574                 next++;
     573                assert(component[clen] == 0);
    575574               
    576575                /* Match the component */
    577576                rc = ops->match(&tmp, cur, component);
    578                 on_error(rc, goto out_with_answer);
     577                if (rc != EOK) {
     578                        async_answer_0(rid, rc);
     579                        goto out;
     580                }
    579581               
    580                 /*
    581                  * If the matching component is a mount point, there are two
    582                  * legitimate semantics of the lookup operation. The first is
    583                  * the commonly used one in which the lookup crosses each mount
    584                  * point into the mounted file system. The second semantics is
    585                  * used mostly during unmount() and differs from the first one
    586                  * only in that the last mount point in the looked up path,
    587                  * which is also its last component, is not crossed.
    588                  */
    589 
    590                 if ((tmp) && (tmp->mp_data.mp_active) &&
    591                     (!(lflag & L_MP) || (next <= last))) {
    592                         if (next > last)
    593                                 next = last = first;
    594                         else
    595                                 next--;
    596                        
    597                         async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
    598                         async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
    599                             last, tmp->mp_data.service_id, lflag, index,
    600                             IPC_FF_ROUTE_FROM_ME);
    601                         async_exchange_end(exch);
    602                        
    603                         (void) ops->node_put(cur);
    604                         (void) ops->node_put(tmp);
    605                         if (par)
    606                                 (void) ops->node_put(par);
    607                         return;
     582                /* Descend one level */
     583                if (par) {
     584                        rc = ops->node_put(par);
     585                        if (rc != EOK) {
     586                                async_answer_0(rid, rc);
     587                                goto out;
     588                        }
    608589                }
    609590               
    610                 /* Handle miss: match amongst siblings */
    611                 if (!tmp) {
    612                         if (next <= last) {
    613                                 /* There are unprocessed components */
    614                                 async_answer_0(rid, ENOENT);
     591                par = cur;
     592                cur = tmp;
     593                tmp = NULL;
     594        }
     595       
     596        /* At this point, par is either NULL or a directory.
     597         * If cur is NULL, the looked up file does not exist yet.
     598         */
     599         
     600        assert(par == NULL || ops->is_directory(par));
     601        assert(par != NULL || cur != NULL);
     602       
     603        /* Check for some error conditions. */
     604       
     605        if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
     606                async_answer_0(rid, EISDIR);
     607                goto out;
     608        }
     609       
     610        if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
     611                async_answer_0(rid, ENOTDIR);
     612                goto out;
     613        }
     614       
     615        /* Unlink. */
     616       
     617        if (lflag & L_UNLINK) {
     618                if (!cur) {
     619                        async_answer_0(rid, ENOENT);
     620                        goto out;
     621                }
     622                if (!par) {
     623                        async_answer_0(rid, EINVAL);
     624                        goto out;
     625                }
     626               
     627                rc = ops->unlink(par, cur, component);
     628                if (rc == EOK) {
     629                        aoff64_t size = ops->size_get(cur);
     630                        async_answer_5(rid, fs_handle, service_id,
     631                            ops->index_get(cur),
     632                            (ops->is_directory(cur) << 16) | last,
     633                            LOWER32(size), UPPER32(size));
     634                } else {
     635                        async_answer_0(rid, rc);
     636                }
     637                goto out;
     638        }
     639       
     640        /* Create. */
     641       
     642        if (lflag & L_CREATE) {
     643                if (cur && (lflag & L_EXCLUSIVE)) {
     644                        async_answer_0(rid, EEXIST);
     645                        goto out;
     646                }
     647       
     648                if (!cur) {
     649                        rc = ops->create(&cur, service_id,
     650                            lflag & (L_FILE | L_DIRECTORY));
     651                        if (rc != EOK) {
     652                                async_answer_0(rid, rc);
     653                                goto out;
     654                        }
     655                        if (!cur) {
     656                                async_answer_0(rid, ENOSPC);
    615657                                goto out;
    616658                        }
    617659                       
    618                         /* Miss in the last component */
    619                         if (lflag & (L_CREATE | L_LINK)) {
    620                                 /* Request to create a new link */
    621                                 if (!ops->is_directory(cur)) {
    622                                         async_answer_0(rid, ENOTDIR);
    623                                         goto out;
    624                                 }
    625                                
    626                                 fs_node_t *fn;
    627                                 if (lflag & L_CREATE)
    628                                         rc = ops->create(&fn, service_id,
    629                                             lflag);
    630                                 else
    631                                         rc = ops->node_get(&fn, service_id,
    632                                             index);
    633                                 on_error(rc, goto out_with_answer);
    634                                
    635                                 if (fn) {
    636                                         rc = ops->link(cur, fn, component);
    637                                         if (rc != EOK) {
    638                                                 if (lflag & L_CREATE)
    639                                                         (void) ops->destroy(fn);
    640                                                 else
    641                                                         (void) ops->node_put(fn);
    642                                                 async_answer_0(rid, rc);
    643                                         } else {
    644                                                 (void) ops->node_put(cur);
    645                                                 cur = fn;
    646                                                 goto out_with_answer;
    647                                         }
    648                                 } else
    649                                         async_answer_0(rid, ENOSPC);
    650                                
     660                        rc = ops->link(par, cur, component);
     661                        if (rc != EOK) {
     662                                (void) ops->destroy(cur);
     663                                cur = NULL;
     664                                async_answer_0(rid, rc);
    651665                                goto out;
    652666                        }
    653                        
    654                         async_answer_0(rid, ENOENT);
    655                         goto out;
    656                 }
    657                
    658                 if (par) {
    659                         rc = ops->node_put(par);
    660                         on_error(rc, goto out_with_answer);
    661                 }
    662                
    663                 /* Descend one level */
    664                 par = cur;
    665                 cur = tmp;
    666                 tmp = NULL;
    667         }
    668        
    669         /* Handle miss: excessive components */
    670         if (next <= last) {
    671                 bool has_children;
    672                 rc = ops->has_children(&has_children, cur);
    673                 on_error(rc, goto out_with_answer);
    674                
    675                 if (has_children)
    676                         goto skip_miss;
    677                
    678                 if (lflag & (L_CREATE | L_LINK)) {
    679                         if (!ops->is_directory(cur)) {
    680                                 async_answer_0(rid, ENOTDIR);
    681                                 goto out;
    682                         }
    683                        
    684                         /* Collect next component */
    685                         len = 0;
    686                         while (next <= last) {
    687                                 if (plb_get_char(next) == '/') {
    688                                         /* More than one component */
    689                                         async_answer_0(rid, ENOENT);
    690                                         goto out;
    691                                 }
    692                                
    693                                 if (len + 1 == NAME_MAX) {
    694                                         /* Component length overflow */
    695                                         async_answer_0(rid, ENAMETOOLONG);
    696                                         goto out;
    697                                 }
    698                                
    699                                 component[len++] = plb_get_char(next);
    700                                 /* Process next character */
    701                                 next++;
    702                         }
    703                        
    704                         assert(len);
    705                         component[len] = '\0';
    706                        
    707                         fs_node_t *fn;
    708                         if (lflag & L_CREATE)
    709                                 rc = ops->create(&fn, service_id, lflag);
    710                         else
    711                                 rc = ops->node_get(&fn, service_id, index);
    712                         on_error(rc, goto out_with_answer);
    713                        
    714                         if (fn) {
    715                                 rc = ops->link(cur, fn, component);
    716                                 if (rc != EOK) {
    717                                         if (lflag & L_CREATE)
    718                                                 (void) ops->destroy(fn);
    719                                         else
    720                                                 (void) ops->node_put(fn);
    721                                         async_answer_0(rid, rc);
    722                                 } else {
    723                                         (void) ops->node_put(cur);
    724                                         cur = fn;
    725                                         goto out_with_answer;
    726                                 }
    727                         } else
    728                                 async_answer_0(rid, ENOSPC);
    729                        
    730                         goto out;
    731                 }
    732                
    733                 async_answer_0(rid, ENOENT);
     667                }
     668        }
     669       
     670        /* Return. */
     671out1:
     672        if (!cur) {
     673                async_answer_5(rid, fs_handle, service_id, ops->index_get(par),
     674                    last_next, -1, true);
    734675                goto out;
    735676        }
    736677       
    737 skip_miss:
    738        
    739         /* Handle hit */
    740         if (lflag & L_UNLINK) {
    741                 unsigned int old_lnkcnt = ops->lnkcnt_get(cur);
    742                 rc = ops->unlink(par, cur, component);
    743                
    744                 if (rc == EOK) {
    745                         aoff64_t size = ops->size_get(cur);
    746                         async_answer_5(rid, fs_handle, service_id,
    747                             ops->index_get(cur), LOWER32(size), UPPER32(size),
    748                             old_lnkcnt);
    749                 } else
    750                         async_answer_0(rid, rc);
    751                
    752                 goto out;
    753         }
    754        
    755         if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
    756             (lflag & L_LINK)) {
    757                 async_answer_0(rid, EEXIST);
    758                 goto out;
    759         }
    760        
    761         if ((lflag & L_FILE) && (ops->is_directory(cur))) {
    762                 async_answer_0(rid, EISDIR);
    763                 goto out;
    764         }
    765        
    766         if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
    767                 async_answer_0(rid, ENOTDIR);
    768                 goto out;
    769         }
    770 
    771         if ((lflag & L_ROOT) && par) {
    772                 async_answer_0(rid, EINVAL);
    773                 goto out;
    774         }
    775        
    776 out_with_answer:
    777        
    778         if (rc == EOK) {
    779                 if (lflag & L_OPEN)
    780                         rc = ops->node_open(cur);
    781                
    782                 if (rc == EOK) {
    783                         aoff64_t size = ops->size_get(cur);
    784                         async_answer_5(rid, fs_handle, service_id,
    785                             ops->index_get(cur), LOWER32(size), UPPER32(size),
    786                             ops->lnkcnt_get(cur));
    787                 } else
    788                         async_answer_0(rid, rc);
    789                
    790         } else
    791                 async_answer_0(rid, rc);
     678        aoff64_t size = ops->size_get(cur);
     679        async_answer_5(rid, fs_handle, service_id, ops->index_get(cur),
     680            (ops->is_directory(cur) << 16) | last, LOWER32(size),
     681            UPPER32(size));
    792682       
    793683out:
    794        
    795684        if (par)
    796685                (void) ops->node_put(par);
     
    862751        memset(&st, 0, sizeof(struct statfs));
    863752
     753        str_cpy(st.fs_name, sizeof(st.fs_name), fs_name);
     754
    864755        if (ops->size_block != NULL) {
    865756                rc = ops->size_block(service_id, &st.f_bsize);
     
    919810        async_answer_4(rid, rc, LOWER32(size), UPPER32(size),
    920811            ops->lnkcnt_get(fn),
    921             (ops->is_file(fn) ? L_FILE : 0) | (ops->is_directory(fn) ? L_DIRECTORY : 0));
     812            (ops->is_file(fn) ? L_FILE : 0) |
     813            (ops->is_directory(fn) ? L_DIRECTORY : 0));
    922814       
    923815        (void) ops->node_put(fn);
  • uspace/lib/fs/libfs.h

    r39f892a9 r368ee04  
    5656
    5757typedef struct {
    58         bool mp_active;
    59         async_sess_t *sess;
    60         fs_handle_t fs_handle;
    61         service_id_t service_id;
    62 } mp_data_t;
    63 
    64 typedef struct {
    65         mp_data_t mp_data;  /**< Mount point info. */
    6658        void *data;         /**< Data of the file system implementation. */
    6759} fs_node_t;
  • uspace/lib/gui/window.c

    r39f892a9 r368ee04  
    3737#include <errno.h>
    3838#include <stdio.h>
     39#include <stdlib.h>
    3940
    4041#include <as.h>
  • uspace/lib/pcut/src/os/generic.c

    r39f892a9 r368ee04  
    137137        fread(extra_output_buffer, 1, OUTPUT_BUFFER_SIZE, tempfile);
    138138        fclose(tempfile);
    139         remove(tempfile_name);
     139        unlink(tempfile_name);
    140140
    141141        pcut_report_test_done_unparsed(test, rc, extra_output_buffer, OUTPUT_BUFFER_SIZE);
  • uspace/lib/pcut/src/os/helenos.c

    r39f892a9 r368ee04  
    4141#include <stdio.h>
    4242#include <task.h>
    43 #include <fcntl.h>
    4443#include <fibril_synch.h>
     44#include <vfs/vfs.h>
    4545#include "../internal.h"
    4646
     
    161161        char tempfile_name[PCUT_TEMP_FILENAME_BUFFER_SIZE];
    162162        snprintf(tempfile_name, PCUT_TEMP_FILENAME_BUFFER_SIZE - 1, "pcut_%lld.tmp", (unsigned long long) task_get_id());
    163         int tempfile = open(tempfile_name, O_CREAT | O_RDWR);
     163        int tempfile = vfs_lookup_open(tempfile_name, WALK_REGULAR | WALK_MAY_CREATE, MODE_READ | MODE_WRITE);
    164164        if (tempfile < 0) {
    165165                pcut_report_test_done(test, TEST_OUTCOME_ERROR, "Failed to create temporary file.", NULL, NULL);
     
    169169        char test_number_argument[MAX_TEST_NUMBER_WIDTH];
    170170        snprintf(test_number_argument, MAX_TEST_NUMBER_WIDTH, "-t%d", test->id);
    171 
    172         int *files[4];
    173         int fd_stdin = fileno(stdin);
    174         files[0] = &fd_stdin;
    175         files[1] = &tempfile;
    176         files[2] = &tempfile;
    177         files[3] = NULL;
    178171
    179172        const char *const arguments[3] = {
     
    186179
    187180        task_wait_t test_task_wait;
    188         int rc = task_spawnvf(&test_task_id, &test_task_wait, self_path, arguments, files);
     181        int rc = task_spawnvf(&test_task_id, &test_task_wait, self_path, arguments,
     182            fileno(stdin), tempfile, tempfile);
    189183        if (rc != EOK) {
    190184                status = TEST_OUTCOME_ERROR;
     
    220214        fibril_mutex_unlock(&forced_termination_mutex);
    221215
    222         read(tempfile, extra_output_buffer, OUTPUT_BUFFER_SIZE);
     216        aoff64_t pos = 0;
     217        vfs_read(tempfile, &pos, extra_output_buffer, OUTPUT_BUFFER_SIZE);
    223218
    224219leave_close_tempfile:
    225         close(tempfile);
    226         unlink(tempfile_name);
     220        vfs_put(tempfile);
     221        vfs_unlink_path(tempfile_name);
    227222
    228223        pcut_report_test_done_unparsed(test, status, extra_output_buffer, OUTPUT_BUFFER_SIZE);
  • uspace/lib/posix/include/posix/fcntl.h

    r39f892a9 r368ee04  
    4141
    4242#include "sys/types.h"
    43 #include "libc/fcntl.h"
    4443#include "errno.h"
     44
     45#undef O_CREAT
     46#undef O_EXCL
     47#undef O_TRUNC
     48#undef O_APPEND
     49#undef O_RDONLY
     50#undef O_RDWR
     51#undef O_WRONLY
     52#define O_CREAT   1
     53#define O_EXCL    2
     54#define O_TRUNC   4
     55#define O_APPEND  8
     56#define O_RDONLY  16
     57#define O_RDWR    32
     58#define O_WRONLY  64
    4559
    4660/* Mask for file access modes. */
  • uspace/lib/posix/include/posix/sys/stat.h

    r39f892a9 r368ee04  
    115115        __POSIX_DEF__(dev_t)     st_dev;     /* ID of device containing file */
    116116        __POSIX_DEF__(ino_t)     st_ino;     /* inode number */
    117         mode_t          st_mode;    /* protection */
     117        __POSIX_DEF__(mode_t)    st_mode;    /* protection */
    118118        __POSIX_DEF__(nlink_t)   st_nlink;   /* number of hard links */
    119119        __POSIX_DEF__(uid_t)     st_uid;     /* user ID of owner */
     
    131131extern int __POSIX_DEF__(lstat)(const char *restrict path, struct __POSIX_DEF__(stat) *restrict st);
    132132extern int __POSIX_DEF__(stat)(const char *restrict path, struct __POSIX_DEF__(stat) *restrict st);
    133 extern int __POSIX_DEF__(chmod)(const char *path, mode_t mode);
    134 extern mode_t __POSIX_DEF__(umask)(mode_t mask);
    135 extern int mkdir(const char *, mode_t);
     133extern int __POSIX_DEF__(chmod)(const char *path, __POSIX_DEF__(mode_t) mode);
     134extern __POSIX_DEF__(mode_t) __POSIX_DEF__(umask)(__POSIX_DEF__(mode_t) mask);
     135extern int __POSIX_DEF__(mkdir)(const char *path, __POSIX_DEF__(mode_t) mode);
    136136
    137137
  • uspace/lib/posix/include/posix/sys/types.h

    r39f892a9 r368ee04  
    5353typedef int64_t __POSIX_DEF__(pid_t);
    5454typedef sysarg_t __POSIX_DEF__(dev_t);
     55typedef unsigned int __POSIX_DEF__(mode_t);
    5556
    5657/* PThread Types */
  • uspace/lib/posix/source/fcntl.c

    r39f892a9 r368ee04  
    100100 *
    101101 * @param pathname Path to the file.
    102  * @param flags Access mode flags.
     102 * @param posix_flags Access mode flags.
    103103 */
    104 int posix_open(const char *pathname, int flags, ...)
     104int posix_open(const char *pathname, int posix_flags, ...)
    105105{
    106         mode_t mode = 0;
    107         if ((flags & O_CREAT) > 0) {
     106        int rc;
     107        posix_mode_t posix_mode = 0;
     108        if (posix_flags & O_CREAT) {
    108109                va_list args;
    109                 va_start(args, flags);
    110                 mode = va_arg(args, mode_t);
     110                va_start(args, posix_flags);
     111                posix_mode = va_arg(args, posix_mode_t);
    111112                va_end(args);
     113                (void) posix_mode;
    112114        }
    113115
    114         return negerrno(open, pathname, flags, mode);
     116        if (((posix_flags & (O_RDONLY | O_WRONLY | O_RDWR)) == 0) ||
     117            ((posix_flags & (O_RDONLY | O_WRONLY)) == (O_RDONLY | O_WRONLY)) ||
     118            ((posix_flags & (O_RDONLY | O_RDWR)) == (O_RDONLY | O_RDWR)) ||
     119            ((posix_flags & (O_WRONLY | O_RDWR)) == (O_WRONLY | O_RDWR))) {
     120                errno = EINVAL;
     121                return -1;
     122        }
     123
     124        int flags = WALK_REGULAR;
     125        if (posix_flags & O_CREAT) {
     126                if (posix_flags & O_EXCL)
     127                        flags |= WALK_MUST_CREATE;
     128                else
     129                        flags |= WALK_MAY_CREATE;
     130        }
     131
     132        int mode =
     133            ((posix_flags & O_RDWR) ? MODE_READ | MODE_WRITE : 0) |
     134            ((posix_flags & O_RDONLY) ? MODE_READ : 0) |
     135            ((posix_flags & O_WRONLY) ? MODE_WRITE : 0) |
     136            ((posix_flags & O_APPEND) ? MODE_APPEND : 0);
     137
     138        int file = rcerrno(vfs_lookup, pathname, flags);
     139        if (file < 0)
     140                return -1;
     141
     142        rc = rcerrno(vfs_open, file, mode);
     143        if (rc != EOK) {
     144                vfs_put(file);
     145                return -1;
     146        }
     147
     148        if (posix_flags & O_TRUNC) {
     149                if (posix_flags & (O_RDWR | O_WRONLY)) {
     150                        rc = rcerrno(vfs_resize, file, 0);
     151                        if (rc != EOK) {
     152                                vfs_put(file);
     153                                return -1;
     154                        }
     155                }
     156        }
     157
     158        return file;
    115159}
    116160
    117161/** @}
    118162 */
     163
  • uspace/lib/posix/source/internal/common.h

    r39f892a9 r368ee04  
    3838#include <stdio.h>
    3939#include <stdlib.h>
     40#include <sys/types.h>
     41#include <vfs/vfs.h>
    4042
    4143#define not_implemented() do { \
     
    5759})
    5860
     61/* Convert error code to positive errno and -1 return value */
     62#define rcerrno(func, ...) ({ \
     63        int rc = func(__VA_ARGS__); \
     64        if (rc < 0) \
     65                errno = -rc; \
     66        rc; \
     67})
     68
     69extern aoff64_t posix_pos[MAX_OPEN_FILES];
     70
    5971#endif /* LIBPOSIX_COMMON_H_ */
    6072
  • uspace/lib/posix/source/stdio.c

    r39f892a9 r368ee04  
    5353#include "libc/malloc.h"
    5454#include "libc/adt/list.h"
    55 #include "libc/sys/stat.h"
    5655
    5756/** Clears the stream's error and end-of-file indicators.
     
    344343static int _dprintf_str_write(const char *str, size_t size, void *fd)
    345344{
    346         ssize_t wr = write(*(int *) fd, str, size);
     345        const int fildes = *(int *) fd;
     346        ssize_t wr = vfs_write(fildes, &posix_pos[fildes], str, size);
    347347        if (wr < 0)
    348                 return errno;
     348                return wr;
    349349        return str_nlength(str, wr);
    350350}
     
    371371                }
    372372               
    373                 if (write(*(int *) fd, buf, sz) != (ssize_t) sz) {
     373                const int fildes = *(int *) fd;
     374                if (vfs_write(fildes, &posix_pos[fildes], buf, sz) < 0)
    374375                        break;
    375                 }
    376376               
    377377                chars++;
     
    575575int posix_remove(const char *path)
    576576{
    577         return negerrno(remove, path);
     577        if (rcerrno(vfs_unlink_path, path) != EOK)
     578                return -1;
     579        else
     580                return 0;
    578581}
    579582
     
    587590int posix_rename(const char *old, const char *new)
    588591{
    589         return negerrno(rename, old, new);
     592        int rc = rcerrno(vfs_rename_path, old, new);
     593        if (rc != EOK)
     594                return -1;
     595        else
     596                return 0;
    590597}
    591598
  • uspace/lib/posix/source/stdlib.c

    r39f892a9 r368ee04  
    431431                }
    432432               
    433                 fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
     433                fd = posix_open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    434434               
    435435                if (fd == -1) {
  • uspace/lib/posix/source/sys/stat.c

    r39f892a9 r368ee04  
    3939#include "../internal/common.h"
    4040#include "posix/sys/stat.h"
    41 #include "libc/sys/stat.h"
     41#include "libc/vfs/vfs.h"
    4242
    4343#include "posix/errno.h"
     
    4949 * @param dest POSIX stat struct.
    5050 * @param src HelenOS stat struct.
     51 *
     52 * @return 0 on success, -1 on error.
    5153 */
    52 static void stat_to_posix(struct posix_stat *dest, struct stat *src)
     54static int stat_to_posix(struct posix_stat *dest, struct stat *src)
    5355{
    5456        memset(dest, 0, sizeof(struct posix_stat));
     
    6870        dest->st_nlink = src->lnkcnt;
    6971        dest->st_size = src->size;
     72
     73        if (src->size > INT64_MAX) {
     74                errno = ERANGE;
     75                return -1;
     76        }
     77
     78        return 0;
    7079}
    7180
     
    8089{
    8190        struct stat hst;
    82         int rc = negerrno(fstat, fd, &hst);
     91        int rc = rcerrno(vfs_stat, fd, &hst);
    8392        if (rc < 0)
    84                 return rc;
    85         stat_to_posix(st, &hst);
    86         return 0;
     93                return -1;
     94        return stat_to_posix(st, &hst);
    8795}
    8896
     
    110118{
    111119        struct stat hst;
    112         int rc = negerrno(stat, path, &hst);
     120        int rc = rcerrno(vfs_stat_path, path, &hst);
    113121        if (rc < 0)
    114                 return rc;
    115         stat_to_posix(st, &hst);
    116         return 0;
     122                return -1;
     123        return stat_to_posix(st, &hst);
    117124}
    118125
     
    124131 * @return Zero on success, -1 otherwise.
    125132 */
    126 int posix_chmod(const char *path, mode_t mode)
     133int posix_chmod(const char *path, posix_mode_t mode)
    127134{
    128135        /* HelenOS doesn't support permissions, return success. */
     
    137144 * @return Previous file mode creation mask.
    138145 */
    139 mode_t posix_umask(mode_t mask)
     146posix_mode_t posix_umask(posix_mode_t mask)
    140147{
    141148        /* HelenOS doesn't support permissions, return empty mask. */
     
    143150}
    144151
     152/**
     153 * Create a directory.
     154 *
     155 * @param path Path to the new directory.
     156 * @param mode Permission bits to be set.
     157 * @return Zero on success, -1 otherwise.
     158 */
     159int posix_mkdir(const char *path, posix_mode_t mode)
     160{
     161        int rc = rcerrno(vfs_link_path, path, KIND_DIRECTORY, NULL);
     162        if (rc != EOK)
     163                return -1;
     164        else
     165                return 0;
     166}
     167
    145168/** @}
    146169 */
  • uspace/lib/posix/source/unistd.c

    r39f892a9 r368ee04  
    4747#include "libc/stats.h"
    4848#include "libc/malloc.h"
     49#include "libc/vfs/vfs.h"
     50
     51aoff64_t posix_pos[MAX_OPEN_FILES];
    4952
    5053/* Array of environment variable strings (NAME=VALUE). */
     
    105108char *posix_getcwd(char *buf, size_t size)
    106109{
    107         char *p = getcwd(buf, size);
    108 
    109         if (p == NULL) {
    110                 errno = -errno;
     110        int rc = rcerrno(vfs_cwd_get, buf, size);
     111        if (rc != EOK)
    111112                return NULL;
    112         }
    113 
    114         return p;
     113        return buf;
    115114}
    116115
     
    122121int posix_chdir(const char *path)
    123122{
    124         return negerrno(chdir, path);
     123        int rc = rcerrno(vfs_cwd_set, path);
     124        if (rc != EOK)
     125                return -1;
     126        return 0;
    125127}
    126128
     
    175177int posix_close(int fildes)
    176178{
    177         return negerrno(close, fildes);
     179        posix_pos[fildes] = 0;
     180        int rc = rcerrno(vfs_put, fildes);
     181        if (rc != EOK)
     182                return -1;
     183        else
     184                return 0;
    178185}
    179186
     
    188195ssize_t posix_read(int fildes, void *buf, size_t nbyte)
    189196{
    190         return negerrno(read, fildes, buf, nbyte);
     197        ssize_t size = rcerrno(vfs_read, fildes, &posix_pos[fildes], buf, nbyte);
     198        if (size < 0)
     199                return -1;
     200        return size;
    191201}
    192202
     
    201211ssize_t posix_write(int fildes, const void *buf, size_t nbyte)
    202212{
    203         return negerrno(write, fildes, buf, nbyte);
     213        ssize_t size = rcerrno(vfs_write, fildes, &posix_pos[fildes], buf, nbyte);
     214        if (size < 0)
     215                return -1;
     216        return size;
    204217}
    205218
     
    215228posix_off_t posix_lseek(int fildes, posix_off_t offset, int whence)
    216229{
    217         return negerrno(lseek, fildes, offset, whence);
     230        struct stat st;
     231        int rc;
     232
     233        switch (whence) {
     234        case SEEK_SET:
     235                posix_pos[fildes] = offset;
     236                break;
     237        case SEEK_CUR:
     238                posix_pos[fildes] += offset;
     239                break;
     240        case SEEK_END:
     241                rc = rcerrno(vfs_stat, fildes, &st);
     242                if (rc != EOK)
     243                        return -1;
     244                posix_pos[fildes] = st.size + offset;
     245                break;
     246        }
     247        if (posix_pos[fildes] > INT64_MAX) {
     248                /* The native width is too large for the POSIX interface. */
     249                errno = ERANGE;
     250                return -1;
     251        }
     252        return posix_pos[fildes];
    218253}
    219254
     
    226261int posix_fsync(int fildes)
    227262{
    228         return negerrno(fsync, fildes);
     263        if (rcerrno(vfs_sync, fildes) != EOK)
     264                return -1;
     265        else
     266                return 0;
    229267}
    230268
     
    238276int posix_ftruncate(int fildes, posix_off_t length)
    239277{
    240         return negerrno(ftruncate, fildes, (aoff64_t) length);
     278        if (rcerrno(vfs_resize, fildes, (aoff64_t) length) != EOK)
     279                return -1;
     280        else
     281                return 0;
    241282}
    242283
     
    249290int posix_rmdir(const char *path)
    250291{
    251         return negerrno(rmdir, path);
     292        if (rcerrno(vfs_unlink_path, path) != EOK)
     293                return -1;
     294        else
     295                return 0;
    252296}
    253297
     
    260304int posix_unlink(const char *path)
    261305{
    262         return negerrno(unlink, path);
     306        if (rcerrno(vfs_unlink_path, path) != EOK)
     307                return -1;
     308        else
     309                return 0;
    263310}
    264311
     
    284331int posix_dup2(int fildes, int fildes2)
    285332{
    286         return negerrno(dup2, fildes, fildes2);
     333        return negerrno(vfs_clone, fildes, fildes2, false);
    287334}
    288335
     
    302349                 * Check file existence by attempting to open it.
    303350                 */
    304                 int fd = negerrno(open, path, O_RDONLY);
    305                 if (fd < 0) {
    306                         /* errno was set by open() */
     351                int fd = posix_open(path, O_RDONLY);
     352                if (fd < 0)
    307353                        return -1;
    308                 }
    309                 close(fd);
     354                posix_close(fd);
    310355                return 0;
    311356        } else {
Note: See TracChangeset for help on using the changeset viewer.