/** * Opens a file at the specified path. The result of opening a nonexistent * file depends on the access flags specified. All intermediate directories * must already exist. * * The mode strings passed to fopen() map to nffs_open()'s access flags as * follows: * "r" - FS_ACCESS_READ * "r+" - FS_ACCESS_READ | FS_ACCESS_WRITE * "w" - FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE * "w+" - FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE * "a" - FS_ACCESS_WRITE | FS_ACCESS_APPEND * "a+" - FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_APPEND * * @param path The path of the file to open. * @param access_flags Flags controlling file access; see above table. * @param out_file On success, a pointer to the newly-created file * handle gets written here. * * @return 0 on success; nonzero on failure. */ static int nffs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) { int rc; struct nffs_file *out_file; nffs_lock(); if (!nffs_ready()) { rc = FS_EUNINIT; goto done; } rc = nffs_file_open(&out_file, path, access_flags); if (rc != 0) { goto done; } *out_fs_file = (struct fs_file *)out_file; done: nffs_unlock(); if (rc != 0) { *out_fs_file = NULL; } return rc; }
/** * Searches for a valid nffs file system among the specified areas. This * function succeeds if a file system is detected among any subset of the * supplied areas. If the area set does not contain a valid file system, * a new one can be created via a separate call to nffs_format(). * * @param area_descs The area set to search. This array must be * terminated with a 0-length area. * * @return 0 on success; * NFFS_ECORRUPT if no valid file system was detected; * other nonzero on error. */ int nffs_detect(const struct nffs_area_desc *area_descs) { int rc; nffs_lock(); rc = nffs_restore_full(area_descs); nffs_unlock(); return rc; }
/** * Retrieves the current read and write position of the specified open file. * * @param file The file to query. * * @return The file offset, in bytes. */ uint32_t nffs_getpos(const struct nffs_file *file) { uint32_t offset; nffs_lock(); offset = file->nf_offset; nffs_unlock(); return offset; }
/** * Positions a file's read and write pointer at the specified offset. The * offset is expressed as the number of bytes from the start of the file (i.e., * seeking to offset 0 places the pointer at the first byte in the file). * * @param file The file to reposition. * @param offset The 0-based file offset to seek to. * * @return 0 on success; nonzero on failure. */ int nffs_seek(struct nffs_file *file, uint32_t offset) { int rc; nffs_lock(); rc = nffs_file_seek(file, offset); nffs_unlock(); return rc; }
/** * Erases all the specified areas and initializes them with a clean nffs * file system. * * @param area_descs The set of areas to format. * * @return 0 on success; * nonzero on failure. */ int nffs_format(const struct nffs_area_desc *area_descs) { int rc; nffs_lock(); rc = nffs_format_full(area_descs); nffs_unlock(); return rc; }
/** * Retrieves the current length of the specified open file. * * @param file The file to query. * @param out_len On success, the number of bytes in the file gets * written here. * * @return 0 on success; nonzero on failure. */ int nffs_file_len(struct nffs_file *file, uint32_t *out_len) { int rc; nffs_lock(); rc = nffs_inode_data_len(file->nf_inode_entry, out_len); nffs_unlock(); return rc; }
/** * Retrieves the current length of the specified open file. * * @param file The file to query. * @param out_len On success, the number of bytes in the file gets * written here. * * @return 0 on success; nonzero on failure. */ static int nffs_file_len(const struct fs_file *fs_file, uint32_t *out_len) { int rc; const struct nffs_file *file = (const struct nffs_file *)fs_file; nffs_lock(); rc = nffs_inode_data_len(file->nf_inode_entry, out_len); nffs_unlock(); return rc; }
/** * Reads data from the specified file. If more data is requested than remains * in the file, all available data is retrieved. Note: this type of short read * results in a success return code. * * @param file The file to read from. * @param len The number of bytes to attempt to read. * @param out_data The destination buffer to read into. * @param out_len On success, the number of bytes actually read gets * written here. Pass null if you don't care. * * @return 0 on success; nonzero on failure. */ int nffs_read(struct nffs_file *file, uint32_t len, void *out_data, uint32_t *out_len) { int rc; nffs_lock(); rc = nffs_file_read(file, len, out_data, out_len); nffs_unlock(); return rc; }
/** * Positions a file's read and write pointer at the specified offset. The * offset is expressed as the number of bytes from the start of the file (i.e., * seeking to offset 0 places the pointer at the first byte in the file). * * @param file The file to reposition. * @param offset The 0-based file offset to seek to. * * @return 0 on success; nonzero on failure. */ static int nffs_seek(struct fs_file *fs_file, uint32_t offset) { int rc; struct nffs_file *file = (struct nffs_file *)fs_file; nffs_lock(); rc = nffs_file_seek(file, offset); nffs_unlock(); return rc; }
/** * Closes the specified directory handle. * * @param dir The directory to close. * * @return 0 on success; nonzero on failure. */ static int nffs_closedir(struct fs_dir *fs_dir) { int rc; struct nffs_dir *dir = (struct nffs_dir *)fs_dir; nffs_lock(); rc = nffs_dir_close(dir); nffs_unlock(); return rc; }
/** * Reads the next entry in an open directory. * * @param dir The directory handle to read from. * @param out_dirent On success, points to the next child entry in * the specified directory. * * @return 0 on success; * FS_ENOENT if there are no more entries in the * parent directory; * other nonzero on error. */ static int nffs_readdir(struct fs_dir *fs_dir, struct fs_dirent **out_fs_dirent) { int rc; struct nffs_dir *dir = (struct nffs_dir *)fs_dir; struct nffs_dirent **out_dirent = (struct nffs_dirent **)out_fs_dirent; nffs_lock(); rc = nffs_dir_read(dir, out_dirent); nffs_unlock(); return rc; }
/** * Closes the specified file and invalidates the file handle. If the file has * already been unlinked, and this is the last open handle to the file, this * operation causes the file to be deleted from disk. * * @param file The file handle to close. * * @return 0 on success; nonzero on failure. */ int nffs_close(struct nffs_file *file) { int rc; if (file == NULL) { return 0; } nffs_lock(); rc = nffs_file_close(file); nffs_unlock(); return rc; }
/** * Tells you whether the specified directory entry is a sub-directory or a * regular file. * * @param dirent The directory entry to query. * * @return 1: The entry is a directory; * 0: The entry is a regular file. */ static int nffs_dirent_is_dir(const struct fs_dirent *fs_dirent) { uint32_t id; const struct nffs_dirent *dirent = (const struct nffs_dirent *)fs_dirent; nffs_lock(); assert(dirent != NULL && dirent->nde_inode_entry != NULL); id = dirent->nde_inode_entry->nie_hash_entry.nhe_id; nffs_unlock(); return nffs_hash_id_is_dir(id); }
/** * Retrieves the filename of the specified directory entry. The retrieved * filename is always null-terminated. To ensure enough space to hold the full * filename plus a null-termintor, a destination buffer of size * (NFFS_FILENAME_MAX_LEN + 1) should be used. * * @param dirent The directory entry to query. * @param max_len The size of the "out_name" character buffer. * @param out_name On success, the entry's filename is written * here; always null-terminated. * @param out_name_len On success, contains the actual length of the * filename, NOT including the * null-terminator. * * @return 0 on success; nonzero on failure. */ static int nffs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len, char *out_name, uint8_t *out_name_len) { int rc; struct nffs_dirent *dirent = (struct nffs_dirent *)fs_dirent; nffs_lock(); assert(dirent != NULL && dirent->nde_inode_entry != NULL); rc = nffs_inode_read_filename(dirent->nde_inode_entry, max_len, out_name, out_name_len); nffs_unlock(); return rc; }
/** * Opens the directory at the specified path. The directory's contents can be * read with subsequent calls to nffs_readdir(). When you are done with the * directory handle, close it with nffs_closedir(). * * Unlinking files from the directory while it is open may result in * unpredictable behavior. New files can be created inside the directory. * * @param path The directory to open. * @param out_dir On success, points to the directory handle. * * @return 0 on success; * FS_ENOENT if the specified directory does not * exist; * other nonzero on error. */ static int nffs_opendir(const char *path, struct fs_dir **out_fs_dir) { int rc; struct nffs_dir **out_dir = (struct nffs_dir **)out_fs_dir; nffs_lock(); if (!nffs_ready()) { rc = FS_EUNINIT; goto done; } rc = nffs_dir_open(path, out_dir); done: nffs_unlock(); return rc; }
/** * Creates the directory represented by the specified path. All intermediate * directories must already exist. The specified path must start with a '/' * character. * * @param path The directory to create. * * @return 0 on success; * nonzero on failure. */ int nffs_mkdir(const char *path) { int rc; nffs_lock(); if (!nffs_ready()) { rc = NFFS_EUNINIT; goto done; } rc = nffs_path_new_dir(path, NULL); if (rc != 0) { goto done; } done: nffs_unlock(); return rc; }
/** * Performs a rename and / or move of the specified source path to the * specified destination. The source path can refer to either a file or a * directory. All intermediate directories in the destination path must * already exist. If the source path refers to a file, the destination path * must contain a full filename path, rather than just the new parent * directory. If an object already exists at the specified destination path, * this function causes it to be unlinked prior to the rename (i.e., the * destination gets clobbered). * * @param from The source path. * @param to The destination path. * * @return 0 on success; * nonzero on failure. */ int nffs_rename(const char *from, const char *to) { int rc; nffs_lock(); if (!nffs_ready()) { rc = NFFS_EUNINIT; goto done; } rc = nffs_path_rename(from, to); if (rc != 0) { goto done; } rc = 0; done: nffs_unlock(); return rc; }
/** * Unlinks the file or directory at the specified path. If the path refers to * a directory, all the directory's descendants are recursively unlinked. Any * open file handles refering to an unlinked file remain valid, and can be * read from and written to. * * @path The path of the file or directory to unlink. * * @return 0 on success; nonzero on failure. */ int nffs_unlink(const char *path) { int rc; nffs_lock(); if (!nffs_ready()) { rc = NFFS_EUNINIT; goto done; } rc = nffs_path_unlink(path); if (rc != 0) { goto done; } rc = 0; done: nffs_unlock(); return rc; }
/** * Writes the supplied data to the current offset of the specified file handle. * * @param file The file to write to. * @param data The data to write. * @param len The number of bytes to write. * * @return 0 on success; nonzero on failure. */ int nffs_write(struct nffs_file *file, const void *data, int len) { int rc; nffs_lock(); if (!nffs_ready()) { rc = NFFS_EUNINIT; goto done; } rc = nffs_write_to_file(file, data, len); if (rc != 0) { goto done; } rc = 0; done: nffs_unlock(); return rc; }