diff --git a/TODO b/TODO index e5900af0373..9a78606f552 100644 --- a/TODO +++ b/TODO @@ -1369,19 +1369,45 @@ o File system / Generic drivers (fs/, drivers/) NOTE: The NXFFS file system has its own TODO list at nuttx/fs/nxffs/README.txt - Title: CHMOD(), TRUNCATE(), AND FSTAT() - Description: Implement chmod(), truncate(), and fstat(). + Title: MISSING FILE SYSTEM FEATURES + Description: Implement missing file system features: chmod() is probably not relevant since file modes are not currently supported. - fstat() may be doable: Most file system implement stat() by - looking up the directory entry associated with the path - then generating the struct stat data. But most file - systems also keep the directory entry in the private data - associated withe open file. So it should possible to - implement fstat() as a file system method and use that - saved directory entry to generate the stat data. + File privileges would also be good to support. But this is + really a small part of a much larger feature. NuttX has no + user IDs, there are no groups, there are no privileges + associated with either. User's don't need credentials. + This is really a system wide issues of which chmod is only + a small part. + + User privileges never seemed important to me since NuttX is + intended for deeply embedded environments where there are + not multiple users with varying levels of trust. + + truncate - The standard way of setting a fixed file size. + Often used with random access, data base files. There is no + simple way of doing that now (other than just writing data + to the file). + + fstat(): Currently in work. The unverified solution is on + the 'fstat' branch in the repository. + + link, unlink, softlink, readlink - For symbolic links. Only + the ROMFS file system currently supports hard and soft links, + so this is not too important. + + File locking + + Special files - NuttX support special files only in the top- + level pseudo file system. Unix systems support many + different special files via mknod(). This would be + important only if it is an objective of NuttX to become a + true Unix OS. Again only supported by ROMFS. + + True inodes - Standard Unix inodes. Currently only supported + by ROMFs. The primary obstacle to all these is that each would require changes to all existing file systems. That number is pretty diff --git a/fs/binfs/fs_binfs.c b/fs/binfs/fs_binfs.c index dd5b1a976f9..f084710792c 100644 --- a/fs/binfs/fs_binfs.c +++ b/fs/binfs/fs_binfs.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/binfs/fs_binfs.c * - * Copyright (C) 2011-2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2013, 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -70,6 +70,7 @@ static ssize_t binfs_read(FAR struct file *filep, char *buffer, size_t buflen); static int binfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int binfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int binfs_fstat(FAR const struct file *filep, FAR struct stat *buf); static int binfs_opendir(struct inode *mountpt, const char *relpath, struct fs_dirent_s *dir); @@ -108,6 +109,7 @@ const struct mountpt_operations binfs_operations = NULL, /* sync */ binfs_dup, /* dup */ + binfs_fstat, /* fstat */ binfs_opendir, /* opendir */ NULL, /* closedir */ @@ -245,6 +247,28 @@ static int binfs_dup(FAR const struct file *oldp, FAR struct file *newp) return OK; } +/**************************************************************************** + * Name: binfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int binfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ + DEBUGASSERT(filep != NULL && buf != NULL); + + /* It's a execute-only file system */ + + buf->st_mode = S_IFREG | S_IXOTH | S_IXGRP | S_IXUSR; + buf->st_size = 0; + buf->st_blksize = 0; + buf->st_blocks = 0; + return OK; +} + /**************************************************************************** * Name: binfs_opendir * diff --git a/fs/fat/fs_fat32.c b/fs/fat/fs_fat32.c index 4ddf1e5f8e3..806de2f4f6f 100644 --- a/fs/fat/fs_fat32.c +++ b/fs/fat/fs_fat32.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/fat/fs_fat32.c * - * Copyright (C) 2007-2009, 2011-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -84,6 +84,8 @@ static int fat_ioctl(FAR struct file *filep, int cmd, static int fat_sync(FAR struct file *filep); static int fat_dup(FAR const struct file *oldp, FAR struct file *newp); +static int fat_fstat(FAR const struct file *filep, + FAR struct stat *buf); static int fat_opendir(FAR struct inode *mountpt, FAR const char *relpath, FAR struct fs_dirent_s *dir); @@ -106,6 +108,12 @@ static int fat_mkdir(FAR struct inode *mountpt, FAR const char *relpath, static int fat_rmdir(FAR struct inode *mountpt, FAR const char *relpath); static int fat_rename(FAR struct inode *mountpt, FAR const char *oldrelpath, FAR const char *newrelpath); +static int fat_stat_common(FAR struct fat_mountpt_s *fs, + FAR uint8_t *direntry, FAR struct stat *buf); +static int fat_stat_file(FAR struct fat_mountpt_s *fs, + FAR uint8_t *direntry, FAR struct stat *buf); +static int fat_stat_root(FAR struct fat_mountpt_s *fs, + FAR uint8_t *direntry, FAR struct stat *buf); static int fat_stat(struct inode *mountpt, const char *relpath, FAR struct stat *buf); @@ -129,6 +137,7 @@ const struct mountpt_operations fat_operations = fat_sync, /* sync */ fat_dup, /* dup */ + fat_fstat, /* fstat */ fat_opendir, /* opendir */ NULL, /* closedir */ @@ -1606,6 +1615,76 @@ errout_with_semaphore: return ret; } +/**************************************************************************** + * Name: fat_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int fat_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ + FAR struct inode *inode; + FAR struct fat_mountpt_s *fs; + FAR struct fat_file_s *ff; + uint8_t *direntry; + int ret; + + /* Sanity checks */ + + DEBUGASSERT(filep->f_priv == NULL && filep->f_inode != NULL); + + /* Get the mountpoint inode reference from the file structure and the + * mountpoint private data from the inode structure + */ + + inode = filep->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL); + + /* Check if the mount is still healthy */ + + fat_semtake(fs); + ret = fat_checkmount(fs); + if (ret != OK) + { + goto errout_with_semaphore; + } + + /* Recover our private data from the struct file instance */ + + ff = filep->f_priv; + + /* Update the directory entry. First read the directory + * entry into the fs_buffer (preserving the ff_buffer) + */ + + ret = fat_fscacheread(fs, ff->ff_dirsector); + if (ret < 0) + { + goto errout_with_semaphore; + } + + /* Recover a pointer to the specific directory entry in the sector using + * the saved directory index. + */ + + direntry = &fs->fs_buffer[(ff->ff_dirindex & DIRSEC_NDXMASK(fs)) * DIR_SIZE]; + + /* Call fat_stat_file() to create the buf and to save information to + * it. + */ + + ret = fat_stat_file(fs, direntry, buf); + +errout_with_semaphore: + fat_semgive(fs); + return ret; +} + /**************************************************************************** * Name: fat_readdir * @@ -2487,6 +2566,123 @@ errout_with_semaphore: return ret; } +/**************************************************************************** + * Name: fat_stat_common + * + * Description: + * Common logic used by fat_stat_file() and fat_fstat_root(). + * + ****************************************************************************/ + +static int fat_stat_common(FAR struct fat_mountpt_s *fs, + FAR uint8_t *direntry, FAR struct stat *buf) +{ + uint16_t fatdate; + uint16_t date2; + uint16_t fattime; + + /* Times */ + + fatdate = DIR_GETWRTDATE(direntry); + fattime = DIR_GETWRTTIME(direntry); + buf->st_mtime = fat_fattime2systime(fattime, fatdate); + + date2 = DIR_GETLASTACCDATE(direntry); + if (fatdate == date2) + { + buf->st_atime = buf->st_mtime; + } + else + { + buf->st_atime = fat_fattime2systime(0, date2); + } + + fatdate = DIR_GETCRDATE(direntry); + fattime = DIR_GETCRTIME(direntry); + buf->st_ctime = fat_fattime2systime(fattime, fatdate); + + /* File/directory size, access block size */ + + buf->st_size = DIR_GETFILESIZE(direntry); + buf->st_blksize = fs->fs_fatsecperclus * fs->fs_hwsectorsize; + buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / buf->st_blksize; + + return OK; +} + +/**************************************************************************** + * Name: fat_stat_file + * + * Description: + * Function to return the status associated with a file in the FAT file + * system. Used by fat_stat() and fat_fstat(). + * + ****************************************************************************/ + +static int fat_stat_file(FAR struct fat_mountpt_s *fs, + FAR uint8_t *direntry, FAR struct stat *buf) +{ + uint8_t attribute; + + /* Initialize the "struct stat" */ + + memset(buf, 0, sizeof(struct stat)); + + /* Get attribute from direntry */ + + attribute = DIR_GETATTRIBUTES(direntry); + if ((attribute & FATATTR_VOLUMEID) != 0) + { + return -ENOENT; + } + + /* Set the access permissions. The file/directory is always readable + * by everyone but may be writeable by no-one. + */ + + buf->st_mode = S_IROTH | S_IRGRP | S_IRUSR; + if ((attribute & FATATTR_READONLY) == 0) + { + buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR; + } + + /* We will report only types file or directory */ + + if ((attribute & FATATTR_DIRECTORY) != 0) + { + buf->st_mode |= S_IFDIR; + } + else + { + buf->st_mode |= S_IFREG; + } + + return fat_stat_common(fs, direntry, buf); +} + +/**************************************************************************** + * Name: fat_stat_root + * + * Description: + * Logic to stat the root directory. Used by fat_stat(). + * + ****************************************************************************/ + +static int fat_stat_root(FAR struct fat_mountpt_s *fs, + FAR uint8_t *direntry, FAR struct stat *buf) +{ + /* Clear the "struct stat" */ + + memset(buf, 0, sizeof(struct stat)); + + /* It's directory name of the mount point */ + + buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR | S_IWOTH | + S_IWGRP | S_IWUSR; + + return fat_stat_common(fs, direntry, buf); +} + /**************************************************************************** * Name: fat_stat * @@ -2499,11 +2695,7 @@ static int fat_stat(FAR struct inode *mountpt, FAR const char *relpath, { FAR struct fat_mountpt_s *fs; struct fat_dirinfo_s dirinfo; - uint16_t fatdate; - uint16_t date2; - uint16_t fattime; FAR uint8_t *direntry; - uint8_t attribute; int ret; /* Sanity checks */ @@ -2534,76 +2726,25 @@ static int fat_stat(FAR struct inode *mountpt, FAR const char *relpath, goto errout_with_semaphore; } - memset(buf, 0, sizeof(struct stat)); - if (dirinfo.fd_root) - { - /* It's directory name of the mount point */ + /* Get a pointer to the directory entry */ - buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR | S_IWOTH | - S_IWGRP | S_IWUSR; - ret = OK; - goto errout_with_semaphore; - } + direntry = &fs->fs_buffer[dirinfo.fd_seq.ds_offset]; /* Get the FAT attribute and map it so some meaningful mode_t values */ - direntry = &fs->fs_buffer[dirinfo.fd_seq.ds_offset]; - attribute = DIR_GETATTRIBUTES(direntry); - if ((attribute & FATATTR_VOLUMEID) != 0) + if (dirinfo.fd_root) { - ret = -ENOENT; - goto errout_with_semaphore; - } - - /* Set the access permissions. The file/directory is always readable - * by everyone but may be writeable by no-one. - */ - - buf->st_mode = S_IROTH | S_IRGRP | S_IRUSR; - if ((attribute & FATATTR_READONLY) == 0) - { - buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR; - } - - /* We will report only types file or directory */ - - if ((attribute & FATATTR_DIRECTORY) != 0) - { - buf->st_mode |= S_IFDIR; + ret = fat_stat_root(fs, direntry, buf); } else { - buf->st_mode |= S_IFREG; + /* Call fat_stat_file() to create the buf and to save information to + * the stat buffer. + */ + + ret = fat_stat_file(fs, direntry, buf); } - /* File/directory size, access block size */ - - buf->st_size = DIR_GETFILESIZE(direntry); - buf->st_blksize = fs->fs_fatsecperclus * fs->fs_hwsectorsize; - buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / buf->st_blksize; - - /* Times */ - - fatdate = DIR_GETWRTDATE(direntry); - fattime = DIR_GETWRTTIME(direntry); - buf->st_mtime = fat_fattime2systime(fattime, fatdate); - - date2 = DIR_GETLASTACCDATE(direntry); - if (fatdate == date2) - { - buf->st_atime = buf->st_mtime; - } - else - { - buf->st_atime = fat_fattime2systime(0, date2); - } - - fatdate = DIR_GETCRDATE(direntry); - fattime = DIR_GETCRTIME(direntry); - buf->st_ctime = fat_fattime2systime(fattime, fatdate); - - ret = OK; - errout_with_semaphore: fat_semgive(fs); return ret; diff --git a/fs/hostfs/hostfs.c b/fs/hostfs/hostfs.c index afee46afd46..be65d2b33a0 100644 --- a/fs/hostfs/hostfs.c +++ b/fs/hostfs/hostfs.c @@ -80,6 +80,8 @@ static int hostfs_ioctl(FAR struct file *filep, int cmd, static int hostfs_sync(FAR struct file *filep); static int hostfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int hostfs_fstat(FAR const struct file *filep, + FAR struct stat *buf); static int hostfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, @@ -136,6 +138,7 @@ const struct mountpt_operations hostfs_operations = hostfs_sync, /* sync */ hostfs_dup, /* dup */ + hostfs_fstat, /* fstat */ hostfs_opendir, /* opendir */ hostfs_closedir, /* closedir */ @@ -644,6 +647,21 @@ static int hostfs_dup(FAR const struct file *oldp, FAR struct file *newp) return OK; } +/**************************************************************************** + * Name: hostfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int hostfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ +#warning Missing logic + return -ENOSYS; +} + /**************************************************************************** * Name: hostfs_opendir * diff --git a/fs/inode/inode.h b/fs/inode/inode.h index 4e2f6aa1508..9c8bc187a25 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -240,6 +240,29 @@ int inode_search(FAR struct inode_search_s *desc); int inode_find(FAR struct inode_search_s *desc); +/**************************************************************************** + * Name: inode_stat + * + * Description: + * The inode_stat() function will obtain information about an 'inode' in + * the pseudo file system and will write it to the area pointed to by 'buf'. + * + * The 'buf' argument is a pointer to a stat structure, as defined in + * , into which information is placed concerning the file. + * + * Input Parameters: + * inode - The indoe of interest + * buf - The caller provide location in which to return information about + * the inode. + * + * Returned Value: + * Zero (OK) returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int inode_stat(FAR struct inode *inode, FAR struct stat *buf); + /**************************************************************************** * Name: inode_free * diff --git a/fs/nfs/nfs_node.h b/fs/nfs/nfs_node.h index 408bd1993e9..6a3e22f5494 100644 --- a/fs/nfs/nfs_node.h +++ b/fs/nfs/nfs_node.h @@ -1,7 +1,7 @@ /**************************************************************************** * fs/nfs/nfs_node.h * - * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2012-2013, 2017 Gregory Nutt. All rights reserved. * Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved. * Author: Jose Pablo Rojas Vargas * Gregory Nutt @@ -74,10 +74,11 @@ struct nfsnode uint8_t n_type; /* File type */ uint8_t n_fhsize; /* Size in bytes of the file handle */ uint8_t n_flags; /* Node flags */ - struct timespec n_mtime; /* File modification time (see NOTE) */ - time_t n_ctime; /* File creation time (see NOTE) */ + uint16_t n_mode; /* File mode for fstat() */ + struct timespec n_mtime; /* File modification time */ + time_t n_ctime; /* File creation time */ nfsfh_t n_fhandle; /* NFS File Handle */ - uint64_t n_size; /* Current size of file (see NOTE) */ + uint64_t n_size; /* Current size of file */ }; #endif /* __FS_NFS_NFS_NODE_H */ diff --git a/fs/nfs/nfs_util.c b/fs/nfs/nfs_util.c index e2dd949dcd2..10d9762bdf4 100644 --- a/fs/nfs/nfs_util.c +++ b/fs/nfs/nfs_util.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/nfs/nfs_util.c * - * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2012-2013, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -577,10 +578,15 @@ int nfs_finddir(struct nfsmount *nmp, FAR const char *relpath, void nfs_attrupdate(FAR struct nfsnode *np, FAR struct nfs_fattr *attributes) { - /* Save a few of the files attribute values in file structur (host order) */ + struct timespec ts; - np->n_type = fxdr_unsigned(uint32_t, attributes->fa_type); + /* Save a few of the files attribute values in file structure (host order) */ + + np->n_type = fxdr_unsigned(uint8_t, attributes->fa_type); + np->n_mode = fxdr_unsigned(uint16_t, attributes->fa_mode); np->n_size = fxdr_hyper(&attributes->fa_size); - fxdr_nfsv3time(&attributes->fa_mtime, &np->n_mtime) - np->n_ctime = fxdr_hyper(&attributes->fa_ctime); + + fxdr_nfsv3time(&attributes->fa_mtime, &np->n_mtime); + fxdr_nfsv3time(&attributes->fa_ctime, &ts); + np->n_ctime = ts.tv_sec; } diff --git a/fs/nfs/nfs_vfsops.c b/fs/nfs/nfs_vfsops.c index 0a7d93a720c..a11495084f6 100644 --- a/fs/nfs/nfs_vfsops.c +++ b/fs/nfs/nfs_vfsops.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/nfs/nfs_vfsops.c * - * Copyright (C) 2012-2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2012-2013, 2015, 2017 Gregory Nutt. All rights reserved. * Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved. * Author: Jose Pablo Rojas Vargas * Gregory Nutt @@ -47,10 +47,10 @@ #include +#include #include #include #include -#include #include #include @@ -103,6 +103,22 @@ # error "Length of cookie verify in fs_dirent_s is incorrect" #endif +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Use to pass file information to nfs_stat_common() */ + +struct nfs_statinfo_s +{ + uint16_t ns_mode; /* File access mode */ + uint8_t ns_type; /* File type */ + uint64_t ns_size; /* File size */ + time_t ns_atime; /* Time of last access */ + time_t ns_mtime; /* Time of last modification */ + time_t ns_ctime; /* Time of last status change */ +}; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -131,6 +147,7 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen); static ssize_t nfs_write(FAR struct file *filep, const char *buffer, size_t buflen); static int nfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int nfs_fstat(FAR const struct file *filep, FAR struct stat *buf); static int nfs_opendir(struct inode *mountpt, const char *relpath, struct fs_dirent_s *dir); static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir); @@ -142,15 +159,20 @@ static int nfs_bind(FAR struct inode *blkdriver, const void *data, void **handle); static int nfs_unbind(FAR void *handle, FAR struct inode **blkdriver, unsigned int flags); -static int nfs_statfs(struct inode *mountpt, struct statfs *buf); -static int nfs_remove(struct inode *mountpt, const char *relpath); -static int nfs_mkdir(struct inode *mountpt, const char *relpath, - mode_t mode); -static int nfs_rmdir(struct inode *mountpt, const char *relpath); -static int nfs_rename(struct inode *mountpt, const char *oldrelpath, - const char *newrelpath); -static int nfs_stat(struct inode *mountpt, const char *relpath, - struct stat *buf); +static int nfs_statfs(FAR struct inode *mountpt, + FAR struct statfs *buf); +static int nfs_remove(FAR struct inode *mountpt, + FAR const char *relpath); +static int nfs_mkdir(FAR struct inode *mountpt, + FAR const char *relpath, mode_t mode); +static int nfs_rmdir(FAR struct inode *mountpt, + FAR const char *relpath); +static int nfs_rename(FAR struct inode *mountpt, + FAR const char *oldrelpath, FAR const char *newrelpath); +static void nfs_stat_common(FAR struct nfs_statinfo_s *info, + FAR struct stat *buf); +static int nfs_stat(struct inode *mountpt, FAR const char *relpath, + FAR struct stat *buf); /**************************************************************************** * Public Data @@ -168,6 +190,7 @@ const struct mountpt_operations nfs_operations = NULL, /* sync */ nfs_dup, /* dup */ + nfs_fstat, /* fstat */ nfs_opendir, /* opendir */ NULL, /* closedir */ @@ -1114,7 +1137,7 @@ errout_with_semaphore: } /**************************************************************************** - * Name: binfs_dup + * Name: nfs_dup * * Description: * Duplicate open file data in the new file structure. @@ -1173,6 +1196,80 @@ static int nfs_dup(FAR const struct file *oldp, FAR struct file *newp) return OK; } +/**************************************************************************** + * Name: nfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int nfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ + FAR struct nfsmount *nmp; + FAR struct nfsnode *np; + struct nfs_statinfo_s info; + struct timespec ts; + int error; + int ret; + + finfo("Buf %p\n", buf); + DEBUGASSERT(filep != NULL && buf != NULL); + + /* Recover our private data from the struct file instance */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + np = (FAR struct nfsnode *)filep->f_priv; + + nmp = (FAR struct nfsmount *)filep->f_inode->i_private; + DEBUGASSERT(nmp != NULL); + + /* Make sure that the mount is still healthy */ + + nfs_semtake(nmp); + error = nfs_checkmount(nmp); + if (error != OK) + { + ferr("ERROR: nfs_checkmount failed: %d\n", error); + goto errout_with_semaphore; + } + + /* Extract the file mode, file type, and file size from the nfsnode + * structure. + */ + + info.ns_mode = np->n_mode; + info.ns_type = np->n_type; + info.ns_size = (off_t)np->n_size; + + /* Extract time values as type time_t in units of seconds. */ + + info.ns_mtime = np->n_mtime.tv_sec; + info.ns_ctime = np->n_ctime; + + /* Use the current time for the time of last access. */ + + ret = clock_gettime(CLOCK_REALTIME, &ts); + if (ret < 0) + { + error = -get_errno(); + ferr("ERROR: clock_gettime failed: %d\n", error); + goto errout_with_semaphore; + } + + info.ns_atime = ts.tv_sec; + + /* Then update the stat buffer with this information */ + + nfs_stat_common(&info, buf); + ret = OK; + +errout_with_semaphore: + nfs_semgive(nmp); + return -error; +} + /**************************************************************************** * Name: nfs_opendir * @@ -2503,84 +2600,45 @@ errout_with_semaphore: } /**************************************************************************** - * Name: nfs_stat + * Name: nfs_stat_common * * Description: - * Return information about the file system object at 'relpath' + * Return information about the file system object described by 'info' * * Returned Value: - * 0 on success; a negated errno value on failure. + * None * ****************************************************************************/ -static int nfs_stat(struct inode *mountpt, const char *relpath, - struct stat *buf) +static void nfs_stat_common(FAR struct nfs_statinfo_s *info, + FAR struct stat *buf) { - struct nfsmount *nmp; - struct file_handle fhandle; - struct nfs_fattr obj_attributes; - uint32_t tmp; - uint32_t mode; - int error; - - /* Sanity checks */ - - DEBUGASSERT(mountpt && mountpt->i_private); - - /* Get the mountpoint private data from the inode structure */ - - nmp = (FAR struct nfsmount *)mountpt->i_private; - DEBUGASSERT(nmp && buf); - - /* Check if the mount is still healthy */ - - nfs_semtake(nmp); - error = nfs_checkmount(nmp); - if (error != OK) - { - ferr("ERROR: nfs_checkmount failed: %d\n", error); - goto errout_with_semaphore; - } - - /* Get the file handle attributes of the requested node */ - - error = nfs_findnode(nmp, relpath, &fhandle, &obj_attributes, NULL); - if (error != OK) - { - ferr("ERROR: nfs_findnode failed: %d\n", error); - goto errout_with_semaphore; - } - - /* Construct the file mode. This is a 32-bit, encoded value containing - * both the access mode and the file type. - */ - - tmp = fxdr_unsigned(uint32_t, obj_attributes.fa_mode); + mode_t mode; /* Here we exploit the fact that most mode bits are the same in NuttX * as in the NFSv3 spec. */ - mode = tmp & (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH | - NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP | - NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR); + mode = info->ns_mode & + (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH | + NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP | + NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR); /* Handle the cases that are not the same */ - if ((mode & NFSMODE_ISGID) != 0) + if ((info->ns_mode & NFSMODE_ISGID) != 0) { mode |= S_ISGID; } - if ((mode & NFSMODE_ISUID) != 0) + if ((info->ns_mode & NFSMODE_ISUID) != 0) { mode |= S_ISUID; } /* Now OR in the file type */ - tmp = fxdr_unsigned(uint32_t, obj_attributes.fa_type); - switch (tmp) + switch (info->ns_mode) { default: case NFNON: /* Unknown type */ @@ -2616,12 +2674,83 @@ static int nfs_stat(struct inode *mountpt, const char *relpath, } buf->st_mode = mode; - buf->st_size = fxdr_hyper(&obj_attributes.fa_size); + buf->st_size = (off_t)info->ns_size; buf->st_blksize = 0; buf->st_blocks = 0; - buf->st_mtime = fxdr_hyper(&obj_attributes.fa_mtime); - buf->st_atime = fxdr_hyper(&obj_attributes.fa_atime); - buf->st_ctime = fxdr_hyper(&obj_attributes.fa_ctime); + buf->st_mtime = info->ns_mtime; + buf->st_atime = info->ns_atime; + buf->st_ctime = info->ns_ctime; +} + +/**************************************************************************** + * Name: nfs_stat + * + * Description: + * Return information about the file system object at 'relpath' + * + * Returned Value: + * 0 on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int nfs_stat(struct inode *mountpt, const char *relpath, + struct stat *buf) +{ + struct nfsmount *nmp; + struct file_handle fhandle; + struct nfs_fattr obj_attributes; + struct nfs_statinfo_s info; + struct timespec ts; + int error; + + /* Sanity checks */ + + DEBUGASSERT(mountpt && mountpt->i_private); + + /* Get the mountpoint private data from the inode structure */ + + nmp = (FAR struct nfsmount *)mountpt->i_private; + DEBUGASSERT(nmp && buf); + + /* Check if the mount is still healthy */ + + nfs_semtake(nmp); + error = nfs_checkmount(nmp); + if (error != OK) + { + ferr("ERROR: nfs_checkmount failed: %d\n", error); + goto errout_with_semaphore; + } + + /* Get the file handle attributes of the requested node */ + + error = nfs_findnode(nmp, relpath, &fhandle, &obj_attributes, NULL); + if (error != OK) + { + ferr("ERROR: nfs_findnode failed: %d\n", error); + goto errout_with_semaphore; + } + + /* Extract the file mode, file type, and file size. */ + + info.ns_mode = fxdr_unsigned(uint16_t, obj_attributes.fa_mode); + info.ns_type = fxdr_unsigned(uint8_t, obj_attributes.fa_type); + info.ns_size = fxdr_hyper(&obj_attributes.fa_size); + + /* Extract time values as type time_t in units of seconds */ + + fxdr_nfsv3time(&obj_attributes.fa_mtime, &ts); + info.ns_mtime = ts.tv_sec; + + fxdr_nfsv3time(&obj_attributes.fa_atime, &ts); + info.ns_atime = ts.tv_sec; + + fxdr_nfsv3time(&obj_attributes.fa_ctime, &ts); + info.ns_ctime = ts.tv_sec; + + /* Then update the stat buffer with this information */ + + nfs_stat_common(&info, buf); errout_with_semaphore: nfs_semgive(nmp); diff --git a/fs/nxffs/nxffs.h b/fs/nxffs/nxffs.h index 04dba9f3afa..30f84b1f328 100644 --- a/fs/nxffs/nxffs.h +++ b/fs/nxffs/nxffs.h @@ -1,7 +1,7 @@ /**************************************************************************** * fs/nxffs/nxffs.h * - * Copyright (C) 2011, 2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013, 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: Linux/Documentation/filesystems/romfs.txt @@ -1092,6 +1092,7 @@ ssize_t nxffs_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); int nxffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); int nxffs_dup(FAR const struct file *oldp, FAR struct file *newp); +int nxffs_fstat(FAR const struct file *filep, FAR struct stat *buf); int nxffs_opendir(FAR struct inode *mountpt, FAR const char *relpath, FAR struct fs_dirent_s *dir); int nxffs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir); diff --git a/fs/nxffs/nxffs_initialize.c b/fs/nxffs/nxffs_initialize.c index 8b99252bba6..bf511c81869 100644 --- a/fs/nxffs/nxffs_initialize.c +++ b/fs/nxffs/nxffs_initialize.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/nxffs/nxffs_initialize.c * - * Copyright (C) 2011, 2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013, 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: Linux/Documentation/filesystems/romfs.txt @@ -73,6 +73,7 @@ const struct mountpt_operations nxffs_operations = NULL, /* sync -- No buffered data */ nxffs_dup, /* dup */ + nxffs_fstat, /* fstat */ nxffs_opendir, /* opendir */ NULL, /* closedir */ diff --git a/fs/nxffs/nxffs_stat.c b/fs/nxffs/nxffs_stat.c index bbbd2a82a7e..7a0f3a2b04c 100644 --- a/fs/nxffs/nxffs_stat.c +++ b/fs/nxffs/nxffs_stat.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/nxffs/nxffs_stat.c * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: Linux/Documentation/filesystems/romfs.txt @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -149,6 +150,8 @@ int nxffs_stat(FAR struct inode *mountpt, FAR const char *relpath, goto errout_with_semaphore; } + /* Return status information based on the directory entry */ + buf->st_blocks = entry.datlen / (volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR); buf->st_mode = S_IFREG | S_IXOTH | S_IXGRP | S_IXUSR; buf->st_size = entry.datlen; @@ -175,3 +178,58 @@ errout_with_semaphore: errout: return ret; } + +/**************************************************************************** + * Name: nxffs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +int nxffs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ + + FAR struct nxffs_volume_s *volume; + FAR struct nxffs_ofile_s *ofile; + int ret; + + finfo("Buf %s\n", buf); + DEBUGASSERT(filep != NULL && buf != NULL); + + /* Recover the open file state from the struct file instance */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + ofile = (FAR struct nxffs_ofile_s *)filep->f_priv; + + /* Recover the volume state from the open file */ + + volume = (FAR struct nxffs_volume_s *)filep->f_inode->i_private; + DEBUGASSERT(volume != NULL); + + /* Get exclusive access to the volume. Note that the volume exclsem + * protects the open file list. + */ + + ret = sem_wait(&volume->exclsem); + if (ret != OK) + { + int errcode = get_errno(); + ferr("ERROR: sem_wait failed: %d\n", errcode); + return -errcode; + } + + /* Return status information based on the directory entry */ + + buf->st_blocks = ofile->entry.datlen / + (volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR); + buf->st_mode = S_IFREG | S_IXOTH | S_IXGRP | S_IXUSR; + buf->st_size = ofile->entry.datlen; + buf->st_atime = ofile->entry.utc; + buf->st_mtime = ofile->entry.utc; + buf->st_ctime = ofile->entry.utc; + + sem_post(&volume->exclsem); + return OK; +} diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index 4f9f2de5188..b68454c76d5 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/procfs/fs_procfs.c * - * Copyright (C) 2013-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -183,6 +183,8 @@ static int procfs_ioctl(FAR struct file *filep, int cmd, static int procfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int procfs_fstat(FAR const struct file *filep, + FAR struct stat *buf); static int procfs_opendir(FAR struct inode *mountpt, const char *relpath, FAR struct fs_dirent_s *dir); @@ -235,6 +237,7 @@ const struct mountpt_operations procfs_operations = NULL, /* sync */ procfs_dup, /* dup */ + procfs_fstat, /* fstat */ procfs_opendir, /* opendir */ procfs_closedir, /* closedir */ @@ -460,6 +463,21 @@ static int procfs_dup(FAR const struct file *oldp, FAR struct file *newp) return oldattr->procfsentry->ops->dup(oldp, newp); } +/**************************************************************************** + * Name: procfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int procfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ +#warning Missing logic + return -ENOSYS; +} + /**************************************************************************** * Name: procfs_opendir * diff --git a/fs/romfs/fs_romfs.c b/fs/romfs/fs_romfs.c index 92584422e9f..9c1a7311d9a 100644 --- a/fs/romfs/fs_romfs.c +++ b/fs/romfs/fs_romfs.c @@ -1,7 +1,7 @@ /**************************************************************************** * rm/romfs/fs_romfs.h * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2009, 2011, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: Linux/Documentation/filesystems/romfs.txt @@ -76,7 +76,10 @@ static off_t romfs_seek(FAR struct file *filep, off_t offset, int whence); static int romfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -static int romfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int romfs_dup(FAR const struct file *oldp, + FAR struct file *newp); +static int romfs_fstat(FAR const struct file *filep, + FAR struct stat *buf); static int romfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, @@ -93,6 +96,8 @@ static int romfs_unbind(FAR void *handle, FAR struct inode **blkdriver, static int romfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf); +static int romfs_stat_common(uint8_t type, uint32_t size, + uint16_t sectorsize, FAR struct stat *buf); static int romfs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct stat *buf); @@ -116,6 +121,7 @@ const struct mountpt_operations romfs_operations = NULL, /* sync */ romfs_dup, /* dup */ + romfs_fstat, /* fstat */ romfs_opendir, /* opendir */ NULL, /* closedir */ @@ -199,7 +205,11 @@ static int romfs_open(FAR struct file *filep, FAR const char *relpath, } /* The full path exists -- but is the final component a file - * or a directory? + * or a directory? Or some other Unix file type that is not + * appropriate in this contex. + * + * REVISIT: This logic should follow hard/soft link file + * types. At present, it returns the ENXIO. */ if (IS_DIRECTORY(dirinfo.rd_next)) @@ -210,6 +220,20 @@ static int romfs_open(FAR struct file *filep, FAR const char *relpath, ferr("ERROR: '%s' is a directory\n", relpath); goto errout_with_semaphore; } + else if (!IS_FILE(dirinfo.rd_next)) + { + /* ENXIO indicates "The named file is a character special or + * block special file, and the device associated with this + * special file does not exist." + * + * Here we also return ENXIO if the file is not a directory + * or a regular file. + */ + + ret = -ENXIO; + ferr("ERROR: '%s' is a special file\n", relpath); + goto errout_with_semaphore; + } #ifdef CONFIG_FILE_MODE # warning "Missing check for privileges based on inode->i_mode" @@ -676,6 +700,51 @@ errout_with_semaphore: return ret; } +/**************************************************************************** + * Name: romfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int romfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ + FAR struct romfs_mountpt_s *rm; + FAR struct romfs_file_s *rf; + int ret; + + finfo("fstat\n"); + + /* Sanity checks */ + + DEBUGASSERT(filep->f_priv == NULL && filep->f_inode != NULL); + + /* Get mountpoint private data from the inode reference from the file + * structure + */ + + rf = filep->f_priv; + rm = (FAR struct romfs_mountpt_s *)filep->f_inode->i_private; + DEBUGASSERT(rm != NULL); + + /* Check if the mount is still healthy */ + + romfs_semtake(rm); + ret = romfs_checkmount(rm); + if (ret >= 0) + { + /* Return information about the directory entry */ + + ret = romfs_stat_common(RFNEXT_FILE, rf->rf_size, + rm->rm_hwsectorsize, buf); + } + + romfs_semgive(rm); + return ret; +} + /**************************************************************************** * Name: romfs_opendir * @@ -1100,6 +1169,54 @@ errout_with_semaphore: return ret; } +/**************************************************************************** + * Name: romfs_stat_common + * + * Description: + * Return information about a file or directory + * + ****************************************************************************/ + +static int romfs_stat_common(uint8_t type, uint32_t size, + uint16_t sectorsize, FAR struct stat *buf) +{ + memset(buf, 0, sizeof(struct stat)); + if (IS_DIRECTORY(type)) + { + /* It's a read-only directory name */ + + buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; + if (IS_EXECUTABLE(type)) + { + buf->st_mode |= S_IXOTH | S_IXGRP | S_IXUSR; + } + } + else if (IS_FILE(type)) + { + /* It's a read-only file name */ + + buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; + if (IS_EXECUTABLE(type)) + { + buf->st_mode |= S_IXOTH | S_IXGRP | S_IXUSR; + } + } + else + { + /* Otherwise, pretend like the unsupported type does not exist */ + + finfo("Unsupported type: %d\n", type); + return -ENOENT; + } + + /* File/directory size, access block size */ + + buf->st_size = size; + buf->st_blksize = sectorsize; + buf->st_blocks = (buf->st_size + sectorsize - 1) / sectorsize; + return OK; +} + /**************************************************************************** * Name: romfs_stat * @@ -1112,6 +1229,7 @@ static int romfs_stat(FAR struct inode *mountpt, FAR const char *relpath, { FAR struct romfs_mountpt_s *rm; FAR struct romfs_dirinfo_s dirinfo; + uint8_t type; int ret; finfo("Entry\n"); @@ -1146,43 +1264,10 @@ static int romfs_stat(FAR struct inode *mountpt, FAR const char *relpath, goto errout_with_semaphore; } - memset(buf, 0, sizeof(struct stat)); - if (IS_DIRECTORY(dirinfo.rd_next)) - { - /* It's a read-only directory name */ + /* Return information about the directory entry */ - buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; - if (IS_EXECUTABLE(dirinfo.rd_next)) - { - buf->st_mode |= S_IXOTH | S_IXGRP | S_IXUSR; - } - } - else if (IS_FILE(dirinfo.rd_next)) - { - /* It's a read-only file name */ - - buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; - if (IS_EXECUTABLE(dirinfo.rd_next)) - { - buf->st_mode |= S_IXOTH | S_IXGRP | S_IXUSR; - } - } - else - { - /* Otherwise, pretend like the unsupported node does not exist */ - - finfo("Unsupported inode: %d\n", dirinfo.rd_next); - ret = -ENOENT; - goto errout_with_semaphore; - } - - /* File/directory size, access block size */ - - buf->st_size = dirinfo.rd_size; - buf->st_blksize = rm->rm_hwsectorsize; - buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / buf->st_blksize; - - ret = OK; + type = (uint8_t)(dirinfo.rd_next & RFNEXT_ALLMODEMASK); + ret = romfs_stat_common(type, dirinfo.rd_size, rm->rm_hwsectorsize, buf); errout_with_semaphore: romfs_semgive(rm); diff --git a/fs/smartfs/smartfs_smart.c b/fs/smartfs/smartfs_smart.c index 64ab2eeb1fc..ee74931036e 100644 --- a/fs/smartfs/smartfs_smart.c +++ b/fs/smartfs/smartfs_smart.c @@ -69,33 +69,50 @@ static int smartfs_open(FAR struct file *filep, const char *relpath, int oflags, mode_t mode); static int smartfs_close(FAR struct file *filep); -static ssize_t smartfs_read(FAR struct file *filep, char *buffer, size_t buflen); +static ssize_t smartfs_read(FAR struct file *filep, char *buffer, + size_t buflen); static ssize_t smartfs_write(FAR struct file *filep, const char *buffer, size_t buflen); -static off_t smartfs_seek(FAR struct file *filep, off_t offset, int whence); -static int smartfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); +static off_t smartfs_seek(FAR struct file *filep, off_t offset, + int whence); +static int smartfs_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); static int smartfs_sync(FAR struct file *filep); -static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int smartfs_dup(FAR const struct file *oldp, + FAR struct file *newp); +static int smartfs_fstat(FAR const struct file *filep, + FAR struct stat *buf); -static int smartfs_opendir(struct inode *mountpt, const char *relpath, - struct fs_dirent_s *dir); -static int smartfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir); -static int smartfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir); +static int smartfs_opendir(FAR struct inode *mountpt, + FAR const char *relpath, + FAR struct fs_dirent_s *dir); +static int smartfs_readdir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir); +static int smartfs_rewinddir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir); -static int smartfs_bind(FAR struct inode *blkdriver, const void *data, - void **handle); +static int smartfs_bind(FAR struct inode *blkdriver, + FAR const void *data, + FAR void **handle); static int smartfs_unbind(void *handle, FAR struct inode **blkdriver, unsigned int flags); -static int smartfs_statfs(struct inode *mountpt, struct statfs *buf); +static int smartfs_statfs(FAR struct inode *mountpt, + FAR struct statfs *buf); -static int smartfs_unlink(struct inode *mountpt, const char *relpath); -static int smartfs_mkdir(struct inode *mountpt, const char *relpath, +static int smartfs_unlink(FAR struct inode *mountpt, + FAR const char *relpath); +static int smartfs_mkdir(FAR struct inode *mountpt, + FAR const char *relpath, mode_t mode); -static int smartfs_rmdir(struct inode *mountpt, const char *relpath); -static int smartfs_rename(struct inode *mountpt, const char *oldrelpath, +static int smartfs_rmdir(FAR struct inode *mountpt, + FAR const char *relpath); +static int smartfs_rename(FAR struct inode *mountpt, + FAR const char *oldrelpath, const char *newrelpath); -static int smartfs_stat(struct inode *mountpt, const char *relpath, struct stat *buf); +static int smartfs_stat(FAR struct inode *mountpt, + FAR const char *relpath, + FAR struct stat *buf); static off_t smartfs_seek_internal(struct smartfs_mountpt_s *fs, struct smartfs_ofile_s *sf, @@ -128,6 +145,7 @@ const struct mountpt_operations smartfs_operations = smartfs_sync, /* sync */ smartfs_dup, /* dup */ + smartfs_fstat, /* fstat */ smartfs_opendir, /* opendir */ NULL, /* closedir */ @@ -1249,6 +1267,21 @@ static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp) return OK; } +/**************************************************************************** + * Name: smartfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int smartfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ +#warning Missing logic + return -ENOSYS; +} + /**************************************************************************** * Name: smartfs_opendir * @@ -1256,7 +1289,8 @@ static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp) * ****************************************************************************/ -static int smartfs_opendir(struct inode *mountpt, const char *relpath, struct fs_dirent_s *dir) +static int smartfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, + FAR struct fs_dirent_s *dir) { struct smartfs_mountpt_s *fs; int ret; diff --git a/fs/tmpfs/fs_tmpfs.c b/fs/tmpfs/fs_tmpfs.c index df265ff17bc..44268ea4ab4 100644 --- a/fs/tmpfs/fs_tmpfs.c +++ b/fs/tmpfs/fs_tmpfs.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/tmpfs/fs_tmpfs.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -91,75 +91,79 @@ static void tmpfs_unlock_reentrant(FAR struct tmpfs_sem_s *sem); static void tmpfs_unlock(FAR struct tmpfs_s *fs); static void tmpfs_lock_object(FAR struct tmpfs_object_s *to); static void tmpfs_unlock_object(FAR struct tmpfs_object_s *to); -static int tmpfs_realloc_directory(FAR struct tmpfs_directory_s **tdo, - unsigned int nentries); -static int tmpfs_realloc_file(FAR struct tmpfs_file_s **tfo, - size_t newsize); +static int tmpfs_realloc_directory(FAR struct tmpfs_directory_s **tdo, + unsigned int nentries); +static int tmpfs_realloc_file(FAR struct tmpfs_file_s **tfo, + size_t newsize); static void tmpfs_release_lockedobject(FAR struct tmpfs_object_s *to); static void tmpfs_release_lockedfile(FAR struct tmpfs_file_s *tfo); -static int tmpfs_find_dirent(FAR struct tmpfs_directory_s *tdo, - FAR const char *name); -static int tmpfs_remove_dirent(FAR struct tmpfs_directory_s *tdo, - FAR const char *name); -static int tmpfs_add_dirent(FAR struct tmpfs_directory_s **tdo, - FAR struct tmpfs_object_s *to, FAR const char *name); +static int tmpfs_find_dirent(FAR struct tmpfs_directory_s *tdo, + FAR const char *name); +static int tmpfs_remove_dirent(FAR struct tmpfs_directory_s *tdo, + FAR const char *name); +static int tmpfs_add_dirent(FAR struct tmpfs_directory_s **tdo, + FAR struct tmpfs_object_s *to, FAR const char *name); static FAR struct tmpfs_file_s *tmpfs_alloc_file(void); -static int tmpfs_create_file(FAR struct tmpfs_s *fs, - FAR const char *relpath, FAR struct tmpfs_file_s **tfo); +static int tmpfs_create_file(FAR struct tmpfs_s *fs, + FAR const char *relpath, FAR struct tmpfs_file_s **tfo); static FAR struct tmpfs_directory_s *tmpfs_alloc_directory(void); -static int tmpfs_create_directory(FAR struct tmpfs_s *fs, - FAR const char *relpath, FAR struct tmpfs_directory_s **tdo); -static int tmpfs_find_object(FAR struct tmpfs_s *fs, - FAR const char *relpath, FAR struct tmpfs_object_s **object, - FAR struct tmpfs_directory_s **parent); -static int tmpfs_find_file(FAR struct tmpfs_s *fs, - FAR const char *relpath, - FAR struct tmpfs_file_s **tfo, - FAR struct tmpfs_directory_s **parent); -static int tmpfs_find_directory(FAR struct tmpfs_s *fs, - FAR const char *relpath, - FAR struct tmpfs_directory_s **tdo, - FAR struct tmpfs_directory_s **parent); -static int tmpfs_statfs_callout(FAR struct tmpfs_directory_s *tdo, - unsigned int index, FAR void *arg); -static int tmpfs_free_callout(FAR struct tmpfs_directory_s *tdo, - unsigned int index, FAR void *arg); -static int tmpfs_foreach(FAR struct tmpfs_directory_s *tdo, - tmpfs_foreach_t callout, FAR void *arg); +static int tmpfs_create_directory(FAR struct tmpfs_s *fs, + FAR const char *relpath, FAR struct tmpfs_directory_s **tdo); +static int tmpfs_find_object(FAR struct tmpfs_s *fs, + FAR const char *relpath, FAR struct tmpfs_object_s **object, + FAR struct tmpfs_directory_s **parent); +static int tmpfs_find_file(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_file_s **tfo, + FAR struct tmpfs_directory_s **parent); +static int tmpfs_find_directory(FAR struct tmpfs_s *fs, + FAR const char *relpath, + FAR struct tmpfs_directory_s **tdo, + FAR struct tmpfs_directory_s **parent); +static int tmpfs_statfs_callout(FAR struct tmpfs_directory_s *tdo, + unsigned int index, FAR void *arg); +static int tmpfs_free_callout(FAR struct tmpfs_directory_s *tdo, + unsigned int index, FAR void *arg); +static int tmpfs_foreach(FAR struct tmpfs_directory_s *tdo, + tmpfs_foreach_t callout, FAR void *arg); /* File system operations */ -static int tmpfs_open(FAR struct file *filep, FAR const char *relpath, - int oflags, mode_t mode); -static int tmpfs_close(FAR struct file *filep); +static int tmpfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode); +static int tmpfs_close(FAR struct file *filep); static ssize_t tmpfs_read(FAR struct file *filep, FAR char *buffer, - size_t buflen); + size_t buflen); static ssize_t tmpfs_write(FAR struct file *filep, FAR const char *buffer, - size_t buflen); + size_t buflen); static off_t tmpfs_seek(FAR struct file *filep, off_t offset, int whence); -static int tmpfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -static int tmpfs_dup(FAR const struct file *oldp, FAR struct file *newp); -static int tmpfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, - FAR struct fs_dirent_s *dir); -static int tmpfs_closedir(FAR struct inode *mountpt, - FAR struct fs_dirent_s *dir); -static int tmpfs_readdir(FAR struct inode *mountpt, - FAR struct fs_dirent_s *dir); -static int tmpfs_rewinddir(FAR struct inode *mountpt, - FAR struct fs_dirent_s *dir); -static int tmpfs_bind(FAR struct inode *blkdriver, FAR const void *data, - FAR void **handle); -static int tmpfs_unbind(FAR void *handle, FAR struct inode **blkdriver, - unsigned int flags); -static int tmpfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf); -static int tmpfs_unlink(FAR struct inode *mountpt, FAR const char *relpath); -static int tmpfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, - mode_t mode); -static int tmpfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath); -static int tmpfs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath, - FAR const char *newrelpath); -static int tmpfs_stat(FAR struct inode *mountpt, FAR const char *relpath, - FAR struct stat *buf); +static int tmpfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); +static int tmpfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int tmpfs_fstat(FAR const struct file *filep, FAR struct stat *buf); + +static int tmpfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, + FAR struct fs_dirent_s *dir); +static int tmpfs_closedir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir); +static int tmpfs_readdir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir); +static int tmpfs_rewinddir(FAR struct inode *mountpt, + FAR struct fs_dirent_s *dir); +static int tmpfs_bind(FAR struct inode *blkdriver, FAR const void *data, + FAR void **handle); +static int tmpfs_unbind(FAR void *handle, FAR struct inode **blkdriver, + unsigned int flags); +static int tmpfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf); +static int tmpfs_unlink(FAR struct inode *mountpt, FAR const char *relpath); +static int tmpfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, + mode_t mode); +static int tmpfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath); +static int tmpfs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath, + FAR const char *newrelpath); +static void tmpfs_stat_common(FAR struct tmpfs_object_s *to, + FAR struct stat *buf); +static int tmpfs_stat(FAR struct inode *mountpt, FAR const char *relpath, + FAR struct stat *buf); /**************************************************************************** * Public Data @@ -175,6 +179,7 @@ const struct mountpt_operations tmpfs_operations = tmpfs_ioctl, /* ioctl */ NULL, /* sync */ tmpfs_dup, /* dup */ + tmpfs_fstat, /* fstat */ tmpfs_opendir, /* opendir */ tmpfs_closedir, /* closedir */ tmpfs_readdir, /* readdir */ @@ -1769,6 +1774,41 @@ static int tmpfs_dup(FAR const struct file *oldp, FAR struct file *newp) return OK; } +/**************************************************************************** + * Name: tmpfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int tmpfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ + FAR struct tmpfs_file_s *tfo; + + finfo("Fstat %p\n", buf); + DEBUGASSERT(filep != NULL && buf != NULL); + + /* Recover our private data from the struct file instance */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + tfo = filep->f_priv; + + /* Get exclusive access to the file */ + + tmpfs_lock_file(tfo); + + /* Return information about the file in the stat buffer.*/ + + tmpfs_stat_common((FAR struct tmpfs_object_s *)tfo, buf); + + /* Release the lock on the file and return success. */ + + tmpfs_unlock_file(tfo); + return OK; +} + /**************************************************************************** * Name: tmpfs_opendir ****************************************************************************/ @@ -2459,41 +2499,15 @@ errout_with_lock: } /**************************************************************************** - * Name: tmpfs_stat + * Name: tmpfs_stat_common ****************************************************************************/ -static int tmpfs_stat(FAR struct inode *mountpt, FAR const char *relpath, - FAR struct stat *buf) +static void tmpfs_stat_common(FAR struct tmpfs_object_s *to, + FAR struct stat *buf) { - FAR struct tmpfs_s *fs; - FAR struct tmpfs_object_s *to; size_t objsize; - int ret; - finfo("mountpt=%p relpath=%s buf=%p\n", mountpt, relpath, buf); - DEBUGASSERT(mountpt != NULL && relpath != NULL && buf != NULL); - - /* Get the file system structure from the inode reference. */ - - fs = mountpt->i_private; - DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); - - /* Get exclusive access to the file system */ - - tmpfs_lock(fs); - - /* Find the tmpfs object at the relpath. If successful, - * tmpfs_find_object() will lock the object and increment the - * reference count on the object. - */ - - ret = tmpfs_find_object(fs, relpath, &to, NULL); - if (ret < 0) - { - goto errout_with_fslock; - } - - /* We found it... Is the object a regular file? */ + /* Is the tmpfs object a regular file? */ memset(buf, 0, sizeof(struct stat)); @@ -2530,8 +2544,50 @@ static int tmpfs_stat(FAR struct inode *mountpt, FAR const char *relpath, buf->st_blksize = CONFIG_FS_TMPFS_BLOCKSIZE; buf->st_blocks = (objsize + CONFIG_FS_TMPFS_BLOCKSIZE - 1) / CONFIG_FS_TMPFS_BLOCKSIZE; +} - /* No... unlock the object and return success */ +/**************************************************************************** + * Name: tmpfs_stat + ****************************************************************************/ + +static int tmpfs_stat(FAR struct inode *mountpt, FAR const char *relpath, + FAR struct stat *buf) +{ + FAR struct tmpfs_s *fs; + FAR struct tmpfs_object_s *to; + int ret; + + finfo("mountpt=%p relpath=%s buf=%p\n", mountpt, relpath, buf); + DEBUGASSERT(mountpt != NULL && relpath != NULL && buf != NULL); + + /* Get the file system structure from the inode reference. */ + + fs = mountpt->i_private; + DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL); + + /* Get exclusive access to the file system */ + + tmpfs_lock(fs); + + /* Find the tmpfs object at the relpath. If successful, + * tmpfs_find_object() will lock the object and increment the + * reference count on the object. + */ + + ret = tmpfs_find_object(fs, relpath, &to, NULL); + if (ret < 0) + { + goto errout_with_fslock; + } + + /* We found it... Return information about the file object in the stat + * buffer. + */ + + DEBUGASSERT(to != NULL); + tmpfs_stat_common(to, buf); + + /* Unlock the object and return success */ tmpfs_release_lockedobject(to); ret = OK; diff --git a/fs/unionfs/fs_unionfs.c b/fs/unionfs/fs_unionfs.c index 2c4ec3dfed4..bb3b6abcfb5 100644 --- a/fs/unionfs/fs_unionfs.c +++ b/fs/unionfs/fs_unionfs.c @@ -160,6 +160,8 @@ static int unionfs_ioctl(FAR struct file *filep, int cmd, static int unionfs_sync(FAR struct file *filep); static int unionfs_dup(FAR const struct file *oldp, FAR struct file *newp); +static int unionfs_fstat(FAR const struct file *filep, + FAR struct stat *buf); /* Operations on directories */ @@ -215,6 +217,7 @@ static const struct mountpt_operations g_unionfs_mops = unionfs_sync, /* sync */ unionfs_dup, /* dup */ + unionfs_fstat, /* fstat */ unionfs_opendir, /* opendir */ unionfs_closedir, /* closedir */ @@ -489,7 +492,7 @@ static int unionfs_trymkdir(FAR struct inode *inode, FAR const char *relpath, } /**************************************************************************** - * Name: unionfs_trystat + * Name: unionfs_tryrename ****************************************************************************/ static int unionfs_tryrename(FAR struct inode *mountpt, @@ -1309,6 +1312,58 @@ static int unionfs_dup(FAR const struct file *oldp, FAR struct file *newp) return ret; } +/**************************************************************************** + * Name: unionfs_fstat + * + * Description: + * Obtain information about an open file associated with the file + * descriptor 'fd', and will write it to the area pointed to by 'buf'. + * + ****************************************************************************/ + +static int unionfs_fstat(FAR const struct file *filep, FAR struct stat *buf) +{ + FAR struct unionfs_inode_s *ui; + FAR struct unionfs_file_s *uf; + FAR struct unionfs_mountpt_s *um; + FAR const struct mountpt_operations *ops; + int ret = -EPERM; + + finfo("Entry\n"); + + /* Recover the open file data from the struct file instance */ + + DEBUGASSERT(filep != NULL && filep->f_inode != NULL); + ui = (FAR struct unionfs_inode_s *)filep->f_inode->i_private; + + /* Get exclusive access to the file system data structures */ + + ret = unionfs_semtake(ui, false); + if (ret < 0) + { + return ret; + } + + DEBUGASSERT(ui != NULL && filep->f_priv != NULL); + uf = (FAR struct unionfs_file_s *)filep->f_priv; + + DEBUGASSERT(uf->uf_ndx == 0 || uf->uf_ndx == 1); + um = &ui->ui_fs[uf->uf_ndx]; + + DEBUGASSERT(um != NULL && um->um_node != NULL && um->um_node->u.i_mops != NULL); + ops = um->um_node->u.i_mops; + + /* Perform the lower level write operation */ + + if (ops->fstat) + { + ret = ops->fstat(&uf->uf_file, buf); + } + + unionfs_semgive(ui); + return ret; +} + /**************************************************************************** * Name: unionfs_opendir ****************************************************************************/ diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index 900dc20534b..019ac35f206 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -72,9 +72,9 @@ else # Common file/socket descriptor support CSRCS += fs_close.c fs_dup.c fs_dup2.c fs_fcntl.c fs_dupfd.c fs_dupfd2.c -CSRCS += fs_epoll.c fs_getfilep.c fs_ioctl.c fs_lseek.c fs_mkdir.c fs_open.c -CSRCS += fs_poll.c fs_read.c fs_rename.c fs_rmdir.c fs_stat.c fs_statfs.c -CSRCS += fs_select.c fs_unlink.c fs_write.c +CSRCS += fs_epoll.c fs_fstat.c fs_getfilep.c fs_ioctl.c fs_lseek.c +CSRCS += fs_mkdir.c fs_open.c fs_poll.c fs_read.c fs_rename.c fs_rmdir.c fs_statfs.c +CSRCS += fs_stat.c fs_select.c fs_unlink.c fs_write.c # Certain interfaces are not available if there is no mountpoint support diff --git a/fs/vfs/fs_fstat.c b/fs/vfs/fs_fstat.c new file mode 100644 index 00000000000..8a79b732657 --- /dev/null +++ b/fs/vfs/fs_fstat.c @@ -0,0 +1,156 @@ +/**************************************************************************** + * fs/vfs/fs_fstat.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include "inode/inode.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fstat + * + * Description: + * The fstat() function will obtain information about an open file + * associated with the file descriptor 'fd', and will write it to the area + * pointed to by 'buf'. + * + * The 'buf' argument is a pointer to a stat structure, as defined in + * , into which information is placed concerning the file. + * + * Input Parameters: + * fd - The file descriptor associated with the open file of interest + * buf - The caller provide location in which to return information about + * the open file. + * + * Returned Value: + * Upon successful completion, 0 shall be returned. Otherwise, -1 shall be + * returned and errno set to indicate the error. + * + ****************************************************************************/ + +int fstat(int fd, FAR struct stat *buf) +{ + FAR struct file *filep; + FAR struct inode *inode; + int ret; + + /* Did we get a valid file descriptor? */ + + if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) + { + /* No networking... it is a bad descriptor in any event */ + + set_errno(EBADF); + return ERROR; + } + + /* The descriptor is in a valid range to file descriptor... do the + * read. First, get the file structure. Note that on failure, + * fs_getfilep() will set the errno variable. + */ + + filep = fs_getfilep(fd); + if (filep == NULL) + { + /* The errno value has already been set */ + + return ERROR; + } + + /* Get the inode from the file structure */ + + inode = filep->f_inode; + DEBUGASSERT(inode != NULL); + + /* The way we handle the stat depends on the type of inode that we + * are dealing with. + */ + +#ifndef CONFIG_DISABLE_MOUNTPOINT + if (INODE_IS_MOUNTPT(inode)) + { + /* The inode is a file system mointpoint. Verify that the mountpoint + * supports the fstat() method + */ + + ret = OK; + if (inode->u.i_mops && inode->u.i_mops->fstat) + { + /* Perform the fstat() operation */ + + ret = inode->u.i_mops->fstat(filep, buf); + } + } + else +#endif + { + /* The inode is part of the root pseudo file system. */ + + ret = inode_stat(inode, buf); + } + + /* Check if the fstat operation was successful */ + + if (ret < 0) + { + ret = -ret; + goto errout_with_inode; + } + + /* Successfully fstat'ed the file */ + + inode_release(inode); + return OK; + +/* Failure conditions always set the errno appropriately */ + +errout_with_inode: + inode_release(inode); + + set_errno(ret); + return ERROR; +} diff --git a/fs/vfs/fs_stat.c b/fs/vfs/fs_stat.c index be1ebef575b..a1c9786cd8a 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -70,7 +70,6 @@ * Private Function Prototypes ****************************************************************************/ -static inline int statpseudo(FAR struct inode *inode, FAR struct stat *buf); static inline int statroot(FAR struct stat *buf); int stat_recursive(FAR const char *path, FAR struct stat *buf); @@ -79,11 +78,197 @@ int stat_recursive(FAR const char *path, FAR struct stat *buf); ****************************************************************************/ /**************************************************************************** - * Name: statpseudo + * Name: statroot ****************************************************************************/ -static inline int statpseudo(FAR struct inode *inode, FAR struct stat *buf) +static inline int statroot(FAR struct stat *buf) { + /* There is no inode associated with the fake root directory */ + + RESET_BUF(buf); + buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; + return OK; +} + +/**************************************************************************** + * Name: stat_recursive + * + * Returned Value: + * Zero on success; -1 on failure with errno set: + * + * EACCES Search permission is denied for one of the directories in the + * path prefix of path. + * EFAULT Bad address. + * ENOENT A component of the path path does not exist, or the path is an + * empty string. + * ENOMEM Out of memory + * ENOTDIR A component of the path is not a directory. + * + ****************************************************************************/ + +int stat_recursive(FAR const char *path, FAR struct stat *buf) +{ + struct inode_search_s desc; + FAR struct inode *inode; + int ret; + + /* Get an inode for this path */ + + SETUP_SEARCH(&desc, path, true); + + ret = inode_find(&desc); + if (ret < 0) + { + /* This name does not refer to an inode in the pseudo file system and + * there is no mountpoint that includes in this path. + */ + + ret = -ret; + goto errout_with_search; + } + + /* Get the search results */ + + inode = desc.node; + DEBUGASSERT(inode != NULL); + + /* The way we handle the stat depends on the type of inode that we + * are dealing with. + */ + +#ifndef CONFIG_DISABLE_MOUNTPOINT + if (INODE_IS_MOUNTPT(inode)) + { + /* The node is a file system mointpoint. Verify that the mountpoint + * supports the stat() method + */ + + if (inode->u.i_mops && inode->u.i_mops->stat) + { + /* Perform the stat() operation */ + + ret = inode->u.i_mops->stat(inode, desc.relpath, buf); + } + } + else +#endif + { + /* The node is part of the root pseudo file system. This path may + * recurse if soft links are supported in the pseudo file system. + */ + + ret = inode_stat(inode, buf); + } + + /* Check if the stat operation was successful */ + + if (ret < 0) + { + ret = -ret; + goto errout_with_inode; + } + + /* Successfully stat'ed the file */ + + inode_release(inode); + RELEASE_SEARCH(&desc); + return OK; + +/* Failure conditions always set the errno appropriately */ + +errout_with_inode: + inode_release(inode); + +errout_with_search: + RELEASE_SEARCH(&desc); + set_errno(ret); + return ERROR; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stat + * + * Returned Value: + * Zero on success; -1 on failure with errno set: + * + * EACCES Search permission is denied for one of the directories in the + * path prefix of path. + * EFAULT Bad address. + * ENOENT A component of the path path does not exist, or the path is an + * empty string. + * ENOMEM Out of memory + * ENOTDIR A component of the path is not a directory. + * + ****************************************************************************/ + +int stat(FAR const char *path, FAR struct stat *buf) +{ + int ret; + + /* Sanity checks */ + + if (path == NULL || buf == NULL) + { + ret = EFAULT; + goto errout; + } + + if (*path == '\0') + { + ret = ENOENT; + goto errout; + } + + /* Check for the fake root directory (which has no inode) */ + + if (strcmp(path, "/") == 0) + { + return statroot(buf); + } + + /* The perform the stat() operation on the path. This is potentially + * recursive if soft link support is enabled. + */ + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + buf->st_count = 0; +#endif + return stat_recursive(path, buf); + +errout: + set_errno(ret); + return ERROR; +} + +/**************************************************************************** + * Name: inode_stat + * + * Description: + * The inode_stat() function will obtain information about an 'inode' in + * the pseudo file system and will write it to the area pointed to by 'buf'. + * + * The 'buf' argument is a pointer to a stat structure, as defined in + * , into which information is placed concerning the file. + * + * Input Parameters: + * inode - The indoe of interest + * buf - The caller provide location in which to return information about + * the inode. + * + * Returned Value: + * Zero (OK) returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int inode_stat(FAR struct inode *inode, FAR struct stat *buf) +{ + DEBUGASSERT(inode != NULL && buf != NULL); + /* Most of the stat entries just do not apply */ RESET_BUF(buf); @@ -210,170 +395,3 @@ static inline int statpseudo(FAR struct inode *inode, FAR struct stat *buf) return OK; } - -/**************************************************************************** - * Name: statroot - ****************************************************************************/ - -static inline int statroot(FAR struct stat *buf) -{ - /* There is no inode associated with the fake root directory */ - - RESET_BUF(buf); - buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; - return OK; -} - -/**************************************************************************** - * Name: stat_recursive - * - * Returned Value: - * Zero on success; -1 on failure with errno set: - * - * EACCES Search permission is denied for one of the directories in the - * path prefix of path. - * EFAULT Bad address. - * ENOENT A component of the path path does not exist, or the path is an - * empty string. - * ENOMEM Out of memory - * ENOTDIR A component of the path is not a directory. - * - ****************************************************************************/ - -int stat_recursive(FAR const char *path, FAR struct stat *buf) -{ - struct inode_search_s desc; - FAR struct inode *inode; - int ret; - - /* Get an inode for this path */ - - SETUP_SEARCH(&desc, path, true); - - ret = inode_find(&desc); - if (ret < 0) - { - /* This name does not refer to a psudeo-inode and there is no - * mountpoint that includes in this path. - */ - - ret = -ret; - goto errout_with_search; - } - - /* Get the search results */ - - inode = desc.node; - DEBUGASSERT(inode != NULL); - - /* The way we handle the stat depends on the type of inode that we - * are dealing with. - */ - -#ifndef CONFIG_DISABLE_MOUNTPOINT - if (INODE_IS_MOUNTPT(inode)) - { - /* The node is a file system mointpoint. Verify that the mountpoint - * supports the stat() method - */ - - if (inode->u.i_mops && inode->u.i_mops->stat) - { - /* Perform the stat() operation */ - - ret = inode->u.i_mops->stat(inode, desc.relpath, buf); - } - } - else -#endif - { - /* The node is part of the root pseudo file system. This path may - * recurse if soft links are supported in the pseudo file system. - */ - - ret = statpseudo(inode, buf); - } - - /* Check if the stat operation was successful */ - - if (ret < 0) - { - ret = -ret; - goto errout_with_inode; - } - - /* Successfully stat'ed the file */ - - inode_release(inode); - RELEASE_SEARCH(&desc); - return OK; - -/* Failure conditions always set the errno appropriately */ - -errout_with_inode: - inode_release(inode); - -errout_with_search: - RELEASE_SEARCH(&desc); - set_errno(ret); - return ERROR; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stat - * - * Returned Value: - * Zero on success; -1 on failure with errno set: - * - * EACCES Search permission is denied for one of the directories in the - * path prefix of path. - * EFAULT Bad address. - * ENOENT A component of the path path does not exist, or the path is an - * empty string. - * ENOMEM Out of memory - * ENOTDIR A component of the path is not a directory. - * - ****************************************************************************/ - -int stat(FAR const char *path, FAR struct stat *buf) -{ - int ret; - - /* Sanity checks */ - - if (path == NULL || buf == NULL) - { - ret = EFAULT; - goto errout; - } - - if (*path == '\0') - { - ret = ENOENT; - goto errout; - } - - /* Check for the fake root directory (which has no inode) */ - - if (strcmp(path, "/") == 0) - { - return statroot(buf); - } - - /* The perform the stat() operation on the path. This is potentially - * recursive if soft link support is enabled. - */ - -#ifdef CONFIG_PSEUDOFS_SOFTLINKS - buf->st_count = 0; -#endif - return stat_recursive(path, buf); - -errout: - set_errno(ret); - return ERROR; -} diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index bdc07646ab6..809325389c7 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -265,6 +265,7 @@ struct mountpt_operations int (*sync)(FAR struct file *filep); int (*dup)(FAR const struct file *oldp, FAR struct file *newp); + int (*fstat)(FAR const struct file *filep, FAR struct stat *buf); /* Directory operations */ diff --git a/include/sys/stat.h b/include/sys/stat.h index 9281515121b..4d82f62d5e2 100644 --- a/include/sys/stat.h +++ b/include/sys/stat.h @@ -130,8 +130,8 @@ struct stat time_t st_mtime; /* Time of last modification */ time_t st_ctime; /* Time of last status change */ - /* Internal fields. These are part this specifi instance and should not - * referenced by application code for portability reasons. + /* Internal fields. These are part this specific implementation and + * should not referenced by application code for portability reasons. */ #ifdef CONFIG_PSEUDOFS_SOFTLINKS @@ -155,9 +155,7 @@ extern "C" int mkdir(FAR const char *pathname, mode_t mode); int mkfifo(FAR const char *pathname, mode_t mode); int stat(const char *path, FAR struct stat *buf); -#if 0 /* Not yet supported */ int fstat(int fd, FAR struct stat *buf); -#endif #undef EXTERN #if defined(__cplusplus)