/* * Count a link. Only for regular files because that's what the caller * does. (And that, in turn, is because the link count of a directory * is a local property.) */ void inode_addlink(uint32_t ino) { struct inodeinfo *inf; inf = inode_find(ino); assert(inf->type == SFS_TYPE_FILE); assert(inf->visited == 0); inf->linkcount++; }
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; }
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 nfs_gfid_loc_fill (inode_table_t *itable, uuid_t gfid, loc_t *loc, int how) { int ret = -EFAULT; inode_t *inode = NULL; if (!loc) return ret; inode = inode_find (itable, gfid); if (!inode) { gf_msg_trace (GF_NFS, 0, "Inode not found in itable, will " "try to create one."); if (how == NFS_RESOLVE_CREATE) { gf_msg_trace (GF_NFS, 0, "Inode needs to be created."); inode = inode_new (itable); if (!inode) { gf_msg (GF_NFS, GF_LOG_ERROR, ENOMEM, NFS_MSG_NO_MEMORY, "Failed to " "allocate memory"); ret = -ENOMEM; goto err; } } else { gf_msg (GF_NFS, GF_LOG_ERROR, ENOENT, NFS_MSG_INODE_NOT_FOUND, "Inode not found in " "itable and no creation was requested."); ret = -ENOENT; goto err; } } else { gf_msg_trace (GF_NFS, 0, "Inode was found in the itable."); } gf_uuid_copy (loc->gfid, gfid); ret = nfs_inode_loc_fill (inode, loc, how); if (ret < 0) { gf_msg (GF_NFS, GF_LOG_ERROR, -ret, NFS_MSG_INODE_LOC_FILL_ERROR, "Inode loc filling failed.: %s", strerror (-ret)); goto err; } err: if (inode) inode_unref (inode); return ret; }
/* * Mark an inode (directories only, because that's all the caller * does) visited. Returns nonzero if already visited. * * Note that there is no way to clear the visited flag for now because * it's only used once (by pass2). */ int inode_visitdir(uint32_t ino) { struct inodeinfo *inf; inf = inode_find(ino); assert(inf->type == SFS_TYPE_DIR); assert(inf->linkcount == 0); if (inf->visited) { return 1; } inf->visited = 1; return 0; }
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; }
struct glfs_object * glfs_h_create_from_handle (struct glfs *fs, unsigned char *handle, int len, struct stat *stat) { loc_t loc = {0, }; int ret = -1; struct iatt iatt = {0, }; inode_t *newinode = NULL; xlator_t *subvol = NULL; struct glfs_object *object = NULL; /* validate in args */ if ((fs == NULL) || (handle == NULL) || (len != GFAPI_HANDLE_LENGTH)) { errno = EINVAL; return NULL; } __glfs_entry_fs (fs); /* get the active volume */ subvol = glfs_active_subvol (fs); if (!subvol) { errno = EIO; goto out; } memcpy (loc.gfid, handle, GFAPI_HANDLE_LENGTH); newinode = inode_find (subvol->itable, loc.gfid); if (newinode) loc.inode = newinode; else { loc.inode = inode_new (subvol->itable); if (!loc.inode) { errno = ENOMEM; goto out; } } ret = syncop_lookup (subvol, &loc, 0, &iatt, 0, 0); DECODE_SYNCOP_ERR (ret); if (ret) { gf_log (subvol->name, GF_LOG_WARNING, "inode refresh of %s failed: %s", uuid_utoa (loc.gfid), strerror (errno)); goto out; } newinode = inode_link (loc.inode, 0, 0, &iatt); if (newinode) inode_lookup (newinode); else { gf_log (subvol->name, GF_LOG_WARNING, "inode linking of %s failed: %s", uuid_utoa (loc.gfid), strerror (errno)); errno = EINVAL; goto out; } /* populate stat */ if (stat) glfs_iatt_to_stat (fs, &iatt, stat); object = GF_CALLOC (1, sizeof(struct glfs_object), glfs_mt_glfs_object_t); if (object == NULL) { errno = ENOMEM; ret = -1; goto out; } /* populate the return object */ object->inode = newinode; uuid_copy (object->gfid, object->inode->gfid); out: /* TODO: Check where the inode ref is being held? */ loc_wipe (&loc); glfs_subvol_done (fs, subvol); return object; }
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 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; }
mqd_t mq_open(FAR const char *mq_name, int oflags, ...) { FAR struct inode *inode; FAR const char *relpath = NULL; FAR struct mqueue_inode_s *msgq; char fullpath[MAX_MQUEUE_PATH]; va_list ap; struct mq_attr *attr; mqd_t mqdes; mode_t mode; int errcode; int ret; /* Make sure that a non-NULL name is supplied */ if (!mq_name) { errcode = EINVAL; goto errout; } /* Get the full path to the message queue */ snprintf(fullpath, MAX_MQUEUE_PATH, CONFIG_FS_MQUEUE_MPATH "/%s", mq_name); /* Make sure that the check for the existence of the message queue * and the creation of the message queue are atomic with respect to * other processes executing mq_open(). A simple sched_lock() should * be sufficient. */ sched_lock(); /* Get the inode for this mqueue. This should succeed if the message * queue has already been created. */ inode = inode_find(fullpath, &relpath); if (inode) { /* It exists. Verify that the inode is a message queue */ if (!INODE_IS_MQUEUE(inode)) { errcode = ENXIO; goto errout_with_inode; } /* It exists and is a message queue. Check if the caller wanted to * create a new mqueue with this name. */ if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) { errcode = EEXIST; goto errout_with_inode; } /* Create a message queue descriptor for the current thread */ msgq = inode->u.i_mqueue; mqdes = mq_descreate(NULL, msgq, oflags); if (!mqdes) { errcode = ENOMEM; goto errout_with_inode; } } else { /* The mqueue does not exists. Were we asked to create it? */ if ((oflags & O_CREAT) == 0) { /* The mqueue does not exist and O_CREAT is not set */ errcode = ENOENT; goto errout_with_lock; } /* Create the mqueue. First we have to extract the additional * parameters from the variable argument list. */ va_start(ap, oflags); mode = va_arg(ap, mode_t); attr = va_arg(ap, FAR struct mq_attr*); va_end(ap); /* Create an inode in the pseudo-filesystem at this path */ inode_semtake(); ret = inode_reserve(fullpath, &inode); inode_semgive(); if (ret < 0) { errcode = -ret; goto errout_with_lock; } /* Allocate memory for the new message queue. */ msgq = (FAR struct mqueue_inode_s*)mq_msgqalloc(mode, attr); if (!msgq) { errcode = ENOSPC; goto errout_with_inode; } /* Create a message queue descriptor for the TCB */ mqdes = mq_descreate(NULL, msgq, oflags); if (!mqdes) { errcode = ENOMEM; goto errout_with_msgq; } /* Bind the message queue and the inode structure */ INODE_SET_MQUEUE(inode); inode->u.i_mqueue = msgq; msgq->inode = inode; } sched_unlock(); return mqdes; errout_with_msgq: mq_msgqfree(msgq); inode->u.i_mqueue = NULL; errout_with_inode: inode_release(inode); errout_with_lock: sched_unlock(); errout: set_errno(errcode); return (mqd_t)ERROR; }
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 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 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 {
int sem_unlink(FAR const char *name) { FAR struct inode *inode; FAR const char *relpath = NULL; char fullpath[MAX_SEMPATH]; int errcode; int ret; /* Get the full path to the semaphore */ snprintf(fullpath, MAX_SEMPATH, CONFIG_FS_NAMED_SEMPATH "/%s", name); /* Get the inode for this semaphore. */ sched_lock(); inode = inode_find(fullpath, &relpath); if (!inode) { /* There is no inode that includes in this path */ errcode = ENOENT; goto errout; } /* Verify that what we found is, indeed, a semaphore */ if (!INODE_IS_NAMEDSEM(inode)) { errcode = ENXIO; goto errout_with_inode; } /* Refuse to unlink the inode if it has children. I.e., if it is * functioning as a directory and the directory is not empty. */ inode_semtake(); if (inode->i_child != NULL) { errcode = ENOTEMPTY; goto errout_with_semaphore; } /* Remove the old inode from the tree. Because we hold a reference count * on the inode, it will not be deleted now. This will set the * FSNODEFLAG_DELETED bit in the inode flags. */ ret = inode_remove(fullpath); /* inode_remove() should always fail with -EBUSY because we hae a reference * on the inode. -EBUSY means taht the inode was, indeed, unlinked but * thatis could not be freed because there are refrences. */ DEBUGASSERT(ret >= 0 || ret == -EBUSY); UNUSED(ret); /* Now we do not release the reference count in the normal way (by calling * inode release. Rather, we call sem_close(). sem_close will decrement * the reference count on the inode. But it will also free the semaphore * if that reference count decrements to zero. Since we hold one reference, * that can only occur if the semaphore is not in-use. */ inode_semgive(); ret = sem_close((FAR sem_t *)inode->u.i_nsem); sched_unlock(); return ret; errout_with_semaphore: inode_semgive(); errout_with_inode: inode_release(inode); errout: set_errno(errcode); sched_unlock(); 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; }
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 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; }