summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMychaela Falconia <mychaela.falconia@gmail.com>2019-02-12 15:21:33 +0700
committerVadim Yanitskiy <axilirator@gmail.com>2019-02-19 15:18:56 +0700
commit947369922990195bccb59cae88cccbd7eefac9c8 (patch)
tree12ae3f62f0c22adc90d9a69a89e8ba3b7e8e5dea
parentedabc799edcc893fcdef707ee861de9807dc78e7 (diff)
firmware/lib: introduce TIFFS filesystem support
All known TI GSM firmwares implement some kind of flash file system, or FFS. We call it TIFFS (Texas Instruments FFS) because it is TI's invention. TIFFS is a file system with a hierarchical directory tree structure, and with Unixy forward-slash-separated, case-sensitive pathnames; the semantics of "what is a file" and "what is a directory" are exactly the same as in UNIX; and TIFFS even supports symlinks, although that support is a little under-developed, and apparently no FFS symlinks were ever used in any production GSM device. Thus the FFS implemented in TI-based GSM devices (modems and "dumbphone" handsets) is really no different from, for example, JFFS2 in embedded Linux systems. The FFS in a GSM device typically stores two kinds of content: - Factory data: IMEI, RF calibration values, device make/model/revision ID strings etc. These files are expected to be programmed on the factory production line and not changed afterward. - Dynamic data written into the FFS in normal device operation: contacts, settings / preferences, call history, received SMS, etc. It should be noted that both Compal (Mot C1xx) and Foxconn (Pirelli DP-L10) vendors moved their vital per-unit factory data out of the FFS into their own ad hoc flash data structures, leaving their FFS only for less critical data. However, we do enable TIFFS access for them anyway. The location of TIFFS within the flash memory of a given GSM device is defined by the firmware design of that device, but is always some integral number of contiguous flash sectors. - On Motorola/Compal C139/140 phones, the FFS used by the original proprietary firmware occupies 5 sectors of 64 KiB each (320 KiB in total), starting at 0x370000. C11x/123 use smaller FFS configurations, whereas C155/156 seem to have switched to some other FFS format, different from our familiar TIFFS. - On the Pirelli DP-L10, the FFS used by the original proprietary firmware occupies 18 sectors of 256 KiB each (for 4.5 MiB in total), starting at the beginning of the 2nd flash chip select (0x02000000 in the ARM7 address space). - On FCDEV3B (FreeCalypso hardware), the FFS is located in the first 8 sectors (of 256 KiB each) in the 2nd flash chip select bank, which appears at 0x01800000 in the ARM7 address space. - On the GTA01/02 GSM modem, FFS occupies 7 sectors of 64 KiB each, starting at flash offset 0x380000. For more information, please refer to the FreeCalypso project documentation, from where this great contribution comes from. Please note that existing MediaTek targets most likely use different storage format as they have nothing from TI Calypso. Also, we don't (yet) know the location of TIFFS on SE J100i and Compal E99 targets. The TIFFS support is needed for the follow-up change, that implements reading of the factory RF calibration values. Tweaked (coding style changes) by Vadim Yanitskiy <axilirator@gmail.com> Change-Id: If6e212baeb10953129fb0d5253d263567f5e12d6 Related: OS#3582
-rw-r--r--src/target/firmware/Makefile2
-rw-r--r--src/target/firmware/board/compal_e86/init.c4
-rwxr-xr-xsrc/target/firmware/board/compal_e88/init.c4
-rw-r--r--src/target/firmware/board/fcdev3b/init.c4
-rw-r--r--src/target/firmware/board/gta0x/init.c4
-rw-r--r--src/target/firmware/board/pirelli_dpl10/init.c4
-rw-r--r--src/target/firmware/include/string.h3
-rw-r--r--src/target/firmware/include/tiffs.h33
-rw-r--r--src/target/firmware/lib/Makefile5
-rw-r--r--src/target/firmware/lib/index.c12
-rw-r--r--src/target/firmware/lib/memcmp.S18
-rw-r--r--src/target/firmware/lib/strcmp.c12
-rw-r--r--src/target/firmware/tiffs/Makefile5
-rw-r--r--src/target/firmware/tiffs/globals.c12
-rw-r--r--src/target/firmware/tiffs/globals.h9
-rw-r--r--src/target/firmware/tiffs/init.c103
-rw-r--r--src/target/firmware/tiffs/readfile.c264
17 files changed, 496 insertions, 2 deletions
diff --git a/src/target/firmware/Makefile b/src/target/firmware/Makefile
index 1196d10..914db6c 100644
--- a/src/target/firmware/Makefile
+++ b/src/target/firmware/Makefile
@@ -107,6 +107,7 @@ ANY_APP_LIBS+= calypso/libcalypso.a \
layer1/liblayer1.a \
lib/libmini.a \
comm/libcomm.a \
+ tiffs/libtiffs.a \
../../shared/libosmocore/build-target/src/.libs/libosmocore.a \
../../shared/libosmocore/build-target/src/gsm/.libs/libosmogsm.a \
../../shared/libosmocore/build-target/src/codec/.libs/libosmocodec.a
@@ -123,6 +124,7 @@ INCLUDES=-Iinclude/ -I../../../include -I../../shared/libosmocore/include -I../.
-include calypso/Makefile
-include layer1/Makefile
-include comm/Makefile
+-include tiffs/Makefile
-include lib/Makefile
# Include rules
diff --git a/src/target/firmware/board/compal_e86/init.c b/src/target/firmware/board/compal_e86/init.c
index fed9f85..725f184 100644
--- a/src/target/firmware/board/compal_e86/init.c
+++ b/src/target/firmware/board/compal_e86/init.c
@@ -31,6 +31,7 @@
#include <keypad.h>
#include <console.h>
#include <flash/cfi_flash.h>
+#include <tiffs.h>
#include <calypso/irq.h>
#include <calypso/clock.h>
@@ -146,4 +147,7 @@ void board_init(int with_irq)
/* enable LEDB driver of Iota for keypad backlight */
twl3025_reg_write(AUXLED, 0x02);
+
+ /* Initialize TIFFS reader (5 sectors of 64 KiB each) */
+ tiffs_init(0x370000, 0x10000, 5);
}
diff --git a/src/target/firmware/board/compal_e88/init.c b/src/target/firmware/board/compal_e88/init.c
index 04ae458..956f7dc 100755
--- a/src/target/firmware/board/compal_e88/init.c
+++ b/src/target/firmware/board/compal_e88/init.c
@@ -30,6 +30,7 @@
#include <keypad.h>
#include <console.h>
#include <flash/cfi_flash.h>
+#include <tiffs.h>
#include <calypso/irq.h>
#include <calypso/clock.h>
@@ -142,4 +143,7 @@ void board_init(int with_irq)
/* Initialize the charging controller */
battery_compal_e88_init();
+
+ /* Initialize TIFFS reader (6 sectors of 8 KiB each) */
+ tiffs_init(0x001f0000, 0x2000, 6);
}
diff --git a/src/target/firmware/board/fcdev3b/init.c b/src/target/firmware/board/fcdev3b/init.c
index 92be667..c070536 100644
--- a/src/target/firmware/board/fcdev3b/init.c
+++ b/src/target/firmware/board/fcdev3b/init.c
@@ -32,6 +32,7 @@
#include <keypad.h>
#include <console.h>
#include <flash/cfi_flash.h>
+#include <tiffs.h>
#include <calypso/irq.h>
#include <calypso/clock.h>
@@ -138,4 +139,7 @@ void board_init(int with_irq)
/* Initialize ABB driver (uses SPI) */
twl3025_init();
+
+ /* Initialize TIFFS reader (8 sectors of 256 KiB each) */
+ tiffs_init(0x01800000, 0x40000, 8);
}
diff --git a/src/target/firmware/board/gta0x/init.c b/src/target/firmware/board/gta0x/init.c
index b93f79c..7fba756 100644
--- a/src/target/firmware/board/gta0x/init.c
+++ b/src/target/firmware/board/gta0x/init.c
@@ -30,6 +30,7 @@
#include <keypad.h>
#include <console.h>
#include <flash/cfi_flash.h>
+#include <tiffs.h>
#include <calypso/irq.h>
#include <calypso/clock.h>
@@ -132,4 +133,7 @@ void board_init(int with_irq)
/* Initialize ABB driver (uses SPI) */
twl3025_init();
+
+ /* Initialize TIFFS reader (7 sectors of 64 KiB each) */
+ tiffs_init(0x380000, 0x10000, 7);
}
diff --git a/src/target/firmware/board/pirelli_dpl10/init.c b/src/target/firmware/board/pirelli_dpl10/init.c
index da23308..1af6e7c 100644
--- a/src/target/firmware/board/pirelli_dpl10/init.c
+++ b/src/target/firmware/board/pirelli_dpl10/init.c
@@ -31,6 +31,7 @@
#include <keypad.h>
#include <console.h>
#include <flash/cfi_flash.h>
+#include <tiffs.h>
#include <calypso/irq.h>
#include <calypso/clock.h>
@@ -156,4 +157,7 @@ void board_init(int with_irq)
/* enable LEDB driver of Iota for keypad backlight */
twl3025_reg_write(AUXLED, 0x02);
+
+ /* Initialize TIFFS reader (18 sectors of 256 KiB each) */
+ tiffs_init(0x02000000, 0x40000, 18);
}
diff --git a/src/target/firmware/include/string.h b/src/target/firmware/include/string.h
index f060659..ecef13d 100644
--- a/src/target/firmware/include/string.h
+++ b/src/target/firmware/include/string.h
@@ -9,4 +9,7 @@ size_t strlen(const char *s);
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
+int memcmp(const void *s1, const void *s2, size_t n);
+int strcmp(const char *s1, const char *s2);
+
#endif
diff --git a/src/target/firmware/include/tiffs.h b/src/target/firmware/include/tiffs.h
new file mode 100644
index 0000000..4713c4e
--- /dev/null
+++ b/src/target/firmware/include/tiffs.h
@@ -0,0 +1,33 @@
+/*
+ * The external API for the TIFFS reader library (libtiffs).
+ *
+ * For the file reading functions, the return code is 0 if the file wasn't
+ * found or there is no valid FFS (no error msg printed), 1 if the file was
+ * found and read successfully, or negative if some other error(s) occurred
+ * (error msg printed internally).
+ */
+
+#define INODE_TO_DATAPTR(i) \
+ ((uint8_t *)tiffs_base_addr + ((i)->dataptr << 4))
+
+#define TIFFS_OBJTYPE_FILE 0xF1
+#define TIFFS_OBJTYPE_DIR 0xF2
+#define TIFFS_OBJTYPE_SEGMENT 0xF4
+
+struct tiffs_inode {
+ uint16_t len;
+ uint8_t reserved1;
+ uint8_t type;
+ uint16_t descend;
+ uint16_t sibling;
+ uint32_t dataptr;
+ uint16_t sequence;
+ uint16_t updates;
+};
+
+int tiffs_init(uint32_t base_addr, uint32_t sector_size, unsigned nsectors);
+
+int tiffs_read_file_maxlen(const char *pathname, uint8_t *buf,
+ size_t maxlen, size_t *lenrtn);
+int tiffs_read_file_fixedlen(const char *pathname, uint8_t *buf,
+ size_t expect_len);
diff --git a/src/target/firmware/lib/Makefile b/src/target/firmware/lib/Makefile
index a2a6d45..7546198 100644
--- a/src/target/firmware/lib/Makefile
+++ b/src/target/firmware/lib/Makefile
@@ -2,6 +2,7 @@
LIBRARIES+=mini
LIB_mini_DIR=lib
LIB_mini_SRCS=vsprintf.c string.c ctype.c printf.c console.c ctors.c \
- changebit.S clearbit.S delay.c div64.S lib1funcs.S memcpy.S memset.S setbit.S testchangebit.S testclearbit.S testsetbit.S
-
+ changebit.S clearbit.S delay.c div64.S lib1funcs.S memcpy.S \
+ memset.S setbit.S testchangebit.S testclearbit.S testsetbit.S \
+ memcmp.S index.c strcmp.c
diff --git a/src/target/firmware/lib/index.c b/src/target/firmware/lib/index.c
new file mode 100644
index 0000000..bb304c0
--- /dev/null
+++ b/src/target/firmware/lib/index.c
@@ -0,0 +1,12 @@
+char *
+index(p, ch)
+ register char *p, ch;
+{
+ for (;; ++p) {
+ if (*p == ch)
+ return(p);
+ if (!*p)
+ return((char *)0);
+ }
+ /* NOTREACHED */
+}
diff --git a/src/target/firmware/lib/memcmp.S b/src/target/firmware/lib/memcmp.S
new file mode 100644
index 0000000..c60b170
--- /dev/null
+++ b/src/target/firmware/lib/memcmp.S
@@ -0,0 +1,18 @@
+ .text
+ .code 32
+ .globl memcmp
+memcmp:
+ cmp r2, #0
+ beq zero_len_out
+ mov r3, r0
+1: ldrb r0, [r3], #1
+ ldrb r12, [r1], #1
+ subs r0, r0, r12
+ bxne lr
+ subs r2, r2, #1
+ bne 1b
+ bx lr
+
+zero_len_out:
+ mov r0, #0
+ bx lr
diff --git a/src/target/firmware/lib/strcmp.c b/src/target/firmware/lib/strcmp.c
new file mode 100644
index 0000000..9a7fa81
--- /dev/null
+++ b/src/target/firmware/lib/strcmp.c
@@ -0,0 +1,12 @@
+/*
+ * Compare strings: s1>s2: >0 s1==s2: 0 s1<s2: <0
+ */
+
+strcmp(s1, s2)
+ register char *s1, *s2;
+{
+ while (*s1 == *s2++)
+ if (*s1++=='\0')
+ return(0);
+ return(*s1 - *--s2);
+}
diff --git a/src/target/firmware/tiffs/Makefile b/src/target/firmware/tiffs/Makefile
new file mode 100644
index 0000000..6ded9e8
--- /dev/null
+++ b/src/target/firmware/tiffs/Makefile
@@ -0,0 +1,5 @@
+
+LIBRARIES+=tiffs
+LIB_tiffs_DIR=tiffs
+LIB_tiffs_SRCS=globals.c init.c readfile.c
+
diff --git a/src/target/firmware/tiffs/globals.c b/src/target/firmware/tiffs/globals.c
new file mode 100644
index 0000000..ffbba42
--- /dev/null
+++ b/src/target/firmware/tiffs/globals.c
@@ -0,0 +1,12 @@
+/* global variables for the TIFFS reader code */
+
+#include <stdint.h>
+#include "globals.h"
+
+uint32_t tiffs_base_addr;
+uint32_t tiffs_sector_size;
+unsigned tiffs_nsectors;
+
+struct tiffs_inode *tiffs_active_index;
+int tiffs_root_ino;
+int tiffs_init_done;
diff --git a/src/target/firmware/tiffs/globals.h b/src/target/firmware/tiffs/globals.h
new file mode 100644
index 0000000..7c64693
--- /dev/null
+++ b/src/target/firmware/tiffs/globals.h
@@ -0,0 +1,9 @@
+/* global variables for the TIFFS reader code - extern declarations */
+
+extern uint32_t tiffs_base_addr;
+extern uint32_t tiffs_sector_size;
+extern unsigned tiffs_nsectors;
+
+extern struct tiffs_inode *tiffs_active_index;
+extern int tiffs_root_ino;
+extern int tiffs_init_done;
diff --git a/src/target/firmware/tiffs/init.c b/src/target/firmware/tiffs/init.c
new file mode 100644
index 0000000..6a3b48a
--- /dev/null
+++ b/src/target/firmware/tiffs/init.c
@@ -0,0 +1,103 @@
+/* TIFFS (TI Flash File System) reader implementation */
+
+/*
+ * (C) 2017 by Mychaela Falconia <mychaela.falconia@gmail.com>
+ * Tweaked (coding style changes) by Vadim Yanitskiy <axilirator@gmail.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <tiffs.h>
+#include "globals.h"
+
+/* Each flash sector used for TIFFS begins with this 6-byte signature */
+static const uint8_t ffs_sector_signature[6] = {
+ 'F', 'f', 's', '#', 0x10, 0x02
+};
+
+static int find_indexblk(void)
+{
+ uint32_t sector_addr;
+ uint8_t *sector_ptr;
+ unsigned i;
+
+ sector_addr = tiffs_base_addr;
+ for (i = 0; i < tiffs_nsectors; i++) {
+ sector_ptr = (uint8_t *) sector_addr;
+ if (!memcmp(sector_ptr, ffs_sector_signature, 6)
+ && sector_ptr[8] == 0xAB) {
+ printf("Found TIFFS active index block "
+ "at 0x%" PRIx32 "\n", sector_addr);
+ tiffs_active_index = (struct tiffs_inode *) sector_addr;
+ return 0;
+ }
+ sector_addr += tiffs_sector_size;
+ }
+
+ puts("TIFFS error: no active index block found\n");
+ return -1;
+}
+
+static int find_rootino(void)
+{
+ struct tiffs_inode *irec;
+ unsigned ino = 0;
+
+ while (++ino < tiffs_sector_size >> 4) {
+ irec = tiffs_active_index + ino;
+ if (irec->type != TIFFS_OBJTYPE_DIR)
+ continue;
+ if (*INODE_TO_DATAPTR(irec) != '/')
+ continue;
+
+ printf("Found TIFFS root inode at #%x\n", ino);
+ tiffs_root_ino = ino;
+ return 0;
+ }
+
+ puts("TIFFS error: no root inode found\n");
+ return -1;
+}
+
+int tiffs_init(uint32_t base_addr, uint32_t sector_size, unsigned nsectors)
+{
+ int rc;
+
+ printf("Looking for TIFFS (TI Flash File System) header at "
+ "0x%" PRIx32 ", %u sectors of 0x%" PRIx32 " bytes\n",
+ base_addr, nsectors, sector_size);
+
+ tiffs_base_addr = base_addr;
+ tiffs_sector_size = sector_size;
+ tiffs_nsectors = nsectors;
+
+ rc = find_indexblk();
+ if (rc < 0)
+ return rc;
+ rc = find_rootino();
+ if (rc < 0)
+ return rc;
+
+ tiffs_init_done = 1;
+ return 0;
+}
diff --git a/src/target/firmware/tiffs/readfile.c b/src/target/firmware/tiffs/readfile.c
new file mode 100644
index 0000000..f3e916f
--- /dev/null
+++ b/src/target/firmware/tiffs/readfile.c
@@ -0,0 +1,264 @@
+/* TIFFS (TI Flash File System) reader implementation */
+
+/*
+ * (C) 2017 by Mychaela Falconia <mychaela.falconia@gmail.com>
+ * Tweaked (coding style changes) by Vadim Yanitskiy <axilirator@gmail.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <tiffs.h>
+#include "globals.h"
+
+extern char *index();
+
+#define MAX_FN_COMPONENT 20
+
+static unsigned find_named_child(unsigned start, const char *seekname)
+{
+ struct tiffs_inode *irec;
+ unsigned ino;
+
+ for (ino = start; ino != 0xFFFF; ino = irec->sibling) {
+ irec = tiffs_active_index + ino;
+ if (!irec->type)
+ continue;
+ if (!strcmp((const char *) INODE_TO_DATAPTR(irec), seekname))
+ return ino;
+ }
+
+ return 0;
+}
+
+static int pathname_to_inode(const char *pathname)
+{
+ char seekname[MAX_FN_COMPONENT + 1];
+ struct tiffs_inode *irec;
+ const char *cur, *next;
+ unsigned ino, namelen;
+
+ cur = pathname;
+ if (*cur == '/')
+ cur++;
+
+ for (ino = tiffs_root_ino; cur; cur = next) {
+ if (!*cur)
+ break;
+
+ next = index(cur, '/');
+ if (next == cur) {
+ puts("Malformed TIFFS pathname: multiple adjacent slashes\n");
+ return -1;
+ } else if (next) {
+ namelen = next - cur;
+ next++;
+ } else {
+ namelen = strlen(cur);
+ }
+
+ if (namelen > MAX_FN_COMPONENT) {
+ puts("Malformed TIFFS pathname: component name too long\n");
+ return -1;
+ }
+
+ memcpy(seekname, cur, namelen);
+ seekname[namelen] = '\0';
+
+ irec = tiffs_active_index + ino;
+ if (irec->type != TIFFS_OBJTYPE_DIR) {
+ /* printf("Error: non-terminal non-directory\n"); */
+ return 0;
+ }
+ ino = find_named_child(irec->descend, seekname);
+ if (!ino) {
+ /* printf("Error: pathname component not found\n"); */
+ return 0;
+ }
+ }
+
+ return ino;
+}
+
+static uint8_t *find_endofchunk(int ino)
+{
+ struct tiffs_inode *irec;
+ uint8_t *ptr;
+ int i;
+
+ irec = tiffs_active_index + ino;
+ ptr = INODE_TO_DATAPTR(irec) + irec->len;
+
+ for (i = 0; i < 16; i++) {
+ ptr--;
+ if (!*ptr)
+ return ptr;
+ if (*ptr != 0xFF)
+ break;
+ }
+
+ printf("TIFFS error: inode #%x has no valid termination\n", ino);
+ return ptr; /* XXX */
+}
+
+static int get_file_head(const char *pathname, uint8_t **startret,
+ size_t *sizeret, int *continue_ret)
+{
+ struct tiffs_inode *irec;
+ uint8_t *start, *end;
+ int ino, cont, size;
+
+ ino = pathname_to_inode(pathname);
+ if (ino <= 0)
+ return ino;
+
+ irec = tiffs_active_index + ino;
+ if (irec->type != TIFFS_OBJTYPE_FILE) {
+ printf("TIFFS error: '%s' is not a regular file\n", pathname);
+ return -1;
+ }
+
+ start = INODE_TO_DATAPTR(irec);
+ start += strlen((const char *) start) + 1;
+ end = find_endofchunk(ino);
+
+ size = end - start;
+ if (size < 0)
+ size = 0;
+
+ cont = irec->descend;
+ if (cont == 0xFFFF)
+ cont = 0;
+ if (startret)
+ *startret = start;
+ if (sizeret)
+ *sizeret = size;
+ if (continue_ret)
+ *continue_ret = cont;
+
+ return 1;
+}
+
+static int get_segment(int ino, uint8_t **startret,
+ size_t *sizeret, int *continue_ret)
+{
+ struct tiffs_inode *irec;
+ uint8_t *start, *end;
+ int cont, size;
+
+ for (;;) {
+ irec = tiffs_active_index + ino;
+ if (irec->type)
+ break;
+ if (irec->sibling == 0xFFFF) {
+ printf("TIFFS error: segment inode #%d: "
+ "deleted and no sibling\n", ino);
+ return -1;
+ }
+ ino = irec->sibling;
+ }
+
+ if (irec->type != TIFFS_OBJTYPE_SEGMENT) {
+ printf("TIFFS error: inode #%x is not a segment\n", ino);
+ return -1;
+ }
+
+ start = INODE_TO_DATAPTR(irec);
+ end = find_endofchunk(ino);
+
+ size = end - start;
+ if (size <= 0) {
+ printf("TIFFS error: segment inode #%x has bad length\n", ino);
+ return -1;
+ }
+
+ cont = irec->descend;
+ if (cont == 0xFFFF)
+ cont = 0;
+ if (startret)
+ *startret = start;
+ if (sizeret)
+ *sizeret = size;
+ if (continue_ret)
+ *continue_ret = cont;
+
+ return 0;
+}
+
+int tiffs_read_file_maxlen(const char *pathname, uint8_t *buf,
+ size_t maxlen, size_t *lenrtn)
+{
+ size_t chunk_size, real_len, roomleft;
+ uint8_t *chunk_start;
+ int stat, cont;
+
+ if (!tiffs_init_done) {
+ puts("TIFFS reader is not initialized\n");
+ return -1;
+ }
+
+ stat = get_file_head(pathname, &chunk_start, &chunk_size, &cont);
+ if (stat <= 0)
+ return stat;
+ if (chunk_size > maxlen) {
+toobig: printf("TIFFS error: '%s' is bigger than the read buffer\n", pathname);
+ return -1;
+ }
+
+ real_len = chunk_size;
+ memcpy(buf, chunk_start, chunk_size);
+ buf += chunk_size;
+ roomleft = maxlen - chunk_size;
+ while (cont) {
+ stat = get_segment(cont, &chunk_start, &chunk_size, &cont);
+ if (stat < 0)
+ return stat;
+ if (chunk_size > roomleft)
+ goto toobig;
+
+ real_len += chunk_size;
+ memcpy(buf, chunk_start, chunk_size);
+ buf += chunk_size;
+ roomleft -= chunk_size;
+ }
+
+ if (lenrtn)
+ *lenrtn = real_len;
+
+ return 1;
+}
+
+int tiffs_read_file_fixedlen(const char *pathname, uint8_t *buf,
+ size_t expect_len)
+{
+ size_t real_len;
+ int rc;
+
+ rc = tiffs_read_file_maxlen(pathname, buf, expect_len, &real_len);
+ if (rc <= 0)
+ return rc;
+ if (real_len != expect_len) {
+ printf("TIFFS error: '%s' has the wrong length\n", pathname);
+ return -1;
+ }
+
+ return 1;
+}