int find_blockdriver(FAR const char *pathname, int mountflags, FAR struct inode **ppinode) { FAR struct inode *inode; int ret = 0; /* Assume success */ /* Sanity checks */ #ifdef CONFIG_DEBUG if (!pathname || !ppinode) { ret = -EINVAL; goto errout; } #endif /* Find the inode registered with this pathname */ inode = inode_find(pathname, NULL); if (!inode) { fdbg("Failed to find %s\n", pathname); ret = -ENOENT; goto errout; } /* Verify that the inode is a block driver. */ if (!INODE_IS_BLOCK(inode)) { fdbg("%s is not a block driver\n", pathname); ret = -ENOTBLK; goto errout_with_inode; } /* Make sure that the inode supports the requested access */ if (!inode->u.i_bops || !inode->u.i_bops->read || (!inode->u.i_bops->write && (mountflags & MS_RDONLY) == 0)) { fdbg("%s does not support requested access\n", pathname); ret = -EACCES; goto errout_with_inode; } *ppinode = inode; return OK; errout_with_inode: inode_release(inode); errout: return ret; }
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 close_blockdriver(FAR struct inode *inode) { int ret = 0; /* Assume success */ /* Sanity checks */ #ifdef CONFIG_DEBUG if (!inode || !inode->u.i_bops) { ret = -EINVAL; goto errout; } #endif /* Verify that the inode is a block driver. */ if (!INODE_IS_BLOCK(inode)) { fdbg("inode is not a block driver\n"); ret = -ENOTBLK; goto errout; } /* Close the block driver. Not that no mutually exclusive access * to the driver is enforced here. That must be done in the driver * if needed. */ if (inode->u.i_bops->close) { ret = inode->u.i_bops->close(inode); } /* Then release the reference on the inode */ inode_release(inode); errout: return ret; }
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; } /* Notify the driver that it has been unlinked. If there are no * open references to the driver instance, then the driver should * release all resources because it is no longer accessible. */ if (INODE_IS_DRIVER(inode) && inode->u.i_ops->unlink) { /* Notify the character driver that it has been unlinked */ ret = inode->u.i_ops->unlink(inode); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } #ifndef CONFIG_DISABLE_MOUNTPOINT else if (INODE_IS_BLOCK(inode) && inode->u.i_bops->unlink) { /* Notify the block driver that it has been unlinked */ ret = inode->u.i_bops->unlink(inode); if (ret < 0) { errcode = -ret; goto errout_with_inode; } } #endif /* 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; }
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 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; }