summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-12-19 21:46:52 +0000
committerAidan MacDonald <amachronic@protonmail.com>2022-12-23 19:54:18 +0000
commitba010851fafea3da0d0655b103158f0a9efe6406 (patch)
treebb26879ee1ac5e2d578948701b20c1bb33db14a9
parent6e794c9a2d9e91a926f70d0fcc66e255b0bdc221 (diff)
downloadrockbox-ba010851fafea3da0d0655b103158f0a9efe6406.tar.gz
rockbox-ba010851fafea3da0d0655b103158f0a9efe6406.zip
Remove lib/x1000-installer
Carrying this library is somewhat of a maintenance burden because some Rockbox APIs are mocked or duplicated in the test suite and thus need to be fixed up when refactoring. It's also unused & incomplete, so there's no good reason to keep it in tree any more. Change-Id: If39c62744b4edc0d81b1b6608ee5df69430e6581
-rw-r--r--lib/x1000-installer/.gitignore5
-rw-r--r--lib/x1000-installer/Makefile82
-rw-r--r--lib/x1000-installer/SOURCES6
-rw-r--r--lib/x1000-installer/include/xf_error.h43
-rw-r--r--lib/x1000-installer/include/xf_flashmap.h91
-rw-r--r--lib/x1000-installer/include/xf_nandio.h130
-rw-r--r--lib/x1000-installer/include/xf_package.h65
-rw-r--r--lib/x1000-installer/include/xf_stream.h64
-rw-r--r--lib/x1000-installer/include/xf_update.h53
-rw-r--r--lib/x1000-installer/src/xf_error.c42
-rw-r--r--lib/x1000-installer/src/xf_flashmap.c327
-rw-r--r--lib/x1000-installer/src/xf_nandio.c292
-rw-r--r--lib/x1000-installer/src/xf_package.c261
-rw-r--r--lib/x1000-installer/src/xf_stream.c211
-rw-r--r--lib/x1000-installer/src/xf_update.c149
-rw-r--r--lib/x1000-installer/test/data/lines_shuffled.txt108
-rw-r--r--lib/x1000-installer/test/data/lines_sorted.txt36
-rw-r--r--lib/x1000-installer/test/main.c86
-rw-r--r--lib/x1000-installer/test/test.h39
-rw-r--r--lib/x1000-installer/test/test_flashmap.c140
-rw-r--r--lib/x1000-installer/test/test_stream.c108
-rw-r--r--lib/x1000-installer/test_lib/core_alloc.c72
-rw-r--r--lib/x1000-installer/test_lib/core_alloc.h43
-rw-r--r--lib/x1000-installer/test_lib/fakenand.c270
-rw-r--r--lib/x1000-installer/test_lib/file.c11
-rw-r--r--lib/x1000-installer/test_lib/file.h18
-rw-r--r--lib/x1000-installer/test_lib/md5.c245
-rw-r--r--lib/x1000-installer/test_lib/md5.h18
-rw-r--r--lib/x1000-installer/test_lib/nand-x1000.h112
-rw-r--r--lib/x1000-installer/test_lib/pathfuncs.c130
-rw-r--r--lib/x1000-installer/test_lib/pathfuncs.h39
-rw-r--r--lib/x1000-installer/test_lib/strlcpy.c50
-rw-r--r--lib/x1000-installer/test_lib/strlcpy.h4
-rw-r--r--lib/x1000-installer/test_lib/system.h10
-rw-r--r--lib/x1000-installer/x1000-installer.make21
35 files changed, 0 insertions, 3381 deletions
diff --git a/lib/x1000-installer/.gitignore b/lib/x1000-installer/.gitignore
deleted file mode 100644
index e7ad25b29f..0000000000
--- a/lib/x1000-installer/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
1xf_test
2fakeNAND.bin
3fakeNAND_meta.bin
4*.profraw
5*.profdata
diff --git a/lib/x1000-installer/Makefile b/lib/x1000-installer/Makefile
deleted file mode 100644
index 54c590dce4..0000000000
--- a/lib/x1000-installer/Makefile
+++ /dev/null
@@ -1,82 +0,0 @@
1OBJ = src/xf_error.o \
2 src/xf_flashmap.o \
3 src/xf_nandio.o \
4 src/xf_package.o \
5 src/xf_stream.o \
6 src/xf_update.o
7LIB = libx1000-installer.a
8
9TOBJ = test_lib/core_alloc.o \
10 test_lib/fakenand.o \
11 test_lib/file.o \
12 test_lib/pathfuncs.o \
13 test_lib/md5.o \
14 test_lib/strlcpy.o \
15 test/main.o \
16 test/test_flashmap.o \
17 test/test_stream.o
18TBIN = xf_test
19
20# dependency needs to be built manually
21MTARINC = -I../microtar/src
22MTARLIB = ../microtar/libmicrotar.a
23
24CPPFLAGS = -Iinclude -Itest_lib $(MTARINC) -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=200809L
25CFLAGS = -std=c99 -Wall -Wextra
26LDFLAGS =
27
28PROFRAW_FILE=$(TBIN).profraw
29PROFDATA_FILE=$(TBIN).profdata
30
31export LLVM_PROFILE_FILE=$(PROFRAW_FILE)
32
33ifeq ($(COVERAGE),1)
34 CC = clang
35 CFLAGS += -g -Og -fprofile-instr-generate -fcoverage-mapping
36 LDFLAGS += -fprofile-instr-generate -fcoverage-mapping
37else
38 CFLAGS += -O2
39endif
40
41ifeq ($(SANITIZE),1)
42 CFLAGS += -fsanitize=address -fsanitize=undefined
43 LDFLAGS += -fsanitize=address -fsanitize=undefined
44endif
45
46.PHONY: all
47all: $(LIB) $(TBIN)
48
49.PHONY: test
50test: $(TBIN)
51 @./$(TBIN)
52
53.PHONY: cov
54cov: $(PROFDATA_FILE)
55 @llvm-cov report $(TBIN) -instr-profile=$(PROFDATA_FILE)
56
57.PHONY: cov-show
58cov-show: $(PROFDATA_FILE)
59 @llvm-cov show $(TBIN) --use-color -instr-profile=$(PROFDATA_FILE) $(f) | less -R
60
61.PHONY: clean
62clean:
63 rm -f $(LIB) $(OBJ)
64 rm -f $(TBIN) $(TOBJ)
65 rm -f $(PROFRAW_FILE) $(PROFDATA_FILE)
66 rm -f fakeNAND.bin fakeNAND_meta.bin
67
68$(LIB): $(OBJ)
69 $(AR) rcs $@ $^ >/dev/null
70
71$(TBIN): $(TOBJ) $(LIB) $(MTARLIB)
72 $(CC) -o $@ $^ $(LDFLAGS)
73
74%.o: %.c
75 $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
76
77# use separate rule instead of depending on 'test' to avoid re-running
78$(PROFRAW_FILE): $(TBIN)
79 @./$(TBIN)
80
81$(PROFDATA_FILE): $(PROFRAW_FILE)
82 @llvm-profdata merge -sparse $(PROFRAW_FILE) -o $(PROFDATA_FILE)
diff --git a/lib/x1000-installer/SOURCES b/lib/x1000-installer/SOURCES
deleted file mode 100644
index cdbd9148d8..0000000000
--- a/lib/x1000-installer/SOURCES
+++ /dev/null
@@ -1,6 +0,0 @@
1src/xf_error.c
2src/xf_flashmap.c
3src/xf_nandio.c
4src/xf_package.c
5src/xf_stream.c
6src/xf_update.c
diff --git a/lib/x1000-installer/include/xf_error.h b/lib/x1000-installer/include/xf_error.h
deleted file mode 100644
index 2f3f6a1a4f..0000000000
--- a/lib/x1000-installer/include/xf_error.h
+++ /dev/null
@@ -1,43 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _XF_ERROR_H_
23#define _XF_ERROR_H_
24
25enum {
26 XF_E_SUCCESS = 0,
27 XF_E_IO = -1,
28 XF_E_LINE_TOO_LONG = -2,
29 XF_E_FILENAME_TOO_LONG = -3,
30 XF_E_INT_OVERFLOW = -4,
31 XF_E_BUF_OVERFLOW = -5,
32 XF_E_SYNTAX_ERROR = -6,
33 XF_E_INVALID_PARAMETER = -7,
34 XF_E_NAND = -8,
35 XF_E_OUT_OF_MEMORY = -9,
36 XF_E_OUT_OF_RANGE = -10,
37 XF_E_VERIFY_FAILED = -11,
38 XF_E_CANNOT_OPEN_FILE = -12,
39};
40
41const char* xf_strerror(int err);
42
43#endif /* _XF_ERROR_H_ */
diff --git a/lib/x1000-installer/include/xf_flashmap.h b/lib/x1000-installer/include/xf_flashmap.h
deleted file mode 100644
index b0470e58e0..0000000000
--- a/lib/x1000-installer/include/xf_flashmap.h
+++ /dev/null
@@ -1,91 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _XF_FLASHMAP_H_
23#define _XF_FLASHMAP_H_
24
25#include "xf_stream.h"
26#include <stdint.h>
27
28#define XF_MAP_NAMELEN 63
29
30enum {
31 XF_MAP_HAS_MD5 = 0x01, /* 'md5' field is valid */
32 XF_MAP_HAS_FILE_LENGTH = 0x02, /* 'file_length' field is valid */
33};
34
35struct xf_map {
36 char name[XF_MAP_NAMELEN+1]; /* file name */
37 uint8_t md5[16]; /* MD5 sum of file */
38 uint32_t file_length; /* length of file in bytes */
39 uint32_t offset; /* offset in flash */
40 uint32_t length; /* region length in flash, in bytes */
41 int flags;
42};
43
44/* Parse a line with space- or tab-delimited fields of the form
45 * <name> <md5> <file_length> <offset> <length>
46 * <name> '-' <offset> <length>
47 *
48 * - name can be up to XF_FMAP_NAMELEN characters long
49 * - md5 is 32 hexadecimal characters (case insensitive)
50 * - file_length, offset, and length are 32-bit unsigned integers
51 * and can be given in decimal or (with '0x' prefix) hexadecimal
52 *
53 * Parsed data is written to *map. Returns zero on success and
54 * nonzero on error.
55 */
56int xf_map_parseline(const char* line, struct xf_map* map);
57
58/* Parse a file calling xf_map_parseline() on each line to populate
59 * a map of up to 'maxnum' regions. Blank and comment lines are
60 * ignored (comments start with '#').
61 *
62 * Returns the number of regions in the resulting map if the file was
63 * parsed successfully, or a negative value on error.
64 */
65int xf_map_parse(struct xf_stream* s, struct xf_map* map, int maxnum);
66
67/* Sort the map so its members are in ascending order with the lowest
68 * flash offset region first. After sorting, xf_map_validate() is used
69 * to check for overlapping regions.
70 *
71 * The return value is that of xf_map_validate().
72 */
73int xf_map_sort(struct xf_map* map, int num);
74
75/* Check if the input map is sorted and contains no overlap.
76 *
77 * Returns 0 if the map is sorted and contains no overlapping regions,
78 * -1 if the map isn't sorted, or if an overlapping region is detected,
79 * the index of the first overlapping region. (A returned index i is
80 * always positive: the two overlapped entries are map[i] and map[i-1].)
81 */
82int xf_map_validate(const struct xf_map* map, int num);
83
84/* Write the map to a stream. This does not check that the map is valid.
85 * Returns the number of bytes written to the stream or a negative value
86 * on error. The stream may be NULL, in which case the number of bytes
87 * that would be written are returned (similar to snprintf).
88 */
89int xf_map_write(struct xf_map* map, int num, struct xf_stream* s);
90
91#endif /* _XF_FLASHMAP_H_ */
diff --git a/lib/x1000-installer/include/xf_nandio.h b/lib/x1000-installer/include/xf_nandio.h
deleted file mode 100644
index a10b71992c..0000000000
--- a/lib/x1000-installer/include/xf_nandio.h
+++ /dev/null
@@ -1,130 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _XF_NANDIO_H_
23#define _XF_NANDIO_H_
24
25#include "nand-x1000.h"
26#include <stdint.h>
27#include <stddef.h>
28
29enum xf_nandio_mode {
30 XF_NANDIO_READ = 0,
31 XF_NANDIO_PROGRAM,
32 XF_NANDIO_VERIFY,
33};
34
35struct xf_nandio {
36 nand_drv* ndrv;
37 int nand_err; /* copy of the last NAND error code */
38 int alloc_handle;
39 enum xf_nandio_mode mode;
40
41 size_t block_size; /* size of a block, in bytes */
42 size_t page_size; /* size of a page, in bytes */
43
44 uint8_t* old_buf; /* contains the 'old' block data already on chip */
45 uint8_t* new_buf; /* contains the possibly modified 'new' block data */
46
47 nand_block_t cur_block; /* address of the current block */
48 size_t offset_in_block; /* byte offset in the current block */
49 unsigned block_valid: 1; /* 1 if buffered block data is valid */
50};
51
52int xf_nandio_init(struct xf_nandio* nio);
53void xf_nandio_destroy(struct xf_nandio* nio);
54
55/** Sets the operational mode, which determines read/write/flush semantics.
56 *
57 * - XF_NANDIO_READ: Accesses the chip in read-only mode. Writes are allowed,
58 * but should not be used. (Writes will modify a temporary buffer but this
59 * will not alter the flash contents.)
60 *
61 * - XF_NANDIO_PROGRAM: Writes are allowed to modify the flash contents.
62 * Writes within a block are accumulated in a temporary buffer. When
63 * crossing a block boundary, either by writing past the end the current
64 * block or by seeking to a new one, the data written to the temporary
65 * buffer is compared against the current flash contents. If the block
66 * has been modified, it is erased and any non-blank pages are programmed
67 * with the new data.
68 *
69 * - XF_NANDIO_VERIFY: This mode allows callers to easily check whether the
70 * flash contents match some expected contents. Callers "write" the expected
71 * contents as if programming it with XF_NANDIO_PROGRAM. When a block is
72 * flushed, if the written data doesn't match the block contents, an
73 * XF_E_VERIFY_FAILED error is returned. The flash contents will not be
74 * altered in this mode.
75 *
76 * \returns XF_E_SUCCESS or a negative error code on failure.
77 */
78int xf_nandio_set_mode(struct xf_nandio* nio, enum xf_nandio_mode mode);
79
80/** Seek to a given byte offset in the NAND flash.
81 *
82 * If the new offset is outside the current block, the current block will
83 * be automatically flushed. Note this can result in verification or program
84 * failures as with any other flush.
85 *
86 * \returns XF_E_SUCCESS or a negative error code on failure.
87 */
88int xf_nandio_seek(struct xf_nandio* nio, size_t offset);
89
90/** Read or write a contiguous sequence of bytes from flash.
91 *
92 * The read or write starts at the current position and continues for `count`
93 * bytes. Both reads and writes may cross block boundaries. Modified blocks
94 * will be flushed automatically if the operation crosses a block boundary.
95 *
96 * After a successful read or write, the current position is advanced by
97 * exactly `count` bytes. After a failure, the position is indeterminate.
98 *
99 * \returns XF_E_SUCCESS or a negative error code on failure.
100 */
101int xf_nandio_read(struct xf_nandio* nio, void* buf, size_t count);
102int xf_nandio_write(struct xf_nandio* nio, const void* buf, size_t count);
103
104/** Get a pointer to the block buffer for direct read/write access.
105 *
106 * These functions can be used to read or write data without intermediate
107 * buffers. The caller passes in the amount of data to be transferred in
108 * `*count`. A pointer to part of the block buffer is returned in `*buf`
109 * and the number of bytes available in `*buf` is returned in `*count`.
110 *
111 * Data at the current position can be read from the returned buffer and
112 * it may be modified by writing to the buffer. The buffer is only valid
113 * until the next call to an `xf_nandio` function.
114 *
115 * The read/write position is advanced by the returned `*count` on success,
116 * and is unchanged on failure.
117 *
118 * \returns XF_E_SUCCESS or a negative error code on failure.
119 */
120int xf_nandio_get_buffer(struct xf_nandio* nio, void** buf, size_t* count);
121
122/** Flush the buffered block to ensure all outstanding program or verification
123 * operations have been performed. This should only be called to ensure the
124 * final modified block is flushed after you have finished writing all data.
125 *
126 * \returns XF_E_SUCCESS or a negative error code on failure.
127 */
128int xf_nandio_flush(struct xf_nandio* nio);
129
130#endif /* _XF_NANDIO_H_ */
diff --git a/lib/x1000-installer/include/xf_package.h b/lib/x1000-installer/include/xf_package.h
deleted file mode 100644
index 6633766bd7..0000000000
--- a/lib/x1000-installer/include/xf_package.h
+++ /dev/null
@@ -1,65 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _XF_PACKAGE_H_
23#define _XF_PACKAGE_H_
24
25/* package format
26 *
27 * - bootloader-info.txt (contains a version label and optional metadata)
28 * - flashmap.txt (describes the flash update map)
29 * - [package must contain any other files referenced by the flash map]
30 * - [other files may be present, but are ignored]
31 */
32
33#include "xf_flashmap.h"
34#include "xf_stream.h"
35#include "microtar.h"
36
37struct xf_package {
38 int alloc_handle;
39 mtar_t* tar;
40 struct xf_map* map;
41 int map_size;
42 char* metadata;
43 size_t metadata_len;
44};
45
46/** Open an update package
47 *
48 * \param pkg Uninitialized package structure
49 * \param file Name of the package file
50 * \param dflt_map Default flash map for loading old format packages
51 * \param dflt_map_size Size of the default flash map
52 * \returns XF_E_SUCCESS or a negative error code
53 */
54int xf_package_open_ex(struct xf_package* pkg, const char* file,
55 const struct xf_map* dflt_map, int dflt_map_size);
56
57/** Close a package which was previously opened successfully */
58void xf_package_close(struct xf_package* pkg);
59
60static inline int xf_package_open(struct xf_package* pkg, const char* file)
61{
62 return xf_package_open_ex(pkg, file, NULL, 0);
63}
64
65#endif /* _XF_PACKAGE_H_ */
diff --git a/lib/x1000-installer/include/xf_stream.h b/lib/x1000-installer/include/xf_stream.h
deleted file mode 100644
index adbde1c6db..0000000000
--- a/lib/x1000-installer/include/xf_stream.h
+++ /dev/null
@@ -1,64 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _XF_STREAM_H_
23#define _XF_STREAM_H_
24
25#include <stddef.h>
26#include <stdint.h>
27#include <sys/types.h> /* ssize_t */
28#include "microtar.h"
29
30struct xf_stream;
31
32struct xf_stream_ops {
33 off_t(*xget_size)(struct xf_stream* s);
34 ssize_t(*xread)(struct xf_stream* s, void* buf, size_t len);
35 ssize_t(*xwrite)(struct xf_stream* s, const void* buf, size_t len);
36 int(*xclose)(struct xf_stream* s);
37};
38
39struct xf_stream {
40 intptr_t data;
41 const struct xf_stream_ops* ops;
42};
43
44inline size_t xf_stream_get_size(struct xf_stream* s)
45{ return s->ops->xget_size(s); }
46
47inline ssize_t xf_stream_read(struct xf_stream* s, void* buf, size_t len)
48{ return s->ops->xread(s, buf, len); }
49
50inline ssize_t xf_stream_write(struct xf_stream* s, const void* buf, size_t len)
51{ return s->ops->xwrite(s, buf, len); }
52
53inline int xf_stream_close(struct xf_stream* s)
54{ return s->ops->xclose(s); }
55
56int xf_open_file(const char* file, int flags, struct xf_stream* s);
57int xf_open_tar(mtar_t* mtar, const char* file, struct xf_stream* s);
58int xf_create_tar(mtar_t* mtar, const char* file, size_t size, struct xf_stream* s);
59
60/* Utility function needed for a few things */
61int xf_stream_read_lines(struct xf_stream* s, char* buf, size_t bufsz,
62 int(*callback)(int n, char* buf, void* arg), void* arg);
63
64#endif /* _XF_STREAM_H_ */
diff --git a/lib/x1000-installer/include/xf_update.h b/lib/x1000-installer/include/xf_update.h
deleted file mode 100644
index e421a21793..0000000000
--- a/lib/x1000-installer/include/xf_update.h
+++ /dev/null
@@ -1,53 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _XF_UPDATE_H_
23#define _XF_UPDATE_H_
24
25#include "xf_package.h"
26#include "xf_nandio.h"
27#include "xf_flashmap.h"
28
29typedef int(*xf_update_open_stream_cb)(void* arg, const char* file,
30 struct xf_stream* stream);
31
32enum xf_update_mode {
33 XF_UPDATE,
34 XF_BACKUP,
35 XF_VERIFY,
36};
37
38/** The main updater entry point
39 *
40 * \param mode Operational mode
41 * \param nio Initialized NAND I/O object.
42 * \param map Flash map describing what regions to update.
43 * \param map_size Number of entries in the map.
44 * \param open_stream Callback used to open a stream for each map entry.
45 * \param arg Argument passed to the `open_stream` callback.
46 *
47 * \returns XF_E_SUCCESS on success or a negative error code on failure.
48 */
49int xf_updater_run(enum xf_update_mode mode, struct xf_nandio* nio,
50 struct xf_map* map, int map_size,
51 xf_update_open_stream_cb open_stream, void* arg);
52
53#endif /* _XF_UPDATE_H_ */
diff --git a/lib/x1000-installer/src/xf_error.c b/lib/x1000-installer/src/xf_error.c
deleted file mode 100644
index 3d4b342a92..0000000000
--- a/lib/x1000-installer/src/xf_error.c
+++ /dev/null
@@ -1,42 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "xf_error.h"
23
24const char* xf_strerror(int err)
25{
26 switch(err) {
27 case XF_E_SUCCESS: return "Success";
28 case XF_E_IO: return "I/O error";
29 case XF_E_LINE_TOO_LONG: return "Line too long";
30 case XF_E_FILENAME_TOO_LONG: return "Filename too long";
31 case XF_E_INT_OVERFLOW: return "Numeric overflow";
32 case XF_E_BUF_OVERFLOW: return "Buffer overflowed";
33 case XF_E_SYNTAX_ERROR: return "Syntax error";
34 case XF_E_INVALID_PARAMETER: return "Invalid parameter";
35 case XF_E_NAND: return "NAND flash error";
36 case XF_E_OUT_OF_MEMORY: return "Out of memory";
37 case XF_E_OUT_OF_RANGE: return "Out of range";
38 case XF_E_VERIFY_FAILED: return "Verification failed";
39 case XF_E_CANNOT_OPEN_FILE: return "Cannot open file";
40 default: return "Unknown error";
41 }
42}
diff --git a/lib/x1000-installer/src/xf_flashmap.c b/lib/x1000-installer/src/xf_flashmap.c
deleted file mode 100644
index 972bf320ad..0000000000
--- a/lib/x1000-installer/src/xf_flashmap.c
+++ /dev/null
@@ -1,327 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "xf_flashmap.h"
23#include "xf_error.h"
24#include <stdbool.h>
25#include <stdlib.h>
26#include <ctype.h>
27#include <string.h>
28
29static int xdigit_to_int(char c)
30{
31 if(c >= 'a' && c <= 'f')
32 return 10 + (c - 'a');
33 if(c >= 'A' && c <= 'F')
34 return 10 + (c - 'A');
35 if(c >= '0' && c <= '9')
36 return c - '0';
37 return -1;
38}
39
40static int isfilenamechar(char c)
41{
42 return (c >= 'a' && c <= 'z') ||
43 (c >= 'A' && c <= 'Z') ||
44 (c >= '0' && c <= '9') ||
45 c == '$' || c == '%' || c == '\'' || c == '-' || c == '_' ||
46 c == '@' || c == '~' || c == '`' || c == '!' || c == '(' ||
47 c == ')' || c == '{' || c == '}' || c == '^' || c == '#' ||
48 c == '&' || c == '+' || c == ',' || c == ';' || c == '=' ||
49 c == '[' || c == ']' || c == '.';
50}
51
52int xf_map_parseline(const char* line, struct xf_map* map)
53{
54 enum {
55 s_name,
56 s_md5,
57 s_first_num,
58 s_file_len = s_first_num,
59 s_offset,
60 s_length,
61 s_done,
62 };
63
64#define skipws() do { while(*line == ' ' || *line == '\t') ++line; } while(0)
65#define nextstate() do { ++state; length = 0; ++line; skipws(); } while(0)
66
67 int state = s_name;
68 int length = 0;
69 int digit_val;
70 uint32_t int_val;
71 uint32_t* num_ptr[3] = {&map->file_length, &map->offset, &map->length};
72 bool has_md5 = true;
73
74 skipws();
75 while(*line && *line != '\n') {
76 switch(state) {
77 case s_name:
78 if(*line == ' ' || *line == '\t') {
79 nextstate();
80 continue;
81 } else if(isfilenamechar(*line)) {
82 if(length == XF_MAP_NAMELEN)
83 return XF_E_FILENAME_TOO_LONG;
84
85 map->name[length++] = *line++;
86 map->name[length] = '\0';
87 continue;
88 } else {
89 return XF_E_SYNTAX_ERROR;
90 }
91
92 case s_md5:
93 if(*line == '-') {
94 memset(map->md5, 0, 16);
95 map->file_length = 0;
96 has_md5 = false;
97 ++line;
98 } else {
99 for(int i = 0; i < 16; ++i) {
100 int_val = 0;
101 for(int j = 0; j < 2; ++j) {
102 digit_val = xdigit_to_int(*line++);
103 if(digit_val < 0)
104 return XF_E_SYNTAX_ERROR;
105
106 int_val <<= 4;
107 int_val |= digit_val;
108 }
109
110 map->md5[i] = int_val;
111 }
112 }
113
114 if(*line == ' ' || *line == '\t') {
115 /* skip file length if md5 is not present */
116 if(!has_md5)
117 ++state;
118
119 nextstate();
120 continue;
121 } else {
122 return XF_E_SYNTAX_ERROR;
123 }
124
125 case s_file_len:
126 case s_offset:
127 case s_length:
128 int_val = 0;
129
130 if(*line == '0') {
131 ++line;
132 if(*line == 'x' || *line == 'X') {
133 ++line;
134 while((digit_val = xdigit_to_int(*line)) >= 0) {
135 ++line;
136
137 if(int_val > UINT32_MAX/16)
138 return XF_E_INT_OVERFLOW;
139
140 int_val *= 16;
141 int_val |= digit_val;
142 }
143 }
144 } else if(*line >= '1' && *line <= '9') {
145 do {
146 if(int_val > UINT32_MAX/10)
147 return XF_E_INT_OVERFLOW;
148 int_val *= 10;
149
150 digit_val = *line++ - '0';
151 if(int_val > UINT32_MAX - digit_val)
152 return XF_E_INT_OVERFLOW;
153
154 int_val += digit_val;
155 } while(*line >= '0' && *line <= '9');
156 }
157
158 *num_ptr[state - s_first_num] = int_val;
159
160 if(*line == ' ' || *line == '\t') {
161 nextstate();
162 continue;
163 } else if(state+1 == s_done && *line == '\0') {
164 /* end of input */
165 continue;
166 } else {
167 return XF_E_SYNTAX_ERROR;
168 }
169
170 case s_done:
171 if(isspace(*line)) {
172 line++;
173 continue; /* swallow trailing spaces, carriage return, etc */
174 } else
175 return XF_E_SYNTAX_ERROR;
176 }
177 }
178
179#undef skipws
180#undef nextstate
181
182 /* one last overflow check - ensure mapped range is addressable */
183 if(map->offset > UINT32_MAX - map->length)
184 return XF_E_INT_OVERFLOW;
185
186 if(has_md5)
187 map->flags = XF_MAP_HAS_MD5 | XF_MAP_HAS_FILE_LENGTH;
188 else
189 map->flags = 0;
190
191 return XF_E_SUCCESS;
192}
193
194struct map_parse_args {
195 struct xf_map* map;
196 int num;
197 int maxnum;
198};
199
200int map_parse_line_cb(int n, char* buf, void* arg)
201{
202 (void)n;
203
204 struct map_parse_args* args = arg;
205
206 /* skip whitespace */
207 while(*buf && isspace(*buf))
208 ++buf;
209
210 /* ignore comments and blank lines */
211 if(*buf == '#' || *buf == '\0')
212 return 0;
213
214 struct xf_map dummy_map;
215 struct xf_map* dst_map;
216 if(args->num < args->maxnum)
217 dst_map = &args->map[args->num];
218 else
219 dst_map = &dummy_map;
220
221 int rc = xf_map_parseline(buf, dst_map);
222 if(rc)
223 return rc;
224
225 args->num++;
226 return 0;
227}
228
229int xf_map_parse(struct xf_stream* s, struct xf_map* map, int maxnum)
230{
231 char buf[200];
232 struct map_parse_args args;
233 args.map = map;
234 args.num = 0;
235 args.maxnum = maxnum;
236
237 int rc = xf_stream_read_lines(s, buf, sizeof(buf),
238 map_parse_line_cb, &args);
239 if(rc < 0)
240 return rc;
241
242 return args.num;
243}
244
245static int xf_map_compare(const void* a, const void* b)
246{
247 const struct xf_map* mapA = a;
248 const struct xf_map* mapB = b;
249
250 if(mapA->offset < mapB->offset)
251 return -1;
252 else if(mapA->offset == mapB->offset)
253 return 0;
254 else
255 return 1;
256}
257
258int xf_map_sort(struct xf_map* map, int num)
259{
260 qsort(map, num, sizeof(struct xf_map), xf_map_compare);
261 return xf_map_validate(map, num);
262}
263
264int xf_map_validate(const struct xf_map* map, int num)
265{
266 for(int i = 1; i < num; ++i)
267 if(map[i].offset <= map[i-1].offset)
268 return -1;
269
270 for(int i = 1; i < num; ++i)
271 if(map[i-1].offset + map[i-1].length > map[i].offset)
272 return i;
273
274 return 0;
275}
276
277int xf_map_write(struct xf_map* map, int num, struct xf_stream* s)
278{
279 static const char hex[] = "0123456789abcdef";
280 char buf[200];
281 char md5str[33];
282 int total_len = 0;
283
284 md5str[32] = '\0';
285
286 for(int i = 0; i < num; ++i) {
287 bool has_md5 = false;
288 if(map->flags & XF_MAP_HAS_MD5) {
289 if(!(map->flags & XF_MAP_HAS_FILE_LENGTH))
290 return XF_E_INVALID_PARAMETER;
291
292 has_md5 = true;
293 for(int j = 0; j < 16; ++j) {
294 uint8_t byte = map[i].md5[j];
295 md5str[2*j] = hex[(byte >> 4) & 0xf];
296 md5str[2*j+1] = hex[byte & 0xf];
297 }
298 }
299
300 int len;
301 if(!has_md5) {
302 len = snprintf(buf, sizeof(buf), "%s - %lx %lu\n",
303 map[i].name,
304 (unsigned long)map[i].offset,
305 (unsigned long)map[i].length);
306 } else {
307 len = snprintf(buf, sizeof(buf), "%s %s %lu 0x%lx %lu\n",
308 map[i].name, md5str,
309 (unsigned long)map[i].file_length,
310 (unsigned long)map[i].offset,
311 (unsigned long)map[i].length);
312 }
313
314 if(len < 0 || (size_t)len >= sizeof(buf))
315 return XF_E_LINE_TOO_LONG;
316
317 if(s) {
318 int rc = xf_stream_write(s, buf, len);
319 if(rc != len)
320 return XF_E_IO;
321 }
322
323 total_len += len;
324 }
325
326 return total_len;
327}
diff --git a/lib/x1000-installer/src/xf_nandio.c b/lib/x1000-installer/src/xf_nandio.c
deleted file mode 100644
index 6dc87bc420..0000000000
--- a/lib/x1000-installer/src/xf_nandio.c
+++ /dev/null
@@ -1,292 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "xf_nandio.h"
23#include "xf_error.h"
24#include "core_alloc.h"
25#include "system.h"
26#include <string.h>
27#include <stdbool.h>
28
29int xf_nandio_init(struct xf_nandio* nio)
30{
31 int rc;
32
33 memset(nio, 0, sizeof(*nio));
34
35 /* open NAND */
36 nio->ndrv = nand_init();
37 nand_lock(nio->ndrv);
38 rc = nand_open(nio->ndrv);
39 if(rc != NAND_SUCCESS) {
40 nio->nand_err = rc;
41 rc = XF_E_NAND;
42 goto out;
43 }
44
45 /* read chip parameters */
46 nio->page_size = nio->ndrv->chip->page_size;
47 nio->block_size = nio->page_size << nio->ndrv->chip->log2_ppb;
48
49 /* allocate memory */
50 size_t alloc_size = 0;
51 alloc_size += CACHEALIGN_SIZE - 1;
52 alloc_size += nio->block_size * 2;
53
54 nio->alloc_handle = core_alloc_ex("xf_nandio", alloc_size, &buflib_ops_locked);
55 if(nio->alloc_handle < 0) {
56 rc = XF_E_OUT_OF_MEMORY;
57 goto out_nclose;
58 }
59
60 uint8_t* buffer = core_get_data(nio->alloc_handle);
61 CACHEALIGN_BUFFER(buffer, alloc_size);
62
63 nio->old_buf = buffer;
64 nio->new_buf = &buffer[nio->block_size];
65
66 rc = XF_E_SUCCESS;
67 goto out;
68
69 out_nclose:
70 nand_close(nio->ndrv);
71 out:
72 nand_unlock(nio->ndrv);
73 return rc;
74}
75
76void xf_nandio_destroy(struct xf_nandio* nio)
77{
78 nio->alloc_handle = core_free(nio->alloc_handle);
79
80 if(nio->ndrv) {
81 nand_lock(nio->ndrv);
82 nand_close(nio->ndrv);
83 nand_unlock(nio->ndrv);
84 nio->ndrv = NULL;
85 }
86}
87
88static bool is_page_blank(const uint8_t* buf, uint32_t length)
89{
90 for(uint32_t i = 0; i < length; ++i)
91 if(buf[i] != 0xff)
92 return false;
93
94 return true;
95}
96
97static int flush_block(struct xf_nandio* nio, bool invalidate)
98{
99 /* no block, or only reading - flush is a no-op */
100 if(!nio->block_valid || nio->mode == XF_NANDIO_READ)
101 return XF_E_SUCCESS;
102
103 /* nothing to do if new data is same as old data */
104 if(!memcmp(nio->old_buf, nio->new_buf, nio->block_size))
105 return XF_E_SUCCESS;
106
107 /* data mismatch during verification - report the error */
108 if(nio->mode == XF_NANDIO_VERIFY)
109 return XF_E_VERIFY_FAILED;
110
111 /* erase the block */
112 int rc = nand_block_erase(nio->ndrv, nio->cur_block);
113 if(rc != NAND_SUCCESS) {
114 nio->block_valid = false;
115 nio->nand_err = rc;
116 return XF_E_NAND;
117 }
118
119 size_t oob_size = nio->ndrv->chip->oob_size;
120
121 unsigned page = 0;
122 nand_page_t page_addr = nio->cur_block;
123 for(; page < nio->ndrv->ppb; ++page, ++page_addr) {
124 /* skip programming blank pages to go faster & reduce wear */
125 uint8_t* page_data = &nio->new_buf[page * nio->page_size];
126 if(is_page_blank(page_data, nio->page_size))
127 continue;
128
129 /* copy page and write blank OOB data */
130 memcpy(nio->ndrv->page_buf, page_data, nio->page_size);
131 memset(&nio->ndrv->page_buf[nio->page_size], 0xff, oob_size);
132
133 /* program the page */
134 rc = nand_page_program(nio->ndrv, page_addr, nio->ndrv->page_buf);
135 if(rc != NAND_SUCCESS) {
136 nio->block_valid = false;
137 nio->nand_err = rc;
138 return XF_E_NAND;
139 }
140 }
141
142 if(invalidate)
143 nio->block_valid = false;
144 else {
145 /* update our 'old' buffer so a subsequent flush
146 * will not reprogram the same block */
147 memcpy(nio->old_buf, nio->new_buf, nio->block_size);
148 }
149
150 return XF_E_SUCCESS;
151}
152
153static int seek_to_block(struct xf_nandio* nio, nand_block_t block_addr,
154 size_t offset_in_block)
155{
156 /* already on this block? */
157 if(nio->block_valid && block_addr == nio->cur_block) {
158 nio->offset_in_block = offset_in_block;
159 return XF_E_SUCCESS;
160 }
161
162 /* ensure new block is within range */
163 if(block_addr >= (nio->ndrv->chip->nr_blocks << nio->ndrv->chip->log2_ppb))
164 return XF_E_OUT_OF_RANGE;
165
166 /* flush old block */
167 int rc = flush_block(nio, true);
168 if(rc)
169 return rc;
170
171 nio->block_valid = false;
172
173 /* read the new block */
174 unsigned page = 0;
175 nand_page_t page_addr = block_addr;
176 for(; page < nio->ndrv->ppb; ++page, ++page_addr) {
177 rc = nand_page_read(nio->ndrv, page_addr, nio->ndrv->page_buf);
178 if(rc != NAND_SUCCESS) {
179 nio->nand_err = rc;
180 return XF_E_NAND;
181 }
182
183 memcpy(&nio->old_buf[page * nio->page_size], nio->ndrv->page_buf, nio->page_size);
184 }
185
186 /* copy to 2nd buffer */
187 memcpy(nio->new_buf, nio->old_buf, nio->block_size);
188
189 /* update position */
190 nio->cur_block = block_addr;
191 nio->offset_in_block = offset_in_block;
192 nio->block_valid = true;
193 return XF_E_SUCCESS;
194}
195
196int xf_nandio_set_mode(struct xf_nandio* nio, enum xf_nandio_mode mode)
197{
198 nand_lock(nio->ndrv);
199
200 /* flush the current block before switching to the new mode,
201 * to ensure consistency */
202 int rc = flush_block(nio, false);
203 if(rc)
204 goto err;
205
206 nio->mode = mode;
207 rc = XF_E_SUCCESS;
208
209 err:
210 nand_unlock(nio->ndrv);
211 return rc;
212}
213
214static int nandio_rdwr(struct xf_nandio* nio, void* buf, size_t count, bool write)
215{
216 while(count > 0) {
217 void* ptr;
218 size_t amount = count;
219 int rc = xf_nandio_get_buffer(nio, &ptr, &amount);
220 if(rc)
221 return rc;
222
223 if(write)
224 memcpy(ptr, buf, amount);
225 else
226 memcpy(buf, ptr, amount);
227
228 count -= amount;
229 }
230
231 return XF_E_SUCCESS;
232}
233
234int xf_nandio_seek(struct xf_nandio* nio, size_t offset)
235{
236 uint32_t block_nr = offset / nio->block_size;
237 size_t offset_in_block = offset % nio->block_size;
238 nand_block_t block_addr = block_nr << nio->ndrv->chip->log2_ppb;
239
240 nand_lock(nio->ndrv);
241 int rc = seek_to_block(nio, block_addr, offset_in_block);
242 nand_unlock(nio->ndrv);
243
244 return rc;
245}
246
247int xf_nandio_read(struct xf_nandio* nio, void* buf, size_t count)
248{
249 return nandio_rdwr(nio, buf, count, false);
250}
251
252int xf_nandio_write(struct xf_nandio* nio, const void* buf, size_t count)
253{
254 return nandio_rdwr(nio, (void*)buf, count, true);
255}
256
257int xf_nandio_get_buffer(struct xf_nandio* nio, void** buf, size_t* count)
258{
259 nand_lock(nio->ndrv);
260
261 /* make sure the current block data is read in */
262 int rc = seek_to_block(nio, nio->cur_block, nio->offset_in_block);
263 if(rc)
264 goto err;
265
266 size_t amount_left = nio->block_size - nio->offset_in_block;
267 if(amount_left == 0) {
268 amount_left = nio->block_size;
269 rc = seek_to_block(nio, nio->cur_block + nio->ndrv->ppb, 0);
270 if(rc)
271 goto err;
272 }
273
274 *buf = &nio->new_buf[nio->offset_in_block];
275 *count = MIN(*count, amount_left);
276
277 nio->offset_in_block += *count;
278 rc = XF_E_SUCCESS;
279
280 err:
281 nand_unlock(nio->ndrv);
282 return rc;
283}
284
285int xf_nandio_flush(struct xf_nandio* nio)
286{
287 nand_lock(nio->ndrv);
288 int rc = flush_block(nio, false);
289 nand_unlock(nio->ndrv);
290
291 return rc;
292}
diff --git a/lib/x1000-installer/src/xf_package.c b/lib/x1000-installer/src/xf_package.c
deleted file mode 100644
index fb107aef72..0000000000
--- a/lib/x1000-installer/src/xf_package.c
+++ /dev/null
@@ -1,261 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "xf_package.h"
23#include "xf_error.h"
24#include "pathfuncs.h"
25#include "file.h"
26#include "core_alloc.h"
27#include "md5.h"
28#include "system.h"
29#include <stdbool.h>
30#include <string.h>
31
32#ifdef ROCKBOX
33# include "microtar-rockbox.h"
34#else
35# include "microtar-stdio.h"
36#endif
37
38#define METADATA_SIZE 4096 /* size of the metadata buffer */
39#define MAX_MAP_SIZE 32 /* maximum number of map entries */
40
41static int pkg_alloc(struct xf_package* pkg)
42{
43 memset(pkg, 0, sizeof(*pkg));
44
45 /* calculate allocation size */
46 size_t alloc_size = 0;
47 alloc_size += ALIGN_UP_P2(sizeof(mtar_t), 3);
48 alloc_size += ALIGN_UP_P2(sizeof(struct xf_map) * MAX_MAP_SIZE, 3);
49 alloc_size += ALIGN_UP_P2(METADATA_SIZE, 3);
50 alloc_size += 7; /* for alignment */
51
52 pkg->alloc_handle = core_alloc_ex("xf_package", alloc_size, &buflib_ops_locked);
53 if(pkg->alloc_handle < 0)
54 return XF_E_OUT_OF_MEMORY;
55
56 /* distribute memory */
57 uint8_t* buf = (uint8_t*)core_get_data(pkg->alloc_handle);
58 memset(buf, 0, alloc_size);
59 ALIGN_BUFFER(buf, alloc_size, 8);
60
61 pkg->tar = (mtar_t*)buf;
62 buf += ALIGN_UP_P2(sizeof(mtar_t), 3);
63
64 pkg->map = (struct xf_map*)buf;
65 buf += ALIGN_UP_P2(sizeof(struct xf_map) * MAX_MAP_SIZE, 3);
66
67 pkg->metadata = (char*)buf;
68 buf += ALIGN_UP_P2(METADATA_SIZE, 3);
69
70 return XF_E_SUCCESS;
71}
72
73static int read_meta_line_cb(int n, char* buf, void* arg)
74{
75 struct xf_package* pkg = (struct xf_package*)arg;
76 size_t length = strlen(buf);
77
78 /* skip blank lines and the first line (it's reserved for old format) */
79 if(n == 0 || length == 0)
80 return 0;
81
82 /* metadata lines require an '=' sign to separate key and value */
83 if(!strchr(buf, '='))
84 return XF_E_SYNTAX_ERROR;
85
86 /* we need space to copy the key-value pair plus a null terminator */
87 if(length + 1 >= METADATA_SIZE - pkg->metadata_len)
88 return XF_E_BUF_OVERFLOW;
89
90 memcpy(&pkg->metadata[pkg->metadata_len], buf, length + 1);
91 pkg->metadata_len += length + 1;
92 return 0;
93}
94
95static int pkg_read_meta(struct xf_package* pkg)
96{
97 struct xf_stream stream;
98 int rc = xf_open_tar(pkg->tar, "bootloader-info.txt", &stream);
99 if(rc)
100 return XF_E_CANNOT_OPEN_FILE;
101
102 char buf[200];
103 rc = xf_stream_read_lines(&stream, buf, sizeof(buf), read_meta_line_cb, pkg);
104 xf_stream_close(&stream);
105 return rc;
106}
107
108static int pkg_read_map(struct xf_package* pkg,
109 const struct xf_map* dflt_map, int dflt_map_size)
110{
111 /* Attempt to load and parse the map file */
112 struct xf_stream stream;
113 int rc = xf_open_tar(pkg->tar, "flashmap.txt", &stream);
114
115 /* If the flash map is absent but a default map has been provided,
116 * then the update is in the old fixed format. */
117 if(rc == MTAR_ENOTFOUND && dflt_map) {
118 if(dflt_map_size > MAX_MAP_SIZE)
119 return XF_E_INVALID_PARAMETER;
120
121 for(int i = 0; i < dflt_map_size; ++i) {
122 pkg->map[i] = dflt_map[i];
123 pkg->map[i].flags &= ~(XF_MAP_HAS_MD5 | XF_MAP_HAS_FILE_LENGTH);
124 }
125
126 pkg->map_size = dflt_map_size;
127 return XF_E_SUCCESS;
128 }
129
130 if(rc != MTAR_ESUCCESS)
131 return XF_E_CANNOT_OPEN_FILE;
132
133 rc = xf_map_parse(&stream, pkg->map, MAX_MAP_SIZE);
134 if(rc < 0)
135 goto err;
136
137 /* Sort the map; reject it if there is any overlap. */
138 pkg->map_size = rc;
139 if(xf_map_sort(pkg->map, pkg->map_size)) {
140 rc = XF_E_INVALID_PARAMETER;
141 goto err;
142 }
143
144 /* All packages in the 'new' format are required to have MD5 sums. */
145 for(int i = 0; i < pkg->map_size; ++i) {
146 if(!(pkg->map[i].flags & XF_MAP_HAS_MD5) ||
147 !(pkg->map[i].flags & XF_MAP_HAS_FILE_LENGTH)) {
148 rc = XF_E_VERIFY_FAILED;
149 goto err;
150 }
151 }
152
153 rc = XF_E_SUCCESS;
154
155 err:
156 xf_stream_close(&stream);
157 return rc;
158}
159
160static int pkg_verify(struct xf_package* pkg)
161{
162 struct xf_stream stream;
163 md5_context ctx;
164 uint8_t buffer[128];
165
166 for(int i = 0; i < pkg->map_size; ++i) {
167 /* At a bare minimum, check that the file exists. */
168 int rc = xf_open_tar(pkg->tar, pkg->map[i].name, &stream);
169 if(rc)
170 return XF_E_VERIFY_FAILED;
171
172 /* Also check that it isn't bigger than the update region.
173 * That would normally indicate a problem. */
174 off_t streamsize = xf_stream_get_size(&stream);
175 if(streamsize > (off_t)pkg->map[i].length) {
176 rc = XF_E_VERIFY_FAILED;
177 goto err;
178 }
179
180 /* Check against the listed file length. */
181 if(pkg->map[i].flags & XF_MAP_HAS_FILE_LENGTH) {
182 if(streamsize != (off_t)pkg->map[i].file_length) {
183 rc = XF_E_VERIFY_FAILED;
184 goto err;
185 }
186 }
187
188 /* Check the MD5 sum if we have it. */
189 if(pkg->map[i].flags & XF_MAP_HAS_MD5) {
190 md5_starts(&ctx);
191 while(1) {
192 ssize_t n = xf_stream_read(&stream, buffer, sizeof(buffer));
193 if(n < 0) {
194 rc = XF_E_IO;
195 goto err;
196 }
197
198 md5_update(&ctx, buffer, n);
199 if((size_t)n < sizeof(buffer))
200 break;
201 }
202
203 md5_finish(&ctx, buffer);
204 if(memcpy(buffer, pkg->map[i].md5, 16)) {
205 rc = XF_E_VERIFY_FAILED;
206 goto err;
207 }
208 }
209
210 err:
211 xf_stream_close(&stream);
212 if(rc)
213 return rc;
214 }
215
216 /* All files passed verification */
217 return XF_E_SUCCESS;
218}
219
220int xf_package_open_ex(struct xf_package* pkg, const char* file,
221 const struct xf_map* dflt_map, int dflt_map_size)
222{
223 int rc = pkg_alloc(pkg);
224 if(rc)
225 return rc;
226
227#ifdef ROCKBOX
228 rc = mtar_open(pkg->tar, file, O_RDONLY);
229#else
230 rc = mtar_open(pkg->tar, file, "r");
231#endif
232 if(rc != MTAR_ESUCCESS) {
233 rc = XF_E_CANNOT_OPEN_FILE;
234 goto err;
235 }
236
237 rc = pkg_read_meta(pkg);
238 if(rc)
239 goto err;
240
241 rc = pkg_read_map(pkg, dflt_map, dflt_map_size);
242 if(rc)
243 goto err;
244
245 rc = pkg_verify(pkg);
246 if(rc)
247 goto err;
248
249 err:
250 if(rc)
251 xf_package_close(pkg);
252 return rc;
253}
254
255void xf_package_close(struct xf_package* pkg)
256{
257 if(mtar_is_open(pkg->tar))
258 mtar_close(pkg->tar);
259
260 pkg->alloc_handle = core_free(pkg->alloc_handle);
261}
diff --git a/lib/x1000-installer/src/xf_stream.c b/lib/x1000-installer/src/xf_stream.c
deleted file mode 100644
index b6391b2c8d..0000000000
--- a/lib/x1000-installer/src/xf_stream.c
+++ /dev/null
@@ -1,211 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "xf_stream.h"
23#include "xf_error.h"
24#include "file.h"
25#include <stdbool.h>
26#include <string.h>
27#include <ctype.h>
28
29/*
30 * File streams
31 */
32
33static off_t file_stream_get_size(struct xf_stream* s)
34{
35 return filesize(s->data);
36}
37
38static ssize_t file_stream_read(struct xf_stream* s, void* buf, size_t len)
39{
40 return read(s->data, buf, len);
41}
42
43static ssize_t file_stream_write(struct xf_stream* s, const void* buf, size_t len)
44{
45 return write(s->data, buf, len);
46}
47
48static int file_stream_close(struct xf_stream* s)
49{
50 return close(s->data);
51}
52
53static const struct xf_stream_ops file_stream_ops = {
54 .xget_size = file_stream_get_size,
55 .xread = file_stream_read,
56 .xwrite = file_stream_write,
57 .xclose = file_stream_close,
58};
59
60int xf_open_file(const char* file, int flags, struct xf_stream* s)
61{
62 s->data = open(file, flags, 0666);
63 s->ops = &file_stream_ops;
64 return (s->data >= 0) ? 0 : -1;
65}
66
67/*
68 * Tar streams
69 */
70
71static off_t tar_stream_get_size(struct xf_stream* s)
72{
73 mtar_t* mtar = (mtar_t*)s->data;
74 return mtar_get_header(mtar)->size;
75}
76
77static ssize_t tar_stream_read(struct xf_stream* s, void* buffer, size_t count)
78{
79 mtar_t* mtar = (mtar_t*)s->data;
80
81 int ret = mtar_read_data(mtar, buffer, count);
82 if(ret < 0)
83 return -1;
84
85 return ret;
86}
87
88static ssize_t tar_stream_write(struct xf_stream* s, const void* buffer, size_t count)
89{
90 mtar_t* mtar = (mtar_t*)s->data;
91
92 int ret = mtar_write_data(mtar, buffer, count);
93 if(ret < 0)
94 return -1;
95
96 return ret;
97}
98
99static int tar_stream_close(struct xf_stream* s)
100{
101 mtar_t* mtar = (mtar_t*)s->data;
102
103 if(mtar_access_mode(mtar) == MTAR_WRITE) {
104 if(mtar_update_file_size(mtar) != MTAR_ESUCCESS)
105 return -1;
106 if(mtar_end_data(mtar) != MTAR_ESUCCESS)
107 return -1;
108 }
109
110 return 0;
111}
112
113static const struct xf_stream_ops tar_stream_ops = {
114 .xget_size = tar_stream_get_size,
115 .xread = tar_stream_read,
116 .xwrite = tar_stream_write,
117 .xclose = tar_stream_close,
118};
119
120int xf_open_tar(mtar_t* mtar, const char* file, struct xf_stream* s)
121{
122 int err = mtar_find(mtar, file);
123 if(err != MTAR_ESUCCESS)
124 return err;
125
126 /* must only read normal files */
127 const mtar_header_t* h = mtar_get_header(mtar);
128 if(h->type != 0 && h->type != MTAR_TREG)
129 return MTAR_EFAILURE;
130
131 s->data = (intptr_t)mtar;
132 s->ops = &tar_stream_ops;
133 return MTAR_ESUCCESS;
134}
135
136int xf_create_tar(mtar_t* mtar, const char* file, size_t size, struct xf_stream* s)
137{
138 int err = mtar_write_file_header(mtar, file, size);
139 if(err)
140 return err;
141
142 s->data = (intptr_t)mtar;
143 s->ops = &tar_stream_ops;
144 return MTAR_ESUCCESS;
145}
146
147/*
148 * Utility functions
149 */
150
151int xf_stream_read_lines(struct xf_stream* s, char* buf, size_t bufsz,
152 int(*callback)(int n, char* buf, void* arg), void* arg)
153{
154 char* startp, *endp;
155 ssize_t bytes_read;
156 int rc;
157
158 int n = 0;
159 size_t pos = 0;
160 bool at_eof = false;
161
162 if(bufsz <= 1)
163 return XF_E_LINE_TOO_LONG;
164
165 while(!at_eof) {
166 bytes_read = xf_stream_read(s, &buf[pos], bufsz - pos - 1);
167 if(bytes_read < 0)
168 return XF_E_IO;
169
170 /* short read is end of file */
171 if((size_t)bytes_read < bufsz - pos - 1)
172 at_eof = true;
173
174 pos += bytes_read;
175 buf[pos] = '\0';
176
177 startp = endp = buf;
178 while(endp != &buf[pos]) {
179 endp = strchr(startp, '\n');
180 if(endp) {
181 *endp = '\0';
182 } else {
183 if(!at_eof) {
184 if(startp == buf)
185 return XF_E_LINE_TOO_LONG;
186 else
187 break; /* read ahead to look for newline */
188 } else {
189 if(startp == &buf[pos])
190 break; /* nothing left to do */
191 else
192 endp = &buf[pos]; /* last line missing a newline -
193 * treat EOF as newline */
194 }
195 }
196
197 rc = callback(n++, startp, arg);
198 if(rc != 0)
199 return rc;
200
201 startp = endp + 1;
202 }
203
204 if(startp <= &buf[pos]) {
205 memmove(buf, startp, &buf[pos] - startp);
206 pos = &buf[pos] - startp;
207 }
208 }
209
210 return 0;
211}
diff --git a/lib/x1000-installer/src/xf_update.c b/lib/x1000-installer/src/xf_update.c
deleted file mode 100644
index 5a7c3b0430..0000000000
--- a/lib/x1000-installer/src/xf_update.c
+++ /dev/null
@@ -1,149 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "xf_update.h"
23#include "xf_error.h"
24#include "file.h"
25#include "md5.h"
26#include <string.h>
27
28static int process_stream(struct xf_nandio* nio,
29 struct xf_map* map,
30 struct xf_stream* stream)
31{
32 void* buffer;
33 size_t count;
34 int rc;
35
36 /* calculate MD5 on the fly if taking a backup */
37 md5_context md5_ctx;
38 if(nio->mode == XF_NANDIO_READ)
39 md5_starts(&md5_ctx);
40
41 /* first deal with the file data */
42 size_t bytes_left = map->length;
43 while(bytes_left > 0) {
44 count = bytes_left;
45 rc = xf_nandio_get_buffer(nio, &buffer, &count);
46 if(rc)
47 return rc;
48
49 if(nio->mode == XF_NANDIO_READ) {
50 md5_update(&md5_ctx, buffer, count);
51 rc = xf_stream_write(stream, buffer, count);
52 } else {
53 rc = xf_stream_read(stream, buffer, count);
54 }
55
56 bytes_left -= count;
57
58 if(rc < 0 || (size_t)rc > count)
59 return XF_E_IO;
60
61 if((size_t)rc < count) {
62 /* backup - we could not write all the data */
63 if(nio->mode == XF_NANDIO_READ)
64 return XF_E_IO;
65
66 /* update - clear rest of buffer to 0xff */
67 memset(buffer + rc, 0xff, count - rc);
68 break;
69 }
70 }
71
72 /* if updating - write blanks to the remainder of the region */
73 while(bytes_left > 0) {
74 count = bytes_left;
75 rc = xf_nandio_get_buffer(nio, &buffer, &count);
76 if(rc)
77 return rc;
78
79 memset(buffer, 0xff, count);
80 bytes_left -= count;
81 }
82
83 /* finalize the MD5 sum */
84 if(nio->mode == XF_NANDIO_READ) {
85 md5_finish(&md5_ctx, map->md5);
86 map->file_length = map->length;
87 map->flags |= XF_MAP_HAS_MD5 | XF_MAP_HAS_FILE_LENGTH;
88 }
89
90 return XF_E_SUCCESS;
91}
92
93static int process_map(struct xf_nandio* nio, struct xf_map* map, int map_size,
94 xf_update_open_stream_cb open_stream, void* os_arg)
95{
96 int rc, rc2;
97 struct xf_stream stream;
98
99 /* ensure the map is sequential and non-overlapping before continuing */
100 if(xf_map_validate(map, map_size) != 0)
101 return XF_E_INVALID_PARAMETER;
102
103 for(int i = 0; i < map_size; ++i) {
104 /* seek to initial offset */
105 rc = xf_nandio_seek(nio, map[i].offset);
106 if(rc)
107 return rc;
108
109 rc = open_stream(os_arg, map[i].name, &stream);
110 if(rc)
111 return XF_E_CANNOT_OPEN_FILE;
112
113 /* process the stream and be sure to close it even on error */
114 rc = process_stream(nio, &map[i], &stream);
115 rc2 = xf_stream_close(&stream);
116
117 /* bail if either operation raised an error */
118 if(rc)
119 return rc;
120 if(rc2)
121 return rc2;
122 }
123
124 /* now flush to ensure all data was written */
125 rc = xf_nandio_flush(nio);
126 if(rc)
127 return rc;
128
129 return XF_E_SUCCESS;
130}
131
132static const enum xf_nandio_mode update_mode_to_nandio[] = {
133 [XF_UPDATE] = XF_NANDIO_PROGRAM,
134 [XF_BACKUP] = XF_NANDIO_READ,
135 [XF_VERIFY] = XF_NANDIO_VERIFY,
136};
137
138int xf_updater_run(enum xf_update_mode mode, struct xf_nandio* nio,
139 struct xf_map* map, int map_size,
140 xf_update_open_stream_cb open_stream, void* arg)
141{
142 /* Switch NAND I/O into the correct mode */
143 int rc = xf_nandio_set_mode(nio, update_mode_to_nandio[mode]);
144 if(rc)
145 return rc;
146
147 /* This does all the real work */
148 return process_map(nio, map, map_size, open_stream, arg);
149}
diff --git a/lib/x1000-installer/test/data/lines_shuffled.txt b/lib/x1000-installer/test/data/lines_shuffled.txt
deleted file mode 100644
index c138fe7e7c..0000000000
--- a/lib/x1000-installer/test/data/lines_shuffled.txt
+++ /dev/null
@@ -1,108 +0,0 @@
11234567890abcdefghijklmnopqrstuvw
21234567890abcdefghijklmnopqrst
3123
41234567890abcdef
51234567890abcdefghijklm
61234567890abcdefghijklmn
71234567890abcdefghijk
81234567890abcdefgh
9123456
101234567
111234567890a
121234567890abcdefghijklm
131
141234567890abcdefghijklmnopq
151234567890abcdefghijkl
161234567890abcdefghijklmno
171234567890abcdefghijklmnopqrstuvwxyz
181234567890abcdefghijklmnopq
191234567890abcdefghijklmno
201234567890abcdefghijklmnopq
211234567890abcdefghijklmn
221234
231234567890abcdefghijklmnop
24123456789
251234
2612345
271234567890ab
281234567890abcdefghijklmnopqrstuvwxy
291234567890abcdefghijklmnopqrst
301234567890abcdefghijklmnopqrs
311234567890abcdefghijklmnopqrs
3212345678
331234567890ab
341234567890a
351234567890abcdefghijklmnopqr
36123456
371234567890abcdefghijkl
381234567890abcdefghijklm
391234567890abcdefghijklmnopqrstuvwxy
401234567890abcdefghijklmnopqrstuvwxy
411234567890abcdefghijklmnopqrstuv
421234567890abcdefghijklmnopqrstuv
431234567890abcdefghijklmnopqrstuvwx
441234567890abcde
451
461234567890abcdefgh
471234567890abcdef
481234567890abcdefghi
491234567890
501
5112345
52123456789
531234567
541234567890abcdefghi
551234567890abcdefghijklmnopqrstu
561234567890abcdefghijklmnopqrstuvwx
571234567890abcdefghijklmnopqrstuv
581234567890abcd
5912345
601234567890abcdefg
611234567890abcd
621234567890abcdefghijklmnopqrstuvw
631234567890abcdefghijklmnopqrstuvwxyz
6412345678
651234567890abcd
661234567890abcdefghijklmnop
67123
681234567890abcdefg
69123456
701234567890abcdefghij
711234567890abcdefg
721234567890abcdefghi
731234567890
741234567890abcdefghijklmno
751234567890abcdefghij
761234567890abcdefghijklmn
771234567890abcde
781234567890abc
79123456789
801234567890abcdefgh
811234567890abcdefghij
821234567890abcdefghijklmnopqrstuvwx
831234567890abcdefghijklmnopqr
841234567890abcdefghijklmnopqrst
851234567890abcdefghijklmnopqrs
861234567890abcdefghijklmnopqrstuvwxyz
871234567890abcdefghijkl
881234
8912
9012
9112345678
921234567
931234567890
94123
951234567890abc
961234567890abcdefghijklmnopqr
9712
981234567890abcde
991234567890abcdef
1001234567890a
1011234567890ab
1021234567890abcdefghijk
1031234567890abcdefghijklmnopqrstu
1041234567890abcdefghijklmnop
1051234567890abcdefghijk
1061234567890abcdefghijklmnopqrstu
1071234567890abcdefghijklmnopqrstuvw
1081234567890abc
diff --git a/lib/x1000-installer/test/data/lines_sorted.txt b/lib/x1000-installer/test/data/lines_sorted.txt
deleted file mode 100644
index 4944efd614..0000000000
--- a/lib/x1000-installer/test/data/lines_sorted.txt
+++ /dev/null
@@ -1,36 +0,0 @@
11
212
3123
41234
512345
6123456
71234567
812345678
9123456789
101234567890
111234567890a
121234567890ab
131234567890abc
141234567890abcd
151234567890abcde
161234567890abcdef
171234567890abcdefg
181234567890abcdefgh
191234567890abcdefghi
201234567890abcdefghij
211234567890abcdefghijk
221234567890abcdefghijkl
231234567890abcdefghijklm
241234567890abcdefghijklmn
251234567890abcdefghijklmno
261234567890abcdefghijklmnop
271234567890abcdefghijklmnopq
281234567890abcdefghijklmnopqr
291234567890abcdefghijklmnopqrs
301234567890abcdefghijklmnopqrst
311234567890abcdefghijklmnopqrstu
321234567890abcdefghijklmnopqrstuv
331234567890abcdefghijklmnopqrstuvw
341234567890abcdefghijklmnopqrstuvwx
351234567890abcdefghijklmnopqrstuvwxy
361234567890abcdefghijklmnopqrstuvwxyz
diff --git a/lib/x1000-installer/test/main.c b/lib/x1000-installer/test/main.c
deleted file mode 100644
index f9bff1b704..0000000000
--- a/lib/x1000-installer/test/main.c
+++ /dev/null
@@ -1,86 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23
24static int test_num_executed = 0;
25static int test_num_failed = 0;
26int test_num_asserts_executed = 0;
27int test_num_asserts_failed = 0;
28
29void test_failure(const char* file, int line, const char* msg)
30{
31 fprintf(stderr, "%s:%d: ASSERTION FAILED: %s\n", file, line, msg);
32 ++test_num_asserts_failed;
33}
34
35typedef void(*test_t)(void);
36
37struct test_info {
38 const char* name;
39 test_t func;
40};
41
42extern void test_stream_read_lines(void);
43extern void test_stream_read_line_too_long(void);
44extern void test_flashmap_parseline(void);
45
46#define TEST(x) {#x, x}
47static const struct test_info all_tests[] = {
48 TEST(test_stream_read_lines),
49 TEST(test_stream_read_line_too_long),
50 TEST(test_flashmap_parseline),
51};
52#undef TEST
53
54void run_test(const struct test_info* tinfo)
55{
56 int asserts_now = test_num_asserts_failed;
57 ++test_num_executed;
58
59 fprintf(stderr, "RUN %s\n", tinfo->name);
60 tinfo->func();
61
62 if(test_num_asserts_failed > asserts_now) {
63 fprintf(stderr, " %s: FAILED!\n", tinfo->name);
64 ++test_num_failed;
65 }
66}
67
68int main(int argc, char* argv[])
69{
70 (void)argc;
71 (void)argv;
72
73 size_t num_tests = sizeof(all_tests) / sizeof(struct test_info);
74 for(size_t i = 0; i < num_tests; ++i)
75 run_test(&all_tests[i]);
76
77 fprintf(stderr, "------------------------------------------\n");
78 fprintf(stderr, "TEST COMPLETE\n");
79 fprintf(stderr, " Tests %d failed / %d executed\n",
80 test_num_failed, test_num_executed);
81 fprintf(stderr, " Assertions %d failed / %d executed\n",
82 test_num_asserts_failed, test_num_asserts_executed);
83
84 if(test_num_failed > 0)
85 return 1;
86}
diff --git a/lib/x1000-installer/test/test.h b/lib/x1000-installer/test/test.h
deleted file mode 100644
index 3d47a19d87..0000000000
--- a/lib/x1000-installer/test/test.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef TEST_H
23#define TEST_H
24
25extern int test_num_asserts_executed;
26extern int test_num_asserts_failed;
27
28extern void test_failure(const char* file, int line, const char* msg);
29
30#define T_ASSERT(cond) \
31 do { \
32 ++test_num_asserts_executed; \
33 if(!(cond)) { \
34 test_failure(__FILE__, __LINE__, #cond); \
35 goto cleanup; \
36 } \
37 } while(0)
38
39#endif
diff --git a/lib/x1000-installer/test/test_flashmap.c b/lib/x1000-installer/test/test_flashmap.c
deleted file mode 100644
index 5e7aa39d78..0000000000
--- a/lib/x1000-installer/test/test_flashmap.c
+++ /dev/null
@@ -1,140 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "test.h"
23#include "xf_stream.h"
24#include "xf_flashmap.h"
25#include "xf_error.h"
26#include "file.h"
27#include <string.h>
28#include <stdbool.h>
29#include <stdio.h>
30
31#define MD5SUM \
32 "abcdef012345ABCDEF012345abcdef01"
33#define MD5SUM_L \
34 "abcdef012345abcdef012345abcdef01"
35#define LONG_NAME \
36 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
37#define OVERLONG_NAME \
38 LONG_NAME "a"
39
40static const struct parseline_test {
41 const char* line;
42 int rc;
43 const char* name;
44 const char* md5;
45 uint32_t file_length;
46 uint32_t offset;
47 uint32_t length;
48 int flags;
49} parseline_tests[] = {
50 {"test1 " MD5SUM " 1234 0x9876 42",
51 XF_E_SUCCESS, "test1", MD5SUM_L, 1234, 0x9876, 42,
52 XF_MAP_HAS_FILE_LENGTH|XF_MAP_HAS_MD5},
53 {" test1 " MD5SUM " 1234 0x9876 42",
54 XF_E_SUCCESS, "test1", MD5SUM_L, 1234, 0x9876, 42,
55 XF_MAP_HAS_FILE_LENGTH|XF_MAP_HAS_MD5},
56 {"test1 " MD5SUM " 1234 0x9876 42 \r",
57 XF_E_SUCCESS, "test1", MD5SUM_L, 1234, 0x9876, 42,
58 XF_MAP_HAS_FILE_LENGTH|XF_MAP_HAS_MD5},
59 {"test1 " MD5SUM " 1234 0x9876 42 # junk",
60 XF_E_SYNTAX_ERROR, NULL, NULL, 0, 0, 0, 0},
61 {OVERLONG_NAME,
62 XF_E_FILENAME_TOO_LONG, NULL, NULL, 0, 0, 0, 0},
63 {LONG_NAME " " MD5SUM " 1234 0x9876 42",
64 XF_E_SUCCESS, LONG_NAME, MD5SUM_L, 1234, 0x9876, 42,
65 XF_MAP_HAS_FILE_LENGTH|XF_MAP_HAS_MD5},
66 {"test1 " MD5SUM " 4294967295 0 0xffffffff",
67 XF_E_SUCCESS, "test1", MD5SUM_L, 4294967295, 0, 0xfffffffful,
68 XF_MAP_HAS_FILE_LENGTH|XF_MAP_HAS_MD5},
69 {"test1 " MD5SUM " 4294967295 1 0xffffffff",
70 XF_E_INT_OVERFLOW, NULL, NULL, 0, 0, 0, 0},
71 {"test1 " MD5SUM " 4294967296 0 0xffffffff",
72 XF_E_INT_OVERFLOW, NULL, NULL, 0, 0, 0, 0},
73 {"test1 " MD5SUM " 100294967295 0 0xffffffff",
74 XF_E_INT_OVERFLOW, NULL, NULL, 0, 0, 0, 0},
75 {"test1 " MD5SUM " 0 0 0xffffffff0",
76 XF_E_INT_OVERFLOW, NULL, NULL, 0, 0, 0, 0},
77 {"test1 " MD5SUM " 0 0 0x100000000",
78 XF_E_INT_OVERFLOW, NULL, NULL, 0, 0, 0, 0},
79 {"test1 " MD5SUM " 0 0 0x100000001",
80 XF_E_INT_OVERFLOW, NULL, NULL, 0, 0, 0, 0},
81 {"<",
82 XF_E_SYNTAX_ERROR, NULL, NULL, 0, 0, 0, 0},
83 {"test1 abcXdef",
84 XF_E_SYNTAX_ERROR, NULL, NULL, 0, 0, 0, 0},
85 {"test1 " MD5SUM "0",
86 XF_E_SYNTAX_ERROR, NULL, NULL, 0, 0, 0, 0},
87 {"test1 - 4567 0xabcd",
88 XF_E_SUCCESS, "test1", NULL, 0, 4567, 0xabcd, 0},
89 {"test1 - 0 0x123456789",
90 XF_E_INT_OVERFLOW, NULL, NULL, 0, 0, 0, 0},
91 {"test1 - 4f",
92 XF_E_SYNTAX_ERROR, NULL, NULL, 0, 0, 0, 0},
93};
94
95static void md5_to_string(char* buf, const uint8_t* md5)
96{
97 const char* hex = "0123456789abcdef";
98 for(int i = 0; i < 16; ++i) {
99 uint8_t byte = md5[i];
100 buf[2*i] = hex[(byte >> 4) & 0xf];
101 buf[2*i+1] = hex[byte & 0xf];
102 }
103
104 buf[32] = '\0';
105}
106
107int test_flashmap_parseline(void)
108{
109 int rc;
110 struct xf_map map;
111 char md5string[33];
112
113 size_t num_cases = sizeof(parseline_tests) / sizeof(struct parseline_test);
114 const struct parseline_test* test = &parseline_tests[0];
115
116 for(; num_cases > 0; --num_cases, ++test) {
117 rc = xf_map_parseline(test->line, &map);
118
119 T_ASSERT(rc == test->rc);
120 if(rc != XF_E_SUCCESS)
121 continue;
122
123 T_ASSERT(strcmp(map.name, test->name) == 0);
124 T_ASSERT(map.offset == test->offset);
125 T_ASSERT(map.length == test->length);
126 T_ASSERT(map.flags == test->flags);
127
128 if(test->flags & XF_MAP_HAS_MD5) {
129 md5_to_string(md5string, map.md5);
130 T_ASSERT(strcmp(md5string, test->md5) == 0);
131 }
132
133 if(test->flags & XF_MAP_HAS_FILE_LENGTH) {
134 T_ASSERT(map.file_length == test->file_length);
135 }
136 }
137
138 cleanup:
139 return rc;
140}
diff --git a/lib/x1000-installer/test/test_stream.c b/lib/x1000-installer/test/test_stream.c
deleted file mode 100644
index b4a5723b76..0000000000
--- a/lib/x1000-installer/test/test_stream.c
+++ /dev/null
@@ -1,108 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "test.h"
23#include "xf_stream.h"
24#include "xf_error.h"
25#include "file.h"
26#include <string.h>
27#include <stdbool.h>
28#include <stdio.h>
29
30#define TESTDATADIR "test/data/"
31#define TESTFILE_SHUFFLED TESTDATADIR "lines_shuffled.txt"
32#define TESTFILE_SORTED TESTDATADIR "lines_sorted.txt"
33
34const char line_string[] = "1234567890abcdefghijklmnopqrstuvwxyz";
35
36static int read_line_cb(int n, char* buf, void* arg)
37{
38 int* max_n = (int*)arg;
39 *max_n = n;
40
41 T_ASSERT(strlen(buf) > 0);
42 T_ASSERT(strncmp(line_string, buf, strlen(buf)) == 0);
43
44 cleanup:
45 return 0;
46}
47
48void test_stream_read_lines(void)
49{
50 struct xf_stream s;
51 int rc;
52 char buf[100];
53 bool s_open = false;
54
55 for(int bufsz = 38; bufsz <= 100; bufsz += 1) {
56 rc = xf_open_file(TESTFILE_SHUFFLED, O_RDONLY, &s);
57 T_ASSERT(rc == 0);
58 s_open = true;
59
60 int max_n = 0;
61 rc = xf_stream_read_lines(&s, buf, bufsz, &read_line_cb, &max_n);
62 T_ASSERT(rc == 0);
63 T_ASSERT(max_n+1 == 108);
64
65 xf_stream_close(&s);
66 s_open = false;
67 }
68
69 cleanup:
70 if(s_open)
71 xf_stream_close(&s);
72 return;
73}
74
75void test_stream_read_line_too_long(void)
76{
77 struct xf_stream s;
78 int rc;
79 char buf[38];
80 bool s_open = false;
81
82 for(int bufsz = 0; bufsz <= 38; bufsz += 1) {
83 rc = xf_open_file(TESTFILE_SORTED, O_RDONLY, &s);
84 T_ASSERT(rc == 0);
85 s_open = true;
86
87 int max_n = -1;
88 rc = xf_stream_read_lines(&s, buf, bufsz, &read_line_cb, &max_n);
89 if(bufsz == 38) {
90 T_ASSERT(rc == 0);
91 T_ASSERT(max_n+1 == 36);
92 } else {
93 T_ASSERT(rc == XF_E_LINE_TOO_LONG);
94 if(bufsz <= 1)
95 T_ASSERT(max_n == -1);
96 else
97 T_ASSERT(max_n+1 == bufsz-2);
98 }
99
100 xf_stream_close(&s);
101 s_open = false;
102 }
103
104 cleanup:
105 if(s_open)
106 xf_stream_close(&s);
107 return;
108}
diff --git a/lib/x1000-installer/test_lib/core_alloc.c b/lib/x1000-installer/test_lib/core_alloc.c
deleted file mode 100644
index 719670f8f2..0000000000
--- a/lib/x1000-installer/test_lib/core_alloc.c
+++ /dev/null
@@ -1,72 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "core_alloc.h"
23#include <stdlib.h>
24
25#define N_POINTERS 100
26
27static void* pointers[N_POINTERS];
28struct buflib_callbacks buflib_ops_locked = {NULL, NULL, NULL};
29
30int core_alloc(const char* name, size_t size)
31{
32 (void)name;
33
34 void* mem = malloc(size);
35 if(!mem)
36 return -1;
37
38 for(int i = 0; i < N_POINTERS; ++i) {
39 if(pointers[i])
40 continue;
41
42 pointers[i] = mem;
43 return i + 1;
44 }
45
46 free(mem);
47 return -1;
48}
49
50int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks* cb)
51{
52 (void)cb;
53 return core_alloc(name, size);
54}
55
56int core_free(int handle)
57{
58 if(handle > 0) {
59 free(pointers[handle-1]);
60 pointers[handle-1] = NULL;
61 }
62
63 return 0;
64}
65
66void* core_get_data(int handle)
67{
68 if(handle > 0)
69 return pointers[handle-1];
70
71 return NULL;
72}
diff --git a/lib/x1000-installer/test_lib/core_alloc.h b/lib/x1000-installer/test_lib/core_alloc.h
deleted file mode 100644
index 2c77e3c274..0000000000
--- a/lib/x1000-installer/test_lib/core_alloc.h
+++ /dev/null
@@ -1,43 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/* fake core_alloc implementation for testing */
23
24#ifndef CORE_ALLOC_H
25#define CORE_ALLOC_H
26
27#include <stddef.h>
28#include <stdbool.h>
29
30struct buflib_callbacks {
31 int (*move_callback)(int handle, void* current, void* new);
32 int (*shrink_callback)(int handle, unsigned hints, void* start, size_t old_size);
33 void (*sync_callback)(int handle, bool sync_on);
34};
35
36extern struct buflib_callbacks buflib_ops_locked;
37
38int core_alloc(const char* name, size_t size);
39int core_alloc_ex(const char* name, size_t size, struct buflib_callbacks* cb);
40int core_free(int handle);
41void* core_get_data(int handle);
42
43#endif
diff --git a/lib/x1000-installer/test_lib/fakenand.c b/lib/x1000-installer/test_lib/fakenand.c
deleted file mode 100644
index 19f1f31cfd..0000000000
--- a/lib/x1000-installer/test_lib/fakenand.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "nand-x1000.h"
23#include <unistd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <stdio.h>
27#include <stdlib.h>
28
29const char* nand_backing_file = "fakeNAND.bin";
30const char* nand_meta_file = "fakeNAND_meta.bin";
31
32struct nand_trace* nand_trace = NULL;
33size_t nand_trace_capacity = 0;
34size_t nand_trace_length = 0;
35
36static struct nand_trace* nand_trace_cur = NULL;
37
38static int injected_err = 0;
39
40#define METAF_PROGRAMMED 1
41
42static const nand_chip fake_chip = {
43 /* ATO25D1GA */
44 .log2_ppb = 6, /* 64 pages */
45 .page_size = 2048,
46 .oob_size = 64,
47 .nr_blocks = 1024,
48};
49
50void nand_trace_reset(size_t size)
51{
52 nand_trace = realloc(nand_trace, size);
53 nand_trace_capacity = size;
54 nand_trace_length = 0;
55 nand_trace_cur = nand_trace;
56}
57
58void nand_inject_error(int rc)
59{
60 injected_err = rc;
61}
62
63nand_drv* nand_init(void)
64{
65 static bool inited = false;
66 static uint8_t scratch_buf[NAND_DRV_SCRATCHSIZE];
67 static uint8_t page_buf[NAND_DRV_MAXPAGESIZE];
68 static nand_drv d;
69
70 if(!inited) {
71 d.scratch_buf = scratch_buf;
72 d.page_buf = page_buf;
73 d.chip = &fake_chip;
74 inited = true;
75 }
76
77 return &d;
78}
79
80static void lock_assert(bool cond, const char* msg)
81{
82 if(!cond) {
83 fprintf(stderr, "%s\n", msg);
84 fflush(stderr);
85 abort();
86 }
87}
88
89void nand_lock(nand_drv* drv)
90{
91 drv->lock_count++;
92}
93
94void nand_unlock(nand_drv* drv)
95{
96 lock_assert(drv->lock_count > 0, "nand_unlock() called when not locked");
97 drv->lock_count--;
98}
99
100#define CHECK_INJECTED_ERROR \
101 do { int __err = injected_err; injected_err = 0; if(__err) return __err; } while(0)
102
103int nand_open(nand_drv* drv)
104{
105 lock_assert(drv->lock_count > 0, "nand_open(): lock not held");
106 CHECK_INJECTED_ERROR;
107
108 if(drv->refcount > 0) {
109 drv->refcount++;
110 return NAND_SUCCESS;
111 }
112
113 /* leaks an fd on error but this is only testing... */
114 drv->fd = open(nand_backing_file, O_RDWR|O_CREAT, 0644);
115 drv->metafd = open(nand_meta_file, O_RDWR|O_CREAT, 0644);
116 if(drv->fd < 0 || drv->metafd < 0)
117 goto err;
118
119 drv->ppb = 1 << drv->chip->log2_ppb;
120 drv->fpage_size = drv->chip->page_size + drv->chip->oob_size;
121
122 /* make backing file the correct size */
123 if(ftruncate(drv->fd, drv->chip->page_size * drv->ppb * drv->chip->nr_blocks) < 0)
124 goto err;
125 if(ftruncate(drv->metafd, drv->chip->nr_blocks * drv->ppb) < 0)
126 goto err;
127
128 drv->refcount++;
129 return NAND_SUCCESS;
130
131 err:
132 if(drv->fd >= 0)
133 close(drv->fd);
134 if(drv->metafd >= 0)
135 close(drv->metafd);
136 return NAND_ERR_OTHER;
137}
138
139void nand_close(nand_drv* drv)
140{
141 lock_assert(drv->lock_count > 0, "nand_close(): lock not held");
142
143 if(--drv->refcount > 0)
144 return;
145
146 close(drv->fd);
147 close(drv->metafd);
148 drv->fd = -1;
149 drv->metafd = -1;
150}
151
152static int read_meta(nand_drv* drv, nand_page_t page)
153{
154 /* probably won't fail */
155 if(lseek(drv->metafd, page, SEEK_SET) < 0)
156 return NAND_ERR_OTHER;
157 if(read(drv->metafd, drv->scratch_buf, 1) != 1)
158 return NAND_ERR_OTHER;
159
160 return drv->scratch_buf[0];
161}
162
163static int write_meta(nand_drv* drv, nand_page_t page, int val)
164{
165 drv->scratch_buf[0] = val;
166
167 if(lseek(drv->metafd, page, SEEK_SET) < 0)
168 return NAND_ERR_OTHER;
169 if(write(drv->metafd, drv->scratch_buf, 1) != 1)
170 return NAND_ERR_OTHER;
171
172 return NAND_SUCCESS;
173}
174
175static int upd_meta(nand_drv* drv, nand_page_t page, uint8_t clr, uint8_t set)
176{
177 int meta = read_meta(drv, page);
178 if(meta < 0)
179 return meta;
180
181 meta &= ~clr;
182 meta |= set;
183
184 return write_meta(drv, page, meta);
185}
186
187static int page_program(nand_drv* drv, nand_page_t page, const void* buffer,
188 uint8_t clr, uint8_t set)
189{
190 if(lseek(drv->fd, page * drv->chip->page_size, SEEK_SET) < 0)
191 return NAND_ERR_OTHER;
192 if(write(drv->fd, buffer, drv->chip->page_size) != (ssize_t)drv->chip->page_size)
193 return NAND_ERR_PROGRAM_FAIL;
194
195 return upd_meta(drv, page, clr, set);
196}
197
198static void trace(enum nand_trace_type ty, enum nand_trace_exception ex, nand_page_t addr)
199{
200 if(nand_trace_length < nand_trace_capacity) {
201 nand_trace_cur->type = ty;
202 nand_trace_cur->exception = ex;
203 nand_trace_cur->addr = addr;
204 nand_trace_cur++;
205 nand_trace_length++;
206 }
207}
208
209int nand_block_erase(nand_drv* drv, nand_block_t block)
210{
211 lock_assert(drv->lock_count > 0, "nand_block_erase(): lock not held");
212 CHECK_INJECTED_ERROR;
213
214 trace(NTT_ERASE, NTE_NONE, block);
215
216 memset(drv->page_buf, 0xff, drv->fpage_size);
217
218 for(unsigned i = 0; i < drv->ppb; ++i) {
219 int rc = page_program(drv, block + i, drv->page_buf, METAF_PROGRAMMED, 0);
220 if(rc < 0)
221 return NAND_ERR_ERASE_FAIL;
222 }
223
224 return NAND_SUCCESS;
225}
226
227int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer)
228{
229 lock_assert(drv->lock_count > 0, "nand_page_program(): lock not held");
230 CHECK_INJECTED_ERROR;
231
232 int meta = read_meta(drv, page);
233 if(meta < 0)
234 return meta;
235
236 enum nand_trace_exception exception = NTE_NONE;
237 if(meta & METAF_PROGRAMMED)
238 exception = NTE_DOUBLE_PROGRAMMED;
239
240 trace(NTT_PROGRAM, exception, page);
241
242 return page_program(drv, page, buffer, 0, METAF_PROGRAMMED);
243}
244
245int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer)
246{
247 lock_assert(drv->lock_count > 0, "nand_page_read(): lock not held");
248 CHECK_INJECTED_ERROR;
249
250 enum nand_trace_exception exception = NTE_NONE;
251
252 int meta = read_meta(drv, page);
253 if(meta < 0)
254 return meta;
255
256 if(meta & METAF_PROGRAMMED) {
257 if(lseek(drv->fd, page * drv->chip->page_size, SEEK_SET) < 0)
258 return NAND_ERR_OTHER;
259 if(read(drv->fd, buffer, drv->chip->page_size) != (ssize_t)drv->chip->page_size)
260 return NAND_ERR_OTHER;
261 } else {
262 memset(buffer, 0xff, drv->chip->page_size);
263 exception = NTE_CLEARED;
264 }
265
266 trace(NTT_READ, exception, page);
267
268 memset(buffer + drv->chip->page_size, 0xff, drv->chip->oob_size);
269 return NAND_SUCCESS;
270}
diff --git a/lib/x1000-installer/test_lib/file.c b/lib/x1000-installer/test_lib/file.c
deleted file mode 100644
index 8769c009a4..0000000000
--- a/lib/x1000-installer/test_lib/file.c
+++ /dev/null
@@ -1,11 +0,0 @@
1#include "file.h"
2
3off_t filesize(int osfd)
4{
5 struct stat sb;
6
7 if (!fstat(osfd, &sb))
8 return sb.st_size;
9 else
10 return -1;
11}
diff --git a/lib/x1000-installer/test_lib/file.h b/lib/x1000-installer/test_lib/file.h
deleted file mode 100644
index 2a6554c695..0000000000
--- a/lib/x1000-installer/test_lib/file.h
+++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef FILE_H
2#define FILE_H
3
4#include <sys/types.h>
5#include <sys/statfs.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <unistd.h>
9
10#ifdef MAX_PATH
11# undef MAX_PATH
12#endif
13
14#define MAX_PATH 260
15
16off_t filesize(int fd);
17
18#endif
diff --git a/lib/x1000-installer/test_lib/md5.c b/lib/x1000-installer/test_lib/md5.c
deleted file mode 100644
index 3050c7ebd8..0000000000
--- a/lib/x1000-installer/test_lib/md5.c
+++ /dev/null
@@ -1,245 +0,0 @@
1/*
2 * RFC 1321 compliant MD5 implementation
3 *
4 * Copyright (C) 2001-2003 Christophe Devine
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <string.h>
22
23#include "md5.h"
24
25#define GET_UINT32(n,b,i) \
26{ \
27 (n) = ( (uint32_t) (b)[(i) ] ) \
28 | ( (uint32_t) (b)[(i) + 1] << 8 ) \
29 | ( (uint32_t) (b)[(i) + 2] << 16 ) \
30 | ( (uint32_t) (b)[(i) + 3] << 24 ); \
31}
32
33#define PUT_UINT32(n,b,i) \
34{ \
35 (b)[(i) ] = (uint8_t) ( (n) ); \
36 (b)[(i) + 1] = (uint8_t) ( (n) >> 8 ); \
37 (b)[(i) + 2] = (uint8_t) ( (n) >> 16 ); \
38 (b)[(i) + 3] = (uint8_t) ( (n) >> 24 ); \
39}
40
41void md5_starts( md5_context *ctx )
42{
43 ctx->total[0] = 0;
44 ctx->total[1] = 0;
45
46 ctx->state[0] = 0x67452301;
47 ctx->state[1] = 0xEFCDAB89;
48 ctx->state[2] = 0x98BADCFE;
49 ctx->state[3] = 0x10325476;
50}
51
52static void md5_process( md5_context *ctx, uint8_t data[64] )
53{
54 uint32_t X[16], A, B, C, D;
55
56 GET_UINT32( X[0], data, 0 );
57 GET_UINT32( X[1], data, 4 );
58 GET_UINT32( X[2], data, 8 );
59 GET_UINT32( X[3], data, 12 );
60 GET_UINT32( X[4], data, 16 );
61 GET_UINT32( X[5], data, 20 );
62 GET_UINT32( X[6], data, 24 );
63 GET_UINT32( X[7], data, 28 );
64 GET_UINT32( X[8], data, 32 );
65 GET_UINT32( X[9], data, 36 );
66 GET_UINT32( X[10], data, 40 );
67 GET_UINT32( X[11], data, 44 );
68 GET_UINT32( X[12], data, 48 );
69 GET_UINT32( X[13], data, 52 );
70 GET_UINT32( X[14], data, 56 );
71 GET_UINT32( X[15], data, 60 );
72
73#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
74
75#define P(a,b,c,d,k,s,t) \
76{ \
77 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
78}
79
80 A = ctx->state[0];
81 B = ctx->state[1];
82 C = ctx->state[2];
83 D = ctx->state[3];
84
85#define F(x,y,z) (z ^ (x & (y ^ z)))
86
87 P( A, B, C, D, 0, 7, 0xD76AA478 );
88 P( D, A, B, C, 1, 12, 0xE8C7B756 );
89 P( C, D, A, B, 2, 17, 0x242070DB );
90 P( B, C, D, A, 3, 22, 0xC1BDCEEE );
91 P( A, B, C, D, 4, 7, 0xF57C0FAF );
92 P( D, A, B, C, 5, 12, 0x4787C62A );
93 P( C, D, A, B, 6, 17, 0xA8304613 );
94 P( B, C, D, A, 7, 22, 0xFD469501 );
95 P( A, B, C, D, 8, 7, 0x698098D8 );
96 P( D, A, B, C, 9, 12, 0x8B44F7AF );
97 P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
98 P( B, C, D, A, 11, 22, 0x895CD7BE );
99 P( A, B, C, D, 12, 7, 0x6B901122 );
100 P( D, A, B, C, 13, 12, 0xFD987193 );
101 P( C, D, A, B, 14, 17, 0xA679438E );
102 P( B, C, D, A, 15, 22, 0x49B40821 );
103
104#undef F
105
106#define F(x,y,z) (y ^ (z & (x ^ y)))
107
108 P( A, B, C, D, 1, 5, 0xF61E2562 );
109 P( D, A, B, C, 6, 9, 0xC040B340 );
110 P( C, D, A, B, 11, 14, 0x265E5A51 );
111 P( B, C, D, A, 0, 20, 0xE9B6C7AA );
112 P( A, B, C, D, 5, 5, 0xD62F105D );
113 P( D, A, B, C, 10, 9, 0x02441453 );
114 P( C, D, A, B, 15, 14, 0xD8A1E681 );
115 P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
116 P( A, B, C, D, 9, 5, 0x21E1CDE6 );
117 P( D, A, B, C, 14, 9, 0xC33707D6 );
118 P( C, D, A, B, 3, 14, 0xF4D50D87 );
119 P( B, C, D, A, 8, 20, 0x455A14ED );
120 P( A, B, C, D, 13, 5, 0xA9E3E905 );
121 P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
122 P( C, D, A, B, 7, 14, 0x676F02D9 );
123 P( B, C, D, A, 12, 20, 0x8D2A4C8A );
124
125#undef F
126
127#define F(x,y,z) (x ^ y ^ z)
128
129 P( A, B, C, D, 5, 4, 0xFFFA3942 );
130 P( D, A, B, C, 8, 11, 0x8771F681 );
131 P( C, D, A, B, 11, 16, 0x6D9D6122 );
132 P( B, C, D, A, 14, 23, 0xFDE5380C );
133 P( A, B, C, D, 1, 4, 0xA4BEEA44 );
134 P( D, A, B, C, 4, 11, 0x4BDECFA9 );
135 P( C, D, A, B, 7, 16, 0xF6BB4B60 );
136 P( B, C, D, A, 10, 23, 0xBEBFBC70 );
137 P( A, B, C, D, 13, 4, 0x289B7EC6 );
138 P( D, A, B, C, 0, 11, 0xEAA127FA );
139 P( C, D, A, B, 3, 16, 0xD4EF3085 );
140 P( B, C, D, A, 6, 23, 0x04881D05 );
141 P( A, B, C, D, 9, 4, 0xD9D4D039 );
142 P( D, A, B, C, 12, 11, 0xE6DB99E5 );
143 P( C, D, A, B, 15, 16, 0x1FA27CF8 );
144 P( B, C, D, A, 2, 23, 0xC4AC5665 );
145
146#undef F
147
148#define F(x,y,z) (y ^ (x | ~z))
149
150 P( A, B, C, D, 0, 6, 0xF4292244 );
151 P( D, A, B, C, 7, 10, 0x432AFF97 );
152 P( C, D, A, B, 14, 15, 0xAB9423A7 );
153 P( B, C, D, A, 5, 21, 0xFC93A039 );
154 P( A, B, C, D, 12, 6, 0x655B59C3 );
155 P( D, A, B, C, 3, 10, 0x8F0CCC92 );
156 P( C, D, A, B, 10, 15, 0xFFEFF47D );
157 P( B, C, D, A, 1, 21, 0x85845DD1 );
158 P( A, B, C, D, 8, 6, 0x6FA87E4F );
159 P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
160 P( C, D, A, B, 6, 15, 0xA3014314 );
161 P( B, C, D, A, 13, 21, 0x4E0811A1 );
162 P( A, B, C, D, 4, 6, 0xF7537E82 );
163 P( D, A, B, C, 11, 10, 0xBD3AF235 );
164 P( C, D, A, B, 2, 15, 0x2AD7D2BB );
165 P( B, C, D, A, 9, 21, 0xEB86D391 );
166
167#undef F
168
169 ctx->state[0] += A;
170 ctx->state[1] += B;
171 ctx->state[2] += C;
172 ctx->state[3] += D;
173}
174
175void md5_update( md5_context *ctx, uint8_t *input, uint32_t length )
176{
177 uint32_t left, fill;
178
179 if( ! length ) return;
180
181 left = ctx->total[0] & 0x3F;
182 fill = 64 - left;
183
184 ctx->total[0] += length;
185 ctx->total[0] &= 0xFFFFFFFF;
186
187 if( ctx->total[0] < length )
188 ctx->total[1]++;
189
190 if( left && length >= fill )
191 {
192 memcpy( (void *) (ctx->buffer + left),
193 (void *) input, fill );
194 md5_process( ctx, ctx->buffer );
195 length -= fill;
196 input += fill;
197 left = 0;
198 }
199
200 while( length >= 64 )
201 {
202 md5_process( ctx, input );
203 length -= 64;
204 input += 64;
205 }
206
207 if( length )
208 {
209 memcpy( (void *) (ctx->buffer + left),
210 (void *) input, length );
211 }
212}
213
214static uint8_t md5_padding[64] =
215{
216 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
220};
221
222void md5_finish( md5_context *ctx, uint8_t digest[16] )
223{
224 uint32_t last, padn;
225 uint32_t high, low;
226 uint8_t msglen[8];
227
228 high = ( ctx->total[0] >> 29 )
229 | ( ctx->total[1] << 3 );
230 low = ( ctx->total[0] << 3 );
231
232 PUT_UINT32( low, msglen, 0 );
233 PUT_UINT32( high, msglen, 4 );
234
235 last = ctx->total[0] & 0x3F;
236 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
237
238 md5_update( ctx, md5_padding, padn );
239 md5_update( ctx, msglen, 8 );
240
241 PUT_UINT32( ctx->state[0], digest, 0 );
242 PUT_UINT32( ctx->state[1], digest, 4 );
243 PUT_UINT32( ctx->state[2], digest, 8 );
244 PUT_UINT32( ctx->state[3], digest, 12 );
245}
diff --git a/lib/x1000-installer/test_lib/md5.h b/lib/x1000-installer/test_lib/md5.h
deleted file mode 100644
index 882636ed9a..0000000000
--- a/lib/x1000-installer/test_lib/md5.h
+++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef _MD5_H
2#define _MD5_H
3
4#include <stdint.h>
5
6typedef struct
7{
8 uint32_t total[2];
9 uint32_t state[4];
10 uint8_t buffer[64];
11}
12md5_context;
13
14void md5_starts( md5_context *ctx );
15void md5_update( md5_context *ctx, uint8_t *input, uint32_t length );
16void md5_finish( md5_context *ctx, uint8_t digest[16] );
17
18#endif /* md5.h */
diff --git a/lib/x1000-installer/test_lib/nand-x1000.h b/lib/x1000-installer/test_lib/nand-x1000.h
deleted file mode 100644
index f34f2ce026..0000000000
--- a/lib/x1000-installer/test_lib/nand-x1000.h
+++ /dev/null
@@ -1,112 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/* Stripped down fake version of X1000 NAND API for testing purposes,
23 * uses a normal file to store the data */
24
25#ifndef __NAND_X1000_H__
26#define __NAND_X1000_H__
27
28#include <stdint.h>
29#include <stddef.h>
30#include <stdbool.h>
31
32#define NAND_SUCCESS 0
33#define NAND_ERR_UNKNOWN_CHIP (-1)
34#define NAND_ERR_PROGRAM_FAIL (-2)
35#define NAND_ERR_ERASE_FAIL (-3)
36#define NAND_ERR_UNALIGNED (-4)
37#define NAND_ERR_OTHER (-5)
38#define NAND_ERR_INJECTED (-6)
39
40/* keep max page size in sync with the NAND chip table in the .c file */
41#define NAND_DRV_SCRATCHSIZE 32
42#define NAND_DRV_MAXPAGESIZE 2112
43
44typedef uint32_t nand_block_t;
45typedef uint32_t nand_page_t;
46
47enum nand_trace_type {
48 NTT_READ,
49 NTT_PROGRAM,
50 NTT_ERASE,
51};
52
53enum nand_trace_exception {
54 NTE_NONE,
55 NTE_DOUBLE_PROGRAMMED,
56 NTE_CLEARED,
57};
58
59struct nand_trace {
60 enum nand_trace_type type;
61 enum nand_trace_exception exception;
62 nand_page_t addr;
63};
64
65typedef struct nand_chip {
66 /* Base2 logarithm of the number of pages per block */
67 unsigned log2_ppb;
68
69 /* Size of a page's main / oob areas, in bytes. */
70 unsigned page_size;
71 unsigned oob_size;
72
73 /* Total number of blocks in the chip */
74 unsigned nr_blocks;
75} nand_chip;
76
77typedef struct nand_drv {
78 /* Backing file */
79 int fd;
80 int metafd;
81 int lock_count;
82
83 unsigned refcount;
84 uint8_t* scratch_buf;
85 uint8_t* page_buf;
86 const nand_chip* chip;
87 unsigned ppb;
88 unsigned fpage_size;
89} nand_drv;
90
91extern const char* nand_backing_file;
92extern const char* nand_meta_file;
93
94extern struct nand_trace* nand_trace;
95extern size_t nand_trace_capacity;
96extern size_t nand_trace_length;
97
98extern void nand_trace_reset(size_t size);
99extern void nand_inject_error(int rc);
100
101extern nand_drv* nand_init(void);
102
103extern void nand_lock(nand_drv* drv);
104extern void nand_unlock(nand_drv* drv);
105
106extern int nand_open(nand_drv* drv);
107extern void nand_close(nand_drv* drv);
108extern int nand_block_erase(nand_drv* drv, nand_block_t block);
109extern int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer);
110extern int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer);
111
112#endif /* __NAND_X1000_H__ */
diff --git a/lib/x1000-installer/test_lib/pathfuncs.c b/lib/x1000-installer/test_lib/pathfuncs.c
deleted file mode 100644
index 341efd4730..0000000000
--- a/lib/x1000-installer/test_lib/pathfuncs.c
+++ /dev/null
@@ -1,130 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "pathfuncs.h"
23#include "strlcpy.h"
24#include "system.h"
25#include <string.h>
26
27static const char* GOBBLE_PATH_SEPCH(const char* p)
28{
29 int c;
30 while((c = *p) == PATH_SEPCH)
31 ++p;
32 return p;
33}
34
35static const char* GOBBLE_PATH_COMP(const char* p)
36{
37 int c;
38 while((c = *p) && c != PATH_SEPCH)
39 ++p;
40 return p;
41}
42
43/* Strips the trailing component from the path
44 * "" *nameptr->NUL, len=0: ""
45 * "/" *nameptr->/, len=1: "/"
46 * "//" *nameptr->2nd /, len=1: "/"
47 * "/a" *nameptr->/, len=1: "/"
48 * "a/" *nameptr->a, len=0: ""
49 * "/a/bc" *nameptr->/, len=2: "/a"
50 * "d" *nameptr->d, len=0: ""
51 * "ef/gh" *nameptr->e, len=2: "ef"
52 *
53 * Notes: * Interpret len=0 as ".".
54 * * In the same string, path_dirname() returns a pointer with the
55 * same or lower address as path_basename().
56 * * Pasting a separator between the returns of path_dirname() and
57 * path_basename() will result in a path equivalent to the input.
58 *
59 */
60size_t path_dirname(const char *name, const char **nameptr)
61{
62 const char *p = GOBBLE_PATH_SEPCH(name);
63 const char *q = name;
64 const char *r = p;
65
66 while (*(p = GOBBLE_PATH_COMP(p)))
67 {
68 const char *s = p;
69
70 if (!*(p = GOBBLE_PATH_SEPCH(p)))
71 break;
72
73 q = s;
74 }
75
76 if (q == name && r > name)
77 name = r, q = name--; /* root - return last slash */
78
79 *nameptr = name;
80 return q - name;
81}
82
83/* Appends one path to another, adding separators between components if needed.
84 * Return value and behavior is otherwise as strlcpy so that truncation may be
85 * detected.
86 *
87 * For basepath and component:
88 * PA_SEP_HARD adds a separator even if the base path is empty
89 * PA_SEP_SOFT adds a separator only if the base path is not empty
90 */
91size_t path_append(char *buf, const char *basepath,
92 const char *component, size_t bufsize)
93{
94 const char *base = basepath && basepath[0] ? basepath : buf;
95 if (!base)
96 return bufsize; /* won't work to get lengths from buf */
97
98 if (!buf)
99 bufsize = 0;
100
101 if (path_is_absolute(component))
102 {
103 /* 'component' is absolute; replace all */
104 basepath = component;
105 component = "";
106 }
107
108 /* if basepath is not null or empty, buffer contents are replaced,
109 otherwise buf contains the base path */
110 size_t len = base == buf ? strlen(buf) : my_strlcpy(buf, basepath, bufsize);
111
112 bool separate = false;
113
114 if (!basepath || !component)
115 separate = !len || base[len-1] != PATH_SEPCH;
116 else if (component[0])
117 separate = len && base[len-1] != PATH_SEPCH;
118
119 /* caller might lie about size of buf yet use buf as the base */
120 if (base == buf && bufsize && len >= bufsize)
121 buf[bufsize - 1] = '\0';
122
123 buf += len;
124 bufsize -= MIN(len, bufsize);
125
126 if (separate && (len++, bufsize > 0) && --bufsize > 0)
127 *buf++ = PATH_SEPCH;
128
129 return len + my_strlcpy(buf, component ?: "", bufsize);
130}
diff --git a/lib/x1000-installer/test_lib/pathfuncs.h b/lib/x1000-installer/test_lib/pathfuncs.h
deleted file mode 100644
index 225b3cdd19..0000000000
--- a/lib/x1000-installer/test_lib/pathfuncs.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef _PATHFUNCS_H_
22#define _PATHFUNCS_H_
23
24#include <stddef.h>
25#include <stdbool.h>
26
27#define PATH_SEPCH '/'
28
29/* return true if path begins with a root '/' component and is not NULL */
30static inline bool path_is_absolute(const char *path)
31{
32 return path && path[0] == PATH_SEPCH;
33}
34
35size_t path_dirname(const char *name, const char **nameptr);
36size_t path_append(char *buf, const char *basepath,
37 const char *component, size_t bufsize);
38
39#endif
diff --git a/lib/x1000-installer/test_lib/strlcpy.c b/lib/x1000-installer/test_lib/strlcpy.c
deleted file mode 100644
index 681d917503..0000000000
--- a/lib/x1000-installer/test_lib/strlcpy.c
+++ /dev/null
@@ -1,50 +0,0 @@
1/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
2
3/*
4 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <string.h>
20
21/*
22 * Copy src to string dst of size siz. At most siz-1 characters
23 * will be copied. Always NUL terminates (unless siz == 0).
24 * Returns strlen(src); if retval >= siz, truncation occurred.
25 */
26size_t
27my_strlcpy(char *dst, const char *src, size_t siz)
28{
29 char *d = dst;
30 const char *s = src;
31 size_t n = siz;
32
33 /* Copy as many bytes as will fit */
34 if (n != 0) {
35 while (--n != 0) {
36 if ((*d++ = *s++) == '\0')
37 break;
38 }
39 }
40
41 /* Not enough room in dst, add NUL and traverse rest of src */
42 if (n == 0) {
43 if (siz != 0)
44 *d = '\0'; /* NUL-terminate dst */
45 while (*s++)
46 ;
47 }
48
49 return(s - src - 1); /* count does not include NUL */
50}
diff --git a/lib/x1000-installer/test_lib/strlcpy.h b/lib/x1000-installer/test_lib/strlcpy.h
deleted file mode 100644
index 0c4b16dd5a..0000000000
--- a/lib/x1000-installer/test_lib/strlcpy.h
+++ /dev/null
@@ -1,4 +0,0 @@
1#ifndef STRLCPY_H
2#define STRLCPY_H
3size_t my_strlcpy(char *dst, const char *src, size_t siz);
4#endif
diff --git a/lib/x1000-installer/test_lib/system.h b/lib/x1000-installer/test_lib/system.h
deleted file mode 100644
index b0a5076ba9..0000000000
--- a/lib/x1000-installer/test_lib/system.h
+++ /dev/null
@@ -1,10 +0,0 @@
1#ifndef SYSTEM_H
2#define SYSTEM_H
3
4#define CACHEALIGN_SIZE 1
5#define CACHEALIGN_BUFFER(x,y) do { } while(0)
6#define MIN(a, b) (((a)<(b))?(a):(b))
7#define ALIGN_BUFFER(ptr, size, align) do { } while(0)
8#define ALIGN_UP_P2(x, p) (((x) + ((1 << (p)) - 1)) & ~((1 << (p)) - 1))
9
10#endif
diff --git a/lib/x1000-installer/x1000-installer.make b/lib/x1000-installer/x1000-installer.make
deleted file mode 100644
index d58bd2042f..0000000000
--- a/lib/x1000-installer/x1000-installer.make
+++ /dev/null
@@ -1,21 +0,0 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7#
8
9X1000INSTALLER_DIR = $(ROOTDIR)/lib/x1000-installer
10X1000INSTALLER_SRC = $(call preprocess, $(X1000INSTALLER_DIR)/SOURCES)
11X1000INSTALLER_OBJ := $(call c2obj, $(X1000INSTALLER_SRC))
12
13X1000INSTALLERLIB = $(BUILDDIR)/lib/libx1000-installer.a
14
15INCLUDES += -I$(X1000INSTALLER_DIR)/include
16OTHER_SRC += $(X1000INSTALLER_SRC)
17CORE_LIBS += $(X1000INSTALLERLIB)
18
19$(X1000INSTALLERLIB): $(X1000INSTALLER_OBJ)
20 $(SILENT)$(shell rm -f $@)
21 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null