FAR struct file *fs_getfilep(int fd) { FAR struct filelist *list; int errcode; if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) { errcode = EBADF; goto errout; } /* The descriptor is in a valid range to file descriptor... Get the * thread-specific file list. */ list = sched_getfiles(); /* The file list can be NULL under one obscure cornercase: When memory * management debug output is enabled. Then there may be attempts to * write to stdout from malloc before the group data has been allocated. */ if (!list) { errcode = EAGAIN; goto errout; } /* And return the file pointer from the list */ return &list->fl_files[fd]; errout: set_errno(errcode); return NULL; }
ssize_t sendfile(int outfd, int infd, off_t *offset, size_t count) { #if defined(CONFIG_NET_TCP) && CONFIG_NSOCKET_DESCRIPTORS > 0 /* Check the destination file descriptor: Is it a (probable) file * descriptor? Check the source file: Is it a normal file? */ if ((unsigned int)outfd >= CONFIG_NFILE_DESCRIPTORS && (unsigned int)infd < CONFIG_NFILE_DESCRIPTORS) { FAR struct filelist *list; /* This appears to be a file-to-socket transfer. Get the thread- * specific file list. */ list = sched_getfiles(); DEBUGASSERT(list); /* Then let net_sendfile do the work. */ return net_sendfile(outfd, &list->fl_files[infd], offset, count); } else #endif { /* No... then this is probably a file-to-file transfer. The generic * lib_sendfile() can handle that case. */ return lib_sendfile(outfd, infd, offset, count); } }
int files_allocate(FAR struct inode *inode, int oflags, off_t pos, int minfd) { FAR struct filelist *list; int i; list = sched_getfiles(); DEBUGASSERT(list); _files_semtake(list); for (i = minfd; i < CONFIG_NFILE_DESCRIPTORS; i++) { if (!list->fl_files[i].f_inode) { list->fl_files[i].f_oflags = oflags; list->fl_files[i].f_pos = pos; list->fl_files[i].f_inode = inode; list->fl_files[i].f_priv = NULL; _files_semgive(list); return i; } } _files_semgive(list); return ERROR; }
int ioctl(int fd, int req, unsigned long arg) { int err; #if CONFIG_NFILE_DESCRIPTORS > 0 FAR struct filelist *list; FAR struct file *filep; FAR struct inode *inode; int ret = OK; /* Did we get a valid file descriptor? */ if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) #endif { /* Perform the socket ioctl */ #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 if ((unsigned int)fd < (CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS)) { return netdev_ioctl(fd, req, arg); } else #endif { err = EBADF; goto errout; } } #if CONFIG_NFILE_DESCRIPTORS > 0 /* Get the thread-specific file list */ list = sched_getfiles(); DEBUGASSERT(list); /* Is a driver registered? Does it support the ioctl method? */ filep = &list->fl_files[fd]; inode = filep->f_inode; if (inode && inode->u.i_ops && inode->u.i_ops->ioctl) { /* Yes, then let it perform the ioctl */ ret = (int)inode->u.i_ops->ioctl(filep, req, arg); if (ret < 0) { err = -ret; goto errout; } } return ret; #endif errout: set_errno(err); return ERROR; }
static inline ssize_t file_write(int fd, FAR const void *buf, size_t nbytes) { FAR struct filelist *list; FAR struct file *this_file; FAR struct inode *inode; int ret; int err; /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { err = EMFILE; goto errout; } /* Was this file opened for write access? */ this_file = &list->fl_files[fd]; if ((this_file->f_oflags & O_WROK) == 0) { err = EBADF; goto errout; } /* Is a driver registered? Does it support the write method? */ inode = this_file->f_inode; if (!inode || !inode->u.i_ops || !inode->u.i_ops->write) { err = EBADF; goto errout; } /* Yes, then let the driver perform the write */ ret = inode->u.i_ops->write(this_file, buf, nbytes); if (ret < 0) { err = -ret; goto errout; } return ret; errout: *get_errno_ptr() = err; return ERROR; }
static int poll_fdsetup(int fd, FAR struct pollfd *fds, bool setup) { FAR struct filelist *list; FAR struct file *this_file; FAR struct inode *inode; int ret = -ENOSYS; /* Check for a valid file descriptor */ if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) { /* Perform the socket ioctl */ #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 if ((unsigned int)fd < (CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS)) { return net_poll(fd, fds, setup); } else #endif { return -EBADF; } } /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { return -EMFILE; } /* Is a driver registered? Does it support the poll method? * If not, return -ENOSYS */ this_file = &list->fl_files[fd]; inode = this_file->f_inode; if (inode && inode->u.i_ops && inode->u.i_ops->poll) { /* Yes, then setup the poll */ ret = (int)inode->u.i_ops->poll(this_file, fds, setup); } return ret; }
void files_release(int fd) { FAR struct filelist *list; list = sched_getfiles(); DEBUGASSERT(list); if (fd >=0 && fd < CONFIG_NFILE_DESCRIPTORS) { _files_semtake(list); list->fl_files[fd].f_oflags = 0; list->fl_files[fd].f_pos = 0; list->fl_files[fd].f_inode = NULL; _files_semgive(list); } }
int dup2(int fildes1, int fildes2) #endif { FAR struct filelist *list; /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { set_errno(EMFILE); return ERROR; } /* Verify that fildes is a valid, open file descriptor */ if (!DUP_ISOPEN(fildes1, list)) { set_errno(EBADF); return ERROR; } /* Handle a special case */ if (fildes1 == fildes2) { return fildes1; } /* Verify fildes2 */ if ((unsigned int)fildes2 >= CONFIG_NFILE_DESCRIPTORS) { set_errno(EBADF); return ERROR; } return files_dup(&list->fl_files[fildes1], &list->fl_files[fildes2]); }
int files_close(int fd) { FAR struct filelist *list; int ret; /* Get the thread-specific file list */ list = sched_getfiles(); DEBUGASSERT(list); /* If the file was properly opened, there should be an inode assigned */ if (fd < 0 || fd >= CONFIG_NFILE_DESCRIPTORS || !list->fl_files[fd].f_inode) { return -EBADF; } /* Perform the protected close operation */ _files_semtake(list); ret = _files_close(&list->fl_files[fd]); _files_semgive(list); return ret; }
static inline int file_vfcntl(int fildes, int cmd, va_list ap) { FAR struct filelist *list; FAR struct file *this_file; int err = 0; int ret = OK; /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { err = EMFILE; goto errout; } /* Was this file opened ? */ this_file = &list->fl_files[fildes]; if (!this_file->f_inode) { err = EBADF; goto errout; } switch (cmd) { case F_DUPFD: /* Return a new file descriptor which shall be the lowest numbered * available (that is, not already open) file descriptor greater than * or equal to the third argument, arg, taken as an integer of type * int. The new file descriptor shall refer to the same open file * description as the original file descriptor, and shall share any * locks. The FD_CLOEXEC flag associated with the new file descriptor * shall be cleared to keep the file open across calls to one of the * exec functions. */ { ret = file_dup(fildes, va_arg(ap, int)); } break; case F_GETFD: /* Get the file descriptor flags defined in <fcntl.h> that are associated * with the file descriptor fildes. File descriptor flags are associated * with a single file descriptor and do not affect other file descriptors * that refer to the same file. */ case F_SETFD: /* Set the file descriptor flags defined in <fcntl.h>, that are associated * with fildes, to the third argument, arg, taken as type int. If the * FD_CLOEXEC flag in the third argument is 0, the file shall remain open * across the exec functions; otherwise, the file shall be closed upon * successful execution of one of the exec functions. */ err = ENOSYS; break; case F_GETFL: /* Get the file status flags and file access modes, defined in <fcntl.h>, * for the file description associated with fildes. The file access modes * can be extracted from the return value using the mask O_ACCMODE, which is * defined in <fcntl.h>. File status flags and file access modes are associated * with the file description and do not affect other file descriptors that * refer to the same file with different open file descriptions. */ { ret = this_file->f_oflags; } break; case F_SETFL: /* Set the file status flags, defined in <fcntl.h>, for the file description * associated with fildes from the corresponding bits in the third argument, * arg, taken as type int. Bits corresponding to the file access mode and * the file creation flags, as defined in <fcntl.h>, that are set in arg shall * be ignored. If any bits in arg other than those mentioned here are changed * by the application, the result is unspecified. */ { int oflags = va_arg(ap, int); oflags &= FFCNTL; this_file->f_oflags &= ~FFCNTL; this_file->f_oflags |= oflags; } break; case F_GETOWN: /* If fildes refers to a socket, get the process or process group ID specified * to receive SIGURG signals when out-of-band data is available. Positive values * indicate a process ID; negative values, other than -1, indicate a process group * ID. If fildes does not refer to a socket, the results are unspecified. */ case F_SETOWN: /* If fildes refers to a socket, set the process or process group ID specified * to receive SIGURG signals when out-of-band data is available, using the value * of the third argument, arg, taken as type int. Positive values indicate a * process ID; negative values, other than -1, indicate a process group ID. If * fildes does not refer to a socket, the results are unspecified. */ err = EBADF; /* Only valid on socket descriptors */ break; case F_GETLK: /* Get the first lock which blocks the lock description pointed to by the third * argument, arg, taken as a pointer to type struct flock, defined in <fcntl.h>. * The information retrieved shall overwrite the information passed to fcntl() in * the structure flock. If no lock is found that would prevent this lock from being * created, then the structure shall be left unchanged except for the lock type * which shall be set to F_UNLCK. */ case F_SETLK: /* Set or clear a file segment lock according to the lock description pointed to * by the third argument, arg, taken as a pointer to type struct flock, defined in * <fcntl.h>. F_SETLK can establish shared (or read) locks (F_RDLCK) or exclusive * (or write) locks (F_WRLCK), as well as to remove either type of lock (F_UNLCK). * F_RDLCK, F_WRLCK, and F_UNLCK are defined in <fcntl.h>. If a shared or exclusive * lock cannot be set, fcntl() shall return immediately with a return value of -1. */ case F_SETLKW: /* This command shall be equivalent to F_SETLK except that if a shared or exclusive * lock is blocked by other locks, the thread shall wait until the request can be * satisfied. If a signal that is to be caught is received while fcntl() is waiting * for a region, fcntl() shall be interrupted. Upon return from the signal handler, * fcntl() shall return -1 with errno set to [EINTR], and the lock operation shall * not be done. */ err = ENOSYS; /* Not implemented */ break; default: err = EINVAL; break; } errout: if (err != 0) { set_errno(err); return ERROR; } return ret; }
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; }
off_t lseek(int fd, off_t offset, int whence) { FAR struct filelist *list; FAR struct file *filep; FAR struct inode *inode; int err; /* Did we get a valid file descriptor? */ if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS) { err = EBADF; goto errout; } /* Get the thread-specific file list */ list = sched_getfiles(); if (!list) { err = EMFILE; goto errout; } /* Is a driver registered? */ filep = &list->fl_files[fd]; inode = filep->f_inode; if (inode && inode->u.i_ops) { /* Does it support the seek method */ if (inode->u.i_ops->seek) { /* Yes, then let it perform the seek */ err = (int)inode->u.i_ops->seek(filep, offset, whence); if (err < 0) { err = -err; goto errout; } } else { /* No... there are a couple of default actions we can take */ switch (whence) { case SEEK_CUR: offset += filep->f_pos; case SEEK_SET: if (offset >= 0) { filep->f_pos = offset; /* Might be beyond the end-of-file */ break; } else { err = EINVAL; goto errout; } break; case SEEK_END: err = ENOSYS; goto errout; default: err = EINVAL; goto errout; } } } return filep->f_pos; errout: *get_errno_ptr() = err; return (off_t)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; }