forked from espressif/esp-idf
feat(fatfs): Add f_expand function as esp_vfs_fat_create_contiguous_file
Add esp_vfs_fat_test_contiguous_file to test it
This commit is contained in:
@@ -40,7 +40,7 @@
|
|||||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_EXPAND 0
|
#define FF_USE_EXPAND 1
|
||||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
@@ -194,6 +194,15 @@ TEST_CASE("(WL) can truncate", "[fatfs][wear_levelling]")
|
|||||||
test_teardown();
|
test_teardown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FF_USE_EXPAND
|
||||||
|
TEST_CASE("(WL) can esp_vfs_fat_create_contiguous_file", "[fatfs][wear_levelling]")
|
||||||
|
{
|
||||||
|
test_setup();
|
||||||
|
test_fatfs_create_contiguous_file("/spiflash", "/spiflash/expand.txt");
|
||||||
|
test_teardown();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST_CASE("(WL) stat returns correct values", "[fatfs][wear_levelling]")
|
TEST_CASE("(WL) stat returns correct values", "[fatfs][wear_levelling]")
|
||||||
{
|
{
|
||||||
test_setup();
|
test_setup();
|
||||||
|
@@ -198,6 +198,16 @@ TEST_CASE("(SD) can ftruncate", "[fatfs][sdmmc]")
|
|||||||
test_teardown_sdmmc(card);
|
test_teardown_sdmmc(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FF_USE_EXPAND
|
||||||
|
TEST_CASE("(SD) can esp_vfs_fat_create_contiguous_file", "[fatfs][sdmmc]")
|
||||||
|
{
|
||||||
|
sdmmc_card_t *card = NULL;
|
||||||
|
test_setup_sdmmc(&card);
|
||||||
|
test_fatfs_create_contiguous_file("/sdcard", "/sdcard/expand.txt");
|
||||||
|
test_teardown_sdmmc(card);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST_CASE("(SD) stat returns correct values", "[fatfs][sdmmc]")
|
TEST_CASE("(SD) stat returns correct values", "[fatfs][sdmmc]")
|
||||||
{
|
{
|
||||||
sdmmc_card_t *card = NULL;
|
sdmmc_card_t *card = NULL;
|
||||||
|
@@ -1011,3 +1011,28 @@ void test_fatfs_info(const char* base_path, const char* filepath)
|
|||||||
ESP_LOGD("fatfs info", "total_bytes=%llu, free_bytes_after_delete=%llu", total_bytes, free_bytes_new);
|
ESP_LOGD("fatfs info", "total_bytes=%llu, free_bytes_after_delete=%llu", total_bytes, free_bytes_new);
|
||||||
TEST_ASSERT_EQUAL(free_bytes, free_bytes_new);
|
TEST_ASSERT_EQUAL(free_bytes, free_bytes_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FF_USE_EXPAND
|
||||||
|
void test_fatfs_create_contiguous_file(const char* base_path, const char* full_path)
|
||||||
|
{
|
||||||
|
size_t desired_file_size = 64;
|
||||||
|
|
||||||
|
// Don't check for errors, file may not exist at first
|
||||||
|
remove(full_path); // esp_vfs_fat_create_contiguous_file will fail if the file already exists
|
||||||
|
|
||||||
|
esp_err_t err = esp_vfs_fat_create_contiguous_file(base_path, full_path, desired_file_size, true);
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
stat(full_path, &st);
|
||||||
|
size = st.st_size;
|
||||||
|
TEST_ASSERT_EQUAL(desired_file_size, size);
|
||||||
|
|
||||||
|
bool is_contiguous = false;
|
||||||
|
err = esp_vfs_fat_test_contiguous_file(base_path, full_path, &is_contiguous);
|
||||||
|
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||||
|
TEST_ASSERT_TRUE(is_contiguous);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -76,3 +76,7 @@ void test_leading_spaces(void);
|
|||||||
void test_fatfs_rw_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool write);
|
void test_fatfs_rw_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool write);
|
||||||
|
|
||||||
void test_fatfs_info(const char* base_path, const char* filepath);
|
void test_fatfs_info(const char* base_path, const char* filepath);
|
||||||
|
|
||||||
|
#if FF_USE_EXPAND
|
||||||
|
void test_fatfs_create_contiguous_file(const char* base_path, const char* full_path);
|
||||||
|
#endif
|
||||||
|
@@ -394,6 +394,38 @@ esp_err_t esp_vfs_fat_spiflash_unmount_ro(const char* base_path, const char* par
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_vfs_fat_info(const char* base_path, uint64_t* out_total_bytes, uint64_t* out_free_bytes);
|
esp_err_t esp_vfs_fat_info(const char* base_path, uint64_t* out_total_bytes, uint64_t* out_free_bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a file with contiguous space at given path
|
||||||
|
*
|
||||||
|
* @note The file cannot exist before calling this function (or the file size has to be 0)
|
||||||
|
* For more information see documentation for `f_expand` from FATFS library
|
||||||
|
*
|
||||||
|
* @param base_path Base path of the partition examined (e.g. "/spiflash")
|
||||||
|
* @param full_path Full path of the file (e.g. "/spiflash/ABC.TXT")
|
||||||
|
* @param size File size expanded to, number of bytes in size to prepare or allocate for the file
|
||||||
|
* @param alloc_now True == allocate space now, false == prepare to allocate -- see `f_expand` from FATFS
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_ARG if invalid arguments (e.g. any of arguments are NULL or size lower or equal to 0)
|
||||||
|
* - ESP_ERR_INVALID_STATE if partition not found
|
||||||
|
* - ESP_FAIL if another FRESULT error (saved in errno)
|
||||||
|
*/
|
||||||
|
esp_err_t esp_vfs_fat_create_contiguous_file(const char* base_path, const char* full_path, uint64_t size, bool alloc_now);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test if a file is contiguous in the FAT filesystem
|
||||||
|
*
|
||||||
|
* @param base_path Base path of the partition examined (e.g. "/spiflash")
|
||||||
|
* @param full_path Full path of the file (e.g. "/spiflash/ABC.TXT")
|
||||||
|
* @param[out] is_contiguous True == allocate space now, false == prepare to allocate -- see `f_expand` from FATFS
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_ARG if invalid arguments (e.g. any of arguments are NULL)
|
||||||
|
* - ESP_ERR_INVALID_STATE if partition not found
|
||||||
|
* - ESP_FAIL if another FRESULT error (saved in errno)
|
||||||
|
*/
|
||||||
|
esp_err_t esp_vfs_fat_test_contiguous_file(const char* base_path, const char* full_path, bool* is_contiguous);
|
||||||
|
|
||||||
/** @cond */
|
/** @cond */
|
||||||
/**
|
/**
|
||||||
* @deprecated Please use `esp_vfs_fat_spiflash_mount_rw_wl` instead
|
* @deprecated Please use `esp_vfs_fat_spiflash_mount_rw_wl` instead
|
||||||
|
@@ -1190,3 +1190,138 @@ static int vfs_fat_utime(void *ctx, const char *path, const struct utimbuf *time
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // CONFIG_VFS_SUPPORT_DIR
|
#endif // CONFIG_VFS_SUPPORT_DIR
|
||||||
|
|
||||||
|
esp_err_t esp_vfs_fat_create_contiguous_file(const char* base_path, const char* full_path, uint64_t size, bool alloc_now)
|
||||||
|
{
|
||||||
|
if (base_path == NULL || full_path == NULL || size <= 0) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ctx = find_context_index_by_path(base_path);
|
||||||
|
if (ctx == FF_VOLUMES) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
vfs_fat_ctx_t* fat_ctx = s_fat_ctxs[ctx];
|
||||||
|
|
||||||
|
_lock_acquire(&fat_ctx->lock);
|
||||||
|
const char* file_path = full_path + strlen(base_path); // shift the pointer and omit the base_path
|
||||||
|
prepend_drive_to_path(fat_ctx, &file_path, NULL);
|
||||||
|
|
||||||
|
FIL* file = (FIL*) ff_memalloc(sizeof(FIL));
|
||||||
|
if (file == NULL) {
|
||||||
|
_lock_release(&fat_ctx->lock);
|
||||||
|
ESP_LOGD(TAG, "esp_vfs_fat_create_contiguous_file alloc failed");
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(file, 0, sizeof(*file));
|
||||||
|
|
||||||
|
FRESULT res = f_open(file, file_path, FA_WRITE | FA_OPEN_ALWAYS);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = f_expand(file, size, alloc_now ? 1 : 0);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
f_close(file);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = f_close(file);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lock_release(&fat_ctx->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
_lock_release(&fat_ctx->lock);
|
||||||
|
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
|
||||||
|
errno = fresult_to_errno(res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FRESULT test_contiguous_file( // From FATFS examples
|
||||||
|
FIL* fp, /* [IN] Open file object to be checked */
|
||||||
|
int* cont /* [OUT] 1:Contiguous, 0:Fragmented or zero-length */
|
||||||
|
) {
|
||||||
|
DWORD clst, clsz, step;
|
||||||
|
FSIZE_t fsz;
|
||||||
|
FRESULT fr;
|
||||||
|
|
||||||
|
*cont = 0;
|
||||||
|
fr = f_rewind(fp); /* Validates and prepares the file */
|
||||||
|
if (fr != FR_OK) return fr;
|
||||||
|
|
||||||
|
#if FF_MAX_SS == FF_MIN_SS
|
||||||
|
clsz = (DWORD)fp->obj.fs->csize * FF_MAX_SS; /* Cluster size */
|
||||||
|
#else
|
||||||
|
clsz = (DWORD)fp->obj.fs->csize * fp->obj.fs->ssize;
|
||||||
|
#endif
|
||||||
|
fsz = f_size(fp);
|
||||||
|
if (fsz > 0) {
|
||||||
|
clst = fp->obj.sclust - 1; /* A cluster leading the first cluster for first test */
|
||||||
|
while (fsz) {
|
||||||
|
step = (fsz >= clsz) ? clsz : (DWORD)fsz;
|
||||||
|
fr = f_lseek(fp, f_tell(fp) + step); /* Advances file pointer a cluster */
|
||||||
|
if (fr != FR_OK) return fr;
|
||||||
|
if (clst + 1 != fp->clust) break; /* Is not the cluster next to previous one? */
|
||||||
|
clst = fp->clust; fsz -= step; /* Get current cluster for next test */
|
||||||
|
}
|
||||||
|
if (fsz == 0) *cont = 1; /* All done without fail? */
|
||||||
|
}
|
||||||
|
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_vfs_fat_test_contiguous_file(const char* base_path, const char* full_path, bool* is_contiguous)
|
||||||
|
{
|
||||||
|
if (base_path == NULL || full_path == NULL || is_contiguous == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ctx = find_context_index_by_path(base_path);
|
||||||
|
if (ctx == FF_VOLUMES) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
vfs_fat_ctx_t* fat_ctx = s_fat_ctxs[ctx];
|
||||||
|
|
||||||
|
_lock_acquire(&fat_ctx->lock);
|
||||||
|
const char* file_path = full_path + strlen(base_path); // shift the pointer and omit the base_path
|
||||||
|
prepend_drive_to_path(fat_ctx, &file_path, NULL);
|
||||||
|
|
||||||
|
FIL* file = (FIL*) ff_memalloc(sizeof(FIL));
|
||||||
|
if (file == NULL) {
|
||||||
|
_lock_release(&fat_ctx->lock);
|
||||||
|
ESP_LOGD(TAG, "esp_vfs_fat_test_contiguous_file alloc failed");
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(file, 0, sizeof(*file));
|
||||||
|
|
||||||
|
FRESULT res = f_open(file, file_path, FA_WRITE | FA_OPEN_ALWAYS);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = test_contiguous_file(file, (int*) is_contiguous);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
f_close(file);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = f_close(file);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lock_release(&fat_ctx->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
_lock_release(&fat_ctx->lock);
|
||||||
|
ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
|
||||||
|
errno = fresult_to_errno(res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user