void seekdir(FAR DIR *dirp, off_t offset) { struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; /* Verify that we were provided with a valid directory structure, * A special case is when we enumerate an "empty", unused inode (fd_root * == 0). That is an inode in the pseudo-filesystem that has no * operations and no children. This is a "dangling" directory entry that * has lost its children. */ if (!idir || !idir->fd_root) { return; } /* The way we handle the readdir depends on the type of inode * that we are dealing with. */ #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(idir->fd_root)) { /* The node is a file system mointpoint */ seekmountptdir(idir, offset); } else #endif { /* The node is part of the root pseudo file system */ seekpseudodir(idir, offset); } }
void seekdir(FAR DIR *dirp, off_t offset) { struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; /* Sanity checks */ if (!idir || !idir->fd_root) { return; } /* The way we handle the readdir depends on the type of inode * that we are dealing with. */ #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(idir->fd_root)) { /* The node is a file system mointpoint */ seekmountptdir(idir, offset); } else #endif { /* The node is part of the root pseudo file system */ seekpseudodir(idir, offset); } }
int rmdir(FAR const char *pathname) { FAR struct inode *inode; const char *relpath = NULL; int ret; /* Get an inode for this file */ inode = inode_find(pathname, &relpath); if (!inode) { /* There is no mountpoint that includes in this path */ ret = ENOENT; goto errout; } /* Verify that the inode is a valid mountpoint. */ if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops) { ret = ENXIO; goto errout_with_inode; } /* Perform the rmdir operation using the relative path * at the mountpoint. */ if (inode->u.i_mops->rmdir) { ret = inode->u.i_mops->rmdir(inode, relpath); if (ret < 0) { ret = -ret; goto errout_with_inode; } } else { ret = ENOSYS; goto errout_with_inode; } /* Successfully removed the directory */ inode_release(inode); return OK; errout_with_inode: inode_release(inode); errout: set_errno(ret); return ERROR; }
static int mountpoint_filter(FAR struct inode *node, FAR char dirpath[PATH_MAX], FAR void *arg) { FAR struct enum_mountpoint_s *info = (FAR struct enum_mountpoint_s *)arg; struct statfs statbuf; int pathlen; int namlen; int ret = OK; DEBUGASSERT(node && info && info->handler); /* Check if the inode is a mountpoint. Mountpoints must support statfs. * If this one does not for some reason, then it will be ignored. * * The root node is a special case: It has no operations (u.i_mops == NULL) */ if (INODE_IS_MOUNTPT(node) && node->u.i_mops && node->u.i_mops->statfs) { /* Yes... get the full path to the inode by concatenating the inode * name and the path to the directory containing the inode. */ pathlen = strlen(dirpath); namlen = strlen(node->i_name) + 1; /* Make sure that this would not exceed the maximum path length */ if (pathlen + namlen > PATH_MAX) { return -ENAMETOOLONG; } /* Append the inode name to the directory path */ sprintf(&dirpath[pathlen], "/%s", node->i_name); /* Get the status of the file system */ ret = node->u.i_mops->statfs(node, &statbuf); if (ret == OK) { /* And pass the full path and file system status to the handler */ ret = info->handler(dirpath, &statbuf, info->arg); } /* Truncate the path name back to the correct length */ dirpath[pathlen] = '\0'; } return ret; }
static inline void syslog_flush(void) { FAR struct inode *inode = g_sysdev.sl_file.f_inode; /* Is this a mountpoint? Does it support the sync method? */ if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops->sync) { /* Yes... synchronize to the stream */ (void)inode->u.i_mops->sync(&g_sysdev.sl_file); } }
int inode_stat(FAR struct inode *inode, FAR struct stat *buf) { DEBUGASSERT(inode != NULL && buf != NULL); memset(buf, 0, sizeof(*buf)); if (INODE_IS_SPECIAL(inode)) { #if defined(CONFIG_FS_NAMED_SEMAPHORES) if (INODE_IS_NAMEDSEM(inode)) { buf->st_mode = S_IFSEM; } else #endif #if !defined(CONFIG_DISABLE_MQUEUE) if (INODE_IS_MQUEUE(inode)) { buf->st_mode = S_IFMQ; } else #endif { } } else if (inode->u.i_ops != NULL) { /* Determine read/write privileges based on the existence of read * and write methods. */ if (inode->u.i_ops->read) { buf->st_mode = S_IROTH | S_IRGRP | S_IRUSR; } if (inode->u.i_ops->write) { buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR; } /* Determine the type of the inode */ if (INODE_IS_MOUNTPT(inode)) { buf->st_mode |= S_IFDIR; } else if (INODE_IS_BLOCK(inode)) { /* What is if also has child inodes? */ buf->st_mode |= S_IFBLK; } else /* if (INODE_IS_DRIVER(inode)) */ { /* What is it if it also has child inodes? */ buf->st_mode |= S_IFCHR; } } else { /* If it has no operations, then it must just be a intermediate * node in the inode tree. It is something like a directory. * We'll say that all pseudo-directories are read-able but not * write-able. */ buf->st_mode |= S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR; } return OK; }
static inline int statpseudo(FAR struct inode *inode, FAR struct stat *buf) { /* Most of the stat entries just do not apply */ memset(buf, 0, sizeof(struct stat) ); if (inode->u.i_ops) { if (inode->u.i_ops->read) { buf->st_mode = S_IROTH|S_IRGRP|S_IRUSR; } if (inode->u.i_ops->write) { buf->st_mode |= S_IWOTH|S_IWGRP|S_IWUSR; } if (INODE_IS_MOUNTPT(inode)) { buf->st_mode |= S_IFDIR; } else if (INODE_IS_BLOCK(inode)) { /* What is it also has child inodes? */ buf->st_mode |= S_IFBLK; } else { /* What is it if it also has child inodes? */ buf->st_mode |= S_IFCHR; } } else { /* If it has no operations, then it must just be a intermediate * node in the inode tree. It is something like a directory. * We'll say that all pseudo-directories are read-able but not * write-able. */ buf->st_mode |= S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR; } return OK; }
int file_fstat(FAR struct file *filep, FAR struct stat *buf) { FAR struct inode *inode; int ret; DEBUGASSERT(filep != NULL); /* 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 mountpoint. Verify that the mountpoint * supports the fstat() method */ ret = -ENOSYS; 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); } return ret; }
void rewinddir(FAR DIR *dirp) { struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; #ifndef CONFIG_DISABLE_MOUNTPOINT struct inode *inode; #endif /* Sanity checks */ if (!idir || !idir->fd_root) { return; } /* The way we handle the readdir depends on the type of inode * that we are dealing with. */ #ifndef CONFIG_DISABLE_MOUNTPOINT inode = idir->fd_root; if (INODE_IS_MOUNTPT(inode)) { /* The node is a file system mointpoint. Verify that the mountpoint * supports the rewinddir() method */ if (inode->u.i_mops && inode->u.i_mops->rewinddir) { /* Perform the rewinddir() operation */ inode->u.i_mops->rewinddir(inode, idir); } } else #endif { /* The node is part of the root pseudo file system */ rewindpseudodir(idir); } }
FAR struct dirent *readdir(DIR *dirp) { FAR struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; struct inode *inode; int ret; /* Verify that we were provided with a valid directory structure */ if (!idir) { ret = EBADF; goto errout; } /* A special case is when we enumerate an "empty", unused inode. That is * an inode in the pseudo-filesystem that has no operations and no children. * This is a "dangling" directory entry that has lost its children. */ inode = idir->fd_root; if (!inode) { /* End of file and error conditions are not distinguishable * with readdir. We return NULL to signal either case. */ ret = OK; goto errout; } /* The way we handle the readdir depends on the type of inode * that we are dealing with. */ #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSEUDONODE(idir->fd_flags)) { /* The node is a file system mointpoint. Verify that the mountpoint * supports the readdir() method */ if (!inode->u.i_mops || !inode->u.i_mops->readdir) { ret = EACCES; goto errout; } /* Perform the readdir() operation */ ret = inode->u.i_mops->readdir(inode, idir); } else #endif { /* The node is part of the root pseudo file system */ ret = readpseudodir(idir); } /* ret < 0 is an error. Special case: ret = -ENOENT is end of file */ if (ret < 0) { if (ret == -ENOENT) { ret = OK; } else { ret = -ret; } goto errout; } /* Success */ idir->fd_position++; return &idir->fd_dir; errout: set_errno(ret); return NULL; }
FAR DIR *opendir(FAR const char *path) { FAR struct inode *inode = NULL; FAR struct fs_dirent_s *dir; FAR const char *relpath; bool isroot = false; int ret; /* If we are given 'nothing' then we will interpret this as * request for the root inode. */ inode_semtake(); if (!path || *path == 0 || strcmp(path, "/") == 0) { inode = root_inode; isroot = true; relpath = NULL; } else { /* We don't know what to do with relative pathes */ if (*path != '/') { ret = -ENOTDIR; goto errout_with_semaphore; } /* Find the node matching the path. */ inode = inode_search(&path, (FAR struct inode**)NULL, (FAR struct inode**)NULL, &relpath); } /* Did we get an inode? */ if (!inode) { /* 'path' is not a does not exist.*/ ret = ENOTDIR; goto errout_with_semaphore; } /* Allocate a type DIR -- which is little more than an inode * container. */ dir = (FAR struct fs_dirent_s *)kuzalloc(sizeof(struct fs_dirent_s)); if (!dir) { /* Insufficient memory to complete the operation.*/ ret = ENOMEM; goto errout_with_semaphore; } /* Populate the DIR structure and return it to the caller. The way that * we do this depends on whenever this is a "normal" pseudo-file-system * inode or a file system mountpoint. */ dir->fd_position = 0; /* This is the position in the read stream */ /* First, handle the special case of the root inode. This must be * special-cased here because the root inode might ALSO be a mountpoint. */ if (isroot) { /* Whatever payload the root inode carries, the root inode is always * a directory inode in the pseudo-file system */ open_pseudodir(inode, dir); } /* Is this a node in the pseudo filesystem? Or a mountpoint? If the node * is the root (isroot == TRUE), then this is a special case. */ #ifndef CONFIG_DISABLE_MOUNTPOINT else if (INODE_IS_MOUNTPT(inode)) { /* Yes, the node is a file system mountpoint */ dir->fd_root = inode; /* Save the inode where we start */ /* Open the directory at the relative path */ ret = open_mountpoint(inode, relpath, dir); if (ret != OK) { goto errout_with_direntry; } } #endif else { /* The node is part of the root pseudo file system. Does the inode * have a child? If so that the child would be the 'root' of a list * of nodes under the directory. */ FAR struct inode *child = inode->i_child; if (child) { /* It looks we have a valid pseudo-filesystem directory node. */ open_pseudodir(child, dir); } else if (!inode->u.i_ops) { /* This is a dangling node with no children and no operations. Set * up to enumerate an empty directory. */ open_emptydir(dir); } else { ret = ENOTDIR; goto errout_with_direntry; } } inode_semgive(); return ((DIR*)dir); /* Nasty goto's make error handling simpler */ errout_with_direntry: kufree(dir); errout_with_semaphore: inode_semgive(); set_errno(ret); return NULL; }
int rmdir(FAR const char *pathname) { FAR struct inode *inode; const char *relpath = NULL; int errcode; /* Get an inode for this file. inode_find() automatically increments the * reference count on the inode if one is found. */ inode = inode_find(pathname, &relpath); if (!inode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } #ifndef CONFIG_DISABLE_MOUNTPOINT /* Check if the inode is a valid mountpoint. */ if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops) { /* Perform the rmdir operation using the relative path * from the mountpoint. */ if (inode->u.i_mops->rmdir) { int ret = inode->u.i_mops->rmdir(inode, relpath); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOSYS; goto errout_with_inode; } } else #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* If this is a "dangling" pseudo-directory node (i.e., it has no operations) * then rmdir should remove the node. */ if (!inode->u.i_ops) { int ret; /* If the directory inode has children, however, then it cannot be * removed. */ if (inode->i_child) { errcode = ENOTEMPTY; goto errout_with_inode; } /* Remove the inode. NOTE: Because we hold a reference count on the * inode, it will not be deleted now. But probably when inode_release() * is called below. inode_remove should return -EBUSY to indicate that * the inode was not deleted now. */ inode_semtake(); ret = inode_remove(pathname); inode_semgive(); if (ret < 0 && ret != -EBUSY) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOTDIR; goto errout_with_inode; } #else { errcode = ENXIO; goto errout_with_inode; } #endif /* Successfully removed the directory */ inode_release(inode); return OK; errout_with_inode: inode_release(inode); errout: set_errno(errcode); return ERROR; }
int open(const char *path, int oflags, ...) { FAR struct filelist *list; FAR struct inode *inode; FAR const char *relpath = NULL; #if defined(CONFIG_FILE_MODE) || !defined(CONFIG_DISABLE_MOUNTPOINT) mode_t mode = 0666; #endif int ret; int fd; /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { ret = EMFILE; goto errout; } #ifdef CONFIG_FILE_MODE # ifdef CONFIG_CPP_HAVE_WARNING # warning "File creation not implemented" # endif /* If the file is opened for creation, then get the mode bits */ if (oflags & (O_WRONLY|O_CREAT) != 0) { va_list ap; va_start(ap, oflags); mode = va_arg(ap, mode_t); va_end(ap); } #endif /* Get an inode for this file */ inode = inode_find(path, &relpath); if (!inode) { /* "O_CREAT is not set and the named file does not exist. Or, a * directory component in pathname does not exist or is a dangling * symbolic link." */ ret = ENOENT; goto errout; } /* Verify that the inode is valid and either a "normal" or a mountpoint. We * specifically exclude block drivers. */ #ifndef CONFIG_DISABLE_MOUNTPOINT if ((!INODE_IS_DRIVER(inode) && !INODE_IS_MOUNTPT(inode)) || !inode->u.i_ops) #else if (!INODE_IS_DRIVER(inode) || !inode->u.i_ops) #endif { ret = ENXIO; goto errout_with_inode; } /* Make sure that the inode supports the requested access */ ret = inode_checkflags(inode, oflags); if (ret < 0) { ret = -ret; goto errout_with_inode; } /* Associate the inode with a file structure */ fd = files_allocate(inode, oflags, 0, 0); if (fd < 0) { ret = EMFILE; goto errout_with_inode; } /* Perform the driver open operation. NOTE that the open method may be * called many times. The driver/mountpoint logic should handled this * because it may also be closed that many times. */ ret = OK; if (inode->u.i_ops->open) { #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(inode)) { ret = inode->u.i_mops->open((FAR struct file*)&list->fl_files[fd], relpath, oflags, mode); } else #endif { ret = inode->u.i_ops->open((FAR struct file*)&list->fl_files[fd]); } } if (ret < 0) { ret = -ret; goto errout_with_fd; } return fd; errout_with_fd: files_release(fd); errout_with_inode: inode_release(inode); errout: set_errno(ret); return ERROR; }
int rename(FAR const char *oldpath, FAR const char *newpath) { FAR struct inode *oldinode; FAR struct inode *newinode; const char *oldrelpath = NULL; #ifndef CONFIG_DISABLE_MOUNTPOINT const char *newrelpath = NULL; #endif int errcode; int ret; /* Ignore paths that are interpreted as the root directory which has no name * and cannot be moved */ if (!oldpath || *oldpath == '\0' || oldpath[0] != '/' || !newpath || *newpath == '\0' || newpath[0] != '/') { return -EINVAL; } /* Get an inode that includes the oldpath */ oldinode = inode_find(oldpath, &oldrelpath); if (!oldinode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } #ifndef CONFIG_DISABLE_MOUNTPOINT /* Verify that the old inode is a valid mountpoint. */ if (INODE_IS_MOUNTPT(oldinode) && oldinode->u.i_mops) { /* Get an inode for the new relpath -- it should like on the same * mountpoint */ newinode = inode_find(newpath, &newrelpath); if (!newinode) { /* There is no mountpoint that includes in this path */ errcode = ENOENT; goto errout_with_oldinode; } /* Verify that the two paths lie on the same mountpoint inode */ if (oldinode != newinode) { errcode = EXDEV; goto errout_with_newinode; } /* Perform the rename operation using the relative paths * at the common mountpoint. */ if (oldinode->u.i_mops->rename) { ret = oldinode->u.i_mops->rename(oldinode, oldrelpath, newrelpath); if (ret < 0) { errcode = -ret; goto errout_with_newinode; } } else { errcode = ENOSYS; goto errout_with_newinode; } /* Successfully renamed */ inode_release(newinode); } else #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS { /* Create a new, empty inode at the destination location. * NOTE that the new inode will be created with a reference count * of zero. */ inode_semtake(); ret = inode_reserve(newpath, &newinode); if (ret < 0) { /* It is an error if a node at newpath already exists in the tree * OR if we fail to allocate memory for the new inode (and possibly * any new intermediate path segments). */ inode_semgive(); errcode = EEXIST; goto errout_with_oldinode; } /* Copy the inode state from the old inode to the newly allocated inode */ newinode->i_child = oldinode->i_child; /* Link to lower level inode */ newinode->i_flags = oldinode->i_flags; /* Flags for inode */ newinode->u.i_ops = oldinode->u.i_ops; /* Inode operations */ #ifdef CONFIG_FILE_MODE newinode->i_mode = oldinode->i_mode; /* Access mode flags */ #endif newinode->i_private = oldinode->i_private; /* Per inode driver private data */ /* We now have two copies of the inode. One with a reference count of * zero (the new one), and one that may have multiple references * including one by this logic (the old one) * * Remove the old inode. Because we hold a reference count on the * inode, it will not be deleted now. It will be deleted when all of * the references to to the inode have been released (perhaps when * inode_release() is called below). inode_remove() should return * -EBUSY to indicate that the inode was not deleted now. */ ret = inode_remove(oldpath); if (ret < 0 && ret != -EBUSY) { /* Remove the new node we just recreated */ (void)inode_remove(newpath); inode_semgive(); errcode = -ret; goto errout_with_oldinode; } /* Remove all of the children from the unlinked inode */ oldinode->i_child = NULL; inode_semgive(); } #else { errcode = ENXIO; goto errout; } #endif /* Successfully renamed */ inode_release(oldinode); return OK; #ifndef CONFIG_DISABLE_MOUNTPOINT errout_with_newinode: inode_release(newinode); #endif errout_with_oldinode: inode_release(oldinode); errout: set_errno(errcode); return ERROR; }
int stat(const char *path, FAR struct stat *buf) { FAR struct inode *inode; const char *relpath = NULL; int ret = OK; /* Sanity checks */ if (!path || !buf) { 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); } /* Get an inode for this file */ inode = inode_find(path, &relpath); if (!inode) { /* This name does not refer to a psudeo-inode and there is no * mountpoint that includes in this path. */ ret = ENOENT; goto errout; } /* 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, relpath, buf); } } else #endif { /* The node is part of the root 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); return OK; /* Failure conditions always set the errno appropriately */ errout_with_inode: inode_release(inode); errout: set_errno(ret); return ERROR; }
int umount(const char *target) { FAR struct inode *mountpt_inode; FAR struct inode *blkdrvr_inode = NULL; int errcode = OK; int status; /* Verify required pointer arguments */ if (!target) { errcode = EFAULT; goto errout; } /* Find the mountpt */ mountpt_inode = inode_find(target, NULL); if (!mountpt_inode) { errcode = ENOENT; goto errout; } /* Verify that the inode is a mountpoint */ if (!INODE_IS_MOUNTPT(mountpt_inode)) { errcode = EINVAL; goto errout_with_mountpt; } /* Unbind the block driver from the file system (destroying any fs * private data. */ if (!mountpt_inode->u.i_mops->unbind) { /* The filesystem does not support the unbind operation ??? */ errcode = EINVAL; goto errout_with_mountpt; } /* The unbind method returns the number of references to the * filesystem (i.e., open files), zero if the unbind was * performed, or a negated error code on a failure. */ inode_semtake(); /* Hold the semaphore through the unbind logic */ status = mountpt_inode->u.i_mops->unbind( mountpt_inode->i_private, &blkdrvr_inode); if (status < 0) { /* The inode is unhappy with the blkdrvr for some reason */ errcode = -status; goto errout_with_semaphore; } else if (status > 0) { errcode = EBUSY; goto errout_with_semaphore; } /* Successfully unbound */ mountpt_inode->i_private = NULL; /* Successfully unbound, remove the mountpoint inode from * the inode tree. The inode will not be deleted yet because * there is still at least reference on it (from the mount) */ status = inode_remove(target); inode_semgive(); /* The return value of -EBUSY is normal (in fact, it should * not be OK) */ if (status != OK && status != -EBUSY) { errcode = -status; goto errout_with_mountpt; } /* Release the mountpoint inode and any block driver inode * returned by the file system unbind above. This should cause * the inode to be deleted (unless there are other references) */ inode_release(mountpt_inode); /* Did the unbind method return a contained block driver */ if (blkdrvr_inode) { inode_release(blkdrvr_inode); } return OK; /* A lot of goto's! But they make the error handling much simpler */ errout_with_semaphore: inode_semgive(); errout_with_mountpt: inode_release(mountpt_inode); if (blkdrvr_inode) { inode_release(blkdrvr_inode); } errout: set_errno(errcode); return ERROR; }
FAR struct dirent *readdir(DIR *dirp) { FAR struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; #ifndef CONFIG_DISABLE_MOUNTPOINT struct inode *inode; #endif int ret; /* Sanity checks */ if (!idir || !idir->fd_root) { ret = EBADF; goto errout; } /* The way we handle the readdir depends on the type of inode * that we are dealing with. */ #ifndef CONFIG_DISABLE_MOUNTPOINT inode = idir->fd_root; if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSUEDONODE(idir->fd_flags)) { /* The node is a file system mointpoint. Verify that the mountpoint * supports the readdir() method */ if (!inode->u.i_mops || !inode->u.i_mops->readdir) { ret = EACCES; goto errout; } /* Perform the readdir() operation */ ret = inode->u.i_mops->readdir(inode, idir); } else #endif { /* The node is part of the root psuedo file system */ ret = readpsuedodir(idir); } /* ret < 0 is an error. Special case: ret = -ENOENT is end of file */ if ( ret < 0) { if (ret == -ENOENT) { ret = OK; } else { ret = -ret; } goto errout; } /* Success */ idir->fd_position++; return &idir->fd_dir; errout: *get_errno_ptr() = ret; return NULL; }
int open(const char *path, int oflags, ...) { FAR struct file *filep; FAR struct inode *inode; FAR const char *relpath = NULL; #if defined(CONFIG_FILE_MODE) || !defined(CONFIG_DISABLE_MOUNTPOINT) mode_t mode = 0666; #endif int ret; int fd; #ifdef CONFIG_FILE_MODE # ifdef CONFIG_CPP_HAVE_WARNING # warning "File creation not implemented" # endif /* If the file is opened for creation, then get the mode bits */ if ((oflags & (O_WRONLY | O_CREAT)) != 0) { va_list ap; va_start(ap, oflags); mode = va_arg(ap, mode_t); va_end(ap); } #endif /* Get an inode for this file */ inode = inode_find(path, &relpath); if (!inode) { /* "O_CREAT is not set and the named file does not exist. Or, a * directory component in pathname does not exist or is a dangling * symbolic link." */ ret = ENOENT; goto errout; } #if !defined(CONFIG_DISABLE_PSEUDOFS_OPERATIONS) && \ !defined(CONFIG_DISABLE_MOUNTPOINT) /* If the inode is block driver, then we may return a character driver * proxy for the block driver. block_proxy() will instantiate a BCH * character driver wrapper around the block driver, open(), then * unlink() the character driver. On success, block_proxy() will * return the file descriptor of the opened character driver. * * NOTE: This will recurse to open the character driver proxy. */ if (INODE_IS_BLOCK(inode)) { /* Release the inode reference */ inode_release(inode); /* Get the file descriptor of the opened character driver proxy */ fd = block_proxy(path, oflags); if (fd < 0) { ret = fd; goto errout; } /* Return the file descriptor */ return fd; } else #endif /* Verify that the inode is either a "normal" character driver or a * mountpoint. We specifically "special" inodes (semaphores, message * queues, shared memory). */ #ifndef CONFIG_DISABLE_MOUNTPOINT if ((!INODE_IS_DRIVER(inode) && !INODE_IS_MOUNTPT(inode)) || !inode->u.i_ops) #else if (!INODE_IS_DRIVER(inode) || !inode->u.i_ops) #endif { ret = ENXIO; goto errout_with_inode; } /* Make sure that the inode supports the requested access */ ret = inode_checkflags(inode, oflags); if (ret < 0) { ret = -ret; goto errout_with_inode; } /* Associate the inode with a file structure */ fd = files_allocate(inode, oflags, 0, 0); if (fd < 0) { ret = EMFILE; goto errout_with_inode; } /* Get the file structure corresponding to the file descriptor. */ filep = fs_getfilep(fd); if (!filep) { /* The errno value has already been set */ return ERROR; } /* Perform the driver open operation. NOTE that the open method may be * called many times. The driver/mountpoint logic should handled this * because it may also be closed that many times. */ ret = OK; if (inode->u.i_ops->open) { #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(inode)) { ret = inode->u.i_mops->open(filep, relpath, oflags, mode); } else #endif { ret = inode->u.i_ops->open(filep); } } if (ret < 0) { ret = -ret; goto errout_with_fd; } return fd; errout_with_fd: files_release(fd); errout_with_inode: inode_release(inode); errout: set_errno(ret); return ERROR; }
FAR struct inode *inode_search(const char **path, FAR struct inode **peer, FAR struct inode **parent, const char **relpath) { const char *name = *path + 1; /* Skip over leading '/' */ FAR struct inode *node = root_inode; FAR struct inode *left = NULL; FAR struct inode *above = NULL; while (node) { int result = _inode_compare(name, node); /* Case 1: The name is less than the name of the node. * Since the names are ordered, these means that there * is no peer node with this name and that there can be * no match in the fileystem. */ if (result < 0) { node = NULL; break; } /* Case 2: the name is greater than the name of the node. * In this case, the name may still be in the list to the * "right" */ else if (result > 0) { left = node; node = node->i_peer; } /* The names match */ else { /* Now there are three more possibilities: * (1) This is the node that we are looking for or, * (2) The node we are looking for is "below" this one. * (3) This node is a mountpoint and will absorb all request * below this one */ name = inode_nextname(name); if (!*name || INODE_IS_MOUNTPT(node)) { /* Either (1) we are at the end of the path, so this must be the * node we are looking for or else (2) this node is a mountpoint * and will handle the remaining part of the pathname */ if (relpath) { *relpath = name; } break; } else { /* More to go, keep looking at the next level "down" */ above = node; left = NULL; node = node->i_child; } } } /* node is null. This can happen in one of four cases: * With node = NULL * (1) We went left past the final peer: The new node * name is larger than any existing node name at * that level. * (2) We broke out in the middle of the list of peers * because the name was not found in the ordered * list. * (3) We went down past the final parent: The new node * name is "deeper" than anything that we currently * have in the tree. * with node != NULL * (4) When the node matching the full path is found */ if (peer) { *peer = left; } if (parent) { *parent = above; } *path = name; return node; }
int mkdir(const char *pathname, mode_t mode) { FAR struct inode *inode; const char *relpath = NULL; int errcode; int ret; /* Find the inode that includes this path */ inode = inode_find(pathname, &relpath); if (inode) { /* An inode was found that includes this path and possibly refers to a * mountpoint. */ #ifndef CONFIG_DISABLE_MOUNTPOINT /* Check if the inode is a valid mountpoint. */ if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops) { /* The inode is not a mountpoint */ errcode = ENXIO; goto errout_with_inode; } /* Perform the mkdir operation using the relative path * at the mountpoint. */ if (inode->u.i_mops->mkdir) { ret = inode->u.i_mops->mkdir(inode, relpath, mode); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOSYS; goto errout_with_inode; } /* Release our reference on the inode */ inode_release(inode); #else /* But mountpoints are not supported in this configuration */ errcode = EEXIST; goto errout_with_inode; #endif } #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* No inode exists that contains this path. Create a new inode in the * pseudo-filesystem at this location. */ else { /* Create an inode in the pseudo-filesystem at this path */ inode_semtake(); ret = inode_reserve(pathname, &inode); inode_semgive(); if (ret < 0) { errcode = -ret; goto errout; } } #else else {
static inline int readpsuedodir(struct fs_dirent_s *idir) { FAR struct inode *prev; /* Check if we are at the end of the list */ if (!idir->u.psuedo.fd_next) { /* End of file and error conditions are not distinguishable * with readdir. Here we return -ENOENT to signal the end * of the directory. */ return -ENOENT; } /* Copy the inode name into the dirent structure */ strncpy(idir->fd_dir.d_name, idir->u.psuedo.fd_next->i_name, NAME_MAX+1); /* If the node has file operations, we will say that it is * a file. */ idir->fd_dir.d_type = 0; if (idir->u.psuedo.fd_next->u.i_ops) { #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_BLOCK(idir->u.psuedo.fd_next)) { idir->fd_dir.d_type |= DTYPE_BLK; } if (INODE_IS_MOUNTPT(idir->u.psuedo.fd_next)) { idir->fd_dir.d_type |= DTYPE_DIRECTORY; } else #endif { idir->fd_dir.d_type |= DTYPE_CHR; } } /* If the node has child node(s), then we will say that it * is a directory. NOTE: that the node can be both! */ if (idir->u.psuedo.fd_next->i_child || !idir->u.psuedo.fd_next->u.i_ops) { idir->fd_dir.d_type |= DTYPE_DIRECTORY; } /* Now get the inode to vist next time that readdir() is called */ inode_semtake(); prev = idir->u.psuedo.fd_next; idir->u.psuedo.fd_next = prev->i_peer; /* The next node to visit */ if (idir->u.psuedo.fd_next) { /* Increment the reference count on this next node */ idir->u.psuedo.fd_next->i_crefs++; } inode_semgive(); if (prev) { inode_release(prev); } return OK; }
int umount2(FAR const char *target, unsigned int flags) { FAR struct inode *mountpt_inode; FAR struct inode *blkdrvr_inode = NULL; struct inode_search_s desc; int errcode = OK; int ret; /* Verify required pointer arguments */ if (!target) { errcode = EFAULT; goto errout; } /* Find the mountpt */ SETUP_SEARCH(&desc, target, false); ret = inode_find(&desc); if (ret < 0) { errcode = ENOENT; goto errout_with_search; } /* Get the search results */ mountpt_inode = desc.node; DEBUGASSERT(mountpt_inode != NULL); /* Verify that the inode is a mountpoint */ if (!INODE_IS_MOUNTPT(mountpt_inode)) { errcode = EINVAL; goto errout_with_mountpt; } /* Unbind the block driver from the file system (destroying any fs * private data. */ if (!mountpt_inode->u.i_mops->unbind) { /* The filesystem does not support the unbind operation ??? */ errcode = EINVAL; goto errout_with_mountpt; } /* The unbind method returns the number of references to the * filesystem (i.e., open files), zero if the unbind was * performed, or a negated error code on a failure. */ inode_semtake(); /* Hold the semaphore through the unbind logic */ ret = mountpt_inode->u.i_mops->unbind(mountpt_inode->i_private, &blkdrvr_inode, flags); if (ret < 0) { /* The inode is unhappy with the blkdrvr for some reason */ errcode = -ret; goto errout_with_semaphore; } else if (ret > 0) { errcode = EBUSY; goto errout_with_semaphore; } /* Successfully unbound. Convert the mountpoint inode to regular * pseudo-file inode. */ mountpt_inode->i_flags &= ~FSNODEFLAG_TYPE_MASK; mountpt_inode->i_private = NULL; mountpt_inode->u.i_mops = NULL; #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* If the node has children, then do not delete it. */ if (mountpt_inode->i_child != NULL) { /* Just decrement the reference count (without deleting it) */ DEBUGASSERT(mountpt_inode->i_crefs > 0); mountpt_inode->i_crefs--; } else #endif { /* Remove the mountpoint inode from the inode tree. The inode will * not be deleted yet because there is still at least reference on * it (from the mount) */ ret = inode_remove(target); inode_semgive(); /* The return value of -EBUSY is normal (in fact, it should * not be OK) */ if (ret != OK && ret != -EBUSY) { errcode = -ret; goto errout_with_mountpt; } /* Release the mountpoint inode and any block driver inode * returned by the file system unbind above. This should cause * the inode to be deleted (unless there are other references) */ inode_release(mountpt_inode); } /* Did the unbind method return a contained block driver */ if (blkdrvr_inode) { inode_release(blkdrvr_inode); } RELEASE_SEARCH(&desc); return OK; /* A lot of goto's! But they make the error handling much simpler */ errout_with_semaphore: inode_semgive(); errout_with_mountpt: inode_release(mountpt_inode); if (blkdrvr_inode) { inode_release(blkdrvr_inode); } errout_with_search: RELEASE_SEARCH(&desc); errout: set_errno(errcode); return ERROR; }
int syslog_initialize(void) { FAR struct inode *inode; FAR const char *relpath = NULL; int ret; /* At this point, the only expected states are SYSLOG_UNINITIALIZED or * SYSLOG_REOPEN.. Not SYSLOG_INITIALIZING, SYSLOG_FAILURE, SYSLOG_OPENED. */ DEBUGASSERT(g_sysdev.sl_state == SYSLOG_UNINITIALIZED || g_sysdev.sl_state == SYSLOG_REOPEN); g_sysdev.sl_state = SYSLOG_INITIALIZING; /* Try to open the device. * * Note that we cannot just call open. The syslog device must work on all * threads. Open returns a file descriptor that is valid only for the * task that opened the device (and its pthread children). Instead, we * essentially re-implement the guts of open() here so that we can get to * the thread-independent structures of the inode. */ /* Get an inode for this file/device */ inode = inode_find(CONFIG_SYSLOG_DEVPATH, &relpath); if (!inode) { /* The inode was not found. In this case, we will attempt to re-open * the device repeatedly. The assumption is that the device path is * valid but that the driver has not yet been registered. */ g_sysdev.sl_state = SYSLOG_REOPEN; return -ENOENT; } /* Verify that the inode is valid and either a character driver or a * mountpoint. */ #ifndef CONFIG_DISABLE_MOUNTPOINT if ((!INODE_IS_DRIVER(inode) && !INODE_IS_MOUNTPT(inode))) #else if (!INODE_IS_DRIVER(inode)) #endif { ret = -ENXIO; goto errout_with_inode; } /* Make sure that the "entity" at this inode supports write access */ if (!inode->u.i_ops || !inode->u.i_ops->write) { ret = -EACCES; goto errout_with_inode; } /* Initialize the file structure */ g_sysdev.sl_file.f_oflags = SYSLOG_OFLAGS; g_sysdev.sl_file.f_pos = 0; g_sysdev.sl_file.f_inode = inode; /* Perform the low-level open operation. */ ret = OK; if (inode->u.i_ops->open) { /* Is the inode a mountpoint? */ #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(inode)) { /* Yes. Open the device write-only, try to create it if it * doesn't exist, if the file that already exists, then append the * new log data to end of the file. */ ret = inode->u.i_mops->open(&g_sysdev.sl_file, relpath, SYSLOG_OFLAGS, 0666); } /* No... then it must be a character driver in the NuttX pseudo- * file system. */ else #endif { ret = inode->u.i_ops->open(&g_sysdev.sl_file); } } /* Was the file/device successfully opened? */ if (ret < 0) { ret = -ret; goto errout_with_inode; } /* The SYSLOG device is open and ready for writing. */ sem_init(&g_sysdev.sl_sem, 0, 1); g_sysdev.sl_holder = NO_HOLDER; g_sysdev.sl_state = SYSLOG_OPENED; return OK; errout_with_inode: inode_release(inode); g_sysdev.sl_state = SYSLOG_FAILURE; return ret; }
static int fat_attrib(const char *path, fat_attrib_t *retattrib, fat_attrib_t setbits, fat_attrib_t clearbits) { struct fat_mountpt_s *fs; struct fat_dirinfo_s dirinfo; FAR struct inode *inode; const char *relpath = NULL; uint8_t *direntry; uint8_t oldattributes; uint8_t newattributes; int ret; /* Get an inode for this file */ inode = inode_find(path, &relpath); if (!inode) { /* There is no mountpoint that includes in this path */ ret = ENOENT; goto errout; } /* Verify that the inode is a valid mountpoint. */ if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops || !inode->i_private) { ret = ENXIO; goto errout_with_inode; } /* Get the mountpoint private data from the inode structure */ fs = inode->i_private; /* Check if the mount is still healthy */ fat_semtake(fs); ret = fat_checkmount(fs); if (ret != OK) { goto errout_with_semaphore; } /* Find the file/directory entry for the oldrelpath */ ret = fat_finddirentry(fs, &dirinfo, relpath); if (ret != OK) { /* Some error occurred -- probably -ENOENT */ goto errout_with_semaphore; } /* Make sure that we found some valid file or directory */ if (dirinfo.fd_root) { /* Ooops.. we found the root directory */ ret = EACCES; goto errout_with_semaphore; } /* Get the current attributes */ direntry = &fs->fs_buffer[dirinfo.fd_seq.ds_offset]; oldattributes = DIR_GETATTRIBUTES(direntry); newattributes = oldattributes; /* Set or clear any bits as requested */ newattributes &= ~(clearbits & (FATATTR_READONLY|FATATTR_HIDDEN|FATATTR_SYSTEM|FATATTR_ARCHIVE)); newattributes |= (setbits & (FATATTR_READONLY|FATATTR_HIDDEN|FATATTR_SYSTEM|FATATTR_ARCHIVE)); /* Did any thingchange? */ if (newattributes != oldattributes) { DIR_PUTATTRIBUTES(direntry, newattributes); fs->fs_dirty = true; ret = fat_updatefsinfo(fs); if (ret != OK) { ret = -ret; goto errout_with_semaphore; } } /* Success */ if (retattrib) { *retattrib = newattributes; } fat_semgive(fs); inode_release(inode); return OK; errout_with_semaphore: fat_semgive(fs); errout_with_inode: inode_release(inode); errout: *get_errno_ptr() = ret; return ERROR; }
int unlink(FAR const char *pathname) { FAR struct inode *inode; const char *relpath = NULL; int errcode; int ret; /* Get an inode for this file */ inode = inode_find(pathname, &relpath); if (!inode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } #ifndef CONFIG_DISABLE_MOUNTPOINT /* Check if the inode is a valid mountpoint. */ if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops) { /* Perform the unlink operation using the relative path at the * mountpoint. */ if (inode->u.i_mops->unlink) { ret = inode->u.i_mops->unlink(inode, relpath); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } else { errcode = ENOSYS; goto errout_with_inode; } } else #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS /* If this is a "dangling" pseudo-file node (i.e., it has operations) then rm * should remove the node. */ if (!INODE_IS_SPECIAL(inode) && inode->u.i_ops) { /* If this is a pseudo-file node (i.e., it has no operations) * then rmdir should remove the node. */ if (inode->u.i_ops) { inode_semtake(); /* Refuse to unlink the inode if it has children. I.e., if it is * functioning as a directory and the directory is not empty. */ if (inode->i_child != NULL) { errcode = ENOTEMPTY; inode_semgive(); goto errout_with_inode; } /* Remove the old inode. Because we hold a reference count on the * inode, it will not be deleted now. It will be deleted when all * of the references to to the inode have been released (perhaps * when inode_release() is called below). inode_remove() will * return -EBUSY to indicate that the inode was not deleted now. */ ret = inode_remove(pathname); inode_semgive(); if (ret < 0 && ret != -EBUSY) { errcode = -ret; goto errout_with_inode; } } else { errcode = EISDIR; goto errout_with_inode; } } else #endif { errcode = ENXIO; goto errout_with_inode; } /* Successfully unlinked */ inode_release(inode); return OK; errout_with_inode: inode_release(inode); errout: set_errno(errcode); return ERROR; }
int files_dup(FAR struct file *filep1, FAR struct file *filep2) { FAR struct filelist *list; FAR struct inode *inode; int err; int ret; if (!filep1 || !filep1->f_inode || !filep2) { err = EBADF; goto errout; } list = sched_getfiles(); DEBUGASSERT(list); _files_semtake(list); /* If there is already an inode contained in the new file structure, * close the file and release the inode. */ ret = _files_close(filep2); if (ret < 0) { /* An error occurred while closing the driver */ goto errout_with_ret; } /* Increment the reference count on the contained inode */ inode = filep1->f_inode; inode_addref(inode); /* Then clone the file structure */ filep2->f_oflags = filep1->f_oflags; filep2->f_pos = filep1->f_pos; filep2->f_inode = inode; /* Call the open method on the file, driver, mountpoint so that it * can maintain the correct open counts. */ if (inode->u.i_ops && inode->u.i_ops->open) { #ifndef CONFIG_DISABLE_MOUNTPOINT if (INODE_IS_MOUNTPT(inode)) { /* Dup the open file on the in the new file structure */ ret = inode->u.i_mops->dup(filep1, filep2); } else #endif { /* (Re-)open the pseudo file or device driver */ ret = inode->u.i_ops->open(filep2); } /* Handle open failures */ if (ret < 0) { goto errout_with_inode; } } _files_semgive(list); return OK; /* Handler various error conditions */ errout_with_inode: inode_release(filep2->f_inode); filep2->f_oflags = 0; filep2->f_pos = 0; filep2->f_inode = NULL; errout_with_ret: err = -ret; _files_semgive(list); errout: set_errno(err); return ERROR; }