Esempio n. 1
0
int fatfs_unlink(vnode_t * dir, const char * name)
{
    struct fatfs_sb * ffsb = get_ffsb_of_sb(dir->sb);
    struct fatfs_inode * indir = get_inode_of_vnode(dir);
    char * in_fpath;
    FRESULT err;
    int retval;

    if (!S_ISDIR(dir->vn_mode))
        return -ENOTDIR;

    in_fpath = format_fpath(indir, name);
    if (!in_fpath)
        return -ENOMEM;

    /* TODO May need checks if file/dir is opened */

    err = f_unlink(&ffsb->ff_fs, in_fpath);
    if (err)
        retval = fresult2errno(err);
    else
        retval = 0;

    kfree(in_fpath);
    return retval;
}
Esempio n. 2
0
int fatfs_open(const char *pathname, int flags)
{
    int ret;
    int fildes;
    FRESULT result;

    fildes = file_alloc();
    if (fildes < 0)
    {
        errno = ENFILE;
        ret = -1;
    }
    else
    {
        result = fatfs_open_file_or_dir(pathname, flags, fildes);
        if (result == FR_OK)
        {
            ret = fildes;
        }
        else
        {
            errno = fresult2errno(result);
            file_free(fildes);
            ret = -1;
        }
    }

    return ret;
}
Esempio n. 3
0
ssize_t fatfs_write(file_t * file, struct uio * uio, size_t count)
{
    void * buf;
    struct fatfs_inode * in = get_inode_of_vnode(file->vnode);
    size_t count_out;
    int err;

    if (!S_ISREG(file->vnode->vn_mode))
        return -EOPNOTSUPP;

    err = f_lseek(&in->fp, file->seek_pos);
    if (err)
        return -EIO;

    err = uio_get_kaddr(uio, &buf);
    if (err)
        return err;

    err = f_write(&in->fp, buf, count, &count_out);
    if (err)
        return fresult2errno(err);

    file->seek_pos = f_tell(&in->fp);

    return count_out;
}
Esempio n. 4
0
int fatfs_readdir(vnode_t * dir, struct dirent * d, off_t * off)
{
    struct fatfs_inode * in = get_inode_of_vnode(dir);
    FILINFO fno;
    int err;

    if (!S_ISDIR(dir->vn_mode))
        return -ENOTDIR;

    /* Emulate . and .. */
    if (*off == DIRENT_SEEK_START) {
        f_readdir(&in->dp, NULL); /* Rewind */

        strlcpy(d->d_name, ".", sizeof(d->d_name));
        d->d_ino = dir->vn_num;
        d->d_type = DT_DIR;
        *off = DIRENT_SEEK_START + 1;

        return 0;
    } else if (*off == DIRENT_SEEK_START + 1) {
        strlcpy(d->d_name, "..", sizeof(d->d_name));
        /* TODO Set d members to proper values */
        d->d_ino = 0; /* TODO ino should be properly set */
        d->d_type = DT_DIR;
        *off = DIRENT_SEEK_START + 2;

        return 0;
    }

#if configFATFS_LFN
    fno.lfname = d->d_name;
    fno.lfsize = NAME_MAX + 1;
#endif

    err = f_readdir(&in->dp, &fno);
    if (err)
        return fresult2errno(err);

    if (fno.fname[0] == '\0')
        return -ESPIPE;

    d->d_ino = fno.ino;
    d->d_type = (fno.fattrib & AM_DIR) ? DT_DIR : DT_REG;
#if configFATFS_LFN
    if (!*fno.lfname)
#endif
        strlcpy(d->d_name, fno.fname, sizeof(d->d_name));

    return 0;
}
Esempio n. 5
0
static
int fatfs_read (int fd, char *ptr, int len)
{
    int ret;
    struct fd *pfd;

    pfd = file_struct_get(fd);

    if (pfd == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (pfd->opaque == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (S_ISREG(pfd->stat.st_mode))
    {
        FIL *filp;
        FRESULT result;
        UINT nbytes_read;

        filp = pfd->opaque;

        result = f_read(filp, ptr, len, &nbytes_read);
        if (result == FR_OK)
        {
            ret = nbytes_read;
        }
        else
        {
            errno = fresult2errno(result);
            ret = -1;
        }
    }
    else if (S_ISDIR(pfd->stat.st_mode))
    {
        errno = EISDIR;
        ret = -1;
    }
    else
    {
        errno = EBADF;
        ret = -1;
    }

    return ret;
}
Esempio n. 6
0
int fatfs_unlink(const char *path)
{
    int ret;
    FRESULT result;

    result = f_unlink(path);
    if (result == FR_OK)
    {
        ret = 0;
    }
    else
    {
        errno = fresult2errno(result);
        ret = -1;
    }

    return ret;
}
Esempio n. 7
0
int fatfs_mknod(vnode_t * dir, const char * name, int mode, void * specinfo,
                vnode_t ** result)
{
    struct fatfs_inode * indir = get_inode_of_vnode(dir);
    struct fatfs_inode * res = NULL;
    char * in_fpath;
    int err;

#ifdef configFATFS_DEBUG
    KERROR(KERROR_DEBUG,
           "fatfs_mknod(dir %p, name \"%s\", mode %u, specinfo %p, result %p)\n",
           dir, name, mode, specinfo, result);
#endif

    if (!S_ISDIR(dir->vn_mode))
        return -ENOTDIR;

    if ((mode & S_IFMT) != S_IFREG)
        return -ENOTSUP; /* FAT only suports regular files. */

    if (specinfo)
        return -EINVAL; /* specinfo not supported. */

    in_fpath = format_fpath(indir, name);
    if (!in_fpath)
        return -ENOMEM;

    err = create_inode(&res, get_ffsb_of_sb(dir->sb), in_fpath,
                       hash32_str(in_fpath, 0), O_CREAT);
    if (err) {
        kfree(in_fpath);
        return fresult2errno(err);
    }

    if (result)
        *result = &res->in_vnode;
    fatfs_chmod(&res->in_vnode, mode);

#ifdef configFATFS_DEBUG
    KERROR(KERROR_DEBUG, "mkdod() ok\n");
#endif

    return 0;
}
Esempio n. 8
0
int fatfs_mkdir(vnode_t * dir,  const char * name, mode_t mode)
{
    struct fatfs_sb * ffsb = get_ffsb_of_sb(dir->sb);
    struct fatfs_inode * indir = get_inode_of_vnode(dir);
    char * in_fpath;
    FRESULT err;
    int retval = 0;

    if (!S_ISDIR(dir->vn_mode))
        return -ENOTDIR;

    in_fpath = format_fpath(indir, name);
    if (!in_fpath)
        return -ENOMEM;

    err = f_mkdir(&ffsb->ff_fs, in_fpath);
    if (err)
        retval = fresult2errno(err);

    kfree(in_fpath);
    return retval;
}
Esempio n. 9
0
int fatfs_rmdir(vnode_t * dir,  const char * name)
{
    int err;
    vnode_t * result;
    mode_t mode;
    FRESULT ferr;

    /* TODO Should fail if name is a mount point */

    if (!S_ISDIR(dir->vn_mode))
        return -ENOTDIR;

    err = fatfs_lookup(dir, name, &result);
    if (err)
        return err;
    mode = result->vn_mode;
    vrele_nunlink(result);
    if (!S_ISDIR(mode))
        return -ENOTDIR;

    ferr = fatfs_unlink(dir, name);

    return fresult2errno(ferr);
}
Esempio n. 10
0
int fatfs_stat(vnode_t * vnode, struct stat * buf)
{
    struct fatfs_sb * ffsb = get_ffsb_of_sb(vnode->sb);
    struct fatfs_inode * in = get_inode_of_vnode(vnode);
    FILINFO fno;
    struct stat mp_stat = { .st_uid = 0, .st_gid = 0 };
    size_t blksize = ffsb->ff_fs.ssize;
    int err;

    memset(&fno, 0, sizeof(fno));

    err = get_mp_stat(vnode, &mp_stat);
    if (err) {
        if (err == -EINPROGRESS) {
#ifdef configFATFS_DEBUG
            KERROR(KERROR_WARN, "vnode->sb->mountpoint should be set\n");
#endif
        } else {
#ifdef configFATFS_DEBUG
            KERROR(KERROR_WARN,
                   "get_mp_stat() returned error (%d)\n",
                   err);
#endif

            return err;
        }
    }

    /* Can't stat FAT root */
    if (vnode == vnode->sb->root) {
        memcpy(buf, &mp_stat, sizeof(struct stat));

        return 0;
    }

    err = f_stat(&ffsb->ff_fs, in->in_fpath, &fno);
    if (err) {
#ifdef configFATFS_DEBUG
        KERROR(KERROR_DEBUG,
                 "f_stat(fs %p, fpath \"%s\", fno %p) failed\n",
                 &ffsb->ff_fs, in->in_fpath, &fno);
#endif
        return fresult2errno(err);
    }

    buf->st_dev = vnode->sb->vdev_id;
    buf->st_ino = vnode->vn_num;
    buf->st_mode = vnode->vn_mode;
    buf->st_nlink = 1; /* Always one link on FAT. */
    buf->st_uid = mp_stat.st_uid;
    buf->st_gid = mp_stat.st_gid;
    buf->st_size = fno.fsize;
    /* TODO Times */
#if 0
    buf->st_atim;
    buf->st_mtim;
    buf->st_ctim;
    buf->st_birthtime;
#endif
    buf->st_flags = fattrib2uflags(fno.fattrib);
    buf->st_blksize = blksize;
    buf->st_blocks = fno.fsize / blksize + 1; /* Best guess. */

    return 0;
}

int fatfs_chmod(vnode_t * vnode, mode_t mode)
{
    struct fatfs_sb * ffsb = get_ffsb_of_sb(vnode->sb);
    struct fatfs_inode * in = get_inode_of_vnode(vnode);
    uint8_t attr = 0;
    const uint8_t mask = AM_RDO;
    int err;

    if (!(mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
        attr |= AM_RDO;

    err = fresult2errno(f_chmod(&ffsb->ff_fs, in->in_fpath, attr, mask));
    if (!err)
        vnode->vn_mode = mode;

    return err;
}

/*
 * Note: Thre is practically two ways to set AM_RDO, either
 * by using chmod() or by this chflags().
 */
int fatfs_chflags(vnode_t * vnode, fflags_t flags)
{
    struct fatfs_sb * ffsb = get_ffsb_of_sb(vnode->sb);
    struct fatfs_inode * in = get_inode_of_vnode(vnode);
    uint8_t attr = 0;
    const uint8_t mask = AM_RDO | AM_ARC | AM_SYS | AM_HID;
    FRESULT fresult;

    if (flags & UF_SYSTEM)
        attr |= AM_SYS;
    if (flags & UF_ARCHIVE)
        attr |= AM_ARC;
    if (flags & UF_READONLY)
        attr |= AM_RDO;
    if (flags & UF_HIDDEN)
        attr |= AM_HID;

    fresult = f_chmod(&ffsb->ff_fs, in->in_fpath, attr, mask);

    return fresult2errno(fresult);
}

/**
 * Initialize fatfs vnode data.
 * @param vnode is the target vnode to be initialized.
 */
static void init_fatfs_vnode(vnode_t * vnode, ino_t inum, mode_t mode,
                             long vn_hash, struct fs_superblock * sb)
{
    struct stat stat;

#ifdef configFATFS_DEBUG
    KERROR(KERROR_DEBUG,
           "init_fatfs_vnode(vnode %p, inum %l, mode %o, vn_hash %u, sb %p)\n",
           vnode, (uint64_t)inum, mode, (uint32_t)vn_hash, sb);
#endif

    fs_vnode_init(vnode, inum, sb, &fatfs_vnode_ops);

    vnode->vn_hash = vn_hash;

    if (S_ISDIR(mode))
        mode |= S_IRWXU | S_IXGRP | S_IXOTH;
    vnode->vn_mode = mode | S_IRUSR | S_IRGRP | S_IROTH;
    fatfs_stat(vnode, &stat);
    vnode->vn_len = stat.st_size;
    if ((stat.st_flags & UF_READONLY) == 0)
        vnode->vn_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
}

/**
 * Get mountpoint stat.
 */
static int get_mp_stat(vnode_t * vnode, struct stat * st)
{
     struct fs_superblock * sb;
     vnode_t * mp;

#ifdef configFATFS_DEBUG
    KASSERT(vnode, "Vnode was given");
    KASSERT(vnode->sb, "Superblock is set");
#endif

    sb = vnode->sb;
    mp = sb->mountpoint;

    if (!mp) {
        /* We are probably mounting and mountpoint is not yet set. */
#ifdef configFATFS_DEBUG
        KERROR(KERROR_DEBUG, "mp not set\n");
#endif
        return -EINPROGRESS;
    }

#ifdef configFATFS_DEBUG
    KASSERT(mp->vnode_ops->stat, "stat() is defined");
#endif

    return mp->vnode_ops->stat(mp, st);
}

static int fresult2errno(int fresult)
{
    switch (fresult) {
    case FR_DISK_ERR:
    case FR_INVALID_OBJECT:
    case FR_INT_ERR:
        return -EIO;
    case FR_NOT_ENABLED:
        return -ENODEV;
    case FR_NO_FILESYSTEM:
        return -ENXIO;
    case FR_NO_FILE:
    case FR_NO_PATH:
        return -ENOENT;
    case FR_DENIED:
        return -EACCES;
    case FR_EXIST:
        return -EEXIST;
    case FR_WRITE_PROTECTED:
        return -EPERM;
    case FR_NOT_READY:
        return -EBUSY;
    case FR_INVALID_NAME:
    case FR_INVALID_DRIVE:
    case FR_MKFS_ABORTED:
    case FR_INVALID_PARAMETER:
        return -EINVAL;
    case FR_TIMEOUT:
        return -EWOULDBLOCK;
    case FR_NOT_ENOUGH_CORE:
        return -ENOMEM;
    case FR_TOO_MANY_OPEN_FILES:
        return -ENFILE;
    default:
        if (fresult != 0) /* Unknown error */
            return -EIO;
    }

    return 0;
}
Esempio n. 11
0
/**
 * Create a inode.
 * @param fpath won't be duplicated.
 * @param oflags O_CREAT, O_DIRECTORY, O_RDONLY, O_WRONLY and O_RDWR
 *               currently supported.
 *               O_WRONLY/O_RDWR creates in write mode if possible, so this
 *               should be always verified with stat.
 */
static int create_inode(struct fatfs_inode ** result, struct fatfs_sb * sb,
                        char * fpath, long vn_hash, int oflags)
{
    struct fatfs_inode * in = NULL;
    FILINFO fno;
    vnode_t * vn;
    vnode_t * xvp;
    mode_t vn_mode;
    ino_t inum;
    int err = 0, retval = 0;

#ifdef configFATFS_DEBUG
    KERROR(KERROR_DEBUG, "create_inode(fpath \"%s\", vn_hash %u)\n",
             fpath, (uint32_t)vn_hash);
#endif

    in = kzalloc(sizeof(struct fatfs_inode));
    if (!in) {
        retval = -ENOMEM;
        goto fail;
    }
    in->in_fpath = fpath;
    vn = &in->in_vnode;

    in->open_count = ATOMIC_INIT(0);

    memset(&fno, 0, sizeof(fno));

    if (oflags & O_DIRECTORY) {
        /* O_DIRECTORY was specified. */
        /* TODO Maybe get mp stat? */
        fno.fattrib = AM_DIR;
    } else if (oflags & O_CREAT) {
        if (sb->sb.mode_flags & MNT_RDONLY)
            return -EROFS;
    } else {
        err = f_stat(&sb->ff_fs, fpath, &fno);
        if (err) {
            retval = fresult2errno(err);
            goto fail;
        }
    }

    /* Try open */
    if (fno.fattrib & AM_DIR) {
        /* it's a directory */
        vn_mode = S_IFDIR;
        err = f_opendir(&in->dp, &sb->ff_fs, in->in_fpath);
        if (err) {
#ifdef configFATFS_DEBUG
            KERROR(KERROR_DEBUG, "Can't open a dir (err: %d)\n", err);
#endif
            retval = fresult2errno(err);
            goto fail;
        }
        inum = in->dp.ino;
    } else {
        /* it's a file */
        unsigned char fomode = 0;

        fomode |= (oflags & O_CREAT) ? FA_OPEN_ALWAYS : FA_OPEN_EXISTING;
        /* The kernel should always have RW if possible. */
        if (sb->sb.mode_flags & MNT_RDONLY) {
            fomode |= FA_READ;
        } else {
            fomode |= FA_READ | FA_WRITE;
        }

        vn_mode = S_IFREG;
        err = f_open(&in->fp, &sb->ff_fs, in->in_fpath, fomode);
        if (err) {
#ifdef configFATFS_DEBUG
            KERROR(KERROR_DEBUG, "Can't open a file (err: %d)\n", err);
#endif
            retval = fresult2errno(err);
            goto fail;
        }
        inum = in->fp.ino;
    }

#ifdef configFATFS_DEBUG
    if (oflags & O_CREAT)
        KERROR(KERROR_DEBUG, "ff: Create & open ok\n");
    else
        KERROR(KERROR_DEBUG, "ff: Open ok\n");
#endif

    init_fatfs_vnode(vn, inum, vn_mode, vn_hash, &(sb->sb));

    /* Insert to the cache */
    err = vfs_hash_insert(vn, vn_hash, &xvp, fatfs_vncmp, fpath);
    if (err) {
        retval = -ENOMEM;
        goto fail;
    }
    if (xvp) {
        /* TODO No idea what to do now */
        KERROR(KERROR_WARN,
               "create_inode(): Found it during insert: \"%s\"\n",
               fpath);
    }

#ifdef configFATFS_DEBUG
    KERROR(KERROR_DEBUG, "create_inode(): ok\n");
#endif

    *result = in;
    vrefset(vn, 1); /* Make ref for the caller. */
    return 0;
fail:
#ifdef configFATFS_DEBUG
    KERROR(KERROR_DEBUG, "create_inode(): retval %i\n", retval);
#endif

    kfree(in);
    return retval;
}
Esempio n. 12
0
/**
 * Mount a new fatfs.
 * @param mode      mount flags.
 * @param param     contains optional mount parameters.
 * @param parm_len  length of param string.
 * @param[out] sb   Returns the superblock of the new mount.
 * @return error code, -errno.
 */
static int fatfs_mount(const char * source, uint32_t mode,
                       const char * parm, int parm_len,
                       struct fs_superblock ** sb)
{
    static dev_t fatfs_vdev_minor;
    struct fatfs_sb * fatfs_sb = NULL;
    vnode_t * vndev;
    char pdrv;
    int err, retval = 0;

    /* Get device vnode */
    err = lookup_vnode(&vndev, curproc->croot, source, 0);
    if (err) {
#ifdef configFATFS_DEBUG
        KERROR(KERROR_DEBUG, "fatfs source not found\n");
#endif
        return err;
    }
    if (!S_ISBLK(vndev->vn_mode))
        return -ENOTBLK;

    /* Allocate superblock */
    fatfs_sb = kzalloc(sizeof(struct fatfs_sb));
    if (!fatfs_sb)
        return -ENOMEM;

    fs_fildes_set(&fatfs_sb->ff_devfile, vndev, O_RDWR);
    fatfs_sb->sb.vdev_id = DEV_MMTODEV(VDEV_MJNR_FATFS, fatfs_vdev_minor++);

    /* Insert sb to fatfs_sb_arr lookup array */
    fatfs_sb_arr[DEV_MINOR(fatfs_sb->sb.vdev_id)] = fatfs_sb;

    /* Mount */
    pdrv = (char)DEV_MINOR(fatfs_sb->sb.vdev_id);
    err = f_mount(&fatfs_sb->ff_fs, 0);
    if (err) {
#ifdef configFATFS_DEBUG
        KERROR(KERROR_DEBUG, "Can't init a work area for FAT (%d)\n", err);
#endif
        retval = fresult2errno(err);
        goto fail;
    }
#ifdef configFATFS_DEBUG
    KERROR(KERROR_DEBUG, "Initialized a work area for FAT\n");
#endif

#if (_FS_NOFSINFO == 0) /* Commit full scan of free clusters */
    DWORD nclst;

    f_getfree(&fatfs_sb->ff_fs, &nclst);
#endif

    /* Init super block */
    fs_init_superblock(&fatfs_sb->sb, &fatfs_fs);
    /* TODO Detect if target dev is rdonly */
    fatfs_sb->sb.mode_flags = mode;
    fatfs_sb->sb.root = create_root(fatfs_sb);
    fatfs_sb->sb.sb_dev = vndev;
    fatfs_sb->sb.sb_hashseed = fatfs_sb->sb.vdev_id;
    /* Function pointers to superblock methods */
    fatfs_sb->sb.get_vnode = NULL; /* Not implemented for FAT. */
    fatfs_sb->sb.delete_vnode = fatfs_delete_vnode;
    fatfs_sb->sb.umount = NULL;

    if (!fatfs_sb->sb.root) {
        KERROR(KERROR_ERR, "Root of fatfs not found\n");

        return -EIO;
    }
    fs_insert_superblock(&fatfs_fs, &fatfs_sb->sb);

fail:
    if (retval) {
        fatfs_sb_arr[DEV_MINOR(fatfs_sb->sb.vdev_id)] = NULL;
        kfree(fatfs_sb);
    }

    *sb = &fatfs_sb->sb;
    return retval;
}
Esempio n. 13
0
off_t fatfs_lseek(int fd, off_t offset, int whence )
{
    off_t ret;
    struct fd *pfd;

    pfd = file_struct_get(fd);

    if (pfd == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (pfd->opaque == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (S_ISREG(pfd->stat.st_mode))
    {
        FIL *filp;
        FRESULT result;
        DWORD pos;

        filp = pfd->opaque;
        if (whence == SEEK_CUR)
        {
            pos = f_tell(filp);
        }
        else if (whence == SEEK_END)
        {
            pos = f_size(filp);
        }
        else if (whence == SEEK_CUR)
        {
            pos = 0;
        }
        else
        {
            /* TODO: error */
            pos = 0;
        }
        pos += offset;

        result = f_lseek(filp, pos);
        if (result == FR_OK)
        {
            ret = pos;
        }
        else
        {
            errno = fresult2errno(result);
            ret = -1;
        }
    }
    else
    {
        errno = EINVAL;
        ret = -1;
    }

    return ret;
}
Esempio n. 14
0
static
int fatfs_close (int fd)
{
    int ret;
    struct fd *pfd;

    pfd = file_struct_get(fd);

    if (pfd == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (pfd->opaque == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (S_ISREG(pfd->stat.st_mode))
    {
        FIL *filp;
        FRESULT result;

        filp = pfd->opaque;

        result = f_close(filp);
        if (result == FR_OK)
        {
            fatfs_fil_free(filp);
            file_free(fd);
            ret = 0;
        }
        else
        {
            errno = fresult2errno(result);
            ret = -1;
        }
    }
    else if (S_ISDIR(pfd->stat.st_mode))
    {
        DIR *dp;
        FRESULT result;

        dp = pfd->opaque;

        result = f_closedir(&dp->ffdir);
        if (result == FR_OK)
        {
            fatfs_dir_free(dp);
            file_free(fd);
            ret = 0;
        }
        else
        {
            errno = fresult2errno(result);
            ret = -1;
        }
    }
    else
    {
        errno = EBADF;
        ret = -1;
    }

    return ret;
}
Esempio n. 15
0
static
int fatfs_write (int fd, char *ptr, int len)
{
    int ret;
    struct fd *pfd;

    pfd = file_struct_get(fd);

    if (pfd == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (pfd->opaque == NULL)
    {
        errno = EBADF;
        ret = -1;
    }
    else if (S_ISREG(pfd->stat.st_mode))
    {
        FIL *filp;
        FRESULT result;
        UINT written;

        filp = pfd->opaque;

        if (pfd->status_flags & O_APPEND)
        {
            DWORD size;

            size = f_size(filp);
            result = f_lseek(filp, size);
        }
        else
        {
            result = FR_OK;
        }

        if (result == FR_OK)
        {
            result = f_write(filp, ptr, len, &written);
        }
        if (result == FR_OK)
        {
            ret = written;
        }
        else
        {
            errno = fresult2errno(result);
            ret = -1;
        }
    }
    else if (S_ISDIR(pfd->stat.st_mode))
    {
        errno = EISDIR;
        ret = -1;
    }
    else
    {
        errno = EBADF;
        ret = -1;
    }

    return ret;
}