43bool g_tarfs_log =
true;
46#if CONFIG_TARFS_INTEGRITY
47static bool s_tarfs_crc64 =
true;
59 log(
"filesystem #%d does not exist!\r\n",i);
87 log(
"filesystem #%d does not exist!\r\n",i);
100static int findfs(
const char *mountpoint) {
105 if (s_tarfs[i] == NULL) {
106 if (mountpoint == NULL) {
107 log(
"empty slot #%d found\r\n", i);
115 if (mountpoint == NULL)
120 log(
"mountpoint %s slot #%d found\r\n", mountpoint, i);
127 if (mountpoint == NULL) {
128 log(
"can not find empty slot\r\n");
133 log(
"can not find slot (%s)\r\n", mountpoint);
155 if (s_tarfs[i] != NULL) {
156 const char *mp = s_tarfs[i]->fs_mountpoint;
157 size_t len = strlen(mp);
162 if (strncmp(path, mp, len) != 0)
166 if (path[len] !=
'\0' &&
190static void commit_unmount(
void *ctx) {
201 log(
"unregistering VFS\r\n");
218 log(
"clearing slot..\r\n");
221 if (s_tarfs[i] == fs) {
224 log(
"FS slot %d cleared\r\n", i);
232 log(
" deleting inodes (%u)\r\n", (
unsigned int)fs->
fs_nino);
240 log(
" unmapping filesystem image, vaddr=%p, size=%u\r\n", (
const void *)fs->
fs_vaddr, (
unsigned int)fs->
fs_size);
246 log(
"deleting FS descriptor %p\r\n", (
void *)fs);
254 return fs == NULL ? 0 : addref(&fs->
fs_ref);
261 return fs == NULL ? 0 : unrefx(&fs->
fs_ref, fs, commit_unmount);
276 if (mountpoint == NULL) {
283 if ((slot = findfs(mountpoint)) >= 0) {
290 log(
"Filesystem %s is in use (%u open fds), unmount delayed\r\n", mountpoint, prev_refc - 1);
310int tarfs_mount_memory(
const void *map,
size_t size,
const char *mountpoint,
const char *link_rebase,
const char *path_rebase) {
318 char base_dir[128] = {
'/' };
320 if (link_rebase == NULL)
324 strncpy(&base_dir[1], path_rebase,
sizeof(base_dir)-1);
326 if (
false ==
tar_rootdir(map,
size, &base_dir[1],
sizeof(base_dir) - 1))
330 if (mountpoint == NULL)
331 mountpoint = base_dir;
333 log(
"detected MP '%s' is overriden with '%s'\r\n", base_dir, mountpoint);
336 len = strlen(mountpoint);
338#if CONFIG_TARFS_INTEGRITY
340 log(
"TAR-CRC64 filesystem is expected\r\n");
343 if (
false == (len > 1 && mountpoint[0] ==
'/' && mountpoint[len - 1] !=
'/')) {
344 log(
"mountpoint is too short or invalid '%s'\r\n", mountpoint);
346unmap_and_return_error:
351 log(
"mountpoint: '%s'\r\n", mountpoint);
353 if (base_dir[1] ==
'\0') {
354 log(
"WARN: tarfile has no root directory\r\n");
356 log(
"common prefix: '%s' (will be stripped)\r\n", &base_dir[1]);
359 if (*link_rebase !=
'\0') {
360 log(
"absolute path rewrite: '%s'\r\n",link_rebase);
362 log(
"preserving absolute paths in hardlinks/symlinks\r\n");
368 goto unmap_and_return_error;
374 if (0 > (slot = findfs( NULL ))) {
377 log(
"too many mounted filesystems (%u)\r\n",s_numfs);
379 goto unmap_and_return_error;
388 log(
"allocated new FS descriptor s_tarfs[%d] = %p\r\n", slot, (
void *)fs);
401 log(
"mounting..\r\n");
404 log(
"filesystem is unusable, no valid inodes were found\r\n");
406 s_tarfs[slot] = NULL;
410 goto unmap_and_return_error;
412 log(
"WARN: running in degraded mode\r\n");
418 log(
"registering TARFS in VFS..\r\n");
420 log(
"Can not register POSIX handlers, only native tarfs API is available\r\n");
422 log(
"VFS registered. (prefix '%s' in VFS)\r\n", mountpoint);
425 log(
"mount is done. filesystem slot is %d\r\n", slot);
427 log(
"-----------\r\n%u blocks (%u bytes) were skipped as BAD\n"
428 "TAR archive has %u files, %u links and %u dirs\r\n"
429 "TAR data/headers ratio: %u data bytes, %u header bytes\r\n"
430 "RAM overhead (total RAM used by the FS): %u bytes\r\n-----------\r\n",
449int tarfs_mount(
const char *label,
const char *mountpoint,
const char *link_rebase,
const char *path_rebase) {
458 log(
"loading OS-specific resource '%s'..\r\n", label);
462 log(
"resource is available at %p, %u bytes. mounting from memory..\r\n", map, (
unsigned int)
size);
467 log(
"success, filesystem slot %d was assigned\r\n", slot);
471 log(
"resource handle is %p, commit_unmount() will do tarfs_os_unmap_tarfile()\r\n", (
void *)os_handle);
483 log(
"failed to mmap() the FS image (errno=%d, label=%s)\r\n", errno, label);
497 memset(buffer, 0,
size);
509 size_t len = strlen(str);
514 memcpy(dst, str, len);
533int tarfs_info(
const char *mp,
size_t *raw_size,
size_t *data_size) {
576 printf(
"Checking filesystem '%s'..\r\n", label);
582 uintptr_t tar_start = (uintptr_t )map;
585 int bad = 0, files = 0, dirs = 0, links = 0, bad_total = 0, hdr_no = 0, bad_files = 0;
586 uintptr_t tar_end = (uintptr_t )((
const uint8_t *)map + tar_length);
588 while (off +
sizeof(tarhdr_t) <= tar_length) {
590 const tarhdr_t *hdr = (
const tarhdr_t *)(tar_start + off);
596 printf(
"Inode#%u : bad metadata, switching to scan\r\n", hdr_no);
600 off +=
sizeof(tarhdr_t);
606 printf(
"Inode#%u : %u headers were skipped, continuing to mount..\r\n", hdr_no, bad);
613 if (((uintptr_t)(hdr + 1)) +
size >= tar_end) {
614 printf(
"Inode#%u : element extends beyond the end of the archive\r\n", hdr_no);
621 case TART_FILE: files++;
break;
624 case TART_HARDLINK: links++;
break;
626 case TART_DIR: dirs++;
break;
628 case TART_PAX_G:
break;
632 printf(
"Unrecognized entry #%u, type=0x%02x\r\n",hdr_no, hdr->type);
637 printf(
"Inode#%u : bad data\r\n", hdr_no);
642 off +=
sizeof(tarhdr_t);
646 off += ((size_t)
size + 511) & ~511u;
653 unsigned int total = files + links + dirs;
655 printf(
"Check finished.\r\n\r\n"
656 "Inodes processed: %u, number of bad metadata headers: %u\r\n\r\n", hdr_no, bad_total);
657 printf(
"Trailing garbage: %u blocks, ~%u bytes\r\n", bad, bad * 512);
658 printf(
"Damaged data: (%u files / pax headers)\r\n",bad_files);
659 printf(
"Available: %u entries (%u files, %u dirs, %u links)\r\n",total, files, dirs, links);
661 num = bad_total + bad_files;
696 fs_idx = (int)(uintptr_t)ctx;
704 memset(st, 0,
sizeof(*st));
720 st->
f_namemax =
sizeof(((
struct dirent *) 0)->d_name) - 1;
737#if CONFIG_TARFS_HAVE_STATVFS_H
740# if CONFIG_TARFS_COUNTERS
746# if CONFIG_TARFS_INTEGRITY
772#if CONFIG_TARFS_INTEGRITY
777 log(
"no such filesystem: %d\r\n", fs_idx);
789 log(
" CRC64 on each open() : %s\r\n", en < 0 ?
"unchanged" : (en ?
"enabled (slow open)" :
"disabled"));
792 log(
"CONFIG_TARFS_INTEGRITY is disabled, flag ignored\r\n");
805#if CONFIG_TARFS_INTEGRITY
807 int ret = s_tarfs_crc64;
810 log(
" CRC64 on mount : %s\r\n", en < 0 ?
"unchanged" : (en ?
"enabled (slow mount)" :
"disabled"));
819 log(
"CONFIG_TARFS_INTEGRITY is disabled, flag ignored\r\n");
838 printf(
" Filesystem ID: %u\r\n",(
unsigned int)st.
f_fsid);
839 printf(
"----------------\r\n");
840 printf(
" Filesystem block size: %u\r\n",(
unsigned int)st.
f_bsize);
841 printf(
" Fragment size: %u\r\n",(
unsigned int)st.
f_frsize);
842 printf(
" Number of blocks: %u\r\n",(
unsigned int)st.
f_blocks);
843 printf(
" Maximum filename length: %u\r\n",(
unsigned int)st.
f_namemax);
845#if CONFIG_TARFS_HAVE_STATVFS_H
850 printf(
" Number of bad/unrecognized 512-byte blocks: %u\r\n",(
unsigned int)st.
f_badblocks);
851 printf(
" Number of bad CRC64 files: %u\r\n",(
unsigned int)st.
f_badcrc);
853 printf(
" Number of files: %u\r\n",(
unsigned int)st.
f_files);
854 printf(
" Number of links: %u\r\n",(
unsigned int)st.
f_links);
855 printf(
" Number of directories: %u\r\n",(
unsigned int)st.
f_dirs);
857 printf(
" Total bytes read()+pread(): %llu\r\n",(
unsigned long long)st.
f_bread);
858 printf(
" Total bytes mmap(): %llu\r\n",(
unsigned long long)st.
f_bmmap);
859 printf(
" Total number of failures: %u\r\n",(
unsigned int)st.
f_nfail);
861 printf(
" Total RAM used by the FS: %u \r\n",(
unsigned int)st.
f_ram);
864 printf(
"failed to statvfs()\r\n");
int tarfs_statvfs(void *ctx, struct statvfs *st)
Obtain filesystem statistics.
int tarfs_fsindex(const char *path)
Find the filesystem responsible for a given path.
int tarfs_unref(struct tarfs_fs *fs)
int tarfs_integrity_on_open(int fs_idx, int en)
Enable/Disable/Get fs_opencrc flag for a filesystem with index fs_idx This flag enable optinal CRC64 ...
unsigned int tarfs_fsck(const char *label)
Perform a deep filesystem integrity check.
int tarfs_unmount(const char *mountpoint)
Unmount tar file system.
void * tarfs_calloc(size_t count, size_t size)
calloc() based on a memory backend; Memory backend must set errno if there were errors
char * tarfs_strdup(char const *str)
struct tarfs_fs * tarfs_getfs(int i)
Lockless, not thread safe, does not increase refcounters.
int tarfs_mount(const char *label, const char *mountpoint, const char *link_rebase, const char *path_rebase)
Actual mount procedure We expect sane label pointer (ASCIIZ) and a sane mountpoint (i....
int tarfs_addref(struct tarfs_fs *fs)
Filesystem reference counting.
int tarfs_dump(int fs_idx)
Dump FS statistics and content This functions is for debugging only and MUST NOT be used in productio...
int tarfs_integrity(int en)
Enables or disables CRC64 integrity verification for TARFS archives.
struct tarfs_fs * tarfs_getfs_addref(int i)
Thread safe, increases refcounter, uses mutex!
int tarfs_mount_memory(const void *map, size_t size, const char *mountpoint, const char *link_rebase, const char *path_rebase)
Mount a TARFS filesystem from an already mapped memory buffer.
int tarfs_info(const char *mp, size_t *raw_size, size_t *data_size)
Get size information for TARFS.
void inode_unmount(struct tarfs_fs *fs, const void *tar_start, size_t tar_size)
Unmount a TAR image.
int inode_mount(struct tarfs_fs *fs, const unsigned char *buf, size_t size, const char *rebase_link, const char *base_dir)
Build an inode index for a TAR image.
void const * tarfs_os_map_tarfile(const char *name, void **os_handle_out, size_t *size_out)
Map a ESP32 flash partition to a virtual address space.
void tarfs_os_unmap_tarfile(void *os_handle, const void *ptr, size_t size)
Opposite of tarfs_os_map_tarfile().
bool tarfs_os_register_fs(const char *prefix, void *context)
Tell the VFS that TARFS is now handle all the paths starting from 'prefix'.
void * tarfs_os_malloc(size_t size)
Memory allocation backend.
void tarfs_os_free(void *buffer)
bool tarfs_os_unregister_fs(const char *prefix)
Tell the VFS that path 'prefix' is not handled by tarfs anymore.
typedef _Atomic(refc_type_t) refc_t
Atomic reference counter type.
unsigned int refc_type_t
Use case:
The statvfs structure for systems without it (e.g.
This descriptor holds all file descriptors opened.
struct tarfs_stats fs_stats
tarfs_inode_t const *const * fs_ino
uint32_t tar_octal(const char *p, size_t max_len)
bool tar_badhdr(tarhdr_t const *hdr)
Validate a TAR header.
bool tar_baddata(struct tarhdr const *hdr, size_t size)
Verify CRC64 checksum stored in a TAR archive, if present.
bool tar_rootdir(const uint8_t *tar_start, size_t tar_length, char *base_dir, size_t out_len)
Detect the archive root directory.