mirror of
https://github.com/google/pebble.git
synced 2025-07-04 13:57:04 -04:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
80
src/fw/services/normal/filesystem/app_file.c
Normal file
80
src/fw/services/normal/filesystem/app_file.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "app_file.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "system/passert.h"
|
||||
#include "resource/resource_storage.h"
|
||||
|
||||
void app_file_name_make(char * restrict buffer, size_t buffer_len,
|
||||
AppInstallId app_id, const char * restrict suffix,
|
||||
size_t suffix_len) {
|
||||
PBL_ASSERTN(buffer_len > APP_FILE_NAME_PREFIX_LENGTH + suffix_len);
|
||||
|
||||
buffer[0] = '@';
|
||||
|
||||
uint32_t unsigned_id = (uint32_t)app_id;
|
||||
for (int i = 8; i >= 1; --i) {
|
||||
uint8_t nybble = unsigned_id & 0xf;
|
||||
if (nybble < 0xa) {
|
||||
buffer[i] = '0' + nybble;
|
||||
} else {
|
||||
buffer[i] = 'a' + (nybble - 0xa);
|
||||
}
|
||||
unsigned_id >>= 4;
|
||||
}
|
||||
|
||||
buffer[9] = '/';
|
||||
|
||||
memcpy(&buffer[10], suffix, suffix_len);
|
||||
buffer[APP_FILE_NAME_PREFIX_LENGTH + suffix_len] = '\0';
|
||||
}
|
||||
|
||||
//! Checks whether the given filename is an app file.
|
||||
bool is_app_file_name(const char *filename) {
|
||||
bool answer = true;
|
||||
answer = answer && strlen(filename) > APP_FILE_NAME_PREFIX_LENGTH;
|
||||
answer = answer && filename[0] == '@' && filename[9] == '/';
|
||||
for (int i = 1; answer && i <= 8; ++i) {
|
||||
char c = filename[i];
|
||||
answer = answer && ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'));
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
//! Checks whether the given filename is an app resource file (suffix = "res")
|
||||
bool is_app_resource_file_name(const char *filename) {
|
||||
return is_app_file_name(filename) &&
|
||||
!strcmp(filename + APP_FILE_NAME_PREFIX_LENGTH, APP_RESOURCES_FILENAME_SUFFIX);
|
||||
}
|
||||
|
||||
//! Parses an app-file name to get the AppInstallId.
|
||||
//! Assumes the file is indeed an app-file
|
||||
AppInstallId app_file_parse_app_id(const char *filename) {
|
||||
return (AppInstallId)strtol(filename + 1, NULL, 16); // + 1 to skip the initial '@'
|
||||
}
|
||||
|
||||
//! Parses an app-file name to get the AppInstallId.
|
||||
//!
|
||||
//! @returns INSTALL_ID_INVALID if the filename is not an app-file.
|
||||
AppInstallId app_file_get_app_id(const char *filename) {
|
||||
if (!is_app_file_name(filename)) {
|
||||
return INSTALL_ID_INVALID;
|
||||
}
|
||||
return app_file_parse_app_id(filename);
|
||||
}
|
61
src/fw/services/normal/filesystem/app_file.h
Normal file
61
src/fw/services/normal/filesystem/app_file.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//! Consistent naming of per-app files.
|
||||
//!
|
||||
//! All files which are specific to an app are named with a consistent scheme
|
||||
//! which identifies the files as belonging to the app. This is done by
|
||||
//! prefixing the filename with a string based on the AppInstallId. Filenames
|
||||
//! take the format printf("@%08x/%s", (uint32_t)app_id, suffix) to form a
|
||||
//! pseudo-directory structure.
|
||||
//!
|
||||
//! The prefix is fixed-length to make it simple to generate, parse and
|
||||
//! identify.
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "process_management/app_install_types.h"
|
||||
|
||||
// The suffix starts at offset 10 in the filename
|
||||
// '@' + "XXXXXXXX" + '/' : (1 + 8 + 1 = 10)
|
||||
#define APP_FILE_NAME_PREFIX_LENGTH (10)
|
||||
|
||||
//! Make an app-file name from the given app_id and suffix string.
|
||||
//!
|
||||
//! @param suffix_len strlen(suffix)
|
||||
//!
|
||||
//! @note buffer_len must be > APP_FILE_NAME_PREFIX_LENGTH + suffix_len to fit
|
||||
//! the full file name including NULL-terminator.
|
||||
void app_file_name_make(char * restrict buffer, size_t buffer_len,
|
||||
AppInstallId app_id, const char * restrict suffix,
|
||||
size_t suffix_len);
|
||||
|
||||
//! Checks whether the given filename is an app file.
|
||||
bool is_app_file_name(const char *filename);
|
||||
|
||||
//! Checks whether the given filename is an app resource file (suffix = "res")
|
||||
bool is_app_resource_file_name(const char *filename);
|
||||
|
||||
//! Parses an app-file name to get the AppInstallId.
|
||||
//! Assumes the file is indeed an app-file
|
||||
AppInstallId app_file_parse_app_id(const char *filename);
|
||||
|
||||
//! Parses an app-file name to get the AppInstallId.
|
||||
//!
|
||||
//! @returns INSTALL_ID_INVALID if the filename is not an app-file.
|
||||
AppInstallId app_file_get_app_id(const char *filename);
|
215
src/fw/services/normal/filesystem/flash_translation.c
Normal file
215
src/fw/services/normal/filesystem/flash_translation.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "flash_translation.h"
|
||||
|
||||
#include "drivers/flash.h"
|
||||
#include "drivers/task_watchdog.h"
|
||||
#include "flash_region/filesystem_regions.h"
|
||||
#include "flash_region/flash_region.h"
|
||||
#include "services/normal/filesystem/pfs.h"
|
||||
#include "system/logging.h"
|
||||
#include "system/passert.h"
|
||||
#include "util/math.h"
|
||||
#include "util/size.h"
|
||||
|
||||
//! Flash translation operation
|
||||
typedef enum {
|
||||
FTLRead,
|
||||
FTLWrite,
|
||||
FTLEraseSector,
|
||||
FTLEraseSubsector
|
||||
} FTLOperation;
|
||||
|
||||
//! Total number of FSRegions listed in s_region_list
|
||||
static const unsigned int TOTAL_NUM_FLASH_REGIONS = ARRAY_LENGTH(s_region_list);
|
||||
|
||||
//! Keeps track of the current total size of our filesystem in bytes.
|
||||
static uint32_t s_ftl_size;
|
||||
|
||||
//! Keeps track of which regions are included in the filesystem.
|
||||
static unsigned int s_next_region_idx = 0;
|
||||
|
||||
//! returns FSRegion size given idx in s_region_list
|
||||
static uint32_t prv_region_size(int idx) {
|
||||
return (s_region_list[idx].end - s_region_list[idx].start);
|
||||
}
|
||||
|
||||
//! add all regions temporarily so that PFS can test on these regions
|
||||
static void prv_layout_version_add_all_regions(bool revert) {
|
||||
static unsigned int original_idx;
|
||||
|
||||
if (!revert) {
|
||||
original_idx = s_next_region_idx;
|
||||
s_next_region_idx = TOTAL_NUM_FLASH_REGIONS;
|
||||
} else {
|
||||
s_next_region_idx = original_idx;
|
||||
}
|
||||
|
||||
s_ftl_size = 0;
|
||||
|
||||
for (unsigned int i = 0; i < s_next_region_idx; i++) {
|
||||
s_ftl_size += prv_region_size(i);
|
||||
}
|
||||
|
||||
PBL_LOG(LOG_LEVEL_DEBUG, "Filesystem: Temporary size - %"PRId32" Kb", (s_ftl_size / 1024));
|
||||
pfs_set_size(s_ftl_size, false /* don't erase regions */);
|
||||
}
|
||||
|
||||
//! return a layout version that associates with the labels from above
|
||||
static uint8_t prv_ftl_get_layout_version(void) {
|
||||
// add all regions so PFS can know about them temporarily
|
||||
prv_layout_version_add_all_regions(false);
|
||||
|
||||
uint8_t flash_version = 0;
|
||||
uint32_t known_size = 0;
|
||||
|
||||
// iterate through all regions idx > 0 and see if PFS is active in the regions. If yes, increment
|
||||
// flash version.
|
||||
for (uint8_t i = flash_version; i < TOTAL_NUM_FLASH_REGIONS; i++) {
|
||||
if ((prv_region_size(i) == 0) ||
|
||||
pfs_active_in_region(known_size, known_size + prv_region_size(i))) {
|
||||
// if active, increment known flash version and increase size to check next region
|
||||
flash_version = i + 1;
|
||||
known_size += prv_region_size(i);
|
||||
} else {
|
||||
// if not active, break and return known flash version
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// go back to the state we were in before the function
|
||||
prv_layout_version_add_all_regions(true);
|
||||
|
||||
return flash_version;
|
||||
}
|
||||
|
||||
void ftl_add_region(uint32_t region_start, uint32_t region_end, bool erase_new_region) {
|
||||
// check if this region equals the next region, if so, then add next region
|
||||
if ((region_start == s_region_list[s_next_region_idx].start) &&
|
||||
(region_end == s_region_list[s_next_region_idx].end) &&
|
||||
(s_next_region_idx < TOTAL_NUM_FLASH_REGIONS)) {
|
||||
s_next_region_idx++;
|
||||
// failure, should never happen
|
||||
} else {
|
||||
PBL_LOG(LOG_LEVEL_WARNING,
|
||||
"Filesystem: Uh oh, we somehow added regions in the wrong order, %"PRIu32" %"PRIu32,
|
||||
region_start, region_end);
|
||||
return;
|
||||
}
|
||||
|
||||
// erase if asked to
|
||||
if (erase_new_region) {
|
||||
flash_region_erase_optimal_range_no_watchdog(region_start, region_start,
|
||||
region_end, region_end);
|
||||
}
|
||||
|
||||
s_ftl_size += (region_end - region_start);
|
||||
|
||||
// call back to PFS to make sure it realizes there is more space to place files.
|
||||
pfs_set_size(s_ftl_size, erase_new_region);
|
||||
}
|
||||
|
||||
void ftl_populate_region_list(void) {
|
||||
uint8_t flash_layout_version = prv_ftl_get_layout_version();
|
||||
PBL_LOG(LOG_LEVEL_INFO, "Filesystem: Old Flash Layout Version: %u", flash_layout_version);
|
||||
|
||||
for (unsigned int i = s_next_region_idx; i < flash_layout_version; i++) {
|
||||
ftl_add_region(s_region_list[i].start, s_region_list[i].end, false);
|
||||
}
|
||||
|
||||
// at this point we have found all the regions that already exist on the flash
|
||||
// so run our cleanup logic in case we rebooted during a filesystem operation
|
||||
pfs_reboot_cleanup();
|
||||
|
||||
for (unsigned int i = s_next_region_idx; i < TOTAL_NUM_FLASH_REGIONS; i++) {
|
||||
ftl_add_region(s_region_list[i].start, s_region_list[i].end, true);
|
||||
}
|
||||
|
||||
PBL_LOG(LOG_LEVEL_DEBUG, "Filesystem: New size - %"PRId32" Kb", (s_ftl_size / 1024));
|
||||
}
|
||||
|
||||
uint32_t ftl_get_size(void) {
|
||||
return s_ftl_size;
|
||||
}
|
||||
|
||||
static void prv_ftl_operation(uint8_t *buffer, uint32_t size, uint32_t offset,
|
||||
FTLOperation operation) {
|
||||
|
||||
uint32_t curr_virt_offset_begin = 0;
|
||||
uint32_t curr_virt_offset_end = 0;
|
||||
|
||||
|
||||
// iterate through all regions and perform read, write, or erase
|
||||
for (unsigned int idx = 0; (idx < s_next_region_idx) && (size != 0); idx++) {
|
||||
curr_virt_offset_end += prv_region_size(idx);
|
||||
if (offset < curr_virt_offset_end) {
|
||||
uint32_t bytes = MIN(curr_virt_offset_end - offset, size);
|
||||
|
||||
if (operation == FTLRead) {
|
||||
flash_read_bytes(
|
||||
buffer, s_region_list[idx].start + offset - curr_virt_offset_begin, bytes);
|
||||
} else if (operation == FTLWrite ) {
|
||||
flash_write_bytes(
|
||||
buffer, s_region_list[idx].start + offset - curr_virt_offset_begin, bytes);
|
||||
} else if (operation == FTLEraseSubsector) {
|
||||
PBL_ASSERTN(size == SUBSECTOR_SIZE_BYTES);
|
||||
flash_erase_subsector_blocking(
|
||||
s_region_list[idx].start + offset - curr_virt_offset_begin);
|
||||
} else if (operation == FTLEraseSector) {
|
||||
PBL_ASSERTN(size == SECTOR_SIZE_BYTES);
|
||||
flash_erase_sector_blocking(
|
||||
s_region_list[idx].start + offset - curr_virt_offset_begin);
|
||||
}
|
||||
|
||||
size -= bytes;
|
||||
offset += bytes;
|
||||
}
|
||||
curr_virt_offset_begin = curr_virt_offset_end;
|
||||
}
|
||||
}
|
||||
|
||||
void ftl_read(void *buffer, size_t size, uint32_t offset) {
|
||||
prv_ftl_operation(buffer, size, offset, FTLRead);
|
||||
}
|
||||
|
||||
void ftl_write(const void *buffer, size_t size, uint32_t offset) {
|
||||
prv_ftl_operation((void *)buffer, size, offset, FTLWrite);
|
||||
}
|
||||
|
||||
void ftl_erase_sector(uint32_t size, uint32_t offset) {
|
||||
prv_ftl_operation(NULL /* not needed for erase */, size, offset, FTLEraseSector);
|
||||
}
|
||||
|
||||
void ftl_erase_subsector(uint32_t size, uint32_t offset) {
|
||||
prv_ftl_operation(NULL /* not needed for erase */, size, offset, FTLEraseSubsector);
|
||||
}
|
||||
|
||||
void ftl_format(void) {
|
||||
}
|
||||
|
||||
//! Only used for tests.
|
||||
void ftl_force_version(int version_idx) {
|
||||
s_next_region_idx = version_idx;
|
||||
s_ftl_size = 0;
|
||||
for (int i = 0; i < version_idx; i++) {
|
||||
s_ftl_size += prv_region_size(i);
|
||||
}
|
||||
|
||||
pfs_set_size(s_ftl_size, false);
|
||||
extern void test_force_recalc_of_gc_region(void);
|
||||
test_force_recalc_of_gc_region();
|
||||
}
|
74
src/fw/services/normal/filesystem/flash_translation.h
Normal file
74
src/fw/services/normal/filesystem/flash_translation.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
//! Flash Translation Layer
|
||||
//!
|
||||
//! This module allows our filesystem, PFS, to grow into multiple flash regions while keeping a
|
||||
//! contiguous virtual address space.
|
||||
//!
|
||||
//! On boot, this module checks each region to see if the filesystem is active in said region.
|
||||
//! If so, it adds the region to the flash translation space and continues processing the
|
||||
//! remaining regions. If the filesystem was not previously active in the region, then the region
|
||||
//! is first migrated (by calling the migration function pointer) and is added to the
|
||||
//! flash translation space.
|
||||
|
||||
//! Adds a flash region to the flash translation layer. This increases the overall size of the
|
||||
//! flash translation space by (region_end - region_start)
|
||||
//! @param region_start start of the region
|
||||
//! @param region_end end of the region
|
||||
//! @param erase_new_region Whether or not to erase the region before adding
|
||||
void ftl_add_region(uint32_t region_start, uint32_t region_end, bool erase_new_region);
|
||||
|
||||
//! Gets the size of the flash translation space.
|
||||
//! @return - the size of the flash translation space in number of bytes.
|
||||
uint32_t ftl_get_size(void);
|
||||
|
||||
//! Erases a SECTOR in the flash translation space starting at the given virtual flash offset.
|
||||
//! There is an ASSERT to check if size is exactly the size of the region being erased.
|
||||
//!
|
||||
//! @param size size of sector to erase. Should be equal to SUBSECTOR_SIZE_BYTES
|
||||
//! @param offset virtual flash offset to erase the SUBSECTOR
|
||||
void ftl_erase_sector(uint32_t size, uint32_t offset);
|
||||
//! same as ftl_erase_sector except it operates on a SUBSECTOR
|
||||
void ftl_erase_subsector(uint32_t size, uint32_t offset);
|
||||
|
||||
//! Reads the data at the virtual flash address given and writes it to the data buffer.
|
||||
//! @param buffer The data block to write to
|
||||
//! @param size The number of bytes from flash to write into buffer (must be <= the size of buffer)
|
||||
//! @param offset Where to read the bytes from in the virtual flash translation space.
|
||||
void ftl_read(void *buffer, size_t size, uint32_t offset);
|
||||
|
||||
//! Writes the data buffer to the virtual flash address given.
|
||||
//! @param buffer The data block to write to flash
|
||||
//! @param size The number of bytes from buffer to write (must be <= the size of buffer)
|
||||
//! @param offset Where to write the bytes in the virtual flash translation space.
|
||||
void ftl_write(const void *buffer, size_t size, uint32_t offset);
|
||||
|
||||
//! Formats all regions added to the flash translation layer
|
||||
void ftl_format(void);
|
||||
|
||||
//! There are two steps to this function.
|
||||
//! 1. Add all regions where PFS already exists, and add them to the flash translation layer.
|
||||
//! 2. Migrate all regions where PFS does NOT exist and add them to the flash translation layer.
|
||||
void ftl_populate_region_list(void);
|
||||
|
||||
void add_initial_space_to_filesystem(void);
|
2386
src/fw/services/normal/filesystem/pfs.c
Normal file
2386
src/fw/services/normal/filesystem/pfs.c
Normal file
File diff suppressed because it is too large
Load diff
223
src/fw/services/normal/filesystem/pfs.h
Normal file
223
src/fw/services/normal/filesystem/pfs.h
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* 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 orginal 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);
|
Loading…
Add table
Add a link
Reference in a new issue