/**************************************************************************** * fs/binfs/fs_binfs.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "inode/inode.h" #include "fs_heap.h" #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_BINFS) /**************************************************************************** * Private Types ****************************************************************************/ struct binfs_dir_s { struct fs_dirent_s base; /* VFS directory structure */ unsigned int index; /* Index to the next named entry point */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static int binfs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode); static int binfs_close(FAR struct file *filep); static ssize_t binfs_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static int binfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int binfs_dup(FAR const struct file *oldp, FAR struct file *newp); static int binfs_fstat(FAR const struct file *filep, FAR struct stat *buf); static int binfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, FAR struct fs_dirent_s **dir); static int binfs_closedir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir); static int binfs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir, FAR struct dirent *entry); static int binfs_rewinddir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir); static int binfs_bind(FAR struct inode *blkdriver, FAR const void *data, FAR void **handle); static int binfs_unbind(FAR void *handle, FAR struct inode **blkdriver, unsigned int flags); static int binfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf); static int binfs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct stat *buf); /**************************************************************************** * Public Data ****************************************************************************/ /* See fs_mount.c -- this structure is explicitly extern'ed there. * We use the old-fashioned kind of initializers so that this will compile * with any compiler. */ const struct mountpt_operations g_binfs_operations = { binfs_open, /* open */ binfs_close, /* close */ binfs_read, /* read */ NULL, /* write */ NULL, /* seek */ binfs_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ NULL, /* poll */ NULL, /* sync */ binfs_dup, /* dup */ binfs_fstat, /* fstat */ NULL, /* fchstat */ binfs_opendir, /* opendir */ binfs_closedir, /* closedir */ binfs_readdir, /* readdir */ binfs_rewinddir, /* rewinddir */ binfs_bind, /* bind */ binfs_unbind, /* unbind */ binfs_statfs, /* statfs */ NULL, /* unlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* rename */ binfs_stat, /* stat */ NULL /* chstat */ }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: binfs_open ****************************************************************************/ static int binfs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { int index; finfo("Open '%s'\n", relpath); /* BINFS is read-only. Any attempt to open with any kind of write * access is not permitted. */ if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) { ferr("ERROR: Only O_RDONLY supported\n"); return -EACCES; } /* Check if the entry exists with this name in the root directory. * so the 'relpath' must be the name of the builtin function. */ index = builtin_isavail(relpath); if (index < 0) { ferr("ERROR: Built-in %s does not exist\n", relpath); return -ENOENT; } /* Save the index as the open-specific state in filep->f_priv */ filep->f_priv = (FAR void *)((uintptr_t)index); return OK; } /**************************************************************************** * Name: binfs_close ****************************************************************************/ static int binfs_close(FAR struct file *filep) { finfo("Closing\n"); return OK; } /**************************************************************************** * Name: binfs_read ****************************************************************************/ static ssize_t binfs_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { /* Reading is not supported. Just return end-of-file */ finfo("Read %zu bytes from offset %jd\n", buflen, (intmax_t)filep->f_pos); return 0; } /**************************************************************************** * Name: binfs_ioctl ****************************************************************************/ static int binfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { int ret; finfo("cmd: %d arg: %08lx\n", cmd, arg); /* Only one IOCTL command is supported */ if (cmd == FIOC_FILEPATH) { /* IN: FAR char *(length >= PATH_MAX) * OUT: The full file path */ FAR char *ptr = (FAR char *)((uintptr_t)arg); if (ptr == NULL) { ret = -EINVAL; } else { ret = inode_getpath(filep->f_inode, ptr, PATH_MAX); if (ret < 0) { return ret; } strlcat(ptr, builtin_getname((int)((uintptr_t)filep->f_priv)), PATH_MAX); } } else { ret = -ENOTTY; } return ret; } /**************************************************************************** * Name: binfs_dup * * Description: * Duplicate open file data in the new file structure. * ****************************************************************************/ static int binfs_dup(FAR const struct file *oldp, FAR struct file *newp) { finfo("Dup %p->%p\n", oldp, newp); /* Copy the index from the old to the new file structure */ newp->f_priv = oldp->f_priv; return OK; } /**************************************************************************** * Name: binfs_fstat * * Description: * Obtain information about an open file associated with the file * descriptor 'fd', and will write it to the area pointed to by 'buf'. * ****************************************************************************/ static int binfs_fstat(FAR const struct file *filep, FAR struct stat *buf) { DEBUGASSERT(buf != NULL); /* It's a execute-only file system */ buf->st_mode = S_IFREG | S_IXOTH | S_IXGRP | S_IXUSR; buf->st_size = 0; buf->st_blksize = 0; buf->st_blocks = 0; return OK; } /**************************************************************************** * Name: binfs_opendir * * Description: * Open a directory for read access * ****************************************************************************/ static int binfs_opendir(FAR struct inode *mountpt, FAR const char *relpath, FAR struct fs_dirent_s **dir) { FAR struct binfs_dir_s *bdir; finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL"); /* The requested directory must be the volume-relative "root" directory */ if (relpath && relpath[0] != '\0') { return -ENOENT; } bdir = fs_heap_zalloc(sizeof(*bdir)); if (bdir == NULL) { return -ENOMEM; } /* Set the index to the first entry */ bdir->index = 0; *dir = (FAR struct fs_dirent_s *)bdir; return OK; } /**************************************************************************** * Name: binfs_closedir * * Description: * Close a directory * ****************************************************************************/ static int binfs_closedir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) { DEBUGASSERT(dir); fs_heap_free(dir); return 0; } /**************************************************************************** * Name: binfs_readdir * * Description: Read the next directory entry * ****************************************************************************/ static int binfs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir, FAR struct dirent *entry) { FAR struct binfs_dir_s *bdir; FAR const char *name; unsigned int index; int ret; /* Have we reached the end of the directory */ bdir = (FAR struct binfs_dir_s *)dir; index = bdir->index; name = builtin_getname(index); if (name == NULL) { /* We signal the end of the directory by returning the * special error -ENOENT */ finfo("Entry %d: End of directory\n", index); ret = -ENOENT; } else { /* Save the filename and file type */ finfo("Entry %d: \"%s\"\n", index, name); entry->d_type = DTYPE_FILE; strlcpy(entry->d_name, name, sizeof(entry->d_name)); /* The application list is terminated by an entry with a NULL name. * Therefore, there is at least one more entry in the list. */ index++; /* Set up the next directory entry offset. NOTE that we could use the * standard f_pos instead of our own private index. */ bdir->index = index; ret = OK; } return ret; } /**************************************************************************** * Name: binfs_rewindir * * Description: Reset directory read to the first entry * ****************************************************************************/ static int binfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir) { finfo("Entry\n"); ((FAR struct binfs_dir_s *)dir)->index = 0; return OK; } /**************************************************************************** * Name: binfs_bind * * Description: This implements a portion of the mount operation. This * function allocates and initializes the mountpoint private data and * binds the blockdriver inode to the filesystem private data. The final * binding of the private data (containing the blockdriver) to the * mountpoint is performed by mount(). * ****************************************************************************/ static int binfs_bind(FAR struct inode *blkdriver, const void *data, void **handle) { finfo("Entry\n"); return OK; } /**************************************************************************** * Name: binfs_unbind * * Description: This implements the filesystem portion of the umount * operation. * ****************************************************************************/ static int binfs_unbind(FAR void *handle, FAR struct inode **blkdriver, unsigned int flags) { finfo("Entry\n"); return OK; } /**************************************************************************** * Name: binfs_statfs * * Description: Return filesystem statistics * ****************************************************************************/ static int binfs_statfs(struct inode *mountpt, struct statfs *buf) { finfo("Entry\n"); /* Fill in the statfs info */ buf->f_type = BINFS_MAGIC; buf->f_bsize = 0; buf->f_blocks = 0; buf->f_bfree = 0; buf->f_bavail = 0; buf->f_namelen = NAME_MAX; return OK; } /**************************************************************************** * Name: binfs_stat * * Description: Return information about a file or directory * ****************************************************************************/ static int binfs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct stat *buf) { finfo("Entry\n"); int index; /* The requested directory must be the volume-relative "root" directory */ if (relpath && relpath[0] != '\0') { /* Check if there is a file with this name. */ index = builtin_isavail(relpath); if (index < 0) { return -ENOENT; } /* It's a execute-only file name */ buf->st_mode = S_IFREG | S_IXOTH | S_IXGRP | S_IXUSR; #ifdef CONFIG_SCHED_USER_IDENTITY buf->st_uid = builtin_getuid(index); buf->st_gid = builtin_getgid(index); buf->st_mode |= builtin_getmode(index); #endif } else { /* It's a read/execute-only directory name */ buf->st_mode = S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR | S_IXOTH | S_IXGRP | S_IXUSR; } /* File/directory size, access block size */ buf->st_size = 0; buf->st_blksize = 0; buf->st_blocks = 0; return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_BINFS */