pebble/src/fw/services/normal/filesystem/pfs.h
Josh Soref f44e5e50e9 spelling: original
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2025-01-29 00:03:26 -05:00

223 lines
9.5 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed 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.
*/
#pragma once
#include <inttypes.h>
#include <stddef.h>
#include "kernel/pebble_tasks.h"
#include "system/status_codes.h"
#include "util/list.h"
//! Exported APIs for the Pebble File System (PFS)
//!
//! Things to note:
//! - All APIs are threadsafe
//! - PFS implements a basic wear-leveling strategy to extend the life of
//! the flash part
//! - PFS allows the allocation of blocks of space which appear to the consumer
//! as a contiguous region. It is up to the consumer to manage how they
//! want to manage the allocated space
//! - Assumes underlying HW is a NOR flash chip. This means that when a
//! 0 bit value is written to a given location, the file needs to be erased
//! or rewritten to change it back to a 1. (pfs_open (i.e OP_FLAG_OVERWRITE)
//! provides a mechanism that consumers can leverage to accomplish this)
//! - Erasing flash sectors is a costly operation (from both a time/power
//! perspective). Care should be taken not to constantly be deleting/creating
//! files
#define OP_FLAG_READ (1 << 0)
#define OP_FLAG_WRITE (1 << 1)
#define OP_FLAG_OVERWRITE (1 << 2)
#define OP_FLAG_SKIP_HDR_CRC_CHECK (1 << 3)
#define OP_FLAG_USE_PAGE_CACHE (1 << 4)
#define FILE_TYPE_STATIC (0xfe)
#define FILE_MAX_NAME_LEN (255)
typedef enum {
FSeekSet,
FSeekCur
} FSeekType;
//! Used by pfs_watch_file to know which events to trigger callbacks on
#define FILE_CHANGED_EVENT_CLOSED (1 << 0)
#define FILE_CHANGED_EVENT_REMOVED (1 << 1)
#define FILE_CHANGED_EVENT_ALL (FILE_CHANGED_EVENT_CLOSED | FILE_CHANGED_EVENT_REMOVED)
//! Types used by pfs_watch_file()
typedef void (*PFSFileChangedCallback)(void *data);
typedef void *PFSCallbackHandle;
//! Used by pfs_list_files() and pfs_remove_files()
typedef bool (*PFSFilenameTestCallback)(const char *name);
//! Format of each entry in the linked list returned by pfs_create_file_list
typedef struct {
ListNode list_node;
char name[];
} PFSFileListEntry;
//! @param name - The name of the file to be opened
//! @param op_flags - The operation to be performed on the file
//!
//! OP_FLAG_READ - Open a file such that pfs_read operations will work. If the
//! file does not exist, opening a file with just this mode set will fail
//!
//! OP_FLAG_WRITE - Creates a file if it does not exist, else opens a file
//! such that pfs_write operations will work. It is up to the user to seek to
//! the desired offset within the file
//!
//! OP_FLAG_OVERWRITE - Provides a safe mechanism to incrementally overwrite
//! a file that already exists with new data. Open will fail if the file does
//! not already exist on flash. The changes for the overwritten file are not
//! committed until the pfs_close is called. Until this time, pfs_open of the
//! 'name' will return a hdl to the original file. This way there is always a
//! valid version of the file which can be read & the caller can copy parts
//! of the original file in hunks rather than allocating a lot of RAM.
//!
//! OP_FLAG_SKIP_HDR_CRC_CHECK - For files which are not accessed frequently,
//! it is a good idea to sanity check the on-flash header CRCs to make sure
//! nothing has gone astray. This has performance ramifications if you are
//! doing thousands of opens on the same file so this flags allows consumers
//! to turn the check off
//!
//! OP_FLAG_USE_PAGE_CACHE - Turns on caching for the translation from
//! virtual filesystem pages to their physical address. For large files with
//! a lot of random access this is advantageous because we need to read
//! flash bytes to get to the correct page. Ideally this should only be
//! used for read operations so that heap corruption does not lead to us
//! corrupting a file
//!
//! The following two parameters are only parsed when a file is
//! overwritten/created:
//!
//! @param file_type - The type of file being opened
//! @param start_size - The initial space to be allocated for a file if it is
//! being created
//! @return - status_t error code if the operation failed,
//! else a fd handle >= 0 if operation was successful
extern int pfs_open(const char *name, uint8_t op_flags, uint8_t file_type,
size_t start_size);
//! Writes data to the fd specified. After each write, the internal file offset
//! is moved forward
//! @param fd - The fd to write data to
//! @param buf - The buffer of data to write
//! @param size - The number of bytes from buf to write
//! (must be <= the size of buf)
//! @return - the number of bytes written or a status_t code on error
extern int pfs_write(int fd, const void *buf, size_t size);
//! Reads data from the fd specified. After each read, the internal file offset
//! is moved forward
//! @param fd - the file to read data from
//! @param buf - the buffer to store read data in
//! @param size - the amount of data to read (must be <= the size of buf)
//! @return - the number of bytes read or a status_t code on error
extern int pfs_read(int fd, void *buf, size_t size);
//! Seeks to offset specified
//! Returns the offset forwarded to on success,
//! status_t code < 0 to indicate type of failure
extern int pfs_seek(int fd, int offset, FSeekType seek_type);
//! Frees up internal tracking data associated with a given file.
//! @param fd - the fd to close
//! @return - S_SUCCESS or appropriate error code on failure
extern status_t pfs_close(int fd);
//! calls pfs_close and pfs_remove on a file successively
//! @param fd - the fd describing the file to remove
extern status_t pfs_close_and_remove(int fd);
//! Unlinks a given file from the filesystem
//! @param name - the name of the file to remove
//! @return - S_SUCCESS or appropriate error code on failure
extern status_t pfs_remove(const char *name);
//! Returns the size of the file. (The amount of bytes that can be read out)
extern size_t pfs_get_file_size(int fd);
//! Should only be called before using FS
extern status_t pfs_init(bool run_filesystem_check);
//! Should only be called once after reboot and before any file operations
//! are performed
extern void pfs_reboot_cleanup(void);
//! erases everything on the filesystem & removes any open
//! file entries from the cache
//! Note: assumes that pfs_init was called before this
extern void pfs_format(bool write_erase_headers);
//! Returns the size of the pfs filesystem.
extern uint32_t pfs_get_size(void);
//! Updates the size of the pfs filesystem.
//! @param new_size new size
//! @param new_region_erased if the pages being added have been erased and should be marked as so.
extern void pfs_set_size(uint32_t new_size, bool new_region_erased);
//! Returns true is pfs is active on this device
extern bool pfs_active(void);
//! Returns true is pfs is active in the region
extern bool pfs_active_in_region(uint32_t start_address, uint32_t ending_address);
//! In the case of a file which can actually make use of additional space
//! beyond a certain minimum, this function will return the optimal size
//! that should be used for such a file, in order to use no more sectors
//! than the minimum size would.
extern int pfs_sector_optimal_size(int min_size, int namelen);
//! Returns the number of bytes available on the filesystem
extern uint32_t get_available_pfs_space(void);
//! Watch a file. The callback is called whenever the given file (by name) is closed with
//! modifications or deleted
//! @param filename - name of the file to watch
//! @param callback - function to invoke when file is changed
//! @param event_flags - which events the callback should be triggered on
//! (see FILE_CHANGED_EVENT_ flags defined above)
//! @param data - pointer passed to callback when invoked
//! @return - cb handle to pass into \ref pfs_unwatch_file
PFSCallbackHandle pfs_watch_file(const char* filename, PFSFileChangedCallback callback,
uint8_t event_flags, void* data);
//! Stop watching a file.
void pfs_unwatch_file(PFSCallbackHandle cb_handle);
//! calculate the CRC32 for a given part of a file
extern uint32_t pfs_crc_calculate_file(int fd, uint32_t offset, uint32_t num_bytes);
//! Get a directory listing, calling the filter callback on each filename.
//! Returns linked list of filenames, filtered by the callback.
//! @param callback - name filter function to be called for each filename, or NULL to include
//! all files.
//! @return - pointer to head node of linked list of names, or NULL if no names match
extern PFSFileListEntry *pfs_create_file_list(PFSFilenameTestCallback callback);
//! Delete a directory list returned by pfs_list_files
//! @param callback - callback to be called for on filename
//! @return - pointer to head node of linked list of names, or NULL if no names match
extern void pfs_delete_file_list(PFSFileListEntry *list);
//! Run each filename in the filesystem through the filter callback and delete all files that match
//! @param callback - callback to be called for on filename
extern void pfs_remove_files(PFSFilenameTestCallback callback);