├── .gitignore ├── .travis.yml ├── LICENSE ├── LINEAR.md ├── README.md ├── files.mk ├── makefile └── src ├── default └── niffs_config.h ├── niffs.h ├── niffs_api.c ├── niffs_internal.c ├── niffs_internal.h └── test ├── main.c ├── niffs_cfg_tests.c ├── niffs_func_tests.c ├── niffs_run_tests.c ├── niffs_sys_tests.c ├── niffs_test_config.h ├── niffs_test_emul.c ├── niffs_test_emul.h ├── testrunner.c ├── testrunner.h └── testsuites.c /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | .cproject 3 | .project 4 | _tests_* 5 | build 6 | *.gcov 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: 4 | - gcc 5 | 6 | before_script: 7 | 8 | script: make clean test 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LINEAR.md: -------------------------------------------------------------------------------- 1 | # Linear Area feature 2 | 3 | Below is a short description of how the linear feature works in niffs. 4 | 5 | The linear area feature allows for having linear files in niffs, meaning files that are not chopped up in pages on medium. This can be handy for e.g. audio, video, code, bytecodes, streaming or FOTA images. 6 | 7 | Features of the linear area: 8 | 9 | * Linear files are linear on flash. 10 | * The linear area is not wear-leveled, so beware doing frequent updates. 11 | * Each linear file claims at least one sector. 12 | * Linear files can be created, written, read, seeked, and deleted. 13 | * Linear files can only be appended when writing - written data cannot be changed. 14 | 15 | ## Build for linear area feature 16 | 17 | Set `NIFFS_LINEAR_AREA` to `1` in your `niffs_config.h` 18 | 19 | ## Assigning a linear area 20 | 21 | When configuring your file system with `NIFFS_config` you specify how many sectors the file system will have the address of the starting sector using arguments `sectors` and `phys_addr`. The argument `lin_sectors` determines how many sectors the linear area comprises. The file system will thus claim `sectors + lin_sectors` number of sectors, starting at `phys_addr`. The linear area is placed after the paged file system sectors. 22 | 23 | For example: 24 | ```C 25 | NIFFS_init(&niffs_fs, 26 | 0x00860000, /* address of starting sector */ 27 | 16, /* number of paged sectors */ 28 | 4096, /* logical sector size */ 29 | 128, /* logical page size */ 30 | work_buf, /* work ram */ 31 | sizeof(work_buf), /* work ram length in bytes */ 32 | desc_buf, /* file descriptor array */ 33 | sizeof(desc_buf) / sizeof(desc_buf[0]), /* number of file descriptors */ 34 | hal_erase_fn, hal_write_fn, /* flash HAL functions */ 35 | 32); /* number of linear sectors */ 36 | ``` 37 | will look like this on your flash: 38 | 39 | | address | sector | type | 40 | | -------- | ------ | ----- | 41 | | 0x860000 | x | paged | 42 | | 0x861000 | x+1 | paged | 43 | | ... | ... | ... | 44 | | 0x86f000 | x+15 | paged | 45 | | 0x870000 | x+16 | linear | 46 | | 0x871000 | x+17 | linear | 47 | | ... | ... | ... | 48 | | 0x88f000 | x+47 | linear | 49 | 50 | ## Understanding linear files 51 | 52 | There are two ways to create linear files. 53 | 54 | * `NIFFS_open` including flags `NIFFS_O_CREAT | NIFFS_O_LINEAR` 55 | * `NIFFS_mknod_linear` 56 | 57 | To understand the difference between these, the linear sector assignment must be described. When a linear file is created, 58 | the linear area is scanned for free sectors. The first found free sector is selected and the file is placed on that sector. 59 | Assume we have a system with five linear sectors: 60 | 61 | | sector0 | sector1 | sector2 | sector3 | sector4 | 62 | | ------- | ------- | ------- | ------- | ------- | 63 | | free | free | free | free | free | 64 | 65 | We create three files, "fileA", "fileB", "fileC". We don't write anything to them yet. 66 | ```C 67 | int fda = NIFFS_open(fs, "fileA", NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_RDWR | NIFFS_O_LINEAR, 0); 68 | int fdb = NIFFS_open(fs, "fileB", NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_RDWR | NIFFS_O_LINEAR, 0); 69 | int fdc = NIFFS_open(fs, "fileC", NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_RDWR | NIFFS_O_LINEAR, 0); 70 | ``` 71 | 72 | | sector0 | sector1 | sector2 | sector3 | sector4 | 73 | | ------- | ------- | ------- | ------- | ------- | 74 | | fileA | fileB | fileC | free | free | 75 | 76 | The meta data for all files resides on the paged part of the filesystem. This means the **linear sectors contain only data**. 77 | Now we write to fileC, two sectors worth of data. 78 | 79 | ```C 80 | u8_t data[2 * sector_size]; 81 | // fill data with something useful 82 | int res = NIFFS_write(fs, fdc, data, sizeof(data)); 83 | ``` 84 | 85 | | sector0 | sector1 | sector2 | sector3 | sector4 | 86 | | ------- | ------- | ------- | ------- | ------- | 87 | | fileA | fileB | fileC | fileC(2)| free | 88 | 89 | Now we want to write the same to fileA. 90 | 91 | ```C 92 | res = NIFFS_write(fs, fda, data, sizeof(data)); 93 | // BAM: res = ERR_NIFFS_LINEAR_NO_SPACE 94 | ``` 95 | This will not work, fileA can at most be one sector long as the sector after is occupied. 96 | In order to do this, we must delete fileB first. 97 | 98 | ```C 99 | res = NIFFS_fremove(fs, fdb); 100 | res = NIFFS_write(fs, fda, data, sizeof(data)); 101 | // all dandy 102 | ``` 103 | | sector0 | sector1 | sector2 | sector3 | sector4 | 104 | | ------- | ------- | ------- | ------- | ------- | 105 | | fileA | fileA(2)| fileC | fileC(2)| free | 106 | 107 | But hey, what if I want all three files and I know that fileB only ever will be one sector long, and the other two must 108 | be at least two sectors long? 109 | Then you use `NIFFS_mknod_linear`. We format our system, and instead of using ´SPIFFS_open` we create our files like this: 110 | ```C 111 | int fda = NIFFS_mknod_linear(fs, "fileA", sector_size*2); 112 | int fdb = NIFFS_mknod_linear(fs, "fileB", sector_size); 113 | int fdc = NIFFS_mknod_linear(fs, "fileC", sector_size*2); 114 | ``` 115 | Still nothing written, but the representation will be like this: 116 | 117 | | sector0 | sector1 | sector2 | sector3 | sector4 | 118 | | ------- | ------- | ------- | ------- | ------- | 119 | | fileA | (fileA) | fileB | fileC | (fileC) | 120 | 121 | Meaning that fileA and fileC will have two sectors worth of data reserved and are guaranteed to be able to contain two sectors 122 | worth of data. The reservation is a minimum length guarantee. Would the sectors after a file be free, it can of course be longer. 123 | 124 | ## Using linear files 125 | 126 | Opening linear files works just like normal. You do not need to know it is a linear file. 127 | ```C 128 | int fd = NIFFS_open(fs, "linearfile", NIFFS_O_RDONLY, 0); // NIFFS_O_LINEAR not needed 129 | ``` 130 | `NIFFS_O_LINEAR` is only necessary when creating files with `NIFFS_open`. 131 | 132 | Also, opening a linear file for writing forcefully sets the `NIFFS_O_APPEND` even if it is not specified. 133 | 134 | ```C 135 | int fd = NIFFS_open(fs, "linearfile", NIFFS_O_WRONLY, 0); 136 | // NIFFS_O_LINEAR not needed, and NIFFS_O_APPEND is set under the hood 137 | ``` 138 | 139 | Seeking, reading, writing, statting, and removing works just like any other file. 140 | 141 | Again, with the exception that writing is only by append. 142 | 143 | **This will not work as expected:** 144 | ```C 145 | // THIS WILL NOT WORK AS EXPECTED 146 | int fd = NIFFS_open(fs, "linearfile", NIFFS_O_WRONLY, 0); 147 | // get file size 148 | int size = NIFFS_lseek(fs, fd, 0, NIFFS_SEEK_END); 149 | // position us in the middle of file 150 | int res = NIFFS_lseek(fs, fd, size/2, NIFFS_SEEK_SET); 151 | // WILL BE WRITTEN TO END OF FILE 152 | res = NIFFS_write(fs, fd, data, len); 153 | ``` 154 | 155 | ## Knowing if a file is linear or not 156 | By `NIFFS_stat`, `NIFFS_fstat`, and `NIFFS_readdir` you check the `type` member of these structs. 157 | 158 | ## When are linear sectors erased? 159 | They are erased on a format, and when overwritten. 160 | 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # niffs 2 | Embedded NOR internal flash file system 3 | 4 | [![Build Status](https://travis-ci.org/pellepl/niffs.svg?branch=master)](https://travis-ci.org/pellepl/niffs) 5 | 6 | Under construction 7 | -------------------------------------------------------------------------------- /files.mk: -------------------------------------------------------------------------------- 1 | ifndef niffs 2 | $(warn defaulting path to generic niffs module, niffs variable not set) 3 | niffs = ../generic/niffs 4 | endif 5 | FLAGS += -DCONFIG_BUILD_NIFFS 6 | INC += -I${niffs}/src 7 | CPATH += ${niffs}/src 8 | CFILES += niffs_api.c 9 | CFILES += niffs_internal.c 10 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | BINARY = linux_niffs_test 2 | 3 | ############ 4 | # 5 | # Paths 6 | # 7 | ############ 8 | 9 | sourcedir = src 10 | builddir = build 11 | 12 | 13 | MKDIR = mkdir -p 14 | 15 | ############### 16 | # 17 | # Files and libs 18 | # 19 | ############### 20 | 21 | CFILES = niffs_internal.c \ 22 | niffs_api.c 23 | 24 | CFILES_TEST = main.c \ 25 | niffs_test_emul.c \ 26 | niffs_cfg_tests.c \ 27 | niffs_func_tests.c \ 28 | niffs_sys_tests.c \ 29 | niffs_run_tests.c \ 30 | testsuites.c \ 31 | testrunner.c 32 | 33 | INCLUDE_DIRECTIVES = -I./${sourcedir} -I./${sourcedir}/default -I./${sourcedir}/test 34 | CFLAGS_ALL = $(INCLUDE_DIRECTIVES) -DNIFFS_TEST_MAKE 35 | CFLAGS = $(CFLAGS_ALL) -fprofile-arcs -ftest-coverage 36 | COMPILEROPTIONS_EXTRA = -Wall \ 37 | -Wall -Wno-format-y2k -W -Wstrict-prototypes -Wmissing-prototypes \ 38 | -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch \ 39 | -Wshadow -Wcast-align -Wchar-subscripts -Winline -Wnested-externs\ 40 | -Wredundant-decls 41 | 42 | # address sanitization 43 | CFLAGS += -fsanitize=address 44 | LFLAGS += -fsanitize=address -fno-omit-frame-pointer -O 45 | LIBS += -lasan 46 | 47 | ############ 48 | # 49 | # Tasks 50 | # 51 | ############ 52 | 53 | vpath %.c ${sourcedir} ${sourcedir}/default ${sourcedir}/test 54 | 55 | OBJFILES_TEST = $(CFILES_TEST:%.c=${builddir}/%.o) 56 | 57 | DEPFILES_TEST = $(CFILES_TEST:%.c=${builddir}/%.d) 58 | 59 | OBJFILES = $(CFILES:%.c=${builddir}/%.o) 60 | 61 | DEPFILES = $(CFILES:%.c=${builddir}/%.d) 62 | 63 | ALLOBJFILES += $(OBJFILES) $(OBJFILES_TEST) 64 | 65 | DEPENDENCIES = $(DEPFILES) $(DEPFILES_TEST) 66 | 67 | # link object files, create binary 68 | ${builddir}/$(BINARY): $(ALLOBJFILES) 69 | @echo "... linking" 70 | @$(CC) $(CFLAGS) $(LINKEROPTIONS) $(LFLAGS) -o ${builddir}/$(BINARY) $(ALLOBJFILES) $(LIBS) 71 | 72 | ifneq ($(MAKECMDGOALS),clean) 73 | -include $(DEPENDENCIES) 74 | endif 75 | 76 | # compile c files test 77 | $(OBJFILES_TEST) : ${builddir}/%.o:%.c 78 | @echo "... compile $@" 79 | @$(MKDIR) $(@D) 80 | @$(CC) $(CFLAGS_ALL) -g -c -o $@ $< 81 | 82 | # make dependencies 83 | $(DEPFILES_TEST) : ${builddir}/%.d:%.c 84 | @echo "... depend $@"; \ 85 | $(RM) $@; \ 86 | $(MKDIR) $(@D); \ 87 | $(CC) $(CFLAGS_ALL) -M $< > $@.$$$$; \ 88 | sed 's,\($*\)\.o[ :]*, ${builddir}/\1.o $@ : ,g' < $@.$$$$ > $@; \ 89 | $(RM) $@.$$$$ 90 | 91 | # compile c files 92 | $(OBJFILES) : ${builddir}/%.o:%.c 93 | @echo "... compile $@" 94 | @$(MKDIR) $(@D) 95 | @$(CC) $(CFLAGS) $(COMPILEROPTIONS_EXTRA) -g -c -o $@ $< 96 | 97 | # make dependencies test 98 | $(DEPFILES) : ${builddir}/%.d:%.c 99 | @echo "... depend $@"; \ 100 | $(RM) $@; \ 101 | $(MKDIR) $(@D); \ 102 | $(CC) $(CFLAGS) -M $< > $@.$$$$; \ 103 | sed 's,\($*\)\.o[ :]*, ${builddir}/\1.o $@ : ,g' < $@.$$$$ > $@; \ 104 | $(RM) $@.$$$$ 105 | 106 | all: $(BINARY) test 107 | 108 | FILTER ?= 109 | 110 | test: ${builddir}/$(BINARY) 111 | ifdef $(FILTER) 112 | ${builddir}/$(BINARY) 113 | else 114 | ${builddir}//$(BINARY) -f $(FILTER) 115 | endif 116 | @for cfile in $(CFILES); do \ 117 | gcov -o ${builddir} ${src}/$$cfile | \ 118 | sed -nr "1 s/File '(.*)'/\1/p;2 s/Lines executed:(.*)/: \1 lines/p" | \ 119 | sed 'N;s/\n/ /'; \ 120 | done 121 | 122 | test-failed: ${builddir}/$(BINARY) 123 | ${builddir}/$(BINARY) _tests_fail 124 | 125 | clean: 126 | @echo ... clean 127 | @$(RM) -r ${builddir} 128 | @$(RM) *.gcov 129 | -------------------------------------------------------------------------------- /src/default/niffs_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_config.h 3 | * 4 | * Created on: Feb 3, 2015 5 | * Author: petera 6 | */ 7 | 8 | #ifndef NIFFS_CONFIG_H_ 9 | #define NIFFS_CONFIG_H_ 10 | 11 | #ifdef NIFFS_TEST_MAKE 12 | #include "niffs_test_config.h" 13 | #endif 14 | 15 | // enable this define to configure for an STM32F1 target 16 | //#define NIFFS_STM32F1 17 | 18 | #ifdef NIFFS_STM32F1 19 | #define NIFFS_WORD_ALIGN (2) 20 | #define NIFFS_TYPE_PAGE_FLAG_SIZE u16_t 21 | #endif 22 | 23 | // for testing 24 | #ifndef TESTATIC 25 | #define TESTATIC static 26 | #endif 27 | 28 | // define for getting niffs debug output 29 | #ifndef NIFFS_DBG 30 | #define NIFFS_DBG(_f, ...) 31 | #endif 32 | 33 | // define NIFFS_DUMP to be able to visualize filesystem with NIFFS_dump 34 | //#define NIFFS_DUMP 35 | #ifdef NIFFS_DUMP 36 | #ifndef NIFFS_DUMP_OUT 37 | // used to output in NIFFS_dump 38 | #define NIFFS_DUMP_OUT(_f, ...) 39 | #endif 40 | #endif 41 | 42 | // max macro 43 | #ifndef NIFFS_MAX 44 | #define NIFFS_MAX(x, y) (x) > (y) ? (x) : (y) 45 | #endif 46 | 47 | // min macro 48 | #ifndef NIFFS_MIN 49 | #define NIFFS_MIN(x, y) (x) < (y) ? (x) : (y) 50 | #endif 51 | 52 | // define for assertions within niffs 53 | #ifndef NIFFS_ASSERT 54 | #define NIFFS_ASSERT(x) 55 | #endif 56 | 57 | // define maximum name length 58 | #ifndef NIFFS_NAME_LEN 59 | #define NIFFS_NAME_LEN (16) 60 | #endif 61 | 62 | // Enable or disable linear area features. 63 | // Files in the linear area are not divided by page headers but are linear on 64 | // medium. To create a linear file, pass NIFFS_O_CREAT and NIFFS_O_CREAT_LINEAR 65 | // when creating the file with open. 66 | // To have more control over the linear file, NIFFS_mknod_linear can also be 67 | // called, see corresponding function for more info. 68 | // The linear area is not wear leveled. Once a linear file is deleted, 69 | // corresponding sectors are immediately erased. 70 | // This implies that each linear file will at least occupy one sector, even if 71 | // the size is 0. 72 | // Linear files can only be appended, never modified. Defragmentation of the 73 | // linear area is up to the user. 74 | #ifndef NIFFS_LINEAR_AREA 75 | #define NIFFS_LINEAR_AREA (1) 76 | #endif 77 | 78 | // define number of bits used for object ids, used for uniquely identify a file 79 | #ifndef NIFFS_OBJ_ID_BITS 80 | #define NIFFS_OBJ_ID_BITS (8) 81 | #endif 82 | 83 | // define number of bits used for span indices, used for uniquely identify part of a file 84 | #ifndef NIFFS_SPAN_IX_BITS 85 | #define NIFFS_SPAN_IX_BITS (8) 86 | #endif 87 | 88 | // word align for target flash, e.g. stm32f1 can only write 16-bit words at a time 89 | #ifndef NIFFS_WORD_ALIGN 90 | #define NIFFS_WORD_ALIGN (1) 91 | #endif 92 | 93 | // garbage collection uses a score system to select sector to erase: 94 | // sector_score = sector_erase_difference * F1 + free_pages * F2 + deleted_pages * F3 + busy_pages * F4 95 | // sector with highest score is selected for garbage collection 96 | 97 | // F1: garbage collection score factor for sector erase difference 98 | #ifndef NIFFS_GC_SCORE_ERASE_CNT_DIFF 99 | #define NIFFS_GC_SCORE_ERASE_CNT_DIFF (100) 100 | #endif 101 | // F2: garbage collection score factor for percentage of free pages in sector 102 | #ifndef NIFFS_GC_SCORE_FREE 103 | #define NIFFS_GC_SCORE_FREE (-4) 104 | #endif 105 | // F3: garbage collection score factor for percentage of deleted pages in sector 106 | #ifndef NIFFS_GC_SCORE_DELE 107 | #define NIFFS_GC_SCORE_DELE (2) 108 | #endif 109 | // F4: garbage collection score factor for percentage of busy/written pages in sector 110 | #ifndef NIFFS_GC_SCORE_BUSY 111 | #define NIFFS_GC_SCORE_BUSY (-2) 112 | #endif 113 | 114 | // formula for selecting sector to garbage collect 115 | // free, dele and busy is the percentage (0-99) of each type 116 | #ifndef NIFFS_GC_SCORE 117 | #define NIFFS_GC_SCORE(era_cnt_diff, free, dele, busy) \ 118 | ((era_cnt_diff) * NIFFS_GC_SCORE_ERASE_CNT_DIFF) + \ 119 | ((free) * NIFFS_GC_SCORE_FREE) + \ 120 | ((dele) * NIFFS_GC_SCORE_DELE) + \ 121 | ((busy) * NIFFS_GC_SCORE_BUSY) 122 | #endif 123 | 124 | // type sizes, depend of the size of the filesystem and the size of the pages 125 | 126 | // must comprise NIFFS_OBJ_ID_BITS 127 | #ifndef NIFFS_TYPE_OBJ_ID_SIZE 128 | #define NIFFS_TYPE_OBJ_ID_SIZE u8_t 129 | #endif 130 | 131 | // must comprise NIFFS_SPAN_IX_BITS 132 | #ifndef NIFFS_TYPE_SPAN_IX_SIZE 133 | #define NIFFS_TYPE_SPAN_IX_SIZE u8_t 134 | #endif 135 | 136 | // must comprise (NIFFS_OBJ_ID_BITS + NIFFS_SPAN_IX_BITS) 137 | #ifndef NIFFS_TYPE_RAW_PAGE_ID_SIZE 138 | #define NIFFS_TYPE_RAW_PAGE_ID_SIZE u16_t 139 | #endif 140 | 141 | // must uniquely address all pages 142 | #ifndef NIFFS_TYPE_PAGE_IX_SIZE 143 | #define NIFFS_TYPE_PAGE_IX_SIZE u16_t 144 | #endif 145 | 146 | // magic bits, must be sized on alignment, NIFFS_WORD_ALIGN 147 | #ifndef NIFFS_TYPE_MAGIC_SIZE 148 | #define NIFFS_TYPE_MAGIC_SIZE u16_t 149 | #endif 150 | 151 | // sector erase counter, must be sized on alignment, NIFFS_WORD_ALIGN 152 | #ifndef NIFFS_TYPE_ERASE_COUNT_SIZE 153 | #define NIFFS_TYPE_ERASE_COUNT_SIZE u16_t 154 | #endif 155 | 156 | // page flag, 3 values, must be sized on alignment, NIFFS_WORD_ALIGN 157 | #ifndef NIFFS_TYPE_PAGE_FLAG_SIZE 158 | #define NIFFS_TYPE_PAGE_FLAG_SIZE u8_t 159 | #endif 160 | 161 | typedef NIFFS_TYPE_OBJ_ID_SIZE niffs_obj_id; 162 | typedef NIFFS_TYPE_SPAN_IX_SIZE niffs_span_ix; 163 | typedef NIFFS_TYPE_RAW_PAGE_ID_SIZE niffs_page_id_raw; 164 | typedef NIFFS_TYPE_PAGE_IX_SIZE niffs_page_ix; 165 | typedef NIFFS_TYPE_MAGIC_SIZE niffs_magic; 166 | typedef NIFFS_TYPE_ERASE_COUNT_SIZE niffs_erase_cnt; 167 | typedef NIFFS_TYPE_PAGE_FLAG_SIZE niffs_flag; 168 | 169 | #endif /* NIFFS_CONFIG_H_ */ 170 | -------------------------------------------------------------------------------- /src/niffs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs.h 3 | * 4 | * Created on: Feb 2, 2015 5 | * Author: petera 6 | */ 7 | 8 | #ifndef NIFFS_H_ 9 | #define NIFFS_H_ 10 | 11 | #include "niffs_config.h" 12 | 13 | #define NIFFS_SEEK_SET (0) 14 | #define NIFFS_SEEK_CUR (1) 15 | #define NIFFS_SEEK_END (2) 16 | 17 | /* Any write to the filehandle is appended to end of the file */ 18 | #define NIFFS_O_APPEND (1<<0) 19 | /* If the opened file exists, it will be truncated to zero length before opened */ 20 | #define NIFFS_O_TRUNC (1<<1) 21 | /* If the opened file does not exist, it will be created before opened */ 22 | #define NIFFS_O_CREAT (1<<2) 23 | /* The opened file may only be read */ 24 | #define NIFFS_O_RDONLY (1<<3) 25 | /* The opened file may only be writted */ 26 | #define NIFFS_O_WRONLY (1<<4) 27 | /* The opened file may be both read and written */ 28 | #define NIFFS_O_RDWR (NIFFS_O_RDONLY | NIFFS_O_WRONLY) 29 | /* Any writes to the filehandle will never be cached */ 30 | #define NIFFS_O_DIRECT (1<<5) 31 | /* If O_CREAT and O_EXCL are set, open() fails if the file exists. */ 32 | #define NIFFS_O_EXCL (1<<6) 33 | /* If O_CREAT and O_LINEAR is enabled, along with config NIFFS_LINEAR_AREA, 34 | the created file will be put in the linear area */ 35 | #define NIFFS_O_LINEAR (1<<7) 36 | 37 | #ifndef NIFFS_ERR_BASE 38 | #define NIFFS_ERR_BASE (11000) 39 | #endif 40 | 41 | #define NIFFS_OK 0 42 | #define ERR_NIFFS_BAD_CONF -(NIFFS_ERR_BASE + 1) 43 | #define ERR_NIFFS_NOT_A_FILESYSTEM -(NIFFS_ERR_BASE + 2) 44 | #define ERR_NIFFS_BAD_SECTOR -(NIFFS_ERR_BASE + 3) 45 | #define ERR_NIFFS_DELETING_FREE_PAGE -(NIFFS_ERR_BASE + 4) 46 | #define ERR_NIFFS_DELETING_DELETED_PAGE -(NIFFS_ERR_BASE + 5) 47 | #define ERR_NIFFS_MOVING_FREE_PAGE -(NIFFS_ERR_BASE + 6) 48 | #define ERR_NIFFS_MOVING_DELETED_PAGE -(NIFFS_ERR_BASE + 7) 49 | #define ERR_NIFFS_MOVING_TO_UNFREE_PAGE -(NIFFS_ERR_BASE + 8) 50 | #define ERR_NIFFS_MOVING_TO_SAME_PAGE -(NIFFS_ERR_BASE + 9) 51 | #define ERR_NIFFS_MOVING_BAD_FLAG -(NIFFS_ERR_BASE + 10) 52 | #define ERR_NIFFS_NO_FREE_PAGE -(NIFFS_ERR_BASE + 11) 53 | #define ERR_NIFFS_SECTOR_UNFORMATTABLE -(NIFFS_ERR_BASE + 12) 54 | #define ERR_NIFFS_NULL_PTR -(NIFFS_ERR_BASE + 13) 55 | #define ERR_NIFFS_NO_FREE_ID -(NIFFS_ERR_BASE + 14) 56 | #define ERR_NIFFS_WR_PHDR_UNFREE_PAGE -(NIFFS_ERR_BASE + 15) 57 | #define ERR_NIFFS_WR_PHDR_BAD_ID -(NIFFS_ERR_BASE + 16) 58 | #define ERR_NIFFS_NAME_CONFLICT -(NIFFS_ERR_BASE + 17) 59 | #define ERR_NIFFS_FULL -(NIFFS_ERR_BASE + 18) 60 | #define ERR_NIFFS_OUT_OF_FILEDESCS -(NIFFS_ERR_BASE + 19) 61 | #define ERR_NIFFS_FILE_NOT_FOUND -(NIFFS_ERR_BASE + 20) 62 | #define ERR_NIFFS_FILEDESC_CLOSED -(NIFFS_ERR_BASE + 21) 63 | #define ERR_NIFFS_FILEDESC_BAD -(NIFFS_ERR_BASE + 22) 64 | #define ERR_NIFFS_INCOHERENT_ID -(NIFFS_ERR_BASE + 23) 65 | #define ERR_NIFFS_PAGE_NOT_FOUND -(NIFFS_ERR_BASE + 24) 66 | #define ERR_NIFFS_END_OF_FILE -(NIFFS_ERR_BASE + 25) 67 | #define ERR_NIFFS_MODIFY_BEYOND_FILE -(NIFFS_ERR_BASE + 26) 68 | #define ERR_NIFFS_TRUNCATE_BEYOND_FILE -(NIFFS_ERR_BASE + 27) 69 | #define ERR_NIFFS_NO_GC_CANDIDATE -(NIFFS_ERR_BASE + 28) 70 | #define ERR_NIFFS_PAGE_DELETED -(NIFFS_ERR_BASE + 29) 71 | #define ERR_NIFFS_PAGE_FREE -(NIFFS_ERR_BASE + 30) 72 | #define ERR_NIFFS_MOUNTED -(NIFFS_ERR_BASE + 31) 73 | #define ERR_NIFFS_NOT_MOUNTED -(NIFFS_ERR_BASE + 32) 74 | #define ERR_NIFFS_NOT_WRITABLE -(NIFFS_ERR_BASE + 33) 75 | #define ERR_NIFFS_NOT_READABLE -(NIFFS_ERR_BASE + 34) 76 | #define ERR_NIFFS_FILE_EXISTS -(NIFFS_ERR_BASE + 35) 77 | #define ERR_NIFFS_OVERFLOW -(NIFFS_ERR_BASE + 36) 78 | #define ERR_NIFFS_LINEAR_FILE -(NIFFS_ERR_BASE + 37) 79 | #define ERR_NIFFS_LINEAR_NO_SPACE -(NIFFS_ERR_BASE + 38) 80 | 81 | typedef int (* niffs_hal_erase_f)(u8_t *addr, u32_t len); 82 | typedef int (* niffs_hal_write_f)(u8_t *addr, const u8_t *src, u32_t len); 83 | // dummy type, for posix compliance 84 | typedef u16_t niffs_mode; 85 | // niffs file descriptor flags 86 | typedef u8_t niffs_fd_flags; 87 | // niffs file type 88 | typedef u8_t niffs_file_type; 89 | 90 | /* file descriptor */ 91 | typedef struct { 92 | // object id 93 | niffs_obj_id obj_id; 94 | // page index for object index 95 | niffs_page_ix obj_pix; 96 | // file type 97 | niffs_file_type type; 98 | // file descriptor offset 99 | u32_t offs; 100 | // page index for current file desc offset 101 | niffs_page_ix cur_pix; 102 | // file descriptor flags 103 | niffs_fd_flags flags; 104 | } niffs_file_desc; 105 | 106 | /* fs struct */ 107 | typedef struct { 108 | /* static cfg */ 109 | // physical address where fs resides 110 | u8_t *phys_addr; 111 | // number of logical sectors 112 | u32_t sectors; 113 | // logical sector size in bytes 114 | u32_t sector_size; 115 | // logical page size in bytes 116 | u32_t page_size; 117 | #if NIFFS_LINEAR_AREA 118 | // number of linear sectors 119 | u32_t lin_sectors; 120 | #endif 121 | 122 | // work buffer 123 | u8_t *buf; 124 | // work buffer length 125 | u32_t buf_len; 126 | 127 | // HAL write function 128 | niffs_hal_write_f hal_wr; 129 | // HAL erase function 130 | niffs_hal_erase_f hal_er; 131 | 132 | /* dynamics */ 133 | // pages per sector 134 | u32_t pages_per_sector; 135 | // last seen free page index 136 | niffs_page_ix last_free_pix; 137 | // whether mounted or not 138 | u8_t mounted; 139 | // number of free pages 140 | u32_t free_pages; 141 | // number of deleted pages 142 | u32_t dele_pages; 143 | // file descriptor array 144 | niffs_file_desc *descs; 145 | // number of file descriptors 146 | u32_t descs_len; 147 | // max erase count 148 | niffs_erase_cnt max_era; 149 | } niffs; 150 | 151 | /* niffs file status struct */ 152 | typedef struct { 153 | // file object id 154 | niffs_obj_id obj_id; 155 | // file size 156 | u32_t size; 157 | // file name 158 | u8_t name[NIFFS_NAME_LEN]; 159 | // file type 160 | niffs_file_type type; 161 | } niffs_stat; 162 | 163 | /* niffs file directory entry struct */ 164 | struct niffs_dirent { 165 | // file object id 166 | niffs_obj_id obj_id; 167 | // file name 168 | u8_t name[NIFFS_NAME_LEN]; 169 | // file size 170 | u32_t size; 171 | // file index header whereabouts 172 | niffs_page_ix pix; 173 | // file type 174 | niffs_file_type type; 175 | }; 176 | 177 | /* niffs file directory struct */ 178 | typedef struct { 179 | // the actual fs 180 | niffs *fs; 181 | // current search page index 182 | niffs_page_ix pix; 183 | } niffs_DIR; 184 | 185 | /* niffs fs info struct */ 186 | typedef struct { 187 | /* total amount of bytes in filesystem (linear parts excluded) */ 188 | s32_t total_bytes; 189 | /* used bytes in filesystem (linear parts excluded) */ 190 | s32_t used_bytes; 191 | /* If non-zero, this means you should delete some files and run a check. 192 | This can happen if filesystem loses power repeatedly during 193 | garbage collection or check. */ 194 | u8_t overflow; 195 | 196 | /* total amount of sectors in the linear part of filesystem */ 197 | s32_t lin_total_sectors; 198 | /* used sectors in the linear part of filesystem */ 199 | s32_t lin_used_sectors; 200 | /* maximum free consecutive area in the linear part of filesystem */ 201 | s32_t lin_max_conseq_free; 202 | } niffs_info; 203 | 204 | /** 205 | * Initializes and configures the file system. 206 | * The file system needs a ram work buffer being at least a logical page size 207 | * big. In some cases, this needs to be extended. NIFFS will return 208 | * ERR_NIFFS_BAD_CONF on bad configurations. If NIFFS_DBG is enabled, a 209 | * descriptive message will also tell you what's wrong. 210 | * 211 | * @param fs the file system struct 212 | * @param phys_addr the starting address of the filesystem on flash 213 | * @param sectors number of sectors comprised by the filesystem 214 | * @param sector_size logical sector size 215 | * @param page_size logical page size 216 | * @param buf ram work buffer 217 | * @param buf_len ram work buffer length 218 | * @param descs ram file descriptor buffer 219 | * @param file_desc_len number of file descriptors in buffer 220 | * @param erase_f HAL erase function 221 | * @param write_f HAL write function 222 | * @param lin_sectors Ignored if NIFFS_LINEAR_AREA is 0. Otherwise, allocates 223 | * lin_sectors of space for the linear area. This space 224 | * will be allotted after the dynamic fs. 225 | */ 226 | int NIFFS_init(niffs *fs, 227 | u8_t *phys_addr, 228 | u32_t sectors, 229 | u32_t sector_size, 230 | u32_t page_size, 231 | u8_t *buf, 232 | u32_t buf_len, 233 | niffs_file_desc *descs, 234 | u32_t file_desc_len, 235 | niffs_hal_erase_f erase_f, 236 | niffs_hal_write_f write_f, 237 | u32_t lin_sectors 238 | ); 239 | 240 | /** 241 | * Mounts the filesystem 242 | * @param fs the file system struct 243 | */ 244 | int NIFFS_mount(niffs *fs); 245 | 246 | /** 247 | * Returns some general info 248 | * @param fs the file system struct 249 | * @param total will be populated with total amount of bytes in filesystem 250 | * @param used will be populated with used bytes in filesystem 251 | * @param overflow if !0, this means you should delete some files and run a check. 252 | * This can happen if filesystem loses power repeatedly during 253 | * garbage collection or check. 254 | */ 255 | int NIFFS_info(niffs *fs, niffs_info *i); 256 | 257 | /** 258 | * Creates a new file. 259 | * @param fs the file system struct 260 | * @param name the name of the new file 261 | * @param mode ignored, for posix compliance 262 | */ 263 | int NIFFS_creat(niffs *fs, const char *name, niffs_mode mode); 264 | 265 | #if NIFFS_LINEAR_AREA 266 | /** 267 | * Creates a new file in the linear area. 268 | * @param fs the file system struct 269 | * @param name the name of the new file 270 | * @param resv_size Hint to the filesystem how large this file will be in 271 | * bytes. May be 0 if not known. 272 | * As linear files cannot be chunked up by pages, they 273 | * will be placed after each other on medium. For example, 274 | * when creating linear file A it will be placed on 275 | * sector x. If creating linear file B directly afterwards, 276 | * B will be placed on sector x+1. This constricts file A 277 | * to grow one sector only. However, if A is created with 278 | * resv_size of 10 sectors, B will be created on sector 279 | * x+10, giving A room to grow 10 sectors instead. 280 | * @return file descriptor with flags O_LINEAR | O_RDWR | O_APPEND or error 281 | */ 282 | int NIFFS_mknod_linear(niffs *fs, const char *name, u32_t resv_size); 283 | #endif 284 | 285 | /** 286 | * Opens/creates a file. 287 | * @param fs the file system struct 288 | * @param path the path of the new file 289 | * @param flags the flags for the open command, can be combinations of 290 | * NIFFS_O_APPEND, NIFFS_O_TRUNC, NIFFS_O_CREAT, NIFFS_O_RDONLY, 291 | * NIFFS_O_WRONLY, NIFFS_O_RDWR, NIFFS_O_DIRECT, NIFFS_O_LINEAR 292 | * @param mode ignored, for posix compliance 293 | * @return file descriptor or error 294 | * 295 | * Note: when creating files with NIFFS_O_LINEAR, NIFFS_O_APPEND is 296 | * automatically set. Linear files cannot be modified, only appended. 297 | */ 298 | int NIFFS_open(niffs *fs, const char *name, u8_t flags, niffs_mode mode); 299 | 300 | /** 301 | * Returns a pointer directly to the flash where data resides, and how many 302 | * bytes which can be read. 303 | * This function does not advance the file descriptor offset, so NIFFS_lseek 304 | * should be called prior to NIFFS_read_ptr. 305 | * @param fs the file system struct 306 | * @param fd the filehandle 307 | * @param ptr ptr which is populated with adress to data 308 | * @param len populated with valid data length 309 | */ 310 | int NIFFS_read_ptr(niffs *fs, int fd, u8_t **ptr, u32_t *len); 311 | 312 | /** 313 | * Reads from given filehandle. 314 | * NB: consider using NIFFS_read_ptr instead. This will basically copy from your 315 | * internal flash to your ram. If you're only interested in reading data and not 316 | * modifying it, this will basically waste cycles and ram on memcpy. 317 | * @param fs the file system struct 318 | * @param fd the filehandle 319 | * @param buf where to put read data 320 | * @param len how much to read 321 | * @returns number of bytes read, or error 322 | */ 323 | int NIFFS_read(niffs *fs, int fd, u8_t *dst, u32_t len); 324 | 325 | /** 326 | * Moves the read/write file offset 327 | * @param fs the file system struct 328 | * @param fh the filehandle 329 | * @param offs how much/where to move the offset 330 | * @param whence if NIFFS_SEEK_SET, the file offset shall be set to offset bytes 331 | * if NIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset 332 | * if NIFFS_SEEK_END, the file offset shall be set to the size of the file plus offset 333 | */ 334 | int NIFFS_lseek(niffs *fs, int fd, s32_t offs, int whence); 335 | 336 | /** 337 | * Removes a file by name 338 | * @param fs the file system struct 339 | * @param name the name of the file to remove 340 | */ 341 | int NIFFS_remove(niffs *fs, const char *name); 342 | 343 | /** 344 | * Removes a file by filehandle 345 | * @param fs the file system struct 346 | * @param fd the filehandle of the file to remove 347 | */ 348 | int NIFFS_fremove(niffs *fs, int fd); 349 | 350 | /** 351 | * Writes to given filehandle. 352 | * @param fs the file system struct 353 | * @param fd the filehandle 354 | * @param buf the data to write 355 | * @param len how much to write 356 | * @returns number of bytes written or error 357 | */ 358 | int NIFFS_write(niffs *fs, int fd, const u8_t *data, u32_t len); 359 | 360 | /** 361 | * Flushes all pending write operations from cache for given file 362 | * @param fs the file system struct 363 | * @param fd the filehandle of the file to flush 364 | */ 365 | int NIFFS_fflush(niffs *fs, int fd); 366 | 367 | /** 368 | * Gets file status by name 369 | * @param fs the file system struct 370 | * @param path the name of the file to stat 371 | * @param s the stat struct to populate 372 | */ 373 | int NIFFS_stat(niffs *fs, const char *name, niffs_stat *s); 374 | 375 | /** 376 | * Gets file status by filehandle 377 | * @param fs the file system struct 378 | * @param fd the filehandle of the file to stat 379 | * @param s the stat struct to populate 380 | */ 381 | int NIFFS_fstat(niffs *fs, int fd, niffs_stat *s); 382 | 383 | /** 384 | * Gets current position in stream 385 | * @param fs the file system struct 386 | * @param fd the filehandle of the file to return position from 387 | */ 388 | int NIFFS_ftell(niffs *fs, int fd); 389 | 390 | /** 391 | * Closes a filehandle. If there are pending write operations, these are finalized before closing. 392 | * @param fs the file system struct 393 | * @param fd the filehandle of the file to close 394 | */ 395 | int NIFFS_close(niffs *fs, int fd); 396 | 397 | /** 398 | * Renames a file. 399 | * @param fs the file system struct 400 | * @param old name of file to rename 401 | * @param new new name of file 402 | */ 403 | int NIFFS_rename(niffs *fs, const char *old_name, const char *new_name); 404 | 405 | /** 406 | * Opens a directory stream corresponding to the given name. 407 | * The stream is positioned at the first entry in the directory. 408 | * The name argument is ignored as hydrogen builds always correspond 409 | * to a flat file structure - no directories. 410 | * @param fs the file system struct 411 | * @param name the name of the directory 412 | * @param d pointer the directory stream to be populated 413 | */ 414 | niffs_DIR *NIFFS_opendir(niffs *fs, const char *name, niffs_DIR *d); 415 | 416 | /** 417 | * Closes a directory stream 418 | * @param d the directory stream to close 419 | */ 420 | int NIFFS_closedir(niffs_DIR *d); 421 | 422 | /** 423 | * Reads a directory into given niffs_dirent struct. 424 | * @param d pointer to the directory stream 425 | * @param e the dirent struct to be populated 426 | * @returns null if error or end of stream, else given dirent is returned 427 | */ 428 | struct niffs_dirent *NIFFS_readdir(niffs_DIR *d, struct niffs_dirent *e); 429 | 430 | /** 431 | * Unmounts the file system. All file handles will be flushed of any 432 | * cached writes and closed. 433 | * @param fs the file system struct 434 | */ 435 | int NIFFS_unmount(niffs *fs); 436 | 437 | /** 438 | * Formats the entire filesystem. 439 | * @param fs the file system struct 440 | */ 441 | int NIFFS_format(niffs *fs); 442 | 443 | /** 444 | * Runs a consistency check on given filesystem and mends any aborted operations. 445 | * @param fs the file system struct 446 | */ 447 | int NIFFS_chk(niffs *fs); 448 | 449 | #ifdef NIFFS_DUMP 450 | /** 451 | * Prints out a visualization of the filesystem. 452 | * @param fs the file system struct 453 | */ 454 | void NIFFS_dump(niffs *fs); 455 | #endif 456 | 457 | #endif /* NIFFS_H_ */ 458 | -------------------------------------------------------------------------------- /src/niffs_api.c: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_api.c 3 | * 4 | * Created on: Feb 22, 2015 5 | * Author: petera 6 | */ 7 | 8 | #include "niffs.h" 9 | #include "niffs_internal.h" 10 | 11 | int NIFFS_info(niffs *fs, niffs_info *i) { 12 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 13 | if (i == 0) return ERR_NIFFS_NULL_PTR; 14 | 15 | i->total_bytes = (fs->sectors-1) * fs->pages_per_sector * _NIFFS_SPIX_2_PDATA_LEN(fs, 1); 16 | i->used_bytes = ((fs->sectors) * fs->pages_per_sector - (fs->free_pages + fs->dele_pages)) * _NIFFS_SPIX_2_PDATA_LEN(fs, 1); 17 | i->overflow = fs->free_pages < fs->pages_per_sector; 18 | 19 | #if NIFFS_LINEAR_AREA 20 | i->lin_total_sectors = fs->lin_sectors; 21 | i->lin_used_sectors = 0; 22 | int res = niffs_linear_map(fs); 23 | if (res) return res; 24 | u32_t lsix; 25 | u32_t max_conseq_free = 0; 26 | u32_t cur_conseq_free = 0; 27 | u8_t taken = 1; 28 | for (lsix = 0; lsix < fs->lin_sectors; lsix++) { 29 | if ((fs->buf[lsix/8] & (1<<(lsix&7)))) { 30 | i->lin_used_sectors++; 31 | cur_conseq_free = 0; 32 | taken = 1; 33 | } else { 34 | cur_conseq_free++; 35 | if (taken) taken = 0; 36 | max_conseq_free = NIFFS_MAX(cur_conseq_free, max_conseq_free); 37 | } 38 | } 39 | i->lin_max_conseq_free = max_conseq_free; 40 | #endif 41 | return NIFFS_OK; 42 | } 43 | 44 | 45 | int NIFFS_creat(niffs *fs, const char *name, niffs_mode mode) { 46 | (void)mode; 47 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 48 | int res; 49 | res = niffs_create(fs, name, _NIFFS_FTYPE_FILE, 0); 50 | return res; 51 | } 52 | 53 | int NIFFS_open(niffs *fs, const char *name, u8_t flags, niffs_mode mode) { 54 | (void)mode; 55 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 56 | int res = NIFFS_OK; 57 | niffs_file_type type = 58 | flags & NIFFS_O_LINEAR ? _NIFFS_FTYPE_LINFILE : _NIFFS_FTYPE_FILE; 59 | #if !NIFFS_LINEAR_AREA 60 | if (type == _NIFFS_FTYPE_LINFILE) return ERR_NIFFS_BAD_CONF; 61 | #endif 62 | if (type) { 63 | flags |= NIFFS_O_APPEND; // force append for linear files 64 | } 65 | int fd_ix = niffs_open(fs, name, flags); 66 | if (fd_ix < 0) { 67 | // file not found 68 | if (fd_ix == ERR_NIFFS_FILE_NOT_FOUND && (flags & NIFFS_O_CREAT)) { 69 | res = niffs_create(fs, name, type, 0); 70 | if (res == NIFFS_OK) { 71 | fd_ix = niffs_open(fs, name, flags); 72 | } else { 73 | fd_ix = res; 74 | } 75 | } 76 | res = fd_ix; 77 | } else { 78 | // file found 79 | if ((flags & (NIFFS_O_CREAT | NIFFS_O_EXCL)) == (NIFFS_O_CREAT | NIFFS_O_EXCL)) { 80 | (void)niffs_close(fs, fd_ix); 81 | return ERR_NIFFS_FILE_EXISTS; 82 | } 83 | } 84 | 85 | if (res != NIFFS_OK) return res; 86 | 87 | if (flags & NIFFS_O_TRUNC) { 88 | niffs_file_desc *fd; 89 | res = niffs_get_filedesc(fs, fd_ix, &fd); 90 | if (res != NIFFS_OK) return res; 91 | niffs_object_hdr *ohdr = (niffs_object_hdr *)_NIFFS_PIX_2_ADDR(fs, fd->obj_pix); 92 | if (ohdr->len != NIFFS_UNDEF_LEN) { 93 | // only truncate if file len is > 0 94 | res = niffs_truncate(fs, fd_ix, 0); 95 | if (res != NIFFS_OK) { 96 | (void)niffs_close(fs, fd_ix); 97 | return res; 98 | } 99 | res = niffs_create(fs, name, type, 0); 100 | if (res != NIFFS_OK) return res; 101 | fd_ix = niffs_open(fs, name, flags); 102 | } 103 | } 104 | 105 | return res < 0 ? res : fd_ix; 106 | } 107 | 108 | #if NIFFS_LINEAR_AREA 109 | 110 | int NIFFS_mknod_linear(niffs *fs, const char *name, u32_t resv_size) { 111 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 112 | u8_t flags = NIFFS_O_LINEAR | NIFFS_O_RDWR | NIFFS_O_APPEND; 113 | int res = NIFFS_OK; 114 | 115 | // check free linear space, fetch starting sector 116 | u32_t lsix_start; 117 | u32_t resv_sects = (resv_size + fs->sector_size - 1) / fs->sector_size; 118 | res = niffs_linear_find_space(fs, resv_sects, &lsix_start); 119 | if (res < 0) return res; 120 | 121 | int fd_ix = niffs_open(fs, name, flags); 122 | if (fd_ix >= 0) { 123 | // file exists 124 | (void)niffs_close(fs, fd_ix); 125 | return ERR_NIFFS_FILE_EXISTS; 126 | } 127 | if (fd_ix != ERR_NIFFS_FILE_NOT_FOUND) { 128 | // some other error 129 | return fd_ix; 130 | } 131 | // create linear file meta header 132 | niffs_linear_file_hdr lfhdr = {.start_sector = lsix_start, .resv_sectors = resv_sects}; 133 | res = niffs_create(fs, name, _NIFFS_FTYPE_LINFILE, &lfhdr); 134 | if (res != NIFFS_OK) return res; 135 | fd_ix = niffs_open(fs, name, flags); 136 | if (fd_ix < 0) return fd_ix; 137 | return fd_ix; 138 | } 139 | 140 | #endif // NIFFS_LINEAR_AREA 141 | 142 | int NIFFS_read_ptr(niffs *fs, int fd, u8_t **ptr, u32_t *len) { 143 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 144 | return niffs_read_ptr(fs, fd, ptr, len); 145 | } 146 | 147 | int NIFFS_read(niffs *fs, int fd_ix, u8_t *dst, u32_t len) { 148 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 149 | 150 | int res = NIFFS_OK; 151 | s32_t read_len = 0; 152 | do { 153 | u8_t *rptr; 154 | u32_t rlen; 155 | res = niffs_read_ptr(fs, fd_ix, &rptr, &rlen); 156 | if (res >= 0 && rlen == 0) res = ERR_NIFFS_END_OF_FILE; 157 | if (res >= 0) { 158 | u32_t clen = NIFFS_MIN(len, rlen); 159 | niffs_memcpy(dst, rptr, clen); 160 | dst += clen; 161 | len -= clen; 162 | read_len += clen; 163 | res = niffs_seek(fs, fd_ix, clen, NIFFS_SEEK_CUR); 164 | } 165 | } while (len > 0 && res >= 0); 166 | 167 | if (res == ERR_NIFFS_END_OF_FILE && read_len >= 0) { 168 | return read_len; 169 | } 170 | 171 | return res == NIFFS_OK ? read_len : res; 172 | } 173 | 174 | int NIFFS_lseek(niffs *fs, int fd_ix, s32_t offs, int whence) { 175 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 176 | int res = niffs_seek(fs, fd_ix, offs, whence); 177 | if (res == NIFFS_OK) { 178 | niffs_file_desc *fd; 179 | res = niffs_get_filedesc(fs, fd_ix, &fd); 180 | if (res != NIFFS_OK) return res; 181 | return (int)fd->offs; 182 | } 183 | return res; 184 | } 185 | 186 | int NIFFS_remove(niffs *fs, const char *name) { 187 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 188 | int res; 189 | 190 | int fd = NIFFS_open(fs, name, NIFFS_O_WRONLY, 0); 191 | if (fd < 0) return fd; 192 | res = niffs_truncate(fs, fd, 0); 193 | (void)niffs_close(fs, fd); 194 | 195 | return res; 196 | } 197 | 198 | int NIFFS_fremove(niffs *fs, int fd) { 199 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 200 | return niffs_truncate(fs, fd, 0); 201 | } 202 | 203 | int NIFFS_write(niffs *fs, int fd_ix, const u8_t *data, u32_t len) { 204 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 205 | int res; 206 | niffs_file_desc *fd; 207 | res = niffs_get_filedesc(fs, fd_ix, &fd); 208 | if (res != NIFFS_OK) return res; 209 | niffs_object_hdr *ohdr = (niffs_object_hdr *)_NIFFS_PIX_2_ADDR(fs, fd->obj_pix); 210 | 211 | s32_t written = 0; 212 | if (fd->flags & NIFFS_O_APPEND) { 213 | // always append 214 | res = niffs_append(fs, fd_ix, data, len); 215 | written += len; 216 | } else { 217 | // check if modify and/or append 218 | u32_t mod_len = (ohdr->len == NIFFS_UNDEF_LEN ? 0 : ohdr->len) - fd->offs; 219 | mod_len = NIFFS_MIN(mod_len, len); 220 | if (mod_len > 0) { 221 | res = niffs_modify(fs, fd_ix, fd->offs, data, mod_len); 222 | if (res != NIFFS_OK) return res; 223 | len -= mod_len; 224 | data += mod_len; 225 | written += mod_len; 226 | } 227 | if (len > 0) { 228 | res = niffs_append(fs, fd_ix, data, len); 229 | written += len; 230 | } 231 | } 232 | 233 | // if (res == NIFFS_OK) { 234 | // res = niffs_seek(fs, fd_ix, len, NIFFS_SEEK_CUR); 235 | // } 236 | 237 | return res == 0 ? written : res; 238 | } 239 | 240 | int NIFFS_fflush(niffs *fs, int fd) { 241 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 242 | (void)fd; 243 | return NIFFS_OK; 244 | } 245 | 246 | int NIFFS_stat(niffs *fs, const char *name, niffs_stat *s) { 247 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 248 | int res; 249 | 250 | int fd = NIFFS_open(fs, name, 0, 0); 251 | if (fd < 0) return fd; 252 | res = NIFFS_fstat(fs, fd, s); 253 | (void)niffs_close(fs, fd); 254 | 255 | return res; 256 | } 257 | 258 | int NIFFS_fstat(niffs *fs, int fd_ix, niffs_stat *s) { 259 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 260 | int res; 261 | 262 | niffs_file_desc *fd; 263 | res = niffs_get_filedesc(fs, fd_ix, &fd); 264 | if (res != NIFFS_OK) return res; 265 | 266 | niffs_object_hdr *ohdr = (niffs_object_hdr *)_NIFFS_PIX_2_ADDR(fs, fd->obj_pix); 267 | 268 | s->obj_id = ohdr->phdr.id.obj_id; 269 | s->size = ohdr->len == NIFFS_UNDEF_LEN ? 0 : ohdr->len; 270 | s->type = ohdr->type; 271 | niffs_strncpy((char *)s->name, (char *)ohdr->name, NIFFS_NAME_LEN); 272 | 273 | return NIFFS_OK; 274 | } 275 | 276 | int NIFFS_ftell(niffs *fs, int fd_ix) { 277 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 278 | int res; 279 | 280 | niffs_file_desc *fd; 281 | res = niffs_get_filedesc(fs, fd_ix, &fd); 282 | if (res != NIFFS_OK) return res; 283 | 284 | return (int)fd->offs; 285 | } 286 | 287 | int NIFFS_close(niffs *fs, int fd) { 288 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 289 | return niffs_close(fs, fd); 290 | } 291 | 292 | int NIFFS_rename(niffs *fs, const char *old_name, const char *new_name) { 293 | if (!fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 294 | return niffs_rename(fs, old_name, new_name); 295 | } 296 | 297 | niffs_DIR *NIFFS_opendir(niffs *fs, const char *name, niffs_DIR *d) { 298 | (void)name; 299 | if (!fs->mounted) return 0; 300 | d->fs = fs; 301 | d->pix = 0; 302 | return d; 303 | } 304 | 305 | int NIFFS_closedir(niffs_DIR *d) { 306 | if (!d->fs->mounted) return ERR_NIFFS_NOT_MOUNTED; 307 | return NIFFS_OK; 308 | } 309 | 310 | static int niffs_readdir_v(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr, void *v_arg) { 311 | (void)fs; 312 | struct niffs_dirent *e = (struct niffs_dirent *)v_arg; 313 | if (_NIFFS_IS_FLAG_VALID(phdr) && !_NIFFS_IS_FREE(phdr) && !_NIFFS_IS_DELE(phdr)) { 314 | if (_NIFFS_IS_OBJ_HDR(phdr)) { 315 | // object header page 316 | niffs_object_hdr *ohdr = (niffs_object_hdr *)phdr; 317 | e->obj_id = ohdr->phdr.id.obj_id; 318 | e->pix = pix; 319 | e->size = ohdr->len == NIFFS_UNDEF_LEN ? 0 : ohdr->len; 320 | e->type = ohdr->type; 321 | niffs_strncpy((char *)e->name, (char *)ohdr->name, NIFFS_NAME_LEN); 322 | return NIFFS_OK; 323 | } 324 | } 325 | return NIFFS_VIS_CONT; 326 | } 327 | 328 | struct niffs_dirent *NIFFS_readdir(niffs_DIR *d, struct niffs_dirent *e) { 329 | if (!d->fs->mounted) return 0; 330 | struct niffs_dirent *ret = 0; 331 | 332 | int res = niffs_traverse(d->fs, d->pix, 0, niffs_readdir_v, e); 333 | if (res == NIFFS_OK) { 334 | d->pix = e->pix + 1; 335 | ret = e; 336 | } else if (res == NIFFS_VIS_END) { 337 | // end of stream 338 | } 339 | 340 | return ret; 341 | } 342 | 343 | int NIFFS_chk(niffs *fs) { 344 | if (fs->mounted) return ERR_NIFFS_MOUNTED; 345 | return niffs_chk(fs); 346 | } 347 | -------------------------------------------------------------------------------- /src/niffs_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_internal.h 3 | * 4 | * FLASH LAYOUT 5 | * SECTOR: 6 | * 7 | * | niffs_sector_hdr | niffs_page_hdr : data | niffs_page_hdr : data | ... | fill | 8 | * | magic : era_cnt | id : flag | .... | id : flag | .... | ... 9 | * | | \ obj_id | \ obj_id | 10 | * | | \ spix | \ spix | 11 | * 12 | * Page status: 13 | * FREE niffs_page_hdr.id 0xff.. 14 | * DELE niffs_page_hdr.id 0x0 15 | * USED niffs_page_hdr.id != 0 && != 0xff.. 16 | * CLEA niffs_page_hdr.flag 0xff.. 17 | * WRIT niffs_page_hdr.flag 0x1 18 | * MOVI niffs_page_hdr.flag 0x0 19 | * 20 | * Free pages: 21 | * FREE & CLEA 22 | * Allocated pages: 23 | * USED 24 | * USED & CLEA : allocated but not yet written (semi bad) 25 | * USED & WRIT : allocated and written 26 | * USED & MOVI : allocated and being moved/updated 27 | * Bad pages: 28 | * FREE & WRIT : not allowed 29 | * FREE & MOVI : not allowed 30 | * 31 | * A page life cycle: FREE->CLEAN(->WRITN(->MOVIN))->DELE->FREE 32 | * 33 | * Object header: 34 | * niffs_page_hdr.id != 0 && != 0xff.. 35 | * niffs_page_hdr.id.spix 0 36 | * 37 | * Invalid object_ids are 0 and 0xff.. 38 | * 39 | * File creation: 40 | * write phdr.flag 41 | * write phdr.id 42 | * ----- page now allocated 43 | * write ohdr (len = -1) 44 | * ----- file now created, size 0 45 | * 46 | * File open: 47 | * * aborted append / updated length: 48 | * If obj header is MOVI: 49 | * try finding a WRIT obj header with id, 50 | * use this if found, delete MOVI. Else, copy MOVI as WRIT and 51 | * delete MOVI. For used obj header: check if there are more spix 52 | * pages than file len allows, delete these 53 | 54 | * File append: 55 | * if spix == 0 & len == -1, use same page, update page after full/finished as WRIT 56 | * for following pages: 57 | * mark obj hdr as MOVI 58 | * if free space in last page 59 | * mark MOVI, fill copy, write WRIT, delete MOVI 60 | * create new pages with new spix as WRIT 61 | * store new obj hdr with correct len as WRIT 62 | * delete obj hdr MOVI 63 | * 64 | * File read: 65 | * * aborted rewrite / updated content: 66 | * if a MOVI page is encountered, niffs must check for pages 67 | * WRIT with same id/span index. If found, use this page instead 68 | * and delete MOVI. Else, copy MOVI page to free page as WRIT, 69 | * delete MOVI page, and use dest. 70 | * 71 | * File trunc: 72 | * trunc to zero/rm: 73 | * set obj hdr file len to 0 74 | * delete all pages with same id 75 | * if aborted, check will clean 76 | * delete obj hdr 77 | * trunc to size: 78 | * mark obj hdr MOVi 79 | * create new obj hdr with correct size as WRIT 80 | * if aborted, check will clean 81 | * rewrite last page if trunc to midst of page (MOVI -> WRIT -> delete) 82 | * delete all removed pages 83 | * 84 | * Check: 85 | * sector headers for valid magic 86 | * 87 | * if FREE & (WRIT | MOVI) bad page, delete 88 | * if MOVI and no equal page with same id, copy and delete original 89 | * if MOVI object header => modified during trunc or append, check length and all spix with same id 90 | * file length - remove all pages where spix is beyond file size 91 | * 92 | * remove orphans - check for WRIT && MOVI with ids and spix > 0 having no corresponding page with spix == 0, remove all 93 | * file length - if length == 0, remove all with same id, including obj hdr 94 | * if obj hdr flag is WRIT, but length is UNDEF, fail during append, remove all containing same id 95 | * 96 | * Created on: Feb 3, 2015 97 | * Author: petera 98 | */ 99 | 100 | #include "niffs.h" 101 | #include "niffs_config.h" 102 | 103 | #ifndef NIFFS_INTERNAL_H_ 104 | #define NIFFS_INTERNAL_H_ 105 | 106 | #define _NIFFS_PAGE_FREE_ID ((niffs_page_id_raw)-1) 107 | #define _NIFFS_PAGE_DELE_ID ((niffs_page_id_raw)0) 108 | 109 | #define _NIFFS_FLAG_CLEAN ((niffs_flag)-1) 110 | #define _NIFFS_FLAG_WRITTEN ((niffs_flag)1) 111 | #define _NIFFS_FLAG_MOVING ((niffs_flag)0) 112 | #define NIFFS_FLAG_MOVE_KEEP ((niffs_flag)0xaa) 113 | 114 | #define _NIFFS_FTYPE_FILE (0) 115 | #define _NIFFS_FTYPE_LINFILE (1) 116 | 117 | // change of magic since file type introduction 118 | #define _NIFFS_SECT_MAGIC(_fs) (niffs_magic)(0xfee1c001 ^ (_fs)->page_size) 119 | 120 | #ifndef _NIFFS_ALIGN 121 | #define _NIFFS_ALIGN __attribute__ (( aligned(NIFFS_WORD_ALIGN) )) 122 | #endif 123 | #ifndef _NIFFS_PACKED 124 | #define _NIFFS_PACKED __attribute__ (( packed )) 125 | #endif 126 | 127 | // checks if page is free, i.e. not used at all 128 | #define _NIFFS_IS_FREE(_pg_hdr) (((_pg_hdr)->id.raw) == _NIFFS_PAGE_FREE_ID) 129 | // checks if page is deleted 130 | #define _NIFFS_IS_DELE(_pg_hdr) (((_pg_hdr)->id.raw) == _NIFFS_PAGE_DELE_ID) 131 | // checks if page is allocated, but has no data written to it 132 | #define _NIFFS_IS_CLEA(_pg_hdr) (((_pg_hdr)->flag) == _NIFFS_FLAG_CLEAN) 133 | // checks if page is written 134 | #define _NIFFS_IS_WRIT(_pg_hdr) (((_pg_hdr)->flag) == _NIFFS_FLAG_WRITTEN) 135 | // checks if page is moving 136 | #define _NIFFS_IS_MOVI(_pg_hdr) (((_pg_hdr)->flag) == _NIFFS_FLAG_MOVING) 137 | 138 | #define _NIFFS_SECTOR_2_ADDR(_fs, _s) \ 139 | ((_fs)->phys_addr + (_fs)->sector_size * (_s)) 140 | #define _NIFFS_ADDR_2_SECTOR(_fs, _addr) \ 141 | (((u8_t *)(_addr) - (_fs)->phys_addr) / (_fs)->sector_size) 142 | 143 | #define _NIFFS_PIX_2_SECTOR(_fs, _pix) \ 144 | ((_pix) / (_fs)->pages_per_sector) 145 | #define _NIFFS_PIX_IN_SECTOR(_fs, _pix) \ 146 | ((_pix) % (_fs)->pages_per_sector) 147 | #define _NIFFS_PIX_AT_SECTOR(_fs, _s) \ 148 | ((_s) * (_fs)->pages_per_sector) 149 | #define _NIFFS_PIX_2_ADDR(_fs, _pix) (\ 150 | _NIFFS_SECTOR_2_ADDR(_fs, _NIFFS_PIX_2_SECTOR(_fs, _pix)) + \ 151 | sizeof(niffs_sector_hdr) + \ 152 | _NIFFS_PIX_IN_SECTOR(_fs, _pix) * (_fs)->page_size \ 153 | ) 154 | 155 | #define _NIFFS_SPIX_2_PDATA_LEN(_fs, _spix) \ 156 | ((_fs)->page_size - sizeof(niffs_page_hdr) - ((_spix) == 0 ? sizeof(niffs_object_hdr) : 0)) 157 | 158 | #define _NIFFS_OFFS_2_SPIX(_fs, _offs) ( \ 159 | (_offs) < _NIFFS_SPIX_2_PDATA_LEN(_fs, 0) ? 0 : \ 160 | (1 + (((_offs) - _NIFFS_SPIX_2_PDATA_LEN(_fs, 0)) / _NIFFS_SPIX_2_PDATA_LEN(_fs, 1))) \ 161 | ) 162 | 163 | #define _NIFFS_OFFS_2_PDATA_OFFS(_fs, _offs) ( \ 164 | (_offs) < _NIFFS_SPIX_2_PDATA_LEN(_fs, 0) ? (_offs) : \ 165 | (((_offs) - _NIFFS_SPIX_2_PDATA_LEN(_fs, 0)) % _NIFFS_SPIX_2_PDATA_LEN(_fs, 1)) \ 166 | ) 167 | 168 | #define _NIFFS_RD(_fs, _dst, _src, _len) do {niffs_memcpy((_dst), (_src), (_len));}while(0) 169 | 170 | #define _NIFFS_IS_ID_VALID(phdr) ((phdr)->id.obj_id != (niffs_obj_id)-1 && (phdr)-> id.obj_id != 0) 171 | #define _NIFFS_IS_FLAG_VALID(phdr) \ 172 | ((phdr)->flag == _NIFFS_FLAG_CLEAN || (phdr)->flag == _NIFFS_FLAG_WRITTEN || (phdr)->flag == _NIFFS_FLAG_MOVING) 173 | #define _NIFFS_IS_OBJ_HDR(phdr) (_NIFFS_IS_ID_VALID(phdr) && (phdr->id.spix) == 0) 174 | 175 | #define NIFFS_EXCL_SECT_NONE (u32_t)-1 176 | #define NIFFS_UNDEF_LEN (u32_t)-1 177 | 178 | #ifndef niffs_memcpy 179 | #define niffs_memcpy(_d, _s, _l) memcpy((_d), (_s), (_l)) 180 | #endif 181 | #ifndef niffs_memset 182 | #define niffs_memset(_d, _v, _l) memset((_d), (_v), (_l)) 183 | #endif 184 | #ifndef niffs_strncpy 185 | #define niffs_strncpy(_d, _s, _l) strncpy((_d), (_s), (_l)) 186 | #endif 187 | 188 | typedef struct { 189 | _NIFFS_ALIGN niffs_erase_cnt era_cnt; 190 | _NIFFS_ALIGN niffs_magic abra; // page size xored with magic 191 | } _NIFFS_PACKED niffs_sector_hdr; 192 | 193 | typedef struct { 194 | union { 195 | niffs_page_id_raw raw; 196 | struct { 197 | niffs_span_ix spix : NIFFS_SPAN_IX_BITS; 198 | niffs_obj_id obj_id : NIFFS_OBJ_ID_BITS; 199 | }; 200 | }; 201 | } _NIFFS_PACKED niffs_page_hdr_id; 202 | 203 | // keep member order, used in offsetof in internals 204 | typedef struct { 205 | _NIFFS_ALIGN niffs_page_hdr_id id; 206 | _NIFFS_ALIGN niffs_flag flag; 207 | } _NIFFS_PACKED niffs_page_hdr; 208 | 209 | // keep member order, used in offsetof in internals 210 | typedef struct { 211 | niffs_page_hdr phdr; 212 | _NIFFS_ALIGN u32_t len; 213 | _NIFFS_ALIGN u8_t name[NIFFS_NAME_LEN]; 214 | _NIFFS_ALIGN niffs_file_type type; 215 | } _NIFFS_PACKED niffs_object_hdr; 216 | 217 | typedef struct { 218 | niffs_object_hdr ohdr; 219 | _NIFFS_ALIGN u32_t start_sector; // absolute index from fs start 220 | _NIFFS_ALIGN u32_t resv_sectors; 221 | } _NIFFS_PACKED niffs_linear_file_hdr; 222 | 223 | // super header containing all header types 224 | typedef union { 225 | niffs_page_hdr_id phdr; 226 | niffs_object_hdr ohdr; 227 | niffs_linear_file_hdr lfhdr; 228 | // .. add more if needed 229 | } niffs_super_hdr; 230 | 231 | #define NIFFS_VIS_CONT 1 232 | #define NIFFS_VIS_END 2 233 | 234 | typedef int (* niffs_visitor_f)(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr, void *v_arg); 235 | 236 | #ifdef NIFFS_TEST 237 | TESTATIC int niffs_find_free_id(niffs *fs, niffs_obj_id *id, const char *conflict_name); 238 | TESTATIC int niffs_find_free_page(niffs *fs, niffs_page_ix *pix, u32_t excl_sector); 239 | TESTATIC int niffs_find_page(niffs *fs, niffs_page_ix *pix, niffs_obj_id oid, niffs_span_ix spix, niffs_page_ix start_pix); 240 | TESTATIC int niffs_erase_sector(niffs *fs, u32_t sector_ix); 241 | TESTATIC int niffs_move_page(niffs *fs, niffs_page_ix src_pix, niffs_page_ix dst_pix, const u8_t *data, u32_t len, niffs_flag force_flag); 242 | TESTATIC int niffs_write_page(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr, const u8_t *data, u32_t len); 243 | TESTATIC int niffs_write_phdr(niffs *fs, niffs_page_ix pix, niffs_page_hdr *phdr); 244 | TESTATIC int niffs_delete_page(niffs *fs, niffs_page_ix pix); 245 | #endif 246 | 247 | int niffs_traverse(niffs *fs, niffs_page_ix pix_start, niffs_page_ix pix_end, niffs_visitor_f v, void *v_arg); 248 | int niffs_get_filedesc(niffs *fs, int fd_ix, niffs_file_desc **fd); 249 | int niffs_create(niffs *fs, const char *name, niffs_file_type type, void *meta); 250 | int niffs_open(niffs *fs, const char *name, niffs_fd_flags flags); 251 | int niffs_close(niffs *fs, int fd_ix); 252 | int niffs_read_ptr(niffs *fs, int fd_ix, u8_t **data, u32_t *avail); 253 | int niffs_seek(niffs *fs, int fd_ix, s32_t offset, u8_t whence); 254 | int niffs_append(niffs *fs, int fd_ix, const u8_t *src, u32_t len); 255 | int niffs_modify(niffs *fs, int fd_ix, u32_t offs, const u8_t *src, u32_t len); 256 | int niffs_truncate(niffs *fs, int fd_ix, u32_t new_len); 257 | int niffs_rename(niffs *fs, const char *old_name, const char *new_name); 258 | 259 | int niffs_gc(niffs *fs, u32_t *freed_pages, u8_t allow_full_pages); 260 | 261 | int niffs_chk(niffs *fs); 262 | 263 | int niffs_linear_map(niffs *fs); 264 | int niffs_linear_find_space(niffs *fs, u32_t sectors, u32_t *start_sector); 265 | int niffs_linear_avail_size(niffs *fs, int fd_ix, u32_t *available_sectors); 266 | 267 | #endif /* NIFFS_INTERNAL_H_ */ 268 | -------------------------------------------------------------------------------- /src/test/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | * 4 | * Created on: Feb 3, 2015 5 | * Author: petera 6 | */ 7 | 8 | #include "testrunner.h" 9 | #include 10 | 11 | int main(int argc, char **args) { 12 | run_tests(argc, args); 13 | exit(EXIT_SUCCESS); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/test/niffs_cfg_tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_cfg_test.c 3 | * 4 | * Created on: Feb 5, 2015 5 | * Author: petera 6 | */ 7 | 8 | 9 | #include "testrunner.h" 10 | #include "niffs_test_emul.h" 11 | 12 | 13 | SUITE(niffs_cfg_tests) 14 | 15 | static void setup(test *t) { 16 | } 17 | 18 | static void teardown(test *t) { 19 | } 20 | 21 | TEST(cfg_init_virgin) { 22 | int res; 23 | static u8_t dummy[1024*2]; 24 | static niffs_file_desc fds[4]; 25 | res = NIFFS_init(&fs, dummy, 2, 1024, 2048, 26 | dummy, 1024, 27 | fds, 4, 28 | 0, 0, 0); 29 | TEST_CHECK_EQ(res, ERR_NIFFS_BAD_CONF); 30 | 31 | res = NIFFS_init(&fs, dummy, 2, 1024, 64, 32 | dummy, 2, 33 | fds, 4, 34 | 0, 0, 0); 35 | TEST_CHECK_EQ(res, ERR_NIFFS_BAD_CONF); 36 | 37 | res = niffs_emul_init(); 38 | TEST_CHECK_EQ(res, NIFFS_OK); 39 | return TEST_RES_OK; 40 | } TEST_END 41 | 42 | 43 | SUITE_TESTS(niffs_cfg_tests) 44 | ADD_TEST(cfg_init_virgin) 45 | SUITE_END(niffs_cfg_tests) 46 | -------------------------------------------------------------------------------- /src/test/niffs_func_tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_func_tests.c 3 | * 4 | * Created on: Feb 3, 2015 5 | * Author: petera 6 | */ 7 | 8 | #include "testrunner.h" 9 | #include "niffs_test_emul.h" 10 | 11 | SUITE(niffs_func_tests) 12 | 13 | static void setup(test *t) { 14 | (void)niffs_emul_init(); 15 | } 16 | 17 | static void teardown(test *t) { 18 | if (t->test_result != TEST_RES_OK) { 19 | NIFFS_dump(&fs); 20 | } 21 | 22 | niffs_emul_destroy_all_data(); 23 | } 24 | 25 | 26 | #ifdef NIFFS_DUMP 27 | TEST(func_dump) { 28 | int res = NIFFS_format(&fs); 29 | TEST_CHECK_EQ(res, NIFFS_OK); 30 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 31 | NIFFS_dump(&fs); 32 | return TEST_RES_OK; 33 | } TEST_END 34 | #endif 35 | 36 | TEST(func_info) { 37 | int res = NIFFS_format(&fs); 38 | TEST_CHECK_EQ(res, NIFFS_OK); 39 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 40 | s32_t tot, used; 41 | u8_t of; 42 | niffs_info i; 43 | TEST_CHECK_EQ(NIFFS_info(&fs, &i), NIFFS_OK); 44 | TEST_CHECK_GE(fs.sector_size * fs.sectors, i.total_bytes); 45 | TEST_CHECK_LE(fs.sector_size * fs.sectors/2, i.total_bytes); 46 | TEST_CHECK_GT(i.total_bytes, i.used_bytes); 47 | TEST_CHECK_GT(i.total_bytes, fs.sector_size); 48 | TEST_CHECK_EQ(i.used_bytes, 0); 49 | return TEST_RES_OK; 50 | } TEST_END 51 | 52 | TEST(func_init_virgin) { 53 | return TEST_RES_OK; 54 | } TEST_END 55 | 56 | TEST(func_format_virgin) { 57 | int res = NIFFS_format(&fs); 58 | TEST_CHECK_EQ(res, NIFFS_OK); 59 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 60 | 61 | niffs_page_ix pix; 62 | res = niffs_find_free_page(&fs, &pix, NIFFS_EXCL_SECT_NONE); 63 | TEST_CHECK_EQ(res, NIFFS_OK); 64 | TEST_CHECK_EQ(pix, 0); 65 | 66 | niffs_obj_id id; 67 | res = niffs_find_free_id(&fs, &id, 0); 68 | TEST_CHECK_EQ(res, NIFFS_OK); 69 | TEST_CHECK_EQ(id, 1); 70 | 71 | return TEST_RES_OK; 72 | } TEST_END 73 | 74 | TEST(func_mount_clean) { 75 | TEST_CHECK_EQ(NIFFS_mount(&fs), ERR_NIFFS_NOT_A_FILESYSTEM); 76 | 77 | return TEST_RES_OK; 78 | } TEST_END 79 | 80 | TEST(func_mount_scrap) { 81 | niffs_emul_rand_filesystem(); 82 | TEST_CHECK_EQ(NIFFS_mount(&fs), ERR_NIFFS_NOT_A_FILESYSTEM); 83 | 84 | return TEST_RES_OK; 85 | } TEST_END 86 | 87 | TEST(func_find_free_page) { 88 | int res = NIFFS_format(&fs); 89 | TEST_CHECK_EQ(res, NIFFS_OK); 90 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 91 | 92 | u32_t s; 93 | for (s = 0; s < fs.sectors; s++) { 94 | niffs_page_ix pix; 95 | res = niffs_find_free_page(&fs, &pix, s); 96 | TEST_CHECK_EQ(res, NIFFS_OK); 97 | TEST_CHECK(s != _NIFFS_PIX_2_SECTOR(&fs, pix)); 98 | } 99 | 100 | return TEST_RES_OK; 101 | } TEST_END 102 | 103 | TEST(func_write_phdr) { 104 | int res = NIFFS_format(&fs); 105 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 106 | 107 | niffs_page_hdr phdr; 108 | phdr.flag = _NIFFS_FLAG_WRITTEN; 109 | phdr.id.spix = 0; 110 | 111 | niffs_page_ix pix = 0; 112 | phdr.id.obj_id = 0; 113 | res = niffs_write_phdr(&fs, pix, &phdr); 114 | TEST_CHECK_EQ(res, ERR_NIFFS_WR_PHDR_BAD_ID); 115 | phdr.id.obj_id = (niffs_obj_id)-1; 116 | res = niffs_write_phdr(&fs, pix, &phdr); 117 | TEST_CHECK_EQ(res, ERR_NIFFS_WR_PHDR_BAD_ID); 118 | 119 | phdr.id.obj_id = 1; 120 | res = niffs_write_phdr(&fs, pix, &phdr); 121 | TEST_CHECK_EQ(res, NIFFS_OK); 122 | 123 | res = niffs_write_phdr(&fs, pix, &phdr); 124 | TEST_CHECK_EQ(res, ERR_NIFFS_WR_PHDR_UNFREE_PAGE); 125 | 126 | return TEST_RES_OK; 127 | } TEST_END 128 | 129 | TEST(func_write_phdr_fill) { 130 | int res = NIFFS_format(&fs); 131 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 132 | 133 | niffs_page_hdr phdr; 134 | phdr.flag = _NIFFS_FLAG_WRITTEN; 135 | phdr.id.spix = 0; 136 | 137 | niffs_page_ix pix; 138 | do { 139 | niffs_obj_id id; 140 | res = niffs_find_free_id(&fs, &id, 0); 141 | if (res != NIFFS_OK) break; 142 | phdr.id.obj_id = id; 143 | res = niffs_find_free_page(&fs, &pix, NIFFS_EXCL_SECT_NONE); 144 | if (res != NIFFS_OK) break; 145 | 146 | res = niffs_write_phdr(&fs, pix, &phdr); 147 | TEST_CHECK_EQ(res, NIFFS_OK); 148 | } while (res == NIFFS_OK); 149 | 150 | TEST_CHECK(res == ERR_NIFFS_NO_FREE_PAGE || res == ERR_NIFFS_NO_FREE_ID); 151 | 152 | return TEST_RES_OK; 153 | } TEST_END 154 | 155 | TEST(func_creat) { 156 | int res = NIFFS_format(&fs); 157 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 158 | 159 | TEST_CHECK_EQ(niffs_create(&fs, 0, _NIFFS_FTYPE_FILE, 0), ERR_NIFFS_NULL_PTR); 160 | TEST_CHECK_EQ(niffs_create(&fs, "test", _NIFFS_FTYPE_FILE, 0), NIFFS_OK); 161 | TEST_CHECK_EQ(niffs_create(&fs, "test", _NIFFS_FTYPE_FILE, 0), ERR_NIFFS_NAME_CONFLICT); 162 | 163 | return TEST_RES_OK; 164 | } TEST_END 165 | 166 | TEST(func_creat_full) { 167 | int res = NIFFS_format(&fs); 168 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 169 | 170 | int i; 171 | for (i = 0; i < (fs.sectors-1) * fs.pages_per_sector; i++) { 172 | char fname[16]; 173 | sprintf(fname, "t%i", i); 174 | res = niffs_create(&fs, fname, _NIFFS_FTYPE_FILE, 0); 175 | TEST_CHECK_EQ(res, NIFFS_OK); 176 | } 177 | 178 | res = niffs_create(&fs, "overflow", _NIFFS_FTYPE_FILE, 0); 179 | TEST_CHECK_EQ(res, ERR_NIFFS_FULL); 180 | 181 | return TEST_RES_OK; 182 | } TEST_END 183 | 184 | TEST(func_fd) { 185 | int res = NIFFS_format(&fs); 186 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 187 | 188 | TEST_CHECK_EQ(niffs_create(&fs, "test", _NIFFS_FTYPE_FILE, 0), NIFFS_OK); 189 | int fd; 190 | int fd_pre = -1; 191 | u32_t i; 192 | for (i = 0; i < fs.descs_len; i++) { 193 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 194 | TEST_CHECK(fd != fd_pre); 195 | fd_pre = fd; 196 | } 197 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 198 | TEST_CHECK_EQ(fd, ERR_NIFFS_OUT_OF_FILEDESCS); 199 | 200 | return TEST_RES_OK; 201 | } TEST_END 202 | 203 | TEST(func_delete) { 204 | int res = NIFFS_format(&fs); 205 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 206 | TEST_CHECK_EQ(niffs_delete_page(&fs, 0), ERR_NIFFS_DELETING_FREE_PAGE); 207 | TEST_CHECK_EQ(niffs_create(&fs, "moo", _NIFFS_FTYPE_FILE, 0), NIFFS_OK); 208 | TEST_CHECK_EQ(niffs_delete_page(&fs, 0), NIFFS_OK); 209 | TEST_CHECK_EQ(niffs_delete_page(&fs, 0), ERR_NIFFS_DELETING_DELETED_PAGE); 210 | 211 | return TEST_RES_OK; 212 | } TEST_END 213 | 214 | TEST(func_move) { 215 | int res = NIFFS_format(&fs); 216 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 217 | TEST_CHECK_EQ(niffs_move_page(&fs, 0, 0, 0, 0, NIFFS_FLAG_MOVE_KEEP), ERR_NIFFS_MOVING_TO_SAME_PAGE); 218 | TEST_CHECK_EQ(niffs_move_page(&fs, 0, 1, 0, 0, NIFFS_FLAG_MOVE_KEEP), ERR_NIFFS_MOVING_FREE_PAGE); 219 | TEST_CHECK_EQ(niffs_create(&fs, "moo", _NIFFS_FTYPE_FILE, 0), NIFFS_OK); 220 | TEST_CHECK_EQ(niffs_move_page(&fs, 0, 1, 0, 0, NIFFS_FLAG_MOVE_KEEP), NIFFS_OK); 221 | TEST_CHECK_EQ(niffs_move_page(&fs, 0, 1, 0, 0, NIFFS_FLAG_MOVE_KEEP), ERR_NIFFS_MOVING_DELETED_PAGE); 222 | TEST_CHECK_EQ(niffs_move_page(&fs, 1, 0, 0, 0, NIFFS_FLAG_MOVE_KEEP), ERR_NIFFS_MOVING_TO_UNFREE_PAGE); 223 | 224 | return TEST_RES_OK; 225 | } TEST_END 226 | 227 | TEST(func_open) { 228 | int res = NIFFS_format(&fs); 229 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 230 | 231 | int fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 232 | TEST_CHECK_EQ(fd, ERR_NIFFS_FILE_NOT_FOUND); 233 | 234 | res = niffs_create(&fs, "test", _NIFFS_FTYPE_FILE, 0); 235 | TEST_CHECK_EQ(res, NIFFS_OK); 236 | 237 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 238 | TEST_CHECK(fd >= 0); 239 | 240 | return TEST_RES_OK; 241 | } TEST_END 242 | 243 | TEST(func_append_read) { 244 | int res = NIFFS_format(&fs); 245 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 246 | 247 | u32_t free_pages_clean = fs.free_pages; 248 | 249 | res = niffs_create(&fs, "test", _NIFFS_FTYPE_FILE, 0); 250 | TEST_CHECK_EQ(res, NIFFS_OK); 251 | 252 | // append to empty file, almost a page 253 | 254 | int fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 255 | TEST_CHECK(fd >= 0); 256 | 257 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0)-4; 258 | u8_t *d = niffs_emul_create_data("test", len); 259 | res = niffs_append(&fs, fd, d, len); 260 | TEST_CHECK_EQ(res, NIFFS_OK); 261 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 262 | 263 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 264 | TEST_CHECK(fd >= 0); 265 | 266 | u8_t *rptr; 267 | u32_t rlen; 268 | u32_t ix = 0; 269 | 270 | while (ix < len) { 271 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 272 | TEST_CHECK(res > 0); 273 | res = memcmp(rptr, &d[ix], rlen); 274 | TEST_CHECK_EQ(res, 0); 275 | ix += rlen; 276 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 277 | TEST_CHECK_EQ(res, NIFFS_OK); 278 | } 279 | 280 | TEST_CHECK_EQ(res, NIFFS_OK); 281 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 282 | TEST_CHECK_EQ(ix, len); 283 | TEST_CHECK_EQ(free_pages_clean - fs.free_pages, 1); 284 | TEST_CHECK_EQ(fs.dele_pages, 0); 285 | 286 | // append one page file, rest of page 287 | 288 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 289 | TEST_CHECK(fd >= 0); 290 | 291 | u32_t len2 = 4; 292 | u8_t *d2 = niffs_emul_create_data("test_rest", len2); 293 | res = niffs_append(&fs, fd, d2, len2); 294 | TEST_CHECK_EQ(res, NIFFS_OK); 295 | 296 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 297 | 298 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 299 | TEST_CHECK(fd >= 0); 300 | 301 | ix = 0; 302 | 303 | while (ix < len) { 304 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 305 | u32_t alen = MIN(rlen, len-ix); 306 | TEST_CHECK(res > 0); 307 | res = memcmp(rptr, &d[ix], alen); 308 | TEST_CHECK_EQ(res, 0); 309 | ix += alen; 310 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 311 | TEST_CHECK_EQ(res, NIFFS_OK); 312 | } 313 | 314 | while (ix < len + len2) { 315 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 316 | TEST_CHECK(res > 0); 317 | u32_t alen = MIN(rlen, len-(ix-len)); 318 | res = memcmp(rptr, &d2[ix-len], alen); 319 | TEST_CHECK_EQ(res, 0); 320 | ix += alen; 321 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 322 | TEST_CHECK_EQ(res, NIFFS_OK); 323 | } 324 | 325 | TEST_CHECK_EQ(res, NIFFS_OK); 326 | 327 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 328 | TEST_CHECK(res == ERR_NIFFS_END_OF_FILE); 329 | 330 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 331 | TEST_CHECK_EQ(ix, len+len2); 332 | TEST_CHECK_EQ(free_pages_clean - fs.free_pages, 1+1); 333 | TEST_CHECK_EQ(fs.dele_pages, 1); 334 | 335 | // append one and a half pages 336 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 337 | TEST_CHECK(fd >= 0); 338 | 339 | u32_t len3 = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)/2; 340 | u8_t *d3 = niffs_emul_create_data("test_1_5_more", len3); 341 | res = niffs_append(&fs, fd, d3, len3); 342 | TEST_CHECK_EQ(res, NIFFS_OK); 343 | 344 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 345 | 346 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 347 | TEST_CHECK(fd >= 0); 348 | 349 | ix = 0; 350 | 351 | while (ix < len) { 352 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 353 | TEST_CHECK(res > 0); 354 | u32_t alen = MIN(rlen, len-ix); 355 | 356 | res = memcmp(rptr, &d[ix], alen); 357 | TEST_CHECK_EQ(res, 0); 358 | ix += alen; 359 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 360 | TEST_CHECK_EQ(res, NIFFS_OK); 361 | } 362 | 363 | while (ix < len + len2) { 364 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 365 | TEST_CHECK(res > 0); 366 | u32_t alen = MIN(rlen, len2-(ix-len)); 367 | res = memcmp(rptr, &d2[ix-len], alen); 368 | TEST_CHECK_EQ(res, 0); 369 | ix += alen; 370 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 371 | TEST_CHECK_EQ(res, NIFFS_OK); 372 | } 373 | 374 | while (ix < len + len2 + len3) { 375 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 376 | TEST_CHECK(res > 0); 377 | u32_t alen = MIN(rlen, len3-(ix-len-len2)); 378 | res = memcmp(rptr, &d3[ix-len-len2], alen); 379 | TEST_CHECK_EQ(res, 0); 380 | ix += alen; 381 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 382 | TEST_CHECK_EQ(res, NIFFS_OK); 383 | } 384 | 385 | TEST_CHECK_EQ(res, NIFFS_OK); 386 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 387 | TEST_CHECK_EQ(ix, len+len2+len3); 388 | TEST_CHECK_EQ(free_pages_clean - fs.free_pages, 1+1+3); 389 | TEST_CHECK_EQ(fs.dele_pages, 2); 390 | 391 | // append just a little more data 392 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 393 | TEST_CHECK(fd >= 0); 394 | 395 | u32_t len4 = 8; 396 | u8_t *d4 = niffs_emul_create_data("littlemore", len4); 397 | res = niffs_append(&fs, fd, d4, len4); 398 | TEST_CHECK_EQ(res, NIFFS_OK); 399 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 400 | 401 | fd = niffs_open(&fs, "test", NIFFS_O_RDWR); 402 | TEST_CHECK(fd >= 0); 403 | 404 | ix = 0; 405 | 406 | while (ix < len) { 407 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 408 | TEST_CHECK(res > 0); 409 | u32_t alen = MIN(rlen, len-ix); 410 | res = memcmp(rptr, &d[ix], alen); 411 | TEST_CHECK_EQ(res, 0); 412 | ix += alen; 413 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 414 | TEST_CHECK_EQ(res, NIFFS_OK); 415 | } 416 | 417 | while (ix < len + len2) { 418 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 419 | TEST_CHECK(res > 0); 420 | u32_t alen = MIN(rlen, len2-(ix-len)); 421 | res = memcmp(rptr, &d2[ix-len], alen); 422 | TEST_CHECK_EQ(res, 0); 423 | ix += alen; 424 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 425 | TEST_CHECK_EQ(res, NIFFS_OK); 426 | } 427 | 428 | while (ix < len + len2 + len3) { 429 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 430 | TEST_CHECK(res > 0); 431 | u32_t alen = MIN(rlen, len3-(ix-len-len2)); 432 | res = memcmp(rptr, &d3[ix-len-len2], alen); 433 | TEST_CHECK_EQ(res, 0); 434 | ix += alen; 435 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 436 | TEST_CHECK_EQ(res, NIFFS_OK); 437 | } 438 | 439 | while (ix < len + len2 + len3 + len4) { 440 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 441 | TEST_CHECK(res > 0); 442 | u32_t alen = MIN(rlen, len4-(ix-len-len2-len3)); 443 | res = memcmp(rptr, &d4[ix-len-len2-len3], alen); 444 | TEST_CHECK_EQ(res, 0); 445 | ix += alen; 446 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 447 | TEST_CHECK_EQ(res, NIFFS_OK); 448 | } 449 | 450 | TEST_CHECK_EQ(res, NIFFS_OK); 451 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 452 | TEST_CHECK_EQ(ix, len+len2+len3+len4); 453 | TEST_CHECK_EQ(fs.dele_pages, 4); 454 | TEST_CHECK_EQ(free_pages_clean - fs.free_pages, 1+1+3+2); 455 | 456 | return TEST_RES_OK; 457 | } TEST_END 458 | 459 | TEST(func_modify_ohdr) { 460 | int res = NIFFS_format(&fs); 461 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 462 | 463 | res = niffs_create(&fs, "modify", _NIFFS_FTYPE_FILE, 0); 464 | TEST_CHECK_EQ(res, NIFFS_OK); 465 | 466 | // append to empty file, one page 467 | int fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 468 | TEST_CHECK(fd >= 0); 469 | 470 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0); 471 | u8_t *d = niffs_emul_create_data("modify", len); 472 | res = niffs_append(&fs, fd, d, len); 473 | TEST_CHECK_EQ(res, NIFFS_OK); 474 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 475 | 476 | u32_t b_ix = 4; 477 | u32_t e_ix = len - 4; 478 | u8_t *dm = niffs_emul_create_data("modified", e_ix - b_ix); 479 | u32_t i; 480 | for (i = b_ix; i < e_ix; i++) { 481 | d[i] = dm[i-b_ix]; 482 | } 483 | 484 | // modify midst of ohdr page 485 | 486 | fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 487 | TEST_CHECK(fd >= 0); 488 | 489 | res = niffs_modify(&fs, fd, b_ix, dm, e_ix - b_ix); 490 | TEST_CHECK_EQ(res, 0); 491 | 492 | u8_t *rptr; 493 | u32_t rlen; 494 | u32_t ix = 0; 495 | 496 | TEST_CHECK_EQ(niffs_seek(&fs, fd, 0, NIFFS_SEEK_SET), NIFFS_OK); 497 | while (ix < len) { 498 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 499 | TEST_CHECK(res > 0); 500 | res = memcmp(rptr, &d[ix], rlen); 501 | TEST_CHECK_EQ(res, 0); 502 | ix += rlen; 503 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 504 | TEST_CHECK_EQ(res, NIFFS_OK); 505 | } 506 | 507 | TEST_CHECK_EQ(res, NIFFS_OK); 508 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 509 | TEST_CHECK_EQ(ix, len); 510 | 511 | 512 | return TEST_RES_OK; 513 | } TEST_END 514 | 515 | TEST(func_modify_page) { 516 | int res = NIFFS_format(&fs); 517 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 518 | 519 | res = niffs_create(&fs, "modify", _NIFFS_FTYPE_FILE, 0); 520 | TEST_CHECK_EQ(res, NIFFS_OK); 521 | 522 | // append to empty file, two pages 523 | int fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 524 | TEST_CHECK(fd >= 0); 525 | 526 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1); 527 | u8_t *d = niffs_emul_create_data("modify", len); 528 | res = niffs_append(&fs, fd, d, len); 529 | TEST_CHECK_EQ(res, NIFFS_OK); 530 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 531 | 532 | u32_t b_ix = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + 4; 533 | u32_t e_ix = len - 4; 534 | u8_t *dm = niffs_emul_create_data("modified", e_ix - b_ix); 535 | u32_t i; 536 | for (i = b_ix; i < e_ix; i++) { 537 | d[i] = dm[i-b_ix]; 538 | } 539 | 540 | // modify midst of data page 541 | 542 | fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 543 | TEST_CHECK(fd >= 0); 544 | 545 | res = niffs_modify(&fs, fd, b_ix, dm, e_ix - b_ix); 546 | TEST_CHECK_EQ(res, 0); 547 | 548 | u8_t *rptr; 549 | u32_t rlen; 550 | u32_t ix = 0; 551 | 552 | TEST_CHECK_EQ(niffs_seek(&fs, fd, 0, NIFFS_SEEK_SET), NIFFS_OK); 553 | while (ix < len) { 554 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 555 | TEST_CHECK(res > 0); 556 | res = memcmp(rptr, &d[ix], rlen); 557 | TEST_CHECK_EQ(res, 0); 558 | ix += rlen; 559 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 560 | TEST_CHECK_EQ(res, NIFFS_OK); 561 | } 562 | 563 | TEST_CHECK_EQ(res, NIFFS_OK); 564 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 565 | TEST_CHECK_EQ(ix, len); 566 | 567 | 568 | return TEST_RES_OK; 569 | } TEST_END 570 | 571 | TEST(func_modify_pagespan) { 572 | int res = NIFFS_format(&fs); 573 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 574 | 575 | res = niffs_create(&fs, "modify", _NIFFS_FTYPE_FILE, 0); 576 | TEST_CHECK_EQ(res, NIFFS_OK); 577 | 578 | // append to empty file, two pages 579 | int fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 580 | TEST_CHECK(fd >= 0); 581 | 582 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1); 583 | u8_t *d = niffs_emul_create_data("modify", len); 584 | res = niffs_append(&fs, fd, d, len); 585 | TEST_CHECK_EQ(res, NIFFS_OK); 586 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 587 | 588 | u32_t b_ix = 4; 589 | u32_t e_ix = len - 4; 590 | u8_t *dm = niffs_emul_create_data("modified", e_ix - b_ix); 591 | u32_t i; 592 | for (i = b_ix; i < e_ix; i++) { 593 | d[i] = dm[i-b_ix]; 594 | } 595 | 596 | // modify midst of ohdr page till midst of data page 597 | 598 | fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 599 | TEST_CHECK(fd >= 0); 600 | 601 | res = niffs_modify(&fs, fd, b_ix, dm, e_ix - b_ix); 602 | TEST_CHECK_EQ(res, 0); 603 | 604 | u8_t *rptr; 605 | u32_t rlen; 606 | u32_t ix = 0; 607 | 608 | TEST_CHECK_EQ(niffs_seek(&fs, fd, 0, NIFFS_SEEK_SET), NIFFS_OK); 609 | while (ix < len) { 610 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 611 | TEST_CHECK(res > 0); 612 | res = memcmp(rptr, &d[ix], rlen); 613 | TEST_CHECK_EQ(res, 0); 614 | ix += rlen; 615 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 616 | TEST_CHECK_EQ(res, NIFFS_OK); 617 | } 618 | 619 | TEST_CHECK_EQ(res, NIFFS_OK); 620 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 621 | TEST_CHECK_EQ(ix, len); 622 | 623 | 624 | return TEST_RES_OK; 625 | } TEST_END 626 | 627 | TEST(func_modify_pagespan_nobreak) { 628 | int res = NIFFS_format(&fs); 629 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 630 | 631 | res = niffs_create(&fs, "modify", _NIFFS_FTYPE_FILE, 0); 632 | TEST_CHECK_EQ(res, NIFFS_OK); 633 | 634 | // append to empty file, four pages 635 | int fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 636 | TEST_CHECK(fd >= 0); 637 | 638 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)*3; 639 | u8_t *d = niffs_emul_create_data("modify", len); 640 | res = niffs_append(&fs, fd, d, len); 641 | TEST_CHECK_EQ(res, NIFFS_OK); 642 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 643 | 644 | u32_t b_ix = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0); 645 | u32_t e_ix = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)*2; 646 | u8_t *dm = niffs_emul_create_data("modified", e_ix - b_ix); 647 | u32_t i; 648 | for (i = b_ix; i < e_ix; i++) { 649 | d[i] = dm[i-b_ix]; 650 | } 651 | 652 | // modify midst of ohdr page till midst of data page 653 | 654 | fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 655 | TEST_CHECK(fd >= 0); 656 | 657 | res = niffs_modify(&fs, fd, b_ix, dm, e_ix - b_ix); 658 | TEST_CHECK_EQ(res, 0); 659 | 660 | u8_t *rptr; 661 | u32_t rlen; 662 | u32_t ix = 0; 663 | 664 | TEST_CHECK_EQ(niffs_seek(&fs, fd, 0, NIFFS_SEEK_SET), NIFFS_OK); 665 | while (ix < len) { 666 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 667 | TEST_CHECK(res > 0); 668 | res = memcmp(rptr, &d[ix], rlen); 669 | TEST_CHECK_EQ(res, 0); 670 | ix += rlen; 671 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 672 | TEST_CHECK_EQ(res, NIFFS_OK); 673 | } 674 | 675 | TEST_CHECK_EQ(res, NIFFS_OK); 676 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 677 | TEST_CHECK_EQ(ix, len); 678 | 679 | 680 | return TEST_RES_OK; 681 | } TEST_END 682 | 683 | TEST(func_modify_beyond) { 684 | int res = NIFFS_format(&fs); 685 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 686 | 687 | res = niffs_create(&fs, "modify", _NIFFS_FTYPE_FILE, 0); 688 | TEST_CHECK_EQ(res, NIFFS_OK); 689 | 690 | // append to empty file, one page 691 | int fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 692 | TEST_CHECK(fd >= 0); 693 | 694 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0); 695 | u8_t *d = niffs_emul_create_data("modify", len); 696 | 697 | res = niffs_modify(&fs, fd, 0, d, len); 698 | TEST_CHECK_EQ(res, ERR_NIFFS_MODIFY_BEYOND_FILE); 699 | 700 | res = niffs_append(&fs, fd, d, len); 701 | TEST_CHECK_EQ(res, NIFFS_OK); 702 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 703 | 704 | fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 705 | TEST_CHECK(fd >= 0); 706 | 707 | u8_t *dm = niffs_emul_create_data("modified", len); 708 | 709 | res = niffs_modify(&fs, fd, 4, dm, len); 710 | TEST_CHECK_EQ(res, ERR_NIFFS_MODIFY_BEYOND_FILE); 711 | 712 | // modify midst of ohdr page 713 | 714 | fd = niffs_open(&fs, "modify", NIFFS_O_RDWR); 715 | TEST_CHECK(fd >= 0); 716 | 717 | u8_t *rptr; 718 | u32_t rlen; 719 | u32_t ix = 0; 720 | 721 | while (ix < len) { 722 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 723 | TEST_CHECK(res > 0); 724 | res = memcmp(rptr, &d[ix], rlen); 725 | TEST_CHECK_EQ(res, 0); 726 | ix += rlen; 727 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 728 | TEST_CHECK_EQ(res, NIFFS_OK); 729 | } 730 | 731 | TEST_CHECK_EQ(res, NIFFS_OK); 732 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 733 | TEST_CHECK_EQ(ix, len); 734 | 735 | 736 | return TEST_RES_OK; 737 | } TEST_END 738 | 739 | TEST(func_truncate) { 740 | int res = NIFFS_format(&fs); 741 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 742 | 743 | res = niffs_create(&fs, "trunc", _NIFFS_FTYPE_FILE, 0); 744 | TEST_CHECK_EQ(res, NIFFS_OK); 745 | 746 | // append to empty file, three pages 747 | int fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 748 | TEST_CHECK(fd >= 0); 749 | 750 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * 2; 751 | u8_t *d = niffs_emul_create_data("trunc", len); 752 | 753 | res = niffs_append(&fs, fd, d, len); 754 | TEST_CHECK_EQ(res, NIFFS_OK); 755 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 756 | 757 | 758 | u8_t *rptr; 759 | u32_t rlen; 760 | u32_t ix = 0; 761 | 762 | fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 763 | TEST_CHECK(fd >= 0); 764 | while (ix < len) { 765 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 766 | TEST_CHECK(res > 0); 767 | res = memcmp(rptr, &d[ix], rlen); 768 | TEST_CHECK_EQ(res, 0); 769 | ix += rlen; 770 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 771 | TEST_CHECK_EQ(res, NIFFS_OK); 772 | } 773 | 774 | TEST_CHECK_EQ(res, NIFFS_OK); 775 | 776 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 777 | TEST_CHECK(res == ERR_NIFFS_END_OF_FILE); 778 | 779 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 780 | TEST_CHECK_EQ(ix, len); 781 | TEST_CHECK_EQ(fs.dele_pages, 0); 782 | 783 | // truncate half a page 784 | 785 | len -= _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) / 2; 786 | fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 787 | TEST_CHECK(fd >= 0); 788 | TEST_CHECK_EQ(niffs_truncate(&fs, fd, len), NIFFS_OK); 789 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 790 | 791 | fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 792 | TEST_CHECK(fd >= 0); 793 | ix = 0; 794 | while (ix < len) { 795 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 796 | TEST_CHECK(res > 0); 797 | res = memcmp(rptr, &d[ix], rlen); 798 | TEST_CHECK_EQ(res, 0); 799 | ix += rlen; 800 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 801 | TEST_CHECK_EQ(res, NIFFS_OK); 802 | } 803 | 804 | TEST_CHECK_EQ(res, NIFFS_OK); 805 | 806 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 807 | TEST_CHECK(res == ERR_NIFFS_END_OF_FILE); 808 | 809 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 810 | TEST_CHECK_EQ(ix, len); 811 | TEST_CHECK_EQ(fs.dele_pages, 1); // rewritten obj hdr 812 | 813 | // truncate to two pages 814 | 815 | len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) * 2; 816 | fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 817 | TEST_CHECK(fd >= 0); 818 | TEST_CHECK_EQ(niffs_truncate(&fs, fd, len), NIFFS_OK); 819 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 820 | 821 | fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 822 | TEST_CHECK(fd >= 0); 823 | ix = 0; 824 | while (ix < len) { 825 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 826 | TEST_CHECK(res > 0); 827 | res = memcmp(rptr, &d[ix], rlen); 828 | TEST_CHECK_EQ(res, 0); 829 | ix += rlen; 830 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 831 | TEST_CHECK_EQ(res, NIFFS_OK); 832 | } 833 | 834 | TEST_CHECK_EQ(res, NIFFS_OK); 835 | 836 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 837 | TEST_CHECK(res == ERR_NIFFS_END_OF_FILE); 838 | 839 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 840 | TEST_CHECK_EQ(ix, len); 841 | TEST_CHECK_EQ(fs.dele_pages, 1 + 2); // rewritten obj hdr + deleted page 842 | 843 | // truncate, rm 844 | 845 | len = 0; 846 | fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 847 | TEST_CHECK(fd >= 0); 848 | TEST_CHECK_EQ(niffs_truncate(&fs, fd, len), NIFFS_OK); 849 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 850 | 851 | fd = niffs_open(&fs, "trunc", NIFFS_O_RDWR); 852 | TEST_CHECK_EQ(fd, ERR_NIFFS_FILE_NOT_FOUND); 853 | TEST_CHECK_EQ(fs.dele_pages, 1 + 2 + 2); // rewritten obj hdr + deleted page 854 | 855 | return TEST_RES_OK; 856 | } TEST_END 857 | 858 | TEST(func_rename) { 859 | int res = NIFFS_format(&fs); 860 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 861 | 862 | res = niffs_create(&fs, "orig", _NIFFS_FTYPE_FILE, 0); 863 | TEST_CHECK_EQ(res, NIFFS_OK); 864 | 865 | // append to empty file, three pages 866 | int fd = niffs_open(&fs, "orig", NIFFS_O_RDWR); 867 | TEST_CHECK(fd >= 0); 868 | 869 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * 2; 870 | u8_t *d = niffs_emul_create_data("orig", len); 871 | 872 | res = niffs_append(&fs, fd, d, len); 873 | TEST_CHECK_EQ(res, NIFFS_OK); 874 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 875 | 876 | TEST_CHECK_EQ(niffs_rename(&fs, "orig", "new"), NIFFS_OK); 877 | 878 | u8_t *rptr; 879 | u32_t rlen; 880 | u32_t ix = 0; 881 | 882 | fd = niffs_open(&fs, "new", NIFFS_O_RDWR); 883 | TEST_CHECK(fd >= 0); 884 | while (ix < len) { 885 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 886 | TEST_CHECK(res > 0); 887 | res = memcmp(rptr, &d[ix], rlen); 888 | TEST_CHECK_EQ(res, 0); 889 | ix += rlen; 890 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 891 | TEST_CHECK_EQ(res, NIFFS_OK); 892 | } 893 | 894 | TEST_CHECK_EQ(res, NIFFS_OK); 895 | 896 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 897 | TEST_CHECK(res == ERR_NIFFS_END_OF_FILE); 898 | 899 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 900 | TEST_CHECK_EQ(ix, len); 901 | 902 | TEST_CHECK_EQ(niffs_rename(&fs, "orig", "new2"), ERR_NIFFS_FILE_NOT_FOUND); 903 | 904 | res = niffs_create(&fs, "new2", _NIFFS_FTYPE_FILE, 0); 905 | TEST_CHECK_EQ(res, NIFFS_OK); 906 | 907 | TEST_CHECK_EQ(niffs_rename(&fs, "new", "new2"), ERR_NIFFS_NAME_CONFLICT); 908 | 909 | return TEST_RES_OK; 910 | } TEST_END 911 | 912 | TEST(func_gc) { 913 | int res = NIFFS_format(&fs); 914 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 915 | int i; 916 | for (i = 0; i < (fs.sectors-1) * fs.pages_per_sector; i++) { 917 | char fname[16]; 918 | sprintf(fname, "t%i", i); 919 | res = niffs_create(&fs, fname, _NIFFS_FTYPE_FILE, 0); 920 | TEST_CHECK_EQ(res, NIFFS_OK); 921 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0); 922 | u8_t *data = niffs_emul_create_data(fname, len); 923 | int fd = niffs_open(&fs, fname, NIFFS_O_RDWR); 924 | TEST_CHECK(fd >= 0); 925 | res = niffs_append(&fs, fd, data, len); 926 | TEST_CHECK_EQ(res, NIFFS_OK); 927 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 928 | } 929 | 930 | res = niffs_create(&fs, "overflow", _NIFFS_FTYPE_FILE, 0); 931 | TEST_CHECK_EQ(res, ERR_NIFFS_FULL); 932 | 933 | TEST_CHECK_EQ(fs.free_pages, fs.pages_per_sector); 934 | TEST_CHECK_EQ(fs.dele_pages, 0); 935 | 936 | int fd = niffs_open(&fs, "t0", NIFFS_O_RDWR); 937 | TEST_CHECK(fd >= 0); 938 | TEST_CHECK_EQ(niffs_truncate(&fs, fd, 0), NIFFS_OK); 939 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 940 | 941 | res = niffs_create(&fs, "overflow", _NIFFS_FTYPE_FILE, 0); 942 | TEST_CHECK_EQ(res, NIFFS_OK); 943 | 944 | TEST_CHECK_EQ(fs.free_pages, fs.pages_per_sector); 945 | TEST_CHECK_EQ(fs.dele_pages, 0); 946 | 947 | fd = niffs_open(&fs, "t2", NIFFS_O_RDWR); 948 | TEST_CHECK(fd >= 0); 949 | TEST_CHECK_EQ(niffs_truncate(&fs, fd, 0), NIFFS_OK); 950 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 951 | fd = niffs_open(&fs, "t3", NIFFS_O_RDWR); 952 | TEST_CHECK(fd >= 0); 953 | TEST_CHECK_EQ(niffs_truncate(&fs, fd, 0), NIFFS_OK); 954 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 955 | fd = niffs_open(&fs, "t4", NIFFS_O_RDWR); 956 | TEST_CHECK(fd >= 0); 957 | TEST_CHECK_EQ(niffs_truncate(&fs, fd, 0), NIFFS_OK); 958 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 959 | 960 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)*3 - 5; 961 | u8_t *data = niffs_emul_create_data("overflow", len); 962 | fd = niffs_open(&fs, "overflow", NIFFS_O_RDWR); 963 | TEST_CHECK(fd >= 0); 964 | res = niffs_append(&fs, fd, data, len); 965 | TEST_CHECK_EQ(res, NIFFS_OK); 966 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 967 | 968 | TEST_CHECK_EQ(fs.free_pages, fs.pages_per_sector); 969 | TEST_CHECK_EQ(fs.dele_pages, 0); 970 | 971 | fd = niffs_open(&fs, "overflow", NIFFS_O_RDWR); 972 | TEST_CHECK(fd >= 0); 973 | u32_t ix = 0; 974 | u8_t *rptr; 975 | u32_t rlen; 976 | while (ix < len) { 977 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 978 | TEST_CHECK(res > 0); 979 | res = memcmp(rptr, &data[ix], rlen); 980 | TEST_CHECK_EQ(res, 0); 981 | ix += rlen; 982 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 983 | TEST_CHECK_EQ(res, NIFFS_OK); 984 | } 985 | 986 | TEST_CHECK_EQ(res, NIFFS_OK); 987 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 988 | TEST_CHECK_EQ(ix, len); 989 | 990 | return TEST_RES_OK; 991 | } TEST_END 992 | 993 | TEST(func_gc_big_hog) { 994 | int res = NIFFS_format(&fs); 995 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 996 | 997 | // create one hog file two sectors big 998 | res = niffs_create(&fs, "bighog", _NIFFS_FTYPE_FILE, 0); 999 | TEST_CHECK_EQ(res, NIFFS_OK); 1000 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * (2*fs.pages_per_sector-1); 1001 | u8_t *data = niffs_emul_create_data("bighog", len); 1002 | int fd = niffs_open(&fs, "bighog", NIFFS_O_RDWR); 1003 | TEST_CHECK(fd >= 0); 1004 | res = niffs_append(&fs, fd, data, len); 1005 | TEST_CHECK_EQ(res, NIFFS_OK); 1006 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1007 | 1008 | // now create loads of short lived small files, trigger gc some times 1009 | int needed_gc_runs_to_move_stalled_sector = 1010 | fs.sectors * 1011 | ((MAX(NIFFS_GC_SCORE_BUSY, -NIFFS_GC_SCORE_BUSY) * 100) / NIFFS_GC_SCORE_ERASE_CNT_DIFF); 1012 | TEST_ASSERT(needed_gc_runs_to_move_stalled_sector > 0); 1013 | 1014 | while (needed_gc_runs_to_move_stalled_sector--) { 1015 | int i; 1016 | for (i = 0; i < (fs.sectors-2) * fs.pages_per_sector; i++) { 1017 | char fname[16]; 1018 | sprintf(fname, "t%i_%i", i, needed_gc_runs_to_move_stalled_sector); 1019 | res = niffs_create(&fs, fname, _NIFFS_FTYPE_FILE, 0); 1020 | TEST_CHECK_EQ(res, NIFFS_OK); 1021 | int fd = niffs_open(&fs, fname, NIFFS_O_RDWR); 1022 | TEST_CHECK(fd >= 0); 1023 | res = niffs_truncate(&fs, fd, 0); 1024 | TEST_CHECK_EQ(res, NIFFS_OK); 1025 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1026 | } 1027 | } 1028 | 1029 | // make sure the big hog has been moved 1030 | u32_t era_min, era_max; 1031 | niffs_emul_get_sector_erase_count_info(&fs, &era_min, &era_max); 1032 | TEST_CHECK(era_max > 1); 1033 | TEST_CHECK(era_min > 1); 1034 | TEST_CHECK(((era_max - era_min)*100)/era_max < 50); 1035 | NIFFS_DBG("ERA INF min:%i max:%i span:%i\n", era_min, era_max, ((era_max - era_min)*100)/era_max); 1036 | 1037 | return TEST_RES_OK; 1038 | } TEST_END 1039 | 1040 | TEST(func_gc_full) { 1041 | int res = NIFFS_format(&fs); 1042 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1043 | 1044 | niffs_page_hdr phdr; 1045 | phdr.flag = _NIFFS_FLAG_WRITTEN; 1046 | phdr.id.spix = 0; 1047 | 1048 | niffs_page_ix pix; 1049 | do { 1050 | niffs_obj_id id; 1051 | res = niffs_find_free_id(&fs, &id, 0); 1052 | if (res != NIFFS_OK) break; 1053 | phdr.id.obj_id = id; 1054 | res = niffs_find_free_page(&fs, &pix, NIFFS_EXCL_SECT_NONE); 1055 | if (res != NIFFS_OK) break; 1056 | 1057 | res = niffs_write_phdr(&fs, pix, &phdr); 1058 | TEST_CHECK_EQ(res, NIFFS_OK); 1059 | } while (res == NIFFS_OK); 1060 | 1061 | TEST_CHECK(res == ERR_NIFFS_NO_FREE_PAGE || res == ERR_NIFFS_NO_FREE_ID); 1062 | 1063 | res = NIFFS_unmount(&fs); 1064 | TEST_CHECK_EQ(res, NIFFS_OK); 1065 | res = NIFFS_mount(&fs); 1066 | TEST_CHECK_EQ(res, NIFFS_OK); 1067 | u32_t freed; 1068 | res = niffs_gc(&fs, &freed, 1); 1069 | TEST_CHECK_EQ(res, ERR_NIFFS_NO_GC_CANDIDATE); 1070 | 1071 | u32_t i; 1072 | for (i = 0; i < fs.pages_per_sector; i++) { 1073 | res = niffs_delete_page(&fs, i); 1074 | TEST_CHECK_EQ(res, NIFFS_OK); 1075 | } 1076 | 1077 | res = NIFFS_unmount(&fs); 1078 | TEST_CHECK_EQ(res, NIFFS_OK); 1079 | res = NIFFS_mount(&fs); 1080 | TEST_CHECK_EQ(res, NIFFS_OK); 1081 | res = niffs_gc(&fs, &freed, 1); 1082 | TEST_CHECK_EQ(res, NIFFS_OK); 1083 | TEST_CHECK_GE(fs.free_pages, fs.pages_per_sector); 1084 | 1085 | return TEST_RES_OK; 1086 | } TEST_END 1087 | 1088 | TEST(func_gc_long_run) { 1089 | #define TEST_CHECK_GC_LONG_RUN_FILES 10 1090 | #define TEST_CHECK_GC_LONG_RUN_RUNS 1000 1091 | int res = NIFFS_format(&fs); 1092 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1093 | 1094 | u8_t *data[TEST_CHECK_GC_LONG_RUN_FILES]; 1095 | int i; 1096 | char name[16]; 1097 | 1098 | // create a bunch of test data 1099 | u32_t max_file_system_data_size = fs.pages_per_sector * (fs.sectors - 1) * fs.page_size - 1100 | (fs.pages_per_sector * (fs.sectors - 1) * sizeof(niffs_object_hdr)); 1101 | const u32_t perc_sizes[TEST_CHECK_GC_LONG_RUN_FILES] = {3,4,5,6,7,8,9,10,15,20}; 1102 | u32_t data_len[TEST_CHECK_GC_LONG_RUN_FILES]; 1103 | for (i = 0; i < TEST_CHECK_GC_LONG_RUN_FILES; i++) { 1104 | sprintf(name, "name%i", i); 1105 | data_len[i] = (perc_sizes[i] * max_file_system_data_size) / 100; 1106 | data[i] = niffs_emul_create_data(name, data_len[i]); 1107 | } 1108 | 1109 | srand(0x20140318); 1110 | 1111 | int runs = 0; 1112 | 1113 | u8_t created_file_map[TEST_CHECK_GC_LONG_RUN_FILES]; 1114 | memset(created_file_map, 0, sizeof(created_file_map)); 1115 | u32_t created_files = 0; 1116 | u8_t deleting = 0; 1117 | 1118 | while (runs < TEST_CHECK_GC_LONG_RUN_RUNS) { 1119 | if (deleting) { 1120 | // randomly choose a file to delete 1121 | u32_t file_to_remove_ix = rand() % created_files; 1122 | u32_t ix = 0; 1123 | for (i = 0; i < TEST_CHECK_GC_LONG_RUN_FILES; i++) { 1124 | if (created_file_map[i]) { 1125 | ix++; 1126 | if (ix >= file_to_remove_ix) { 1127 | sprintf(name, "name%i", i); 1128 | int fd = niffs_open(&fs, name, NIFFS_O_RDWR); 1129 | TEST_CHECK(fd >= 0); 1130 | res = niffs_truncate(&fs, fd, 0); 1131 | TEST_CHECK_EQ(res, NIFFS_OK); 1132 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1133 | created_files--; 1134 | created_file_map[i] = 0; 1135 | break; 1136 | } 1137 | } 1138 | } 1139 | if (created_files <= 5) { 1140 | deleting = 0; 1141 | } 1142 | } else { 1143 | // randomly choose a file to create 1144 | u32_t file_to_create_ix = rand() % (TEST_CHECK_GC_LONG_RUN_FILES-created_files); 1145 | u32_t ix = 0; 1146 | for (i = 0; i < TEST_CHECK_GC_LONG_RUN_FILES; i++) { 1147 | if (created_file_map[i] == 0) { 1148 | ix++; 1149 | if (ix >= file_to_create_ix) { 1150 | sprintf(name, "name%i", i); 1151 | res = niffs_create(&fs, name, _NIFFS_FTYPE_FILE, 0); 1152 | TEST_CHECK_EQ(res, NIFFS_OK); 1153 | 1154 | int fd = niffs_open(&fs, name, NIFFS_O_RDWR); 1155 | TEST_CHECK(fd >= 0); 1156 | res = niffs_append(&fs, fd, data[i], data_len[i]); 1157 | TEST_CHECK_EQ(res, NIFFS_OK); 1158 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1159 | created_files++; 1160 | created_file_map[i] = 1; 1161 | break; 1162 | } 1163 | } 1164 | } 1165 | if (created_files >= 9) { 1166 | deleting = 1; 1167 | } 1168 | } 1169 | runs++; 1170 | } 1171 | 1172 | // check current file validity 1173 | for (i = 0; i < TEST_CHECK_GC_LONG_RUN_FILES; i++) { 1174 | if (created_file_map[i]) { 1175 | sprintf(name, "name%i", i); 1176 | int fd = niffs_open(&fs, name, NIFFS_O_RDWR); 1177 | TEST_CHECK(fd >= 0); 1178 | 1179 | u8_t *rptr; 1180 | u32_t rlen; 1181 | u32_t ix = 0; 1182 | u32_t len = data_len[i]; 1183 | 1184 | while (ix < len) { 1185 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 1186 | TEST_CHECK(res > 0); 1187 | res = memcmp(rptr, &data[i][ix], rlen); 1188 | TEST_CHECK_EQ(res, 0); 1189 | ix += rlen; 1190 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 1191 | TEST_CHECK_EQ(res, NIFFS_OK); 1192 | } 1193 | 1194 | TEST_CHECK_EQ(res, NIFFS_OK); 1195 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1196 | TEST_CHECK_EQ(ix, len); 1197 | } else { 1198 | sprintf(name, "name%i", i); 1199 | int fd = niffs_open(&fs, name, NIFFS_O_RDWR); 1200 | TEST_CHECK(fd == ERR_NIFFS_FILE_NOT_FOUND); 1201 | } 1202 | } 1203 | 1204 | // check erase counts 1205 | u32_t era_min, era_max; 1206 | niffs_emul_get_sector_erase_count_info(&fs, &era_min, &era_max); 1207 | TEST_CHECK(era_max > 1); 1208 | TEST_CHECK(era_min > 1); 1209 | TEST_CHECK(((era_max - era_min)*100)/era_max < 50); 1210 | NIFFS_DBG("ERA INF min:%i max:%i span:%i\n", era_min, era_max, ((era_max - era_min)*100)/era_max); 1211 | 1212 | return TEST_RES_OK; 1213 | } TEST_END 1214 | 1215 | TEST(func_check_aborted_delete) { 1216 | int res = NIFFS_format(&fs); 1217 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1218 | 1219 | // create one big file two sectors big 1220 | res = niffs_create(&fs, "undel", _NIFFS_FTYPE_FILE, 0); 1221 | TEST_CHECK_EQ(res, NIFFS_OK); 1222 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * (2*fs.pages_per_sector-1); 1223 | u8_t *data = niffs_emul_create_data("undel", len); 1224 | int fd = niffs_open(&fs, "undel", NIFFS_O_RDWR); 1225 | TEST_CHECK(fd >= 0); 1226 | res = niffs_append(&fs, fd, data, len); 1227 | TEST_CHECK_EQ(res, NIFFS_OK); 1228 | 1229 | u32_t written_pre = fs.sectors * fs.pages_per_sector - fs.free_pages - fs.dele_pages; 1230 | 1231 | // create one small file two pages big 1232 | res = niffs_create(&fs, "noorphan", _NIFFS_FTYPE_FILE, 0); 1233 | TEST_CHECK_EQ(res, NIFFS_OK); 1234 | len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1); 1235 | data = niffs_emul_create_data("noorphan", len); 1236 | fd = niffs_open(&fs, "noorphan", NIFFS_O_RDWR); 1237 | TEST_CHECK(fd >= 0); 1238 | res = niffs_append(&fs, fd, data, len); 1239 | TEST_CHECK_EQ(res, NIFFS_OK); 1240 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1241 | 1242 | // truncate header size for file to 0 1243 | fd = niffs_open(&fs, "undel", NIFFS_O_RDWR); 1244 | TEST_CHECK(fd >= 0); 1245 | niffs_emul_set_write_byte_limit(sizeof(u32_t)); // length in obj header 1246 | res = niffs_truncate(&fs, fd, 0); 1247 | TEST_CHECK_EQ(res, ERR_NIFFS_TEST_ABORTED_WRITE); 1248 | 1249 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1250 | 1251 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 1252 | 1253 | TEST_CHECK_EQ(niffs_chk(&fs), NIFFS_OK); 1254 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1255 | TEST_CHECK_EQ(written_pre, fs.dele_pages); 1256 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 1257 | 1258 | return TEST_RES_OK; 1259 | } TEST_END 1260 | 1261 | TEST(func_check_orphans) { 1262 | int res = NIFFS_format(&fs); 1263 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1264 | 1265 | // create one big file two sectors big 1266 | res = niffs_create(&fs, "orphan", _NIFFS_FTYPE_FILE, 0); 1267 | TEST_CHECK_EQ(res, NIFFS_OK); 1268 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * (2*fs.pages_per_sector-1); 1269 | u8_t *data = niffs_emul_create_data("orphan", len); 1270 | int fd = niffs_open(&fs, "orphan", NIFFS_O_RDWR); 1271 | TEST_CHECK(fd >= 0); 1272 | res = niffs_append(&fs, fd, data, len); 1273 | TEST_CHECK_EQ(res, NIFFS_OK); 1274 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1275 | 1276 | u32_t written_pre = fs.sectors * fs.pages_per_sector - fs.free_pages - fs.dele_pages; 1277 | 1278 | // create one small file two pages big 1279 | res = niffs_create(&fs, "noorphan", _NIFFS_FTYPE_FILE, 0); 1280 | TEST_CHECK_EQ(res, NIFFS_OK); 1281 | len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1); 1282 | data = niffs_emul_create_data("noorphan", len); 1283 | fd = niffs_open(&fs, "noorphan", NIFFS_O_RDWR); 1284 | TEST_CHECK(fd >= 0); 1285 | res = niffs_append(&fs, fd, data, len); 1286 | TEST_CHECK_EQ(res, NIFFS_OK); 1287 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1288 | 1289 | // delete obj header for orphan file 1290 | TEST_CHECK_EQ(niffs_delete_page(&fs, 0), NIFFS_OK); 1291 | 1292 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 1293 | 1294 | TEST_CHECK_EQ(niffs_chk(&fs), NIFFS_OK); 1295 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1296 | TEST_CHECK_EQ(written_pre, fs.dele_pages); 1297 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 1298 | 1299 | return TEST_RES_OK; 1300 | } TEST_END 1301 | 1302 | TEST(func_check_aborted_append) { 1303 | int res = NIFFS_format(&fs); 1304 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1305 | 1306 | // create file 1307 | res = niffs_create(&fs, "abortapp", _NIFFS_FTYPE_FILE, 0); 1308 | TEST_CHECK_EQ(res, NIFFS_OK); 1309 | u32_t orig_len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0); 1310 | u8_t *orig_data = niffs_emul_create_data("abortapp", orig_len); 1311 | int fd = niffs_open(&fs, "abortapp", NIFFS_O_RDWR); 1312 | TEST_CHECK(fd >= 0); 1313 | res = niffs_append(&fs, fd, orig_data, orig_len); 1314 | TEST_CHECK_EQ(res, NIFFS_OK); 1315 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1316 | 1317 | // append to file, abort 1318 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector; 1319 | u8_t *data = niffs_emul_create_data("abortapp_more", len); 1320 | fd = niffs_open(&fs, "abortapp", NIFFS_O_RDWR); 1321 | TEST_CHECK(fd >= 0); 1322 | niffs_emul_set_write_byte_limit(len-4); 1323 | res = niffs_append(&fs, fd, data, len); 1324 | TEST_CHECK_EQ(res, ERR_NIFFS_TEST_ABORTED_WRITE); 1325 | 1326 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1327 | 1328 | TEST_CHECK_EQ(res, ERR_NIFFS_TEST_ABORTED_WRITE); 1329 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 1330 | TEST_CHECK_EQ(niffs_chk(&fs), NIFFS_OK); 1331 | 1332 | u8_t *rptr; 1333 | u32_t rlen; 1334 | u32_t ix = 0; 1335 | 1336 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1337 | fd = niffs_open(&fs, "abortapp", NIFFS_O_RDWR); 1338 | TEST_CHECK(fd >= 0); 1339 | TEST_CHECK_EQ(niffs_seek(&fs, fd, 0, NIFFS_SEEK_SET), NIFFS_OK); 1340 | while (ix < orig_len) { 1341 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 1342 | TEST_CHECK(res > 0); 1343 | res = memcmp(rptr, &orig_data[ix], rlen); 1344 | TEST_CHECK_EQ(res, 0); 1345 | ix += rlen; 1346 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 1347 | TEST_CHECK_EQ(res, NIFFS_OK); 1348 | } 1349 | 1350 | TEST_CHECK_EQ(res, NIFFS_OK); 1351 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1352 | TEST_CHECK_EQ(ix, orig_len); 1353 | 1354 | 1355 | return TEST_RES_OK; 1356 | } TEST_END 1357 | 1358 | TEST(func_check_aborted_modify) { 1359 | int res = NIFFS_format(&fs); 1360 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1361 | 1362 | // create file 1363 | res = niffs_create(&fs, "abortapp", _NIFFS_FTYPE_FILE, 0); 1364 | TEST_CHECK_EQ(res, NIFFS_OK); 1365 | u32_t orig_len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector; 1366 | u8_t *orig_data = niffs_emul_create_data("abortapp", orig_len); 1367 | int fd = niffs_open(&fs, "abortapp", NIFFS_O_RDWR); 1368 | TEST_CHECK(fd >= 0); 1369 | res = niffs_append(&fs, fd, orig_data, orig_len); 1370 | TEST_CHECK_EQ(res, NIFFS_OK); 1371 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1372 | 1373 | // modify file, abort 1374 | u32_t mod_len = orig_len / 2; 1375 | u8_t *mod_data = niffs_emul_create_data("abortapp_more", mod_len); 1376 | fd = niffs_open(&fs, "abortapp", NIFFS_O_RDWR); 1377 | TEST_CHECK(fd >= 0); 1378 | niffs_emul_set_write_byte_limit(mod_len/2); 1379 | res = niffs_modify(&fs, fd, orig_len / 4, mod_data, mod_len); 1380 | TEST_CHECK_EQ(res, ERR_NIFFS_TEST_ABORTED_WRITE); 1381 | 1382 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1383 | 1384 | TEST_CHECK_EQ(res, ERR_NIFFS_TEST_ABORTED_WRITE); 1385 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 1386 | TEST_CHECK_EQ(niffs_chk(&fs), NIFFS_OK); 1387 | 1388 | u8_t *rptr; 1389 | u32_t rlen; 1390 | u32_t ix = 0; 1391 | 1392 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1393 | fd = niffs_open(&fs, "abortapp", NIFFS_O_RDWR); 1394 | TEST_CHECK(fd >= 0); 1395 | TEST_CHECK_EQ(niffs_seek(&fs, fd, 0, NIFFS_SEEK_SET), NIFFS_OK); 1396 | while (ix < orig_len) { 1397 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 1398 | TEST_CHECK(res > 0); 1399 | ix += rlen; 1400 | res = niffs_seek(&fs, fd, ix, NIFFS_SEEK_SET); 1401 | TEST_CHECK_EQ(res, NIFFS_OK); 1402 | } 1403 | 1404 | TEST_CHECK_EQ(res, NIFFS_OK); 1405 | TEST_CHECK_EQ(niffs_close(&fs, fd), NIFFS_OK); 1406 | TEST_CHECK_EQ(ix, orig_len); 1407 | 1408 | 1409 | return TEST_RES_OK; 1410 | } TEST_END 1411 | 1412 | TEST(func_check_aborted_erase) { 1413 | int res = NIFFS_format(&fs); 1414 | TEST_CHECK_EQ(res, NIFFS_OK); 1415 | 1416 | niffs_emul_set_write_byte_limit(1); 1417 | res = NIFFS_format(&fs); 1418 | TEST_CHECK_EQ(res, ERR_NIFFS_TEST_ABORTED_WRITE); 1419 | 1420 | TEST_CHECK_EQ(niffs_chk(&fs), NIFFS_OK); 1421 | 1422 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1423 | 1424 | return TEST_RES_OK; 1425 | } TEST_END 1426 | 1427 | #if NIFFS_LINEAR_AREA 1428 | 1429 | TEST(func_lin_alloc_virgin) { 1430 | u32_t start_sect; 1431 | int res = NIFFS_format(&fs); 1432 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1433 | 1434 | res = niffs_linear_find_space(&fs, 1, &start_sect); 1435 | TEST_CHECK_EQ(res, NIFFS_OK); 1436 | TEST_CHECK_EQ(start_sect, fs.sectors); 1437 | 1438 | res = niffs_linear_find_space(&fs, fs.lin_sectors, &start_sect); 1439 | TEST_CHECK_EQ(res, NIFFS_OK); 1440 | TEST_CHECK_EQ(start_sect, fs.sectors); 1441 | 1442 | res = niffs_linear_find_space(&fs, fs.lin_sectors+1, &start_sect); 1443 | TEST_CHECK_EQ(res, ERR_NIFFS_LINEAR_NO_SPACE); 1444 | 1445 | return TEST_RES_OK; 1446 | } TEST_END 1447 | 1448 | TEST(func_lin_alloc_mknod) { 1449 | u32_t start_sect; 1450 | int res = NIFFS_format(&fs); 1451 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1452 | int fd; 1453 | 1454 | fd = NIFFS_mknod_linear(&fs, "1_1", 0); 1455 | TEST_CHECK_GE(fd, NIFFS_OK); 1456 | NIFFS_close(&fs, fd); 1457 | res = niffs_linear_find_space(&fs, 1, &start_sect); 1458 | TEST_CHECK_EQ(res, NIFFS_OK); 1459 | TEST_CHECK_EQ(start_sect, fs.sectors+1); 1460 | 1461 | fd = NIFFS_mknod_linear(&fs, "2_1", 0); 1462 | TEST_CHECK_GE(fd, NIFFS_OK); 1463 | NIFFS_close(&fs, fd); 1464 | res = niffs_linear_find_space(&fs, 1, &start_sect); 1465 | TEST_CHECK_EQ(res, NIFFS_OK); 1466 | TEST_CHECK_EQ(start_sect, fs.sectors+1+1); 1467 | 1468 | fd = NIFFS_mknod_linear(&fs, "3_8", fs.sector_size*8-1); 1469 | TEST_CHECK_GE(fd, NIFFS_OK); 1470 | NIFFS_close(&fs, fd); 1471 | res = niffs_linear_find_space(&fs, 1, &start_sect); 1472 | TEST_CHECK_EQ(res, NIFFS_OK); 1473 | TEST_CHECK_EQ(start_sect, fs.sectors+1+1+8); 1474 | 1475 | fd = NIFFS_mknod_linear(&fs, "4_1", fs.sector_size/2); 1476 | TEST_CHECK_GE(fd, NIFFS_OK); 1477 | NIFFS_close(&fs, fd); 1478 | res = niffs_linear_find_space(&fs, 1, &start_sect); 1479 | TEST_CHECK_EQ(res, NIFFS_OK); 1480 | TEST_CHECK_EQ(start_sect, fs.sectors+1+1+8+1); 1481 | 1482 | fd = NIFFS_mknod_linear(&fs, "5_lots", fs.lin_sectors); 1483 | TEST_CHECK_GE(fd, ERR_NIFFS_LINEAR_NO_SPACE); 1484 | 1485 | return TEST_RES_OK; 1486 | } TEST_END 1487 | 1488 | TEST(func_lin_write) { 1489 | int res = NIFFS_format(&fs); 1490 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1491 | int fd; 1492 | 1493 | const u32_t len = fs.sector_size*5; 1494 | u8_t *data = niffs_emul_create_data("linear", len); 1495 | TEST_CHECK(data); 1496 | 1497 | fd = NIFFS_mknod_linear(&fs, "linear", 0); 1498 | TEST_CHECK_GE(fd, NIFFS_OK); 1499 | res = NIFFS_write(&fs, fd, data, len/2); 1500 | TEST_CHECK_EQ(res, len/2); 1501 | 1502 | res = NIFFS_write(&fs, fd, &data[len/2], len/2); 1503 | TEST_CHECK_EQ(res, len/2); 1504 | 1505 | res = NIFFS_close(&fs, fd); 1506 | TEST_CHECK_EQ(res, NIFFS_OK); 1507 | 1508 | res = niffs_emul_verify_file(&fs, "linear"); 1509 | TEST_CHECK_EQ(res, NIFFS_OK); 1510 | 1511 | return TEST_RES_OK; 1512 | } TEST_END 1513 | 1514 | TEST(func_lin_overwrite) { 1515 | int res = NIFFS_format(&fs); 1516 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1517 | int fd; 1518 | 1519 | const u32_t len = fs.sector_size*5; 1520 | u8_t *data = niffs_emul_create_data("linear", len); 1521 | TEST_CHECK(data); 1522 | 1523 | fd = NIFFS_mknod_linear(&fs, "linear", 0); 1524 | TEST_CHECK_GE(fd, NIFFS_OK); 1525 | res = NIFFS_write(&fs, fd, data, len); 1526 | TEST_CHECK_EQ(res, len); 1527 | res = NIFFS_close(&fs, fd); 1528 | TEST_CHECK_EQ(res, NIFFS_OK); 1529 | 1530 | fd = NIFFS_open(&fs, "linear", NIFFS_O_RDONLY, 0); 1531 | TEST_CHECK_GE(fd, NIFFS_OK); 1532 | niffs_file_desc *desc; 1533 | res = niffs_get_filedesc(&fs, fd, &desc); 1534 | TEST_CHECK_EQ(res, NIFFS_OK); 1535 | u32_t start_sec1 = ((niffs_linear_file_hdr *)_NIFFS_PIX_2_ADDR(&fs, desc->obj_pix))->start_sector; 1536 | 1537 | res = NIFFS_remove(&fs, "linear"); 1538 | TEST_CHECK_EQ(res, NIFFS_OK); 1539 | 1540 | data = niffs_emul_create_data("linear2", len); 1541 | TEST_CHECK(data); 1542 | fd = NIFFS_mknod_linear(&fs, "linear2", 0); 1543 | TEST_CHECK_GE(fd, NIFFS_OK); 1544 | res = NIFFS_write(&fs, fd, data, len); 1545 | TEST_CHECK_EQ(res, len); 1546 | res = NIFFS_close(&fs, fd); 1547 | TEST_CHECK_EQ(res, NIFFS_OK); 1548 | 1549 | fd = NIFFS_open(&fs, "linear2", NIFFS_O_RDONLY, 0); 1550 | TEST_CHECK_GE(fd, NIFFS_OK); 1551 | res = niffs_get_filedesc(&fs, fd, &desc); 1552 | TEST_CHECK_EQ(res, NIFFS_OK); 1553 | u32_t start_sec2 = ((niffs_linear_file_hdr *)_NIFFS_PIX_2_ADDR(&fs, desc->obj_pix))->start_sector; 1554 | 1555 | TEST_CHECK_EQ(start_sec1, start_sec2); 1556 | 1557 | res = niffs_emul_verify_file(&fs, "linear2"); 1558 | TEST_CHECK_EQ(res, NIFFS_OK); 1559 | 1560 | res = niffs_emul_verify_file(&fs, "linear"); 1561 | TEST_CHECK_EQ(res, ERR_NIFFS_FILE_NOT_FOUND); 1562 | 1563 | return TEST_RES_OK; 1564 | } TEST_END 1565 | 1566 | TEST(func_lin_clamp) { 1567 | int res = NIFFS_format(&fs); 1568 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1569 | int fd; 1570 | 1571 | u32_t len = fs.sector_size*2; 1572 | 1573 | u8_t *data = niffs_emul_create_data("linear1", len); 1574 | TEST_CHECK(data); 1575 | fd = NIFFS_mknod_linear(&fs, "linear1", 0); 1576 | TEST_CHECK_GE(fd, NIFFS_OK); 1577 | res = NIFFS_write(&fs, fd, data, len); 1578 | TEST_CHECK_EQ(res, len); 1579 | res = NIFFS_close(&fs, fd); 1580 | TEST_CHECK_EQ(res, NIFFS_OK); 1581 | 1582 | data = niffs_emul_create_data("linear2", len); 1583 | TEST_CHECK(data); 1584 | fd = NIFFS_mknod_linear(&fs, "linear2", 0); 1585 | TEST_CHECK_GE(fd, NIFFS_OK); 1586 | res = NIFFS_write(&fs, fd, data, len); 1587 | TEST_CHECK_EQ(res, len); 1588 | res = NIFFS_close(&fs, fd); 1589 | TEST_CHECK_EQ(res, NIFFS_OK); 1590 | 1591 | res = niffs_emul_verify_file(&fs, "linear1"); 1592 | TEST_CHECK_EQ(res, NIFFS_OK); 1593 | 1594 | res = niffs_emul_verify_file(&fs, "linear2"); 1595 | TEST_CHECK_EQ(res, NIFFS_OK); 1596 | 1597 | res = NIFFS_remove(&fs, "linear1"); 1598 | TEST_CHECK_EQ(res, NIFFS_OK); 1599 | 1600 | len = fs.sector_size*2 + 1; 1601 | 1602 | data = niffs_emul_create_data("linear1_2", len); 1603 | TEST_CHECK(data); 1604 | fd = NIFFS_mknod_linear(&fs, "linear1_2", 0); 1605 | TEST_CHECK_GE(fd, NIFFS_OK); 1606 | res = NIFFS_write(&fs, fd, data, len); 1607 | TEST_CHECK_EQ(res, ERR_NIFFS_LINEAR_NO_SPACE); 1608 | res = NIFFS_write(&fs, fd, data, len-1); 1609 | TEST_CHECK_EQ(res, len-1); 1610 | res = NIFFS_close(&fs, fd); 1611 | TEST_CHECK_EQ(res, NIFFS_OK); 1612 | 1613 | res = niffs_emul_verify_file(&fs, "linear1_2"); 1614 | TEST_CHECK_EQ(res, NIFFS_OK); 1615 | 1616 | return TEST_RES_OK; 1617 | } TEST_END 1618 | 1619 | TEST(func_lin_full) { 1620 | int res = NIFFS_format(&fs); 1621 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1622 | int fd; 1623 | 1624 | u32_t len = fs.sector_size*fs.lin_sectors+2; 1625 | 1626 | u8_t *data = niffs_emul_create_data("linearbig", len); 1627 | TEST_CHECK(data); 1628 | fd = NIFFS_mknod_linear(&fs, "linearbig", 0); 1629 | TEST_CHECK_GE(fd, NIFFS_OK); 1630 | res = NIFFS_write(&fs, fd, data, len-NIFFS_WORD_ALIGN*3); 1631 | TEST_CHECK_EQ(res, len-NIFFS_WORD_ALIGN*3); 1632 | data += len-NIFFS_WORD_ALIGN*3; 1633 | res = NIFFS_write(&fs, fd, data, NIFFS_WORD_ALIGN); 1634 | TEST_CHECK_EQ(res, NIFFS_WORD_ALIGN); 1635 | data += NIFFS_WORD_ALIGN; 1636 | res = NIFFS_write(&fs, fd, data, NIFFS_WORD_ALIGN); 1637 | TEST_CHECK_EQ(res, NIFFS_WORD_ALIGN); 1638 | data += NIFFS_WORD_ALIGN; 1639 | res = NIFFS_write(&fs, fd, data, NIFFS_WORD_ALIGN); 1640 | TEST_CHECK_EQ(res, ERR_NIFFS_LINEAR_NO_SPACE); 1641 | res = NIFFS_close(&fs, fd); 1642 | TEST_CHECK_EQ(res, NIFFS_OK); 1643 | 1644 | res = niffs_emul_verify_file(&fs, "linearbig"); 1645 | TEST_CHECK_EQ(res, NIFFS_OK); 1646 | 1647 | return TEST_RES_OK; 1648 | } TEST_END 1649 | 1650 | #endif //NIFFS_LINEAR_AREA 1651 | 1652 | SUITE_TESTS(niffs_func_tests) 1653 | ADD_TEST(func_dump) 1654 | ADD_TEST(func_info) 1655 | ADD_TEST(func_init_virgin) 1656 | ADD_TEST(func_format_virgin) 1657 | ADD_TEST(func_mount_clean) 1658 | ADD_TEST(func_mount_scrap) 1659 | ADD_TEST(func_find_free_page) 1660 | ADD_TEST(func_write_phdr) 1661 | ADD_TEST(func_write_phdr_fill) 1662 | ADD_TEST(func_creat) 1663 | ADD_TEST(func_creat_full) 1664 | ADD_TEST(func_fd) 1665 | ADD_TEST(func_delete) 1666 | ADD_TEST(func_move) 1667 | ADD_TEST(func_open) 1668 | ADD_TEST(func_append_read) 1669 | ADD_TEST(func_modify_ohdr) 1670 | ADD_TEST(func_modify_page) 1671 | ADD_TEST(func_modify_pagespan) 1672 | ADD_TEST(func_modify_pagespan_nobreak) 1673 | ADD_TEST(func_modify_beyond) 1674 | ADD_TEST(func_truncate) 1675 | ADD_TEST(func_rename) 1676 | ADD_TEST(func_gc) 1677 | ADD_TEST(func_gc_big_hog) 1678 | ADD_TEST(func_gc_full) 1679 | ADD_TEST(func_gc_long_run) 1680 | ADD_TEST(func_check_aborted_delete) 1681 | ADD_TEST(func_check_orphans) 1682 | ADD_TEST(func_check_aborted_append) 1683 | ADD_TEST(func_check_aborted_modify) 1684 | ADD_TEST(func_check_aborted_erase) 1685 | #if NIFFS_LINEAR_AREA 1686 | ADD_TEST(func_lin_alloc_virgin) 1687 | ADD_TEST(func_lin_alloc_mknod) 1688 | ADD_TEST(func_lin_write) 1689 | ADD_TEST(func_lin_overwrite) 1690 | ADD_TEST(func_lin_clamp) 1691 | ADD_TEST(func_lin_full) 1692 | #endif 1693 | SUITE_END(niffs_func_tests) 1694 | -------------------------------------------------------------------------------- /src/test/niffs_run_tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_run_tests.c 3 | * 4 | * Created on: Feb 24, 2015 5 | * Author: petera 6 | */ 7 | 8 | #include "testrunner.h" 9 | #include "niffs_test_emul.h" 10 | 11 | #define NIFFS_DBG_TEST(...) //printf(__VA_ARGS__) 12 | 13 | static u32_t trand(void) { 14 | static u32_t seed = 0x12312112; 15 | srand(seed); 16 | u32_t r = rand(); 17 | seed = r; 18 | return r; 19 | } 20 | 21 | SUITE(niffs_run_tests) 22 | 23 | static void setup(test *t) { 24 | (void)niffs_emul_init(); 25 | NIFFS_format(&fs); 26 | NIFFS_mount(&fs); 27 | } 28 | 29 | static void teardown(test *t) { 30 | if (t->test_result != TEST_RES_OK) { 31 | NIFFS_dump(&fs); 32 | } 33 | niffs_emul_destroy_all_data(); 34 | } 35 | 36 | 37 | TEST(run_create_many_small) 38 | { 39 | int files = 100 * (fs.sectors - 1) * fs.pages_per_sector; 40 | int fileno = 0; 41 | int res; 42 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 0); 43 | 44 | while (fileno < files) { 45 | char name[NIFFS_NAME_LEN]; 46 | sprintf(name, "file%i", fileno); 47 | u32_t len = mlen - (fileno % (mlen/2)); 48 | u8_t *data = niffs_emul_create_data(name, len); 49 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 50 | if (fd >= 0) { 51 | res = NIFFS_write(&fs, fd, data, len); 52 | if (res == ERR_NIFFS_FULL) { 53 | int res2 = NIFFS_fremove(&fs, fd); 54 | TEST_CHECK_EQ(res2, NIFFS_OK); 55 | } else { 56 | TEST_CHECK_EQ(res, len); 57 | (void)NIFFS_close(&fs, fd); 58 | res = NIFFS_OK; 59 | } 60 | } else { 61 | res = fd; 62 | } 63 | if (res == NIFFS_OK) { 64 | fileno++; 65 | if ((fileno % (files/50))==0) { 66 | printf("."); 67 | fflush(stdout); 68 | } 69 | } else if (res == ERR_NIFFS_FULL) { 70 | niffs_emul_destroy_data(name); 71 | niffs_emul_reset_data_cursor(); 72 | int ix = 0; 73 | char *dname; 74 | while ((dname = niffs_emul_get_next_data_name())) { 75 | ix++; 76 | if (((ix + fileno) % 5) == 0) { 77 | res = NIFFS_remove(&fs, dname); 78 | TEST_CHECK_EQ(res, NIFFS_OK); 79 | niffs_emul_destroy_data(dname); 80 | } 81 | } 82 | } else { 83 | TEST_CHECK_EQ(res, NIFFS_OK); 84 | } 85 | } 86 | 87 | niffs_emul_reset_data_cursor(); 88 | char *dname; 89 | while ((dname = niffs_emul_get_next_data_name())) { 90 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 91 | } 92 | 93 | printf("\n"); 94 | return TEST_RES_OK; 95 | } 96 | TEST_END 97 | 98 | TEST(run_create_many_medium) 99 | { 100 | int files = 100 * (fs.sectors - 1); 101 | int fileno = 0; 102 | int res; 103 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector; 104 | 105 | while (fileno < files) { 106 | char name[NIFFS_NAME_LEN]; 107 | sprintf(name, "file%i", fileno); 108 | u32_t len = mlen - (fileno % (mlen/2)); 109 | u8_t *data = niffs_emul_create_data(name, len); 110 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 111 | 112 | if (fd >= 0) { 113 | res = NIFFS_write(&fs, fd, data, len); 114 | if (res == ERR_NIFFS_FULL) { 115 | int res2 = NIFFS_fremove(&fs, fd); 116 | TEST_CHECK_EQ(res2, NIFFS_OK); 117 | } else { 118 | TEST_CHECK_EQ(res, len); 119 | (void)NIFFS_close(&fs, fd); 120 | res = NIFFS_OK; 121 | } 122 | } else { 123 | res = fd; 124 | } 125 | if (res == NIFFS_OK) { 126 | fileno++; 127 | if ((fileno % (files/50))==0) { 128 | printf("."); 129 | fflush(stdout); 130 | } 131 | } else if (res == ERR_NIFFS_FULL) { 132 | niffs_emul_destroy_data(name); 133 | 134 | niffs_emul_reset_data_cursor(); 135 | char *dname; 136 | while ((dname = niffs_emul_get_next_data_name())) { 137 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 138 | } 139 | 140 | niffs_emul_reset_data_cursor(); 141 | int ix = 0; 142 | while ((dname = niffs_emul_get_next_data_name())) { 143 | ix++; 144 | if (((ix + fileno) % 5) == 0) { 145 | res = NIFFS_remove(&fs, dname); 146 | TEST_CHECK_EQ(res, NIFFS_OK); 147 | niffs_emul_destroy_data(dname); 148 | } 149 | } 150 | } else { 151 | TEST_CHECK_EQ(res, NIFFS_OK); 152 | } 153 | } 154 | 155 | niffs_emul_reset_data_cursor(); 156 | char *dname; 157 | while ((dname = niffs_emul_get_next_data_name())) { 158 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 159 | } 160 | 161 | printf("\n"); 162 | return TEST_RES_OK; 163 | } 164 | TEST_END 165 | 166 | TEST(run_create_many_large) 167 | { 168 | int files = 100 * (fs.sectors - 1); 169 | int fileno = 0; 170 | int res; 171 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector * (fs.sectors / 3); 172 | 173 | while (fileno < files) { 174 | char name[NIFFS_NAME_LEN]; 175 | sprintf(name, "file%i", fileno); 176 | u32_t len = mlen - (fileno % (mlen/2)); 177 | u8_t *data = niffs_emul_create_data(name, len); 178 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 179 | 180 | if (fd >= 0) { 181 | res = NIFFS_write(&fs, fd, data, len); 182 | if (res == ERR_NIFFS_FULL) { 183 | int res2 = NIFFS_fremove(&fs, fd); 184 | TEST_CHECK_EQ(res2, NIFFS_OK); 185 | } else { 186 | TEST_CHECK_EQ(res, len); 187 | (void)NIFFS_close(&fs, fd); 188 | res = NIFFS_OK; 189 | } 190 | } else { 191 | res = fd; 192 | } 193 | if (res == NIFFS_OK) { 194 | fileno++; 195 | if ((fileno % (files/50))==0) { 196 | printf("."); 197 | fflush(stdout); 198 | } 199 | } else if (res == ERR_NIFFS_FULL) { 200 | niffs_emul_destroy_data(name); 201 | 202 | niffs_emul_reset_data_cursor(); 203 | char *dname; 204 | while ((dname = niffs_emul_get_next_data_name())) { 205 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 206 | } 207 | 208 | niffs_emul_reset_data_cursor(); 209 | int ix = 0; 210 | while ((dname = niffs_emul_get_next_data_name())) { 211 | ix++; 212 | if (((ix + fileno) % 2) == 0) { 213 | res = NIFFS_remove(&fs, dname); 214 | TEST_CHECK_EQ(res, NIFFS_OK); 215 | niffs_emul_destroy_data(dname); 216 | } 217 | } 218 | } else { 219 | TEST_CHECK_EQ(res, NIFFS_OK); 220 | } 221 | } 222 | 223 | niffs_emul_reset_data_cursor(); 224 | char *dname; 225 | while ((dname = niffs_emul_get_next_data_name())) { 226 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 227 | } 228 | 229 | printf("\n"); 230 | return TEST_RES_OK; 231 | } 232 | TEST_END 233 | 234 | TEST(run_create_huge) 235 | { 236 | int files = 100; 237 | int fileno = 0; 238 | int res; 239 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector * (fs.sectors - 2); 240 | 241 | while (fileno < files) { 242 | char name[NIFFS_NAME_LEN]; 243 | sprintf(name, "file%i", fileno); 244 | u32_t len = mlen - (fileno % (mlen/2)); 245 | u8_t *data = niffs_emul_create_data(name, len); 246 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 247 | if (fd >= 0) { 248 | res = NIFFS_write(&fs, fd, data, len); 249 | if (res == ERR_NIFFS_FULL) { 250 | int res2 = NIFFS_fremove(&fs, fd); 251 | TEST_CHECK_EQ(res2, NIFFS_OK); 252 | } else { 253 | TEST_CHECK_EQ(res, len); 254 | (void)NIFFS_close(&fs, fd); 255 | res = NIFFS_OK; 256 | } 257 | } else { 258 | res = fd; 259 | } 260 | if (res == NIFFS_OK) { 261 | fileno++; 262 | if ((fileno % (files/50))==0) { 263 | printf("."); 264 | fflush(stdout); 265 | } 266 | } else if (res == ERR_NIFFS_FULL) { 267 | niffs_emul_destroy_data(name); 268 | 269 | niffs_emul_reset_data_cursor(); 270 | char *dname; 271 | while ((dname = niffs_emul_get_next_data_name())) { 272 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 273 | } 274 | 275 | niffs_emul_reset_data_cursor(); 276 | int ix = 0; 277 | while ((dname = niffs_emul_get_next_data_name())) { 278 | res = NIFFS_remove(&fs, dname); 279 | TEST_CHECK_EQ(res, NIFFS_OK); 280 | niffs_emul_destroy_data(dname); 281 | } 282 | } else { 283 | TEST_CHECK_EQ(res, NIFFS_OK); 284 | } 285 | } 286 | 287 | niffs_emul_reset_data_cursor(); 288 | char *dname; 289 | while ((dname = niffs_emul_get_next_data_name())) { 290 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 291 | } 292 | 293 | printf("\n"); 294 | return TEST_RES_OK; 295 | } 296 | TEST_END 297 | 298 | // loop: 299 | // create random sized files until full 300 | // when full, check current and remove some 301 | TEST(run_create_many_garbled) 302 | { 303 | int files = 100 * (fs.sectors - 1) * fs.pages_per_sector; 304 | int fileno = 0; 305 | int res; 306 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector * fs.sectors / 4; 307 | 308 | while (fileno < files) { 309 | char name[NIFFS_NAME_LEN]; 310 | sprintf(name, "file%i", fileno); 311 | u32_t len = 1 + (trand() % mlen); 312 | u8_t *data = niffs_emul_create_data(name, len); 313 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 314 | if (fd >= 0) { 315 | res = NIFFS_write(&fs, fd, data, len); 316 | if (res == ERR_NIFFS_FULL) { 317 | int res2 = NIFFS_fremove(&fs, fd); 318 | TEST_CHECK_EQ(res2, NIFFS_OK); 319 | } else { 320 | TEST_CHECK_EQ(res, len); 321 | (void)NIFFS_close(&fs, fd); 322 | res = NIFFS_OK; 323 | } 324 | } else { 325 | res = fd; 326 | } 327 | if (res == NIFFS_OK) { 328 | fileno++; 329 | if ((fileno % (files/50))==0) { 330 | printf("."); 331 | fflush(stdout); 332 | } 333 | } else if (res == ERR_NIFFS_FULL) { 334 | niffs_emul_destroy_data(name); 335 | 336 | niffs_emul_reset_data_cursor(); 337 | char *dname; 338 | while ((dname = niffs_emul_get_next_data_name())) { 339 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 340 | } 341 | 342 | niffs_emul_reset_data_cursor(); 343 | int ix = 0; 344 | while ((dname = niffs_emul_get_next_data_name())) { 345 | ix++; 346 | if (((ix + fileno) % 5) == 0) { 347 | res = NIFFS_remove(&fs, dname); 348 | TEST_CHECK_EQ(res, NIFFS_OK); 349 | niffs_emul_destroy_data(dname); 350 | } 351 | } 352 | } else { 353 | TEST_CHECK_EQ(res, NIFFS_OK); 354 | } 355 | } 356 | 357 | niffs_emul_reset_data_cursor(); 358 | char *dname; 359 | while ((dname = niffs_emul_get_next_data_name())) { 360 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 361 | } 362 | 363 | printf("\n"); 364 | return TEST_RES_OK; 365 | } 366 | TEST_END 367 | 368 | // create constant file, never touched 369 | // loop: 370 | // create random sized files until full 371 | // when full, check current and remove some 372 | TEST(run_create_many_garbled_one_constant) 373 | { 374 | int files = 100 * (fs.sectors - 1) * fs.pages_per_sector; 375 | int fileno = 0; 376 | int res; 377 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector * fs.sectors / 4; 378 | u32_t seed = 0x12312312; 379 | 380 | TEST_CHECK_EQ(niffs_emul_create_file(&fs, "constant", mlen/2), NIFFS_OK); 381 | 382 | while (fileno < files) { 383 | char name[NIFFS_NAME_LEN]; 384 | sprintf(name, "file%i", fileno); 385 | u32_t len = 1 + (trand() % mlen); 386 | u8_t *data = niffs_emul_create_data(name, len); 387 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 388 | if (fd >= 0) { 389 | res = NIFFS_write(&fs, fd, data, len); 390 | if (res == ERR_NIFFS_FULL) { 391 | int res2 = NIFFS_fremove(&fs, fd); 392 | TEST_CHECK_EQ(res2, NIFFS_OK); 393 | } else { 394 | TEST_CHECK_EQ(res, len); 395 | (void)NIFFS_close(&fs, fd); 396 | res = NIFFS_OK; 397 | } 398 | } else { 399 | res = fd; 400 | } 401 | if (res == NIFFS_OK) { 402 | fileno++; 403 | if ((fileno % (files/50))==0) { 404 | printf("."); 405 | fflush(stdout); 406 | } 407 | } else if (res == ERR_NIFFS_FULL) { 408 | niffs_emul_destroy_data(name); 409 | 410 | niffs_emul_reset_data_cursor(); 411 | char *dname; 412 | while ((dname = niffs_emul_get_next_data_name())) { 413 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 414 | } 415 | 416 | niffs_emul_reset_data_cursor(); 417 | int ix = 0; 418 | while ((dname = niffs_emul_get_next_data_name())) { 419 | ix++; 420 | if (strcmp("constant", dname) == 0) continue; 421 | if (((ix + fileno) % 3) == 0) { 422 | res = NIFFS_remove(&fs, dname); 423 | TEST_CHECK_EQ(res, NIFFS_OK); 424 | niffs_emul_destroy_data(dname); 425 | } 426 | } 427 | } else { 428 | TEST_CHECK_EQ(res, NIFFS_OK); 429 | } 430 | } 431 | 432 | niffs_emul_reset_data_cursor(); 433 | char *dname; 434 | while ((dname = niffs_emul_get_next_data_name())) { 435 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 436 | } 437 | 438 | printf("\n"); 439 | return TEST_RES_OK; 440 | } 441 | TEST_END 442 | 443 | 444 | // aborted create, gc, rm test 445 | // 446 | // create constant file which is never removed 447 | // loop: 448 | // create random sized files until full 449 | // when full, check current and remove some 450 | // abort sporadically 451 | // when aborted, run check 452 | // if check gives overflow, remove all but constant 453 | TEST(run_create_many_garbled_one_constant_aborted) 454 | { 455 | int files = 500 * (fs.sectors - 1) * fs.pages_per_sector; 456 | int fileno = 0; 457 | int res; 458 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector * fs.sectors / 4; 459 | 460 | TEST_CHECK_EQ(niffs_emul_create_file(&fs, "constant", mlen/2), NIFFS_OK); 461 | 462 | while (fileno < files) { 463 | u8_t data_already_freed = 0; 464 | char name[NIFFS_NAME_LEN]; 465 | sprintf(name, "file%i", fileno); 466 | u32_t len = 1 + (trand() % mlen); 467 | u8_t *data = niffs_emul_create_data(name, len); 468 | 469 | NIFFS_DBG_TEST("create %s %i bytes\n", name, len); 470 | 471 | // random power loss simulation 472 | int abort = (trand() % 100) < 10; 473 | if (abort) { 474 | u32_t abort_len = 1 + (trand() % len ); 475 | niffs_emul_set_write_byte_limit(abort_len); 476 | NIFFS_DBG_TEST("abort after %i bytes (of %i)\n", abort_len, len); 477 | } else { 478 | niffs_emul_set_write_byte_limit(0); 479 | } 480 | 481 | // try creating 482 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 483 | if (fd >= 0) { 484 | res = NIFFS_write(&fs, fd, data, len); 485 | if (res == ERR_NIFFS_FULL) { 486 | int res2 = NIFFS_fremove(&fs, fd); 487 | if (res2 == ERR_NIFFS_TEST_ABORTED_WRITE) { 488 | res = res2; 489 | (void)NIFFS_close(&fs, fd); 490 | } else { 491 | TEST_CHECK_EQ(res2, NIFFS_OK); 492 | } 493 | } else if (res == ERR_NIFFS_TEST_ABORTED_WRITE) { 494 | (void)NIFFS_close(&fs, fd); 495 | } else { 496 | TEST_CHECK_EQ(res, len); 497 | (void)NIFFS_close(&fs, fd); 498 | res = NIFFS_OK; 499 | } 500 | } else { 501 | res = fd; 502 | } 503 | 504 | if (res == NIFFS_OK) { 505 | fileno++; 506 | if ((fileno % (files/50))==0) { 507 | printf("."); 508 | fflush(stdout); 509 | } 510 | } else if (res == ERR_NIFFS_FULL) { 511 | // full, verify all and remove some 512 | niffs_emul_destroy_data(name); 513 | data_already_freed = 1; 514 | NIFFS_DBG_TEST("full on %s\n", name); 515 | 516 | NIFFS_DBG_TEST("verify when full\n"); 517 | niffs_emul_reset_data_cursor(); 518 | char *dname; 519 | while ((dname = niffs_emul_get_next_data_name())) { 520 | NIFFS_DBG_TEST(" .. check %s\n", dname); 521 | res = niffs_emul_verify_file(&fs, dname); 522 | if (res != NIFFS_OK) { 523 | NIFFS_dump(&fs); 524 | } 525 | TEST_CHECK_EQ(res, NIFFS_OK); 526 | } 527 | 528 | int deleted = 0; 529 | int ix = 0; 530 | int runs = 0; 531 | while (deleted == 0) { 532 | niffs_emul_reset_data_cursor(); 533 | while (res == NIFFS_OK && (dname = niffs_emul_get_next_data_name())) { 534 | ix++; 535 | if (strcmp("constant", dname) == 0) continue; 536 | if (((ix + fileno) % MAX(1, 3-runs)) == 0) { 537 | NIFFS_DBG_TEST("remove %s\n", dname); 538 | res = NIFFS_remove(&fs, dname); 539 | if (res != ERR_NIFFS_TEST_ABORTED_WRITE) { 540 | TEST_CHECK_EQ(res, NIFFS_OK); 541 | } 542 | niffs_emul_destroy_data(dname); 543 | deleted++; 544 | } 545 | } 546 | runs++; 547 | if (runs == 100) { 548 | // too many remove runs, major failure 549 | niffs_DIR d; 550 | struct niffs_dirent e; 551 | struct niffs_dirent *pe = &e; 552 | 553 | NIFFS_DBG_TEST("niffs contents\n"); 554 | NIFFS_opendir(&fs, "/", &d); 555 | while ((pe = NIFFS_readdir(&d, pe))) { 556 | NIFFS_DBG_TEST(" * %s %i oid:%04x pix:%04x\n", pe->name, pe->size, pe->obj_id, pe->pix); 557 | if (pe->size > mlen || !(strncmp("file", pe->name, 4) == 0 || strncmp("const", pe->name, 5)== 0)) { 558 | NIFFS_DBG_TEST("found crap file pix %04x length %i objid %04x name %s\n", pe->pix, pe->size, pe->obj_id, pe->name); 559 | niffs_emul_dump_pix(&fs, pe->pix); 560 | TEST_CHECK(0); 561 | } 562 | } 563 | NIFFS_closedir(&d); 564 | 565 | NIFFS_DBG_TEST("ram contents\n"); 566 | niffs_emul_reset_data_cursor(); 567 | while (res == NIFFS_OK && (dname = niffs_emul_get_next_data_name())) { 568 | NIFFS_DBG_TEST(" * %s\n", dname); 569 | } 570 | 571 | NIFFS_dump(&fs); 572 | TEST_CHECK(0); 573 | } 574 | } 575 | } 576 | 577 | if (res == ERR_NIFFS_TEST_ABORTED_WRITE) { 578 | // aborted, check consistency 579 | NIFFS_DBG_TEST("aborted on %s\n", name); 580 | if (!data_already_freed) { 581 | niffs_emul_destroy_data(name); 582 | } 583 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 584 | res = NIFFS_chk(&fs); 585 | if (res == ERR_NIFFS_OVERFLOW) { 586 | // crammed, remove all but constant 587 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 588 | NIFFS_DBG_TEST("niffs overflow %s\n", name); 589 | niffs_emul_set_write_byte_limit(0); 590 | niffs_emul_reset_data_cursor(); 591 | int ix = 0; 592 | char *dname; 593 | while ((dname = niffs_emul_get_next_data_name())) { 594 | ix++; 595 | if (strcmp("constant", dname) == 0) continue; 596 | NIFFS_DBG_TEST("remove %s\n", dname); 597 | res = NIFFS_remove(&fs, dname); 598 | TEST_CHECK_EQ(res, NIFFS_OK); 599 | niffs_emul_destroy_data(dname); 600 | } 601 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 602 | res = NIFFS_chk(&fs); 603 | } 604 | if (res != NIFFS_OK) { 605 | NIFFS_dump(&fs); 606 | } 607 | TEST_CHECK_EQ(res, NIFFS_OK); 608 | 609 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 610 | TEST_CHECK_EQ(niffs_emul_remove_all_zerosized_files(&fs), NIFFS_OK); 611 | 612 | // check all files after cleanup 613 | niffs_emul_reset_data_cursor(); 614 | char *dname; 615 | NIFFS_DBG_TEST("verify after check\n"); 616 | 617 | while ((dname = niffs_emul_get_next_data_name())) { 618 | NIFFS_DBG_TEST(" .. check %s\n", dname); 619 | res = niffs_emul_verify_file(&fs, dname); 620 | if (res != NIFFS_OK) { 621 | NIFFS_dump(&fs); 622 | } 623 | TEST_CHECK_EQ(res, NIFFS_OK); 624 | } 625 | } 626 | 627 | // check for garbage files 628 | NIFFS_DBG_TEST("find crap\n"); 629 | niffs_DIR d; 630 | struct niffs_dirent e; 631 | struct niffs_dirent *pe = &e; 632 | 633 | NIFFS_opendir(&fs, "/", &d); 634 | while ((pe = NIFFS_readdir(&d, pe))) { 635 | if (pe->size > mlen || !(strncmp("file", pe->name, 4) == 0 || strncmp("const", pe->name, 5)== 0)) { 636 | NIFFS_DBG_TEST("found crap file pix %04x length %i objid %04x name %s\n", pe->pix, pe->size, pe->obj_id, pe->name); 637 | niffs_emul_dump_pix(&fs, pe->pix); 638 | TEST_CHECK(0); 639 | } 640 | } 641 | NIFFS_closedir(&d); 642 | 643 | if (res != NIFFS_OK) { 644 | NIFFS_dump(&fs); 645 | } 646 | 647 | TEST_CHECK_EQ(res, NIFFS_OK); 648 | 649 | // check erase span 650 | u32_t era_min, era_max; 651 | niffs_emul_get_sector_erase_count_info(&fs, &era_min, &era_max); 652 | if (era_max > 0) { 653 | NIFFS_DBG_TEST("ERA INF min:%i max:%i span:%i\n", era_min, era_max, ((era_max - era_min)*100)/era_max); 654 | if (era_max > 100) TEST_CHECK_LT(((era_max - era_min)*100)/era_max, 50); 655 | } 656 | } // main loop 657 | 658 | NIFFS_DBG_TEST("verify final\n"); 659 | niffs_emul_reset_data_cursor(); 660 | char *dname; 661 | while ((dname = niffs_emul_get_next_data_name())) { 662 | NIFFS_DBG_TEST(" .. check %s\n", dname); 663 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, dname), NIFFS_OK); 664 | } 665 | 666 | printf("\n"); 667 | 668 | return TEST_RES_OK; 669 | } 670 | TEST_END 671 | 672 | // aborted create, gc, rm, append test 673 | // 674 | // create constant file which is never removed 675 | // loop: 676 | // if less than 5 files, create files, random sized 677 | // if more or equal, modify/append files until full 678 | // sometimes, modify constant file, one page only 679 | // when full, remove one 680 | // abort sporadically 681 | // when aborted, run check 682 | // if check gives overflow, remove all but constant 683 | TEST(run_create_modify_append_some_garbled_one_constant_aborted) 684 | { 685 | int run = 0; 686 | int runs = 500 * (fs.sectors - 1) * fs.pages_per_sector; 687 | int fileno = 0; 688 | int active_files = 0; 689 | int res; 690 | u32_t mlen = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * fs.pages_per_sector * fs.sectors / 8; 691 | 692 | u32_t const_len = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) * 3; 693 | TEST_CHECK_EQ(niffs_emul_create_file(&fs, "constant", const_len), NIFFS_OK); 694 | char name[NIFFS_NAME_LEN]; 695 | 696 | while (run < runs) { 697 | NIFFS_DBG_TEST("run#%i\n", run); 698 | //TODO if (run == 11660) __dbg = 1; 699 | //TODO if (run >= 11660) NIFFS_dump(&fs); 700 | u8_t data_already_freed = 0; 701 | u8_t create_else_mod = 0; 702 | 703 | if (active_files < 5) { 704 | 705 | // create file 706 | 707 | create_else_mod = 1; 708 | sprintf(name, "file%i", fileno); 709 | u32_t len = 1 + (trand() % mlen); 710 | u8_t *data = niffs_emul_create_data(name, len); 711 | NIFFS_DBG_TEST("create %s %i bytes\n", name, len); 712 | 713 | // random power loss simulation 714 | int abort = (trand() % 100) < 10; 715 | if (abort) { 716 | u32_t abort_len = 1 + (trand() % len ); 717 | niffs_emul_set_write_byte_limit(abort_len); 718 | NIFFS_DBG_TEST("abort after %i bytes (of %i)\n", abort_len, len); 719 | } else { 720 | niffs_emul_set_write_byte_limit(0); 721 | } 722 | 723 | // try creating 724 | int fd = NIFFS_open(&fs, name, NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_RDWR, 0); 725 | if (fd >= 0) { 726 | res = NIFFS_write(&fs, fd, data, len); 727 | if (res == ERR_NIFFS_FULL) { 728 | int res2 = NIFFS_fremove(&fs, fd); 729 | if (res2 == ERR_NIFFS_TEST_ABORTED_WRITE) { 730 | res = res2; 731 | (void)NIFFS_close(&fs, fd); 732 | } else { 733 | TEST_CHECK_EQ(res2, NIFFS_OK); 734 | } 735 | } else if (res == ERR_NIFFS_TEST_ABORTED_WRITE) { 736 | (void)NIFFS_close(&fs, fd); 737 | } else { 738 | TEST_CHECK_EQ(res, len); 739 | (void)NIFFS_close(&fs, fd); 740 | res = NIFFS_OK; 741 | } 742 | } else { 743 | res = fd; 744 | } 745 | 746 | if (res == NIFFS_OK) { 747 | fileno++; 748 | active_files++; 749 | } 750 | 751 | } else { 752 | 753 | // find file and modify/append 754 | 755 | create_else_mod = 0; 756 | u32_t len; 757 | u32_t offs; 758 | u32_t flen; 759 | int fd; 760 | if (active_files == 0 || trand() % 100 < 20) { 761 | // select constant file 762 | strcpy(name, "constant"); 763 | NIFFS_DBG_TEST("select %s\n", name); 764 | 765 | fd = NIFFS_open(&fs, name, NIFFS_O_RDWR, 0); 766 | if (fd < 0) res = fd; 767 | TEST_CHECK_EQ(res, NIFFS_OK); 768 | niffs_stat s; 769 | res = NIFFS_fstat(&fs, fd, &s); 770 | TEST_CHECK_EQ(res, NIFFS_OK); 771 | TEST_CHECK_EQ(s.size, const_len); 772 | len = 1 + (trand() % (1 + s.size/3)); 773 | offs = trand() % (s.size - len); 774 | NIFFS_ASSERT(len+offs < s.size); 775 | flen = s.size; 776 | } else { 777 | // select arbitrary other file 778 | char *dname; 779 | u32_t selected = 0; 780 | u32_t ix = 0; 781 | u32_t sel_ix = trand() % active_files; 782 | while (selected == 0) { 783 | niffs_emul_reset_data_cursor(); 784 | while (res == NIFFS_OK && (dname = niffs_emul_get_next_data_name())) { 785 | if (strcmp("constant", dname) == 0) continue; 786 | if (ix >= sel_ix) { 787 | selected = 1; 788 | break; 789 | } 790 | ix++; 791 | } 792 | } 793 | 794 | strcpy(name, dname); 795 | NIFFS_DBG_TEST("select %s\n", name); 796 | 797 | fd = NIFFS_open(&fs, name, NIFFS_O_RDWR, 0); 798 | if (fd < 0) res = fd; 799 | TEST_CHECK_EQ(res, NIFFS_OK); 800 | niffs_stat s; 801 | res = NIFFS_fstat(&fs, fd, &s); 802 | TEST_CHECK_EQ(res, NIFFS_OK); 803 | len = 1 + (trand() % (1+s.size/3)); 804 | offs = s.size / 2 + trand() % (1+s.size / 2); 805 | flen = s.size; 806 | } 807 | 808 | NIFFS_DBG_TEST("modify %s %i bytes offs %i / %i\n", name, len, offs, flen); 809 | 810 | res = NIFFS_lseek(&fs, fd, offs, NIFFS_SEEK_SET); 811 | TEST_CHECK_EQ(res, offs); 812 | 813 | u8_t *mdata; 814 | if (strcmp("constant", name) == 0) { 815 | u32_t dummy; 816 | mdata = niffs_emul_get_data("constant", &dummy); 817 | mdata += offs; 818 | } else { 819 | mdata = malloc(len); 820 | } 821 | NIFFS_ASSERT(mdata); 822 | memrand(mdata, len, run*0xead1c9f1); 823 | res = NIFFS_write(&fs, fd, mdata, len); 824 | if (strcmp("constant", name)) { 825 | free(mdata); 826 | } 827 | 828 | (void)NIFFS_close(&fs, fd); 829 | if (res != ERR_NIFFS_FULL && res != ERR_NIFFS_TEST_ABORTED_WRITE) { 830 | TEST_CHECK_EQ(res, len); 831 | res = NIFFS_OK; 832 | } 833 | } 834 | 835 | // handle problems 836 | 837 | if (res == ERR_NIFFS_FULL) { 838 | res = NIFFS_OK; 839 | data_already_freed = 1; 840 | NIFFS_DBG_TEST("full on %s, remove\n", name); 841 | if (create_else_mod) niffs_emul_destroy_data(name); 842 | 843 | int deleted = 0; 844 | int ix = 0; 845 | int remove_runs = 0; 846 | char *dname; 847 | while (deleted == 0) { 848 | niffs_emul_reset_data_cursor(); 849 | while (res == NIFFS_OK && deleted == 0 && (dname = niffs_emul_get_next_data_name())) { 850 | ix++; 851 | if (strcmp("constant", dname) == 0) continue; 852 | if (((ix + fileno) % MAX(1, 3-remove_runs)) == 0) { 853 | NIFFS_DBG_TEST("remove %s\n", dname); 854 | res = NIFFS_remove(&fs, dname); 855 | if (res != ERR_NIFFS_TEST_ABORTED_WRITE) { 856 | TEST_CHECK_EQ(res, NIFFS_OK); 857 | } 858 | niffs_emul_destroy_data(dname); 859 | deleted++; 860 | active_files--; 861 | } 862 | } 863 | remove_runs++; 864 | if (remove_runs == 100) { 865 | // too many remove runs, major failure 866 | niffs_DIR d; 867 | struct niffs_dirent e; 868 | struct niffs_dirent *pe = &e; 869 | 870 | NIFFS_DBG_TEST("niffs contents\n"); 871 | NIFFS_opendir(&fs, "/", &d); 872 | while ((pe = NIFFS_readdir(&d, pe))) { 873 | NIFFS_DBG_TEST(" * %s %i oid:%04x pix:%04x\n", pe->name, pe->size, pe->obj_id, pe->pix); 874 | if (pe->size > mlen || !(strncmp("file", pe->name, 4) == 0 || strncmp("const", pe->name, 5)== 0)) { 875 | NIFFS_DBG_TEST("found crap file pix %04x length %i objid %04x name %s\n", pe->pix, pe->size, pe->obj_id, pe->name); 876 | niffs_emul_dump_pix(&fs, pe->pix); 877 | TEST_CHECK(0); 878 | } 879 | } 880 | NIFFS_closedir(&d); 881 | 882 | NIFFS_DBG_TEST("ram contents\n"); 883 | niffs_emul_reset_data_cursor(); 884 | while (res == NIFFS_OK && (dname = niffs_emul_get_next_data_name())) { 885 | NIFFS_DBG_TEST(" * %s\n", dname); 886 | } 887 | 888 | NIFFS_dump(&fs); 889 | TEST_CHECK(0); 890 | } 891 | } 892 | } 893 | 894 | if (res == ERR_NIFFS_TEST_ABORTED_WRITE) { 895 | // aborted, check consistency 896 | NIFFS_DBG_TEST("aborted on %s\n", name); 897 | if (!data_already_freed && create_else_mod) { 898 | niffs_emul_destroy_data(name); 899 | } 900 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 901 | res = NIFFS_chk(&fs); 902 | if (res == ERR_NIFFS_OVERFLOW) { 903 | // crammed, remove all but constant 904 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 905 | NIFFS_DBG_TEST("niffs overflow %s\n", name); 906 | niffs_emul_set_write_byte_limit(0); 907 | niffs_emul_reset_data_cursor(); 908 | int ix = 0; 909 | char *dname; 910 | while ((dname = niffs_emul_get_next_data_name())) { 911 | ix++; 912 | if (strcmp("constant", dname) == 0) continue; 913 | NIFFS_DBG_TEST("remove %s\n", dname); 914 | res = NIFFS_remove(&fs, dname); 915 | TEST_CHECK_EQ(res, NIFFS_OK); 916 | niffs_emul_destroy_data(dname); 917 | } 918 | active_files = 0; 919 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 920 | res = NIFFS_chk(&fs); 921 | } 922 | if (res != NIFFS_OK) { 923 | NIFFS_dump(&fs); 924 | } 925 | TEST_CHECK_EQ(res, NIFFS_OK); 926 | 927 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 928 | TEST_CHECK_EQ(niffs_emul_remove_all_zerosized_files(&fs), NIFFS_OK); 929 | } 930 | 931 | // check "constant" length 932 | niffs_stat s; 933 | TEST_CHECK_EQ(NIFFS_stat(&fs, "constant", &s), NIFFS_OK); 934 | TEST_CHECK_EQ(s.size, const_len); 935 | 936 | // check for garbage files 937 | niffs_DIR d; 938 | struct niffs_dirent e; 939 | struct niffs_dirent *pe = &e; 940 | 941 | NIFFS_opendir(&fs, "/", &d); 942 | while ((pe = NIFFS_readdir(&d, pe))) { 943 | if (!(strncmp("file", pe->name, 4) == 0 || strncmp("const", pe->name, 5)== 0)) { 944 | NIFFS_DBG_TEST("found crap file pix %04x length %i objid %04x name %s\n", pe->pix, pe->size, pe->obj_id, pe->name); 945 | niffs_emul_dump_pix(&fs, pe->pix); 946 | TEST_CHECK(0); 947 | } 948 | } 949 | NIFFS_closedir(&d); 950 | 951 | if (res != NIFFS_OK) { 952 | NIFFS_dump(&fs); 953 | } 954 | 955 | TEST_CHECK_EQ(res, NIFFS_OK); 956 | 957 | // check erase span 958 | u32_t era_min, era_max; 959 | niffs_emul_get_sector_erase_count_info(&fs, &era_min, &era_max); 960 | if (era_max > 0) { 961 | NIFFS_DBG_TEST("ERA INF min:%i max:%i span:%i\n", era_min, era_max, ((era_max - era_min)*100)/era_max); 962 | if (era_max > 100) TEST_CHECK_LT(((era_max - era_min)*100)/era_max, 50); 963 | } 964 | run++; 965 | if ((run % (runs/50))==0) { 966 | printf("."); 967 | fflush(stdout); 968 | } 969 | } // main loop 970 | 971 | TEST_CHECK_EQ(niffs_emul_verify_file(&fs, "constant"), NIFFS_OK); 972 | 973 | printf("\n"); 974 | 975 | return TEST_RES_OK; 976 | } 977 | TEST_END 978 | 979 | 980 | // full system 981 | TEST(run_full) 982 | { 983 | int res; 984 | u32_t of_len = fs.sectors * fs.sector_size; 985 | u8_t buf[EMUL_PAGE_SIZE]; 986 | memrand(buf, sizeof(buf), 0x20070515); 987 | int fd = NIFFS_open(&fs, "overflow", NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 988 | TEST_CHECK_GE(fd, 0); 989 | 990 | printf(" fill fs but one page\n"); 991 | res = NIFFS_OK; 992 | while (res >= NIFFS_OK) { 993 | res = NIFFS_write(&fs, fd, buf, sizeof(buf)); 994 | } 995 | TEST_CHECK_EQ(res, ERR_NIFFS_FULL); 996 | 997 | niffs_stat s; 998 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 999 | printf(" %s\t%i bytes\n", s.name, s.size); 1000 | 1001 | NIFFS_close(&fs, fd); 1002 | 1003 | printf(" create a file in last page\n"); 1004 | fd = NIFFS_open(&fs, "full", NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 1005 | TEST_CHECK_GE(fd, 0); 1006 | res = NIFFS_write(&fs, fd, buf, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0)); 1007 | TEST_CHECK_GE(res, NIFFS_OK); 1008 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 1009 | printf(" %s\t%i bytes\n", s.name, s.size); 1010 | TEST_CHECK_EQ(s.size, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0)); 1011 | printf(" remove file in last page\n"); 1012 | TEST_CHECK_EQ(NIFFS_remove(&fs, "full"), NIFFS_OK); 1013 | 1014 | printf(" create a file in last page again\n"); 1015 | fd = NIFFS_open(&fs, "fullagain", NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 1016 | TEST_CHECK_GE(fd, 0); 1017 | res = NIFFS_write(&fs, fd, buf, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0)); 1018 | TEST_CHECK_GE(res, NIFFS_OK); 1019 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 1020 | printf(" %s\t%i bytes\n", s.name, s.size); 1021 | TEST_CHECK_EQ(s.size, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0)); 1022 | printf(" remove file in last page\n"); 1023 | TEST_CHECK_EQ(NIFFS_remove(&fs, "fullagain"), NIFFS_OK); 1024 | 1025 | printf(" create a file in last page again, now with too big a size\n"); 1026 | fd = NIFFS_open(&fs, "fullof", NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 1027 | TEST_CHECK_GE(fd, 0); 1028 | res = NIFFS_write(&fs, fd, buf, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + 1); 1029 | TEST_CHECK_EQ(res, ERR_NIFFS_FULL); 1030 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 1031 | printf(" %s\t%i bytes\n", s.name, s.size); 1032 | TEST_CHECK_EQ(s.size, 0); 1033 | 1034 | printf(" remove huge file\n"); 1035 | TEST_CHECK_EQ(NIFFS_remove(&fs, "overflow"), NIFFS_OK); 1036 | 1037 | printf(" write to file in last page again, with the big size\n"); 1038 | res = NIFFS_write(&fs, fd, buf, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + 1); 1039 | TEST_CHECK_EQ(res, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + 1); 1040 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 1041 | printf(" %s\t%i bytes\n", s.name, s.size); 1042 | TEST_CHECK_EQ(s.size, _NIFFS_SPIX_2_PDATA_LEN(&fs, 0) + 1); 1043 | 1044 | return TEST_RES_OK; 1045 | } 1046 | TEST_END 1047 | 1048 | TEST(run_full_single_byte) 1049 | { 1050 | int res; 1051 | u32_t of_len = fs.sectors * fs.sector_size; 1052 | int fd = NIFFS_open(&fs, "overflow", NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 1053 | TEST_CHECK_GE(fd, 0); 1054 | 1055 | printf(" fill fs, byte wise\n"); 1056 | res = NIFFS_OK; 1057 | while (res >= NIFFS_OK) { 1058 | u8_t data = 'z'; 1059 | res = NIFFS_write(&fs, fd, &data, 1); 1060 | } 1061 | TEST_CHECK_EQ(res, ERR_NIFFS_FULL); 1062 | 1063 | niffs_stat s; 1064 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 1065 | printf(" %s\t%i bytes\n", s.name, s.size); 1066 | 1067 | NIFFS_close(&fs, fd); 1068 | 1069 | printf(" create a file when full\n"); 1070 | fd = NIFFS_open(&fs, "full", NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 1071 | TEST_CHECK_EQ(fd, ERR_NIFFS_FULL); 1072 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), ERR_NIFFS_FILEDESC_BAD); 1073 | TEST_CHECK_EQ(NIFFS_stat(&fs, "full", &s), ERR_NIFFS_FILE_NOT_FOUND); 1074 | 1075 | printf(" remove huge file\n"); 1076 | TEST_CHECK_EQ(NIFFS_remove(&fs, "overflow"), NIFFS_OK); 1077 | 1078 | printf(" create a file again\n"); 1079 | fd = NIFFS_open(&fs, "notfull", NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 1080 | TEST_CHECK_GE(fd, NIFFS_OK); 1081 | int i; 1082 | res = NIFFS_OK; 1083 | for (i = 0; i < 1000 && res >= NIFFS_OK; i++) { 1084 | u8_t data = 'x'; 1085 | res = NIFFS_write(&fs, fd, &data, 1); 1086 | } 1087 | TEST_CHECK_GE(res, NIFFS_OK); 1088 | 1089 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 1090 | printf(" %s\t%i bytes\n", s.name, s.size); 1091 | TEST_CHECK_EQ(s.size, 1000); 1092 | 1093 | return TEST_RES_OK; 1094 | } 1095 | TEST_END 1096 | 1097 | #if NIFFS_LINEAR_AREA 1098 | TEST(run_lin_aborted) 1099 | { 1100 | const u32_t flen = fs.lin_sectors * fs.sector_size; 1101 | u8_t *data = niffs_emul_create_data("lin", flen); 1102 | TEST_CHECK(data); 1103 | int res; 1104 | 1105 | int fd; 1106 | u32_t written; 1107 | u8_t created = 0; 1108 | do { 1109 | if (created) { 1110 | fd = NIFFS_open(&fs, "lin", NIFFS_O_LINEAR | NIFFS_O_WRONLY | NIFFS_O_APPEND, 0); 1111 | } else { 1112 | fd = NIFFS_mknod_linear(&fs, "lin", flen); 1113 | created = 1; 1114 | } 1115 | TEST_CHECK_GE(fd, 0); 1116 | niffs_stat s; 1117 | res = NIFFS_fstat(&fs, fd, &s); 1118 | TEST_CHECK_EQ(res, NIFFS_OK); 1119 | written = s.size; 1120 | TEST_CHECK_LE(written, flen); 1121 | if (written == flen) break; 1122 | 1123 | u32_t write = trand() % (flen / 100); 1124 | write = (write % NIFFS_WORD_ALIGN) ? write - (write%NIFFS_WORD_ALIGN) : write; 1125 | write = MAX(NIFFS_WORD_ALIGN, write); 1126 | write = MIN(flen - written, write); 1127 | 1128 | // printf("---written %d, write %d\n", written, write); 1129 | if (trand() % 100 < 30) { 1130 | u32_t abort = (trand() % write) & (~(NIFFS_WORD_ALIGN-1)); 1131 | // printf("---abort @ %d\n", abort); 1132 | niffs_emul_set_write_byte_limit(abort+50); 1133 | } else { 1134 | niffs_emul_set_write_byte_limit(0); 1135 | } 1136 | 1137 | res = NIFFS_write(&fs, fd, &data[written], write); 1138 | if (res == ERR_NIFFS_TEST_ABORTED_WRITE) { 1139 | // printf("---aborted: unmounting, checking, remounting\n"); 1140 | TEST_CHECK_EQ(NIFFS_unmount(&fs), NIFFS_OK); 1141 | res = NIFFS_chk(&fs); 1142 | TEST_CHECK_EQ(res, NIFFS_OK); 1143 | TEST_CHECK_EQ(NIFFS_mount(&fs), NIFFS_OK); 1144 | } else { 1145 | TEST_CHECK_EQ(res, write); 1146 | res = NIFFS_close(&fs, fd); 1147 | TEST_CHECK_EQ(res, NIFFS_OK); 1148 | } 1149 | } while (written < flen); 1150 | 1151 | niffs_emul_verify_file(&fs, "lin"); 1152 | 1153 | return TEST_RES_OK; 1154 | } 1155 | TEST_END 1156 | #endif // NIFFS_LINEAR_AREA 1157 | 1158 | SUITE_TESTS(niffs_run_tests) 1159 | ADD_TEST(run_create_many_small) 1160 | ADD_TEST(run_create_many_medium) 1161 | ADD_TEST(run_create_many_large) 1162 | ADD_TEST(run_create_huge) 1163 | ADD_TEST(run_create_many_garbled) 1164 | ADD_TEST(run_create_many_garbled_one_constant) 1165 | ADD_TEST(run_create_many_garbled_one_constant_aborted) 1166 | ADD_TEST(run_create_modify_append_some_garbled_one_constant_aborted) 1167 | ADD_TEST(run_full) 1168 | ADD_TEST(run_full_single_byte) 1169 | #if NIFFS_LINEAR_AREA 1170 | ADD_TEST(run_lin_aborted) 1171 | #endif // NIFFS_LINEAR_AREA 1172 | SUITE_END(niffs_run_tests) 1173 | -------------------------------------------------------------------------------- /src/test/niffs_sys_tests.c: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_sys_tests.c 3 | * 4 | * Created on: Feb 23, 2015 5 | * Author: petera 6 | */ 7 | 8 | #include "testrunner.h" 9 | #include "niffs_test_emul.h" 10 | 11 | SUITE(niffs_sys_tests) 12 | 13 | static void setup(test *t) { 14 | (void)niffs_emul_init(); 15 | NIFFS_format(&fs); 16 | NIFFS_mount(&fs); 17 | } 18 | 19 | static void teardown(test *t) { 20 | niffs_emul_destroy_all_data(); 21 | } 22 | 23 | 24 | TEST(sys_missing_file) 25 | { 26 | int fd = NIFFS_open(&fs, "this_wont_exist", NIFFS_O_RDONLY, 0); 27 | TEST_CHECK_LT(fd, 0); 28 | return TEST_RES_OK; 29 | } 30 | TEST_END 31 | 32 | 33 | TEST(sys_bad_fd) 34 | { 35 | int res; 36 | niffs_stat s; 37 | int fd = NIFFS_open(&fs, "this_wont_exist", NIFFS_O_RDONLY, 0); 38 | TEST_CHECK_LT(fd, 0); 39 | res = NIFFS_fstat(&fs, fd, &s); 40 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_BAD); 41 | res = NIFFS_fremove(&fs, fd); 42 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_BAD); 43 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_CUR); 44 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_BAD); 45 | res = NIFFS_read(&fs, fd, 0, 0); 46 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_BAD); 47 | res = NIFFS_write(&fs, fd, 0, 0); 48 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_BAD); 49 | return TEST_RES_OK; 50 | } 51 | TEST_END 52 | 53 | 54 | TEST(sys_closed_fd) 55 | { 56 | int res; 57 | niffs_stat s; 58 | res = niffs_emul_create_file(&fs, "file", _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 59 | TEST_CHECK_EQ(res, NIFFS_OK); 60 | int fd = NIFFS_open(&fs, "file", NIFFS_O_RDONLY, 0); 61 | TEST_CHECK_GE(fd, 0); 62 | NIFFS_close(&fs, fd); 63 | 64 | res = NIFFS_fstat(&fs, fd, &s); 65 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 66 | res = NIFFS_fremove(&fs, fd); 67 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 68 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_CUR); 69 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 70 | res = NIFFS_read(&fs, fd, 0, 0); 71 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 72 | res = NIFFS_write(&fs, fd, 0, 0); 73 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 74 | return TEST_RES_OK; 75 | } 76 | TEST_END 77 | 78 | TEST(sys_deleted_same_fd) 79 | { 80 | int res; 81 | niffs_stat s; 82 | int fd; 83 | res = niffs_emul_create_file(&fs, "remove", _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 84 | TEST_CHECK_EQ(res, NIFFS_OK); 85 | fd = NIFFS_open(&fs, "remove", NIFFS_O_RDWR, 0); 86 | TEST_CHECK_GE(fd, 0); 87 | fd = NIFFS_open(&fs, "remove", NIFFS_O_RDWR, 0); 88 | TEST_CHECK(fd >= 0); 89 | res = NIFFS_fremove(&fs, fd); 90 | TEST_CHECK(res >= 0); 91 | 92 | res = NIFFS_fstat(&fs, fd, &s); 93 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 94 | res = NIFFS_fremove(&fs, fd); 95 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 96 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_CUR); 97 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 98 | res = NIFFS_read(&fs, fd, 0, 0); 99 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 100 | res = NIFFS_write(&fs, fd, 0, 0); 101 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 102 | 103 | return TEST_RES_OK; 104 | } 105 | TEST_END 106 | 107 | 108 | TEST(sys_deleted_other_fd) 109 | { 110 | int res; 111 | niffs_stat s; 112 | int fd, fd_orig; 113 | res = niffs_emul_create_file(&fs, "remove", _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 114 | TEST_CHECK_EQ(res, NIFFS_OK); 115 | fd_orig = NIFFS_open(&fs, "remove", NIFFS_O_RDWR, 0); 116 | TEST_CHECK_GE(fd_orig, 0); 117 | fd = NIFFS_open(&fs, "remove", NIFFS_O_RDWR, 0); 118 | TEST_CHECK_GE(fd, 0); 119 | res = NIFFS_fremove(&fs, fd_orig); 120 | TEST_CHECK_EQ(res, NIFFS_OK); 121 | NIFFS_close(&fs, fd_orig); 122 | 123 | res = NIFFS_fstat(&fs, fd, &s); 124 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 125 | res = NIFFS_fremove(&fs, fd); 126 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 127 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_CUR); 128 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 129 | res = NIFFS_read(&fs, fd, 0, 0); 130 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 131 | res = NIFFS_write(&fs, fd, 0, 0); 132 | TEST_CHECK_EQ(res, ERR_NIFFS_FILEDESC_CLOSED); 133 | 134 | return TEST_RES_OK; 135 | } 136 | TEST_END 137 | 138 | 139 | TEST(sys_fd_overflow) 140 | { 141 | int res; 142 | niffs_stat s; 143 | res = niffs_emul_create_file(&fs, "file", _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 144 | TEST_CHECK_EQ(res, NIFFS_OK); 145 | int i = 0; 146 | while (i < fs.descs_len) { 147 | int fd = NIFFS_open(&fs, "file", NIFFS_O_RDONLY, 0); 148 | TEST_CHECK_GE(fd, 0); 149 | i++; 150 | } 151 | int fd = NIFFS_open(&fs, "file", NIFFS_O_RDONLY, 0); 152 | TEST_CHECK_EQ(fd, ERR_NIFFS_OUT_OF_FILEDESCS); 153 | 154 | return TEST_RES_OK; 155 | } 156 | TEST_END 157 | 158 | 159 | 160 | TEST(sys_file_by_open) 161 | { 162 | int res; 163 | niffs_stat s; 164 | int fd = NIFFS_open(&fs, "filebopen", NIFFS_O_CREAT, 0); 165 | TEST_CHECK_GE(fd, 0); 166 | res = NIFFS_fstat(&fs, fd, &s); 167 | TEST_CHECK_EQ(res, NIFFS_OK); 168 | TEST_CHECK_EQ(strcmp((char*)s.name, "filebopen"), 0); 169 | TEST_CHECK_EQ(s.size, 0); 170 | NIFFS_close(&fs, fd); 171 | 172 | fd = NIFFS_open(&fs, "filebopen", NIFFS_O_RDONLY, 0); 173 | TEST_CHECK_GE(fd, 0); 174 | res = NIFFS_fstat(&fs, fd, &s); 175 | TEST_CHECK_EQ(res, NIFFS_OK); 176 | TEST_CHECK_EQ(strcmp((char*)s.name, "filebopen"), 0); 177 | TEST_CHECK_EQ(s.size, 0); 178 | NIFFS_close(&fs, fd); 179 | 180 | return TEST_RES_OK; 181 | } 182 | TEST_END 183 | 184 | TEST(sys_file_by_open_flags) 185 | { 186 | u8_t buf[8]; 187 | int res = niffs_emul_create_file(&fs, "reffile", _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 188 | TEST_CHECK_EQ(res, NIFFS_OK); 189 | 190 | // creat excl on created file 191 | int fd = NIFFS_open(&fs, "reffile", NIFFS_O_RDWR | NIFFS_O_CREAT | NIFFS_O_EXCL | NIFFS_O_TRUNC, 0); 192 | TEST_CHECK_EQ(fd, ERR_NIFFS_FILE_EXISTS); 193 | niffs_stat s; 194 | res = NIFFS_stat(&fs, "reffile", &s); 195 | TEST_CHECK_EQ(res, NIFFS_OK); 196 | TEST_CHECK_EQ(s.size, (u32_t)_NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 197 | 198 | // read only 199 | fd = NIFFS_open(&fs, "reffile", NIFFS_O_RDONLY, 0); 200 | TEST_CHECK_GE(fd, 0); 201 | res = NIFFS_read(&fs, fd, buf, sizeof(buf)); 202 | TEST_CHECK_EQ(res, (s32_t)sizeof(buf)); 203 | res = NIFFS_write(&fs, fd, buf, sizeof(buf)); 204 | TEST_CHECK_EQ(res, ERR_NIFFS_NOT_WRITABLE); 205 | res = NIFFS_fremove(&fs, fd); 206 | TEST_CHECK_EQ(res, ERR_NIFFS_NOT_WRITABLE); 207 | (void)NIFFS_close(&fs, fd); 208 | 209 | // creat on created file 210 | fd = NIFFS_open(&fs, "reffile", NIFFS_O_RDWR | NIFFS_O_CREAT, 0); 211 | TEST_CHECK_GE(fd, 0); 212 | res = NIFFS_fstat(&fs, fd, &s); 213 | TEST_CHECK_EQ(res, NIFFS_OK); 214 | TEST_CHECK_EQ(s.size, (u32_t)_NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 215 | (void)NIFFS_close(&fs, fd); 216 | res = niffs_emul_verify_file(&fs, "reffile"); 217 | TEST_CHECK_EQ(res, NIFFS_OK); 218 | 219 | // write only 220 | memset(buf, 0xee, sizeof(buf)); 221 | fd = NIFFS_open(&fs, "reffile", NIFFS_O_WRONLY, 0); 222 | TEST_CHECK_GE(fd, 0); 223 | res = NIFFS_read(&fs, fd, buf, sizeof(buf)); 224 | TEST_CHECK_EQ(res, ERR_NIFFS_NOT_READABLE); 225 | res = NIFFS_write(&fs, fd, buf, sizeof(buf)); 226 | TEST_CHECK_EQ(res, (s32_t)sizeof(buf)); 227 | (void)NIFFS_close(&fs, fd); 228 | res = niffs_emul_verify_file(&fs, "reffile"); 229 | TEST_CHECK_EQ(res, ERR_NIFFS_TEST_REF_DATA_MISMATCH); 230 | 231 | // creat trunc on created file 232 | fd = NIFFS_open(&fs, "reffile", NIFFS_O_RDWR | NIFFS_O_CREAT | NIFFS_O_TRUNC, 0); 233 | TEST_CHECK_EQ(fd, NIFFS_OK); 234 | res = NIFFS_fstat(&fs, fd, &s); 235 | TEST_CHECK_EQ(res, NIFFS_OK); 236 | TEST_CHECK_EQ(s.size, 0); 237 | (void)NIFFS_close(&fs, fd); 238 | 239 | // append 240 | fd = NIFFS_open(&fs, "reffile", NIFFS_O_RDWR | NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_APPEND, 0); 241 | TEST_CHECK_EQ(fd, NIFFS_OK); 242 | res = NIFFS_fstat(&fs, fd, &s); 243 | TEST_CHECK_EQ(res, NIFFS_OK); 244 | TEST_CHECK_EQ(s.size, 0); 245 | u32_t dlen; 246 | u8_t *data = niffs_emul_get_data("reffile", &dlen); 247 | u32_t offs = 0; 248 | while (offs < dlen) { 249 | u32_t wlen = MIN(dlen - offs, 7); 250 | res = NIFFS_write(&fs, fd, &data[offs], wlen); 251 | TEST_CHECK_EQ(res, wlen); 252 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_SET); 253 | TEST_CHECK_EQ(res, 0); 254 | offs += wlen; 255 | } 256 | (void)NIFFS_close(&fs, fd); 257 | res = niffs_emul_verify_file(&fs, "reffile"); 258 | TEST_CHECK_EQ(res, NIFFS_OK); 259 | 260 | return TEST_RES_OK; 261 | } 262 | TEST_END 263 | 264 | TEST(sys_file_by_creat) 265 | { 266 | int res; 267 | res = niffs_emul_create_file(&fs, "filebcreat", _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 268 | TEST_CHECK_EQ(res, NIFFS_OK); 269 | res = NIFFS_creat(&fs, "filebcreat", 0); 270 | TEST_CHECK_EQ(res, ERR_NIFFS_NAME_CONFLICT); 271 | return TEST_RES_OK; 272 | } 273 | TEST_END 274 | 275 | TEST(sys_list_dir) 276 | { 277 | int res; 278 | 279 | char *files[4] = { 280 | "file1", 281 | "file2", 282 | "file3", 283 | "file4" 284 | }; 285 | int file_cnt = sizeof(files)/sizeof(char *); 286 | 287 | int i; 288 | 289 | for (i = 0; i < file_cnt; i++) { 290 | res = niffs_emul_create_file(&fs, files[i], _NIFFS_SPIX_2_PDATA_LEN(&fs, 1)); 291 | TEST_CHECK_EQ(res, NIFFS_OK); 292 | } 293 | 294 | niffs_DIR d; 295 | struct niffs_dirent e; 296 | struct niffs_dirent *pe = &e; 297 | 298 | NIFFS_opendir(&fs, "/", &d); 299 | int found = 0; 300 | while ((pe = NIFFS_readdir(&d, pe))) { 301 | printf(" %s [%04x] size:%i type:%02x\n", pe->name, pe->obj_id, pe->size, pe->type); 302 | for (i = 0; i < file_cnt; i++) { 303 | if (strcmp(files[i], pe->name) == 0) { 304 | found++; 305 | break; 306 | } 307 | } 308 | } 309 | NIFFS_closedir(&d); 310 | 311 | TEST_CHECK_EQ(found, file_cnt); 312 | 313 | return TEST_RES_OK; 314 | } 315 | TEST_END 316 | 317 | TEST(sys_write) { 318 | int res; 319 | int fd; 320 | fd = NIFFS_open(&fs, "testfile", NIFFS_O_RDWR | NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_APPEND, 0); 321 | TEST_CHECK_GE(fd, 0); 322 | 323 | u8_t test_hdr[4] = {1,2,3,4}; 324 | res = NIFFS_write(&fs, fd, (u8_t *)&test_hdr, sizeof(test_hdr)); 325 | TEST_CHECK_EQ(res, (int)sizeof(test_hdr)); 326 | 327 | u8_t test_data[8+3] = {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x20,0x21,0x22}; 328 | u8_t pin; 329 | for (pin = 0; pin < 24; pin++) { 330 | u8_t *cfg = (u8_t *)test_data; 331 | res = NIFFS_write(&fs, fd, cfg, sizeof(test_data)); 332 | TEST_CHECK_EQ(res, (int)sizeof(test_data)); 333 | } 334 | TEST_CHECK_EQ(NIFFS_close(&fs, fd), NIFFS_OK);; 335 | 336 | return TEST_RES_OK; 337 | } 338 | TEST_END 339 | 340 | 341 | 342 | TEST(sys_simultaneous_write) { 343 | int res; 344 | res = NIFFS_creat(&fs, "simul1", 0); 345 | TEST_CHECK_EQ(res, NIFFS_OK); 346 | 347 | int fd1 = NIFFS_open(&fs, "simul1", NIFFS_O_RDWR, 0); 348 | TEST_CHECK_GE(fd1, 0); 349 | int fd2 = NIFFS_open(&fs, "simul1", NIFFS_O_RDWR, 0); 350 | TEST_CHECK_GE(fd2, 0); 351 | int fd3 = NIFFS_open(&fs, "simul1", NIFFS_O_RDWR, 0); 352 | TEST_CHECK_GE(fd3, 0); 353 | 354 | u8_t data1 = 1; 355 | u8_t data2 = 2; 356 | u8_t data3 = 3; 357 | 358 | res = NIFFS_write(&fs, fd1, &data1, 1); 359 | TEST_CHECK_GE(res, 0); 360 | NIFFS_close(&fs, fd1); 361 | res = NIFFS_write(&fs, fd2, &data2, 1); 362 | TEST_CHECK_GE(res, 0); 363 | NIFFS_close(&fs, fd2); 364 | res = NIFFS_write(&fs, fd3, &data3, 1); 365 | TEST_CHECK_GE(res, 0); 366 | NIFFS_close(&fs, fd3); 367 | 368 | niffs_stat s; 369 | res = NIFFS_stat(&fs, "simul1", &s); 370 | TEST_CHECK_EQ(res, NIFFS_OK); 371 | 372 | TEST_CHECK_EQ(s.size, 1); 373 | 374 | u8_t rdata; 375 | int fd = NIFFS_open(&fs, "simul1", NIFFS_O_RDONLY, 0); 376 | TEST_CHECK_GE(fd, 0); 377 | res = NIFFS_read(&fs, fd, &rdata, 1); 378 | TEST_CHECK_GE(res, 0); 379 | 380 | TEST_CHECK_EQ(rdata, data3); 381 | 382 | return TEST_RES_OK; 383 | } 384 | TEST_END 385 | 386 | TEST(sys_simultaneous_write_append) { 387 | int res = NIFFS_creat(&fs, "simul2", 0); 388 | TEST_CHECK_EQ(res, NIFFS_OK); 389 | 390 | int fd1 = NIFFS_open(&fs, "simul2", NIFFS_O_RDWR | NIFFS_O_APPEND, 0); 391 | TEST_CHECK_GE(fd1, 0); 392 | int fd2 = NIFFS_open(&fs, "simul2", NIFFS_O_RDWR | NIFFS_O_APPEND, 0); 393 | TEST_CHECK_GE(fd2, 0); 394 | int fd3 = NIFFS_open(&fs, "simul2", NIFFS_O_RDWR | NIFFS_O_APPEND, 0); 395 | TEST_CHECK_GE(fd3, 0); 396 | 397 | u8_t data1 = 1; 398 | u8_t data2 = 2; 399 | u8_t data3 = 3; 400 | 401 | res = NIFFS_write(&fs, fd1, &data1, 1); 402 | TEST_CHECK_EQ(res, 1); 403 | NIFFS_close(&fs, fd1); 404 | res = NIFFS_write(&fs, fd2, &data2, 1); 405 | TEST_CHECK_EQ(res, 1); 406 | NIFFS_close(&fs, fd2); 407 | res = NIFFS_write(&fs, fd3, &data3, 1); 408 | TEST_CHECK_EQ(res, 1); 409 | NIFFS_close(&fs, fd3); 410 | 411 | niffs_stat s; 412 | res = NIFFS_stat(&fs, "simul2", &s); 413 | TEST_CHECK_EQ(res, NIFFS_OK); 414 | 415 | TEST_CHECK_EQ(s.size, 3); 416 | 417 | u8_t rdata[3]; 418 | int fd = NIFFS_open(&fs, "simul2", NIFFS_O_RDONLY, 0); 419 | TEST_CHECK_GE(fd, 0); 420 | res = NIFFS_read(&fs, fd, (u8_t*)&rdata, 3); 421 | TEST_CHECK_EQ(res, 3); 422 | 423 | TEST_CHECK_EQ(rdata[0], data1); 424 | TEST_CHECK_EQ(rdata[1], data2); 425 | TEST_CHECK_EQ(rdata[2], data3); 426 | 427 | return TEST_RES_OK; 428 | } 429 | TEST_END 430 | 431 | TEST(sys_rename) { 432 | int res; 433 | 434 | char *src_name = "baah"; 435 | char *dst_name = "booh"; 436 | char *dst_name2 = "beeh"; 437 | int size = _NIFFS_SPIX_2_PDATA_LEN(&fs, 1); 438 | 439 | res = niffs_emul_create_file(&fs, src_name, size); 440 | TEST_CHECK_EQ(res, NIFFS_OK); 441 | 442 | res = NIFFS_rename(&fs, src_name, dst_name); 443 | TEST_CHECK_EQ(res, NIFFS_OK); 444 | 445 | res = NIFFS_rename(&fs, dst_name, dst_name); 446 | TEST_CHECK_EQ(res, ERR_NIFFS_NAME_CONFLICT); 447 | 448 | res = NIFFS_rename(&fs, src_name, dst_name2); 449 | TEST_CHECK_EQ(res, ERR_NIFFS_FILE_NOT_FOUND); 450 | 451 | return TEST_RES_OK; 452 | } TEST_END 453 | 454 | TEST(sys_remove_single_by_path) 455 | { 456 | int res; 457 | int fd; 458 | res = niffs_emul_create_file(&fs, "remove", 8); 459 | TEST_CHECK_EQ(res, NIFFS_OK); 460 | res = NIFFS_remove(&fs, "remove"); 461 | TEST_CHECK_EQ(res, NIFFS_OK); 462 | fd = NIFFS_open(&fs, "remove", NIFFS_O_RDONLY, 0); 463 | TEST_CHECK_EQ(fd, ERR_NIFFS_FILE_NOT_FOUND); 464 | 465 | return TEST_RES_OK; 466 | } 467 | TEST_END 468 | 469 | 470 | TEST(sys_remove_single_by_fd) 471 | { 472 | int res; 473 | int fd; 474 | res = niffs_emul_create_file(&fs, "remove", 8); 475 | TEST_CHECK_EQ(res, NIFFS_OK); 476 | fd = NIFFS_open(&fs, "remove", NIFFS_O_RDWR, 0); 477 | TEST_CHECK_GE(fd, 0); 478 | res = NIFFS_fremove(&fs, fd); 479 | TEST_CHECK_EQ(res, NIFFS_OK); 480 | (void)NIFFS_close(&fs, fd); 481 | fd = NIFFS_open(&fs, "remove", NIFFS_O_RDONLY, 0); 482 | TEST_CHECK_EQ(fd, ERR_NIFFS_FILE_NOT_FOUND); 483 | 484 | return TEST_RES_OK; 485 | } 486 | TEST_END 487 | 488 | TEST(sys_read_beyond) 489 | { 490 | int res; 491 | int fd; 492 | u8_t buf[8]; 493 | u32_t len = sizeof(buf); 494 | res = niffs_emul_create_file(&fs, "read", len); 495 | TEST_CHECK_EQ(res, NIFFS_OK); 496 | fd = NIFFS_open(&fs, "read", NIFFS_O_RDONLY, 0); 497 | TEST_CHECK_GE(fd, 0); 498 | res = NIFFS_read(&fs, fd, buf, len); 499 | TEST_CHECK_EQ(res, len); 500 | res = NIFFS_read(&fs, fd, buf, len); 501 | TEST_CHECK_EQ(res, 0); /* 502 | If the starting position is at or after the end-of-file, 0 shall be returned. 503 | [http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html] */ 504 | 505 | return TEST_RES_OK; 506 | } 507 | TEST_END 508 | 509 | TEST(sys_read_empty) 510 | { 511 | int res; 512 | int fd; 513 | u8_t buf[8]; 514 | u32_t len = sizeof(buf); 515 | res = NIFFS_creat(&fs, "empty", 0); 516 | TEST_CHECK_EQ(res, NIFFS_OK); 517 | niffs_stat s; 518 | res = NIFFS_stat(&fs, "empty", &s); 519 | TEST_CHECK_EQ(s.size, 0); 520 | fd = NIFFS_open(&fs, "empty", NIFFS_O_RDONLY, 0); 521 | TEST_CHECK_GE(fd, 0); 522 | res = NIFFS_read(&fs, fd, buf, len); 523 | TEST_CHECK_EQ(res, 0); /* 524 | If the starting position is at or after the end-of-file, 0 shall be returned. 525 | [http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html] */ 526 | 527 | return TEST_RES_OK; 528 | } 529 | TEST_END 530 | 531 | TEST(sys_read_ptr_beyond) 532 | { 533 | int res; 534 | int fd; 535 | u32_t len = 8; 536 | res = niffs_emul_create_file(&fs, "read", len); 537 | TEST_CHECK_EQ(res, NIFFS_OK); 538 | fd = NIFFS_open(&fs, "read", NIFFS_O_RDONLY, 0); 539 | TEST_CHECK_GE(fd, 0); 540 | u8_t *rptr; 541 | u32_t rlen; 542 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 543 | TEST_CHECK_EQ(res, len); 544 | TEST_CHECK_EQ(rlen, len); 545 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_END); 546 | TEST_CHECK_EQ(res, len); 547 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 548 | TEST_CHECK_EQ(res, ERR_NIFFS_END_OF_FILE); 549 | TEST_CHECK_EQ(rlen, 0); 550 | 551 | return TEST_RES_OK; 552 | } 553 | TEST_END 554 | 555 | TEST(sys_read_ptr_empty) 556 | { 557 | int res; 558 | int fd; 559 | u32_t len = 8; 560 | res = NIFFS_creat(&fs, "empty", 0); 561 | TEST_CHECK_EQ(res, NIFFS_OK); 562 | niffs_stat s; 563 | res = NIFFS_stat(&fs, "empty", &s); 564 | TEST_CHECK_EQ(s.size, 0); 565 | fd = NIFFS_open(&fs, "empty", NIFFS_O_RDONLY, 0); 566 | TEST_CHECK_GE(fd, 0); 567 | u8_t *rptr; 568 | u32_t rlen; 569 | res = niffs_emul_read_ptr(&fs, fd, &rptr, &rlen); 570 | TEST_CHECK_EQ(res, ERR_NIFFS_END_OF_FILE); 571 | TEST_CHECK_EQ(rlen, 0); 572 | 573 | return TEST_RES_OK; 574 | } 575 | TEST_END 576 | 577 | TEST(sys_write_flush) 578 | { 579 | int res; 580 | int fd; 581 | u32_t len = 8; 582 | fd = NIFFS_open(&fs, "write", NIFFS_O_CREAT | NIFFS_O_RDWR, 0); 583 | TEST_CHECK_GE(fd, 0); 584 | u8_t *data = niffs_emul_create_data("write", len); 585 | TEST_CHECK(data); 586 | 587 | u32_t i; 588 | for (i = 0; i < len; i++) { 589 | res = NIFFS_write(&fs, fd, &data[i], 1); 590 | TEST_CHECK_EQ(res, 1); 591 | niffs_stat s; 592 | res = NIFFS_fstat(&fs, fd, &s); 593 | TEST_CHECK_EQ(res, NIFFS_OK); 594 | TEST_CHECK_EQ(s.size, i+1); 595 | } 596 | 597 | res = NIFFS_fflush(&fs, fd); 598 | TEST_CHECK_EQ(res, NIFFS_OK); 599 | 600 | (void)NIFFS_close(&fs, fd); 601 | 602 | res = niffs_emul_verify_file(&fs, "write"); 603 | TEST_CHECK_EQ(res, NIFFS_OK); 604 | 605 | return TEST_RES_OK; 606 | } 607 | TEST_END 608 | 609 | TEST(sys_file_uniqueness) 610 | { 611 | int res; 612 | int fd; 613 | char fname[NIFFS_NAME_LEN]; 614 | int files = (fs.sectors - 1) * (fs.pages_per_sector); 615 | int i; 616 | printf(" creating %i files\n", files); 617 | for (i = 0; i < files; i++) { 618 | char content[20]; 619 | sprintf(fname, "file%i", i); 620 | sprintf(content, "%i", i); 621 | fd = NIFFS_open(&fs, fname, NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 622 | TEST_CHECK_GE(fd, 0); 623 | res = NIFFS_write(&fs, fd, content, strlen(content)+1); 624 | TEST_CHECK_EQ(res, (u32_t)strlen(content)+1); 625 | (void)NIFFS_close(&fs, fd); 626 | } 627 | printf(" checking %i files\n", files); 628 | for (i = 0; i < files; i++) { 629 | char content[20]; 630 | char ref_content[20]; 631 | sprintf(fname, "file%i", i); 632 | sprintf(content, "%i", i); 633 | fd = NIFFS_open(&fs, fname, NIFFS_O_RDONLY, 0); 634 | TEST_CHECK_GE(fd, 0); 635 | res = NIFFS_read(&fs, fd, ref_content, strlen(content)+1); 636 | TEST_CHECK_EQ(res, (u32_t)strlen(content)+1); 637 | TEST_CHECK_EQ(strcmp(ref_content, content), 0); 638 | (void)NIFFS_close(&fs, fd); 639 | } 640 | printf(" removing %i files\n", files/2); 641 | for (i = 0; i < files; i += 2) { 642 | sprintf(fname, "file%i", i); 643 | res = NIFFS_remove(&fs, fname); 644 | TEST_CHECK_EQ(res, 0); 645 | } 646 | printf(" creating %i files\n", files/2); 647 | for (i = 0; i < files; i += 2) { 648 | char content[20]; 649 | sprintf(fname, "file%i", i); 650 | sprintf(content, "new%i", i); 651 | fd = NIFFS_open(&fs, fname, NIFFS_O_CREAT | NIFFS_O_APPEND | NIFFS_O_RDWR, 0); 652 | TEST_CHECK_GE(fd, 0); 653 | res = NIFFS_write(&fs, fd, content, strlen(content)+1); 654 | TEST_CHECK_EQ(res, (u32_t)strlen(content)+1); 655 | (void)NIFFS_close(&fs, fd); 656 | } 657 | printf(" checking %i files\n", files); 658 | for (i = 0; i < files; i++) { 659 | char content[20]; 660 | char ref_content[20]; 661 | sprintf(fname, "file%i", i); 662 | if ((i & 1) == 0) { 663 | sprintf(content, "new%i", i); 664 | } else { 665 | sprintf(content, "%i", i); 666 | } 667 | fd = NIFFS_open(&fs, fname, NIFFS_O_RDONLY, 0); 668 | TEST_CHECK_GE(fd, 0); 669 | res = NIFFS_read(&fs, fd, ref_content, strlen(content)+1); 670 | TEST_CHECK_EQ(res, (u32_t)strlen(content)+1); 671 | TEST_CHECK_EQ(strcmp(ref_content, content), 0); 672 | (void)NIFFS_close(&fs, fd); 673 | } 674 | 675 | return TEST_RES_OK; 676 | } 677 | TEST_END 678 | 679 | TEST(sys_lseek_simple_modification) { 680 | int res; 681 | int fd; 682 | char *fname = "seekfile"; 683 | int i; 684 | int len = 4096; 685 | fd = NIFFS_open(&fs, fname, NIFFS_O_TRUNC | NIFFS_O_CREAT | NIFFS_O_RDWR, 0); 686 | TEST_CHECK_GE(fd, 0); 687 | 688 | u8_t *buf = niffs_emul_create_data("seekfile", len); 689 | res = NIFFS_write(&fs, fd, buf, len); 690 | TEST_CHECK_EQ(res, len); 691 | 692 | res = niffs_emul_verify_file(&fs, "seekfile"); 693 | TEST_CHECK_EQ(res, NIFFS_OK); 694 | 695 | res = NIFFS_lseek(&fs, fd, len/2, NIFFS_SEEK_SET); 696 | TEST_CHECK_EQ(res, len/2); 697 | 698 | u8_t *nbuf = niffs_emul_create_data("newdata", len/2); 699 | res = NIFFS_write(&fs, fd, nbuf, len/2); 700 | TEST_CHECK_EQ(res, len/2); 701 | 702 | niffs_stat s; 703 | res = NIFFS_fstat(&fs, fd, &s); 704 | TEST_CHECK_EQ(res, NIFFS_OK); 705 | TEST_CHECK_EQ(s.size, len); 706 | 707 | u8_t *ref = malloc(len); 708 | memcpy(ref, buf, len/2); 709 | memcpy(&ref[len/2], nbuf, len/2); 710 | 711 | res = niffs_emul_verify_file_against_data(&fs, "seekfile", ref); 712 | free(ref); 713 | TEST_CHECK_EQ(res, NIFFS_OK); 714 | 715 | (void)NIFFS_close(&fs, fd); 716 | 717 | return TEST_RES_OK; 718 | } 719 | TEST_END 720 | 721 | TEST(sys_lseek_modification_append) { 722 | int res; 723 | int fd; 724 | char *fname = "seekfile"; 725 | int i; 726 | int len = 4096; 727 | fd = NIFFS_open(&fs, fname, NIFFS_O_TRUNC | NIFFS_O_CREAT | NIFFS_O_RDWR, 0); 728 | TEST_CHECK_GE(fd, 0); 729 | 730 | u8_t *buf = niffs_emul_create_data("seekfile", len); 731 | res = NIFFS_write(&fs, fd, buf, len); 732 | TEST_CHECK_EQ(res, len); 733 | 734 | res = niffs_emul_verify_file(&fs, "seekfile"); 735 | TEST_CHECK_EQ(res, NIFFS_OK); 736 | 737 | res = NIFFS_lseek(&fs, fd, len/2, NIFFS_SEEK_SET); 738 | TEST_CHECK_EQ(res, len/2); 739 | 740 | u8_t *nbuf = niffs_emul_create_data("newdata", len); 741 | res = NIFFS_write(&fs, fd, nbuf, len); 742 | TEST_CHECK_EQ(res, len); 743 | 744 | niffs_stat s; 745 | res = NIFFS_fstat(&fs, fd, &s); 746 | TEST_CHECK_EQ(res, NIFFS_OK); 747 | TEST_CHECK_EQ(s.size, len + len/2); 748 | 749 | u8_t *ref = malloc(len/2 + len); 750 | memcpy(ref, buf, len/2); 751 | memcpy(&ref[len/2], nbuf, len); 752 | 753 | res = niffs_emul_verify_file_against_data(&fs, "seekfile", ref); 754 | free(ref); 755 | TEST_CHECK_EQ(res, NIFFS_OK); 756 | 757 | (void)NIFFS_close(&fs, fd); 758 | 759 | return TEST_RES_OK; 760 | } 761 | TEST_END 762 | 763 | TEST(sys_lseek_modification_append_multi) { 764 | int res; 765 | int fd; 766 | char *fname = "seekfile"; 767 | int len = 1024; 768 | int runs = (fs.sectors-1) * fs.pages_per_sector * _NIFFS_SPIX_2_PDATA_LEN(&fs, 1) / len; 769 | 770 | u8_t *refbuf = niffs_emul_create_data("null", len + runs * (len / 2)); 771 | 772 | fd = NIFFS_open(&fs, fname, NIFFS_O_TRUNC | NIFFS_O_CREAT | NIFFS_O_RDWR, 0); 773 | TEST_CHECK_GE(fd, 0); 774 | 775 | u8_t *buf = niffs_emul_create_data("seekfile", len); 776 | res = NIFFS_write(&fs, fd, buf, len); 777 | TEST_CHECK_EQ(res, len); 778 | memcpy(refbuf, buf, len); 779 | u32_t offs = len; 780 | 781 | while (runs--) { 782 | res = NIFFS_lseek(&fs, fd, -len/2, NIFFS_SEEK_END); 783 | offs -= len/2; 784 | TEST_CHECK_EQ(res, offs); 785 | 786 | char seedname[32]; 787 | sprintf(seedname, "mod%i", runs); 788 | u8_t *bufmod = niffs_emul_create_data(seedname, len); 789 | res = NIFFS_write(&fs, fd, bufmod, len); 790 | TEST_CHECK_EQ(res, len); 791 | memcpy(&refbuf[offs], bufmod, len); 792 | offs += len; 793 | 794 | res = niffs_emul_verify_file_against_data(&fs, "seekfile", refbuf); 795 | TEST_CHECK_GE(res, 0); 796 | } 797 | 798 | (void)NIFFS_close(&fs, fd); 799 | 800 | return TEST_RES_OK; 801 | } 802 | TEST_END 803 | 804 | TEST(sys_lseek) { 805 | int res; 806 | int fd; 807 | char *fname = "seekfile"; 808 | int len = ((fs.sectors-1) * fs.pages_per_sector / 2) * _NIFFS_SPIX_2_PDATA_LEN(&fs, 1); 809 | 810 | fd = NIFFS_open(&fs, fname, NIFFS_O_TRUNC | NIFFS_O_CREAT | NIFFS_O_RDWR, 0); 811 | TEST_CHECK_GE(fd, 0); 812 | 813 | u8_t *refbuf = niffs_emul_create_data("seekfile", len); 814 | res = NIFFS_write(&fs, fd, refbuf, len); 815 | TEST_CHECK_EQ(res, len); 816 | 817 | niffs_stat s; 818 | TEST_CHECK_EQ(NIFFS_fstat(&fs, fd, &s), NIFFS_OK); 819 | 820 | int offs; 821 | int i; 822 | 823 | for (i = 1; i < s.size; i++) { 824 | res = NIFFS_lseek(&fs, fd, -i, NIFFS_SEEK_END); 825 | TEST_CHECK_EQ(res, len-i); 826 | offs = s.size - i; 827 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 828 | } 829 | 830 | for (i = 0; i < s.size; i++) { 831 | res = NIFFS_lseek(&fs, fd, i, NIFFS_SEEK_SET); 832 | TEST_CHECK_EQ(res, i); 833 | offs = i; 834 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 835 | } 836 | 837 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_SET); 838 | TEST_CHECK_EQ(res, NIFFS_OK); 839 | offs = 0; 840 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 841 | for (i = 0; i < s.size; i++) { 842 | res = NIFFS_lseek(&fs, fd, 1, NIFFS_SEEK_CUR); 843 | TEST_CHECK_EQ(res, i+1); 844 | offs++; 845 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 846 | } 847 | for (i = 0; i < s.size; i++) { 848 | res = NIFFS_lseek(&fs, fd, -1, NIFFS_SEEK_CUR); 849 | TEST_CHECK_EQ(res, s.size-i-1); 850 | offs--; 851 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 852 | } 853 | 854 | (void)NIFFS_close(&fs, fd); 855 | 856 | return TEST_RES_OK; 857 | } 858 | TEST_END 859 | 860 | TEST(sys_lseek_read_ftell) { 861 | int res; 862 | int fd; 863 | char *fname = "seekfile"; 864 | int len = ((fs.sectors-1) * fs.pages_per_sector / 2) * _NIFFS_SPIX_2_PDATA_LEN(&fs, 1); 865 | int runs = 10000; 866 | 867 | fd = NIFFS_open(&fs, fname, NIFFS_O_TRUNC | NIFFS_O_CREAT | NIFFS_O_RDWR, 0); 868 | TEST_CHECK_GE(fd, 0); 869 | 870 | u8_t *refbuf = niffs_emul_create_data("seekfile", len); 871 | res = NIFFS_write(&fs, fd, refbuf, len); 872 | TEST_CHECK_EQ(res, len); 873 | 874 | int offs = 0; 875 | res = NIFFS_lseek(&fs, fd, 0, NIFFS_SEEK_SET); 876 | TEST_CHECK_EQ(res, NIFFS_OK); 877 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 878 | 879 | while (runs--) { 880 | int i; 881 | u8_t buf[64]; 882 | if (offs + 41 + sizeof(buf) >= len) { 883 | offs = (offs + 41 + sizeof(buf)) % len; 884 | res = NIFFS_lseek(&fs, fd, offs, NIFFS_SEEK_SET); 885 | TEST_CHECK_EQ(res, offs); 886 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 887 | } 888 | res = NIFFS_lseek(&fs, fd, 41, NIFFS_SEEK_CUR); 889 | TEST_CHECK_EQ(res, offs+41); 890 | offs += 41; 891 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 892 | res = NIFFS_read(&fs, fd, buf, sizeof(buf)); 893 | TEST_CHECK_EQ(res, (u32_t)sizeof(buf)); 894 | for (i = 0; i < sizeof(buf); i++) { 895 | if (buf[i] != refbuf[offs+i]) { 896 | printf(" mismatch at offs %i\n", offs); 897 | } 898 | TEST_CHECK_EQ(buf[i], refbuf[offs+i]); 899 | } 900 | offs += sizeof(buf); 901 | 902 | res = NIFFS_lseek(&fs, fd, -((u32_t)sizeof(buf)+11), NIFFS_SEEK_CUR); 903 | TEST_CHECK_EQ(res, offs - ((u32_t)sizeof(buf)+11)); 904 | offs -= (sizeof(buf)+11); 905 | TEST_CHECK_EQ(NIFFS_ftell(&fs, fd), offs); 906 | res = NIFFS_read(&fs, fd, buf, sizeof(buf)); 907 | TEST_CHECK_EQ(res, (u32_t)sizeof(buf)); 908 | for (i = 0; i < sizeof(buf); i++) { 909 | if (buf[i] != refbuf[offs+i]) { 910 | printf(" mismatch at offs %i\n", offs); 911 | } 912 | TEST_CHECK_EQ(buf[i], refbuf[offs+i]); 913 | } 914 | offs += sizeof(buf); 915 | } 916 | 917 | (void)NIFFS_close(&fs, fd); 918 | 919 | return TEST_RES_OK; 920 | } 921 | TEST_END 922 | 923 | #if NIFFS_LINEAR_AREA 924 | 925 | TEST(sys_lin_open) { 926 | int res; 927 | int fd; 928 | 929 | u8_t *data = niffs_emul_create_data("linear", fs.lin_sectors * fs.sector_size); 930 | TEST_CHECK(data); 931 | 932 | u32_t mul; 933 | for (mul = 1; mul <= fs.lin_sectors; mul++) { 934 | const u32_t fsize = fs.sector_size * mul; 935 | fd = NIFFS_open(&fs, "linear", NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_LINEAR | NIFFS_O_RDWR, 0); 936 | TEST_CHECK_GE(fd,0); 937 | res = NIFFS_write(&fs, fd, data, fsize); 938 | TEST_CHECK_EQ(res, fsize); 939 | res = NIFFS_close(&fs, fd); 940 | TEST_CHECK_EQ(res, NIFFS_OK); 941 | fd = NIFFS_open(&fs, "linear", NIFFS_O_RDONLY, 0); 942 | TEST_CHECK_GE(fd,0); 943 | res = niffs_emul_verify_file(&fs, "linear"); 944 | TEST_CHECK_EQ(res, NIFFS_OK); 945 | u8_t *ptr; 946 | u32_t len; 947 | res = NIFFS_read_ptr(&fs, fd, &ptr, &len); 948 | TEST_CHECK_EQ(res, fsize); 949 | TEST_CHECK_EQ(len, fsize); 950 | niffs_stat s; 951 | res = NIFFS_fstat(&fs, fd, &s); 952 | TEST_CHECK_EQ(res, NIFFS_OK); 953 | TEST_CHECK_EQ(s.size, fsize); 954 | TEST_CHECK_EQ(s.type, _NIFFS_FTYPE_LINFILE); 955 | res = NIFFS_close(&fs, fd); 956 | TEST_CHECK_EQ(res, NIFFS_OK); 957 | } 958 | return TEST_RES_OK; 959 | } 960 | TEST_END 961 | 962 | TEST(sys_lin_lseek) { 963 | int res; 964 | int fd; 965 | 966 | const u32_t fsize = fs.lin_sectors * fs.sector_size; 967 | u8_t *data = niffs_emul_create_data("linear", fsize); 968 | TEST_CHECK(data); 969 | 970 | fd = NIFFS_open(&fs, "linear", NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_LINEAR | NIFFS_O_RDWR, 0); 971 | TEST_CHECK_GE(fd,0); 972 | res = NIFFS_write(&fs, fd, data, fsize); 973 | TEST_CHECK_EQ(res, fsize); 974 | res = NIFFS_close(&fs, fd); 975 | TEST_CHECK_EQ(res, NIFFS_OK); 976 | fd = NIFFS_open(&fs, "linear", NIFFS_O_RDONLY, 0); 977 | TEST_CHECK_GE(fd,0); 978 | res = niffs_emul_verify_file(&fs, "linear"); 979 | TEST_CHECK_EQ(res, NIFFS_OK); 980 | 981 | u32_t offs; 982 | for (offs = 0; offs < fsize; offs += 3) { 983 | u8_t *ptr; 984 | u32_t len; 985 | res = NIFFS_lseek(&fs, fd, offs, NIFFS_SEEK_SET); 986 | TEST_CHECK_EQ(res, offs); 987 | res = NIFFS_read_ptr(&fs, fd, &ptr, &len); 988 | TEST_CHECK_EQ(res, fsize - offs); 989 | TEST_CHECK_EQ(len, fsize - offs); 990 | } 991 | 992 | return TEST_RES_OK; 993 | } 994 | TEST_END 995 | 996 | TEST(sys_lin_info) { 997 | int res; 998 | niffs_info i; 999 | res = NIFFS_info(&fs, &i); 1000 | TEST_CHECK_EQ(res, NIFFS_OK); 1001 | TEST_CHECK_EQ(i.lin_total_sectors, fs.lin_sectors); 1002 | TEST_CHECK_EQ(i.lin_used_sectors, 0); 1003 | TEST_CHECK_EQ(i.lin_max_conseq_free, i.lin_total_sectors); 1004 | int fileno = 0; 1005 | int fd; 1006 | do { 1007 | char fname[12]; 1008 | sprintf(fname, "file%i", fileno); 1009 | fd = NIFFS_mknod_linear(&fs, fname, 2 * fs.sector_size); 1010 | if (fd == NIFFS_OK) { 1011 | fileno++; 1012 | res = NIFFS_close(&fs, fd); 1013 | } 1014 | TEST_CHECK_EQ(res, NIFFS_OK); 1015 | } while (fd == NIFFS_OK); 1016 | TEST_CHECK_EQ(fd, ERR_NIFFS_LINEAR_NO_SPACE); 1017 | res = NIFFS_info(&fs, &i); 1018 | TEST_CHECK_EQ(res, NIFFS_OK); 1019 | TEST_CHECK_EQ(i.lin_used_sectors, (fs.lin_sectors/2)*2); 1020 | TEST_CHECK_EQ(i.lin_max_conseq_free, i.lin_total_sectors - (fs.lin_sectors/2)*2); 1021 | 1022 | int rm_fileno; 1023 | for (rm_fileno = 0; rm_fileno < fileno; rm_fileno += 2) { 1024 | char fname[12]; 1025 | sprintf(fname, "file%i", rm_fileno); 1026 | res = NIFFS_remove(&fs, fname); 1027 | TEST_CHECK_EQ(res, NIFFS_OK); 1028 | } 1029 | 1030 | res = NIFFS_info(&fs, &i); 1031 | TEST_CHECK_EQ(res, NIFFS_OK); 1032 | TEST_CHECK_EQ(i.lin_used_sectors, (fs.lin_sectors/2)); 1033 | TEST_CHECK_EQ(i.lin_max_conseq_free, 2); 1034 | 1035 | res = NIFFS_remove(&fs, "file1"); 1036 | TEST_CHECK_EQ(res, NIFFS_OK); 1037 | 1038 | res = NIFFS_info(&fs, &i); 1039 | TEST_CHECK_EQ(res, NIFFS_OK); 1040 | TEST_CHECK_EQ(i.lin_used_sectors, (fs.lin_sectors/2)-2); 1041 | TEST_CHECK_EQ(i.lin_max_conseq_free, 6); 1042 | 1043 | return TEST_RES_OK; 1044 | } 1045 | TEST_END 1046 | 1047 | #endif // NIFFS_LINEAR_AREA 1048 | 1049 | SUITE_TESTS(niffs_sys_tests) 1050 | ADD_TEST(sys_missing_file) 1051 | ADD_TEST(sys_bad_fd) 1052 | ADD_TEST(sys_closed_fd) 1053 | ADD_TEST(sys_deleted_same_fd) 1054 | ADD_TEST(sys_deleted_other_fd) 1055 | ADD_TEST(sys_fd_overflow) 1056 | ADD_TEST(sys_file_by_open) 1057 | ADD_TEST(sys_file_by_open_flags) 1058 | ADD_TEST(sys_file_by_creat) 1059 | ADD_TEST(sys_list_dir) 1060 | ADD_TEST(sys_write) 1061 | ADD_TEST(sys_simultaneous_write) 1062 | ADD_TEST(sys_simultaneous_write_append) 1063 | ADD_TEST(sys_rename) 1064 | ADD_TEST(sys_remove_single_by_path) 1065 | ADD_TEST(sys_remove_single_by_fd) 1066 | ADD_TEST(sys_read_beyond) 1067 | ADD_TEST(sys_read_empty) 1068 | ADD_TEST(sys_read_ptr_beyond) 1069 | ADD_TEST(sys_read_ptr_empty) 1070 | ADD_TEST(sys_write_flush) 1071 | ADD_TEST(sys_file_uniqueness) 1072 | ADD_TEST(sys_lseek_simple_modification) 1073 | ADD_TEST(sys_lseek_modification_append) 1074 | ADD_TEST(sys_lseek_modification_append_multi) 1075 | ADD_TEST(sys_lseek) 1076 | ADD_TEST(sys_lseek_read_ftell) 1077 | #if NIFFS_LINEAR_AREA 1078 | ADD_TEST(sys_lin_open) 1079 | ADD_TEST(sys_lin_lseek) 1080 | ADD_TEST(sys_lin_info) 1081 | #endif // NIFFS_LINEAR_AREA 1082 | SUITE_END(niffs_sys_tests) 1083 | -------------------------------------------------------------------------------- /src/test/niffs_test_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_test_config.h 3 | * 4 | * Created on: Feb 3, 2015 5 | * Author: petera 6 | */ 7 | 8 | #ifndef NIFFS_TEST_CONFIG_H_ 9 | #define NIFFS_TEST_CONFIG_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | typedef unsigned int u32_t; 17 | typedef unsigned short u16_t; 18 | typedef unsigned char u8_t; 19 | typedef signed int s32_t; 20 | typedef signed short s16_t; 21 | typedef signed char s8_t; 22 | 23 | #define MIN(x,y) ((x)>(y)?(y):(x)) 24 | #define MAX(x,y) ((x)>(y)?(x):(y)) 25 | 26 | // test config 27 | 28 | // for test framework 29 | #define NIFFS_TEST 30 | #define TESTATIC 31 | // emulate 16 sectors 32 | #define EMUL_SECTORS 16 33 | // emulate 16 lienar sectors 34 | #define EMUL_LIN_SECTORS 16 35 | // each sector is 1024 bytes 36 | #define EMUL_SECTOR_SIZE 1024 37 | // use max 4 filedescriptors 38 | #define EMUL_FILE_DESCS 4 39 | // divide sectors in maximum 128 byte blocks 40 | #define EMUL_PAGE_SIZE 128 41 | // give niffs a 128 byte work buffer 42 | #define EMUL_BUF_SIZE 128 43 | 44 | // enable checks for stm32f1 flash writes 45 | #define TEST_CHECK_UNALIGNED_ACCESS 46 | #define TEST_CHECK_WRITE_ON_NONERASED_DATA_OTHER_THAN_ZERO 47 | 48 | // niffs config 49 | 50 | extern u8_t __dbg; 51 | #define NIFFS_DBG_DEFAULT 0 52 | #define NIFFS_DBG(_f, ...) if (__dbg) printf(_f, ## __VA_ARGS__) 53 | #define NIFFS_NAME_LEN (16) // max 16 characters file name 54 | #define NIFFS_OBJ_ID_BITS (8) // max 256-2 files 55 | #define NIFFS_SPAN_IX_BITS (8) // max 256 pages of data per file 56 | #define NIFFS_WORD_ALIGN (2) //16-bit word alignment 57 | #define NIFFS_TYPE_OBJ_ID_SIZE u8_t // see NIFFS_OBJ_ID_BITS 58 | #define NIFFS_TYPE_SPAN_IX_SIZE u8_t // see NIFFS_SPAN_IX_BITS 59 | #define NIFFS_TYPE_RAW_PAGE_ID_SIZE u16_t // see NIFFS_OBJ_ID_BITS + NIFFS_SPAN_IX_BITS 60 | #define NIFFS_TYPE_PAGE_IX_SIZE u16_t // max 65536 pages in filesystem 61 | #define NIFFS_TYPE_PAGE_FLAG_SIZE u16_t // use 16-bit page flag 62 | #define NIFFS_TYPE_MAGIC_SIZE u16_t // use 16-bit magic nbr 63 | #define NIFFS_TYPE_ERASE_COUNT_SIZE u16_t // use 16-bit sector erase counter 64 | #define NIFFS_DUMP // enable dumping 65 | #define NIFFS_DUMP_OUT(_f, ...) printf(_f, ## __VA_ARGS__) 66 | 67 | // enable linear features in test 68 | #define NIFFS_LINEAR_AREA 1 69 | 70 | #define NIFFS_ASSERT(x) do { \ 71 | if (!(x)) { \ 72 | printf("ASSERT on %s:%i\n", __FILE__, __LINE__); \ 73 | exit(0); \ 74 | } \ 75 | } while (0) 76 | 77 | 78 | // test internals 79 | 80 | #define ERR_NIFFS_TEST_UNLIGNED_WRITE_LEN -1000 81 | #define ERR_NIFFS_TEST_UNLIGNED_WRITE_ADDR -1001 82 | #define ERR_NIFFS_TEST_WRITE_TO_NONERASED_DATA -1002 83 | #define ERR_NIFFS_TEST_BAD_ADDR -1003 84 | #define ERR_NIFFS_TEST_BAD_LEN -1004 85 | #define ERR_NIFFS_TEST_ABORTED_WRITE -1005 86 | #define ERR_NIFFS_TEST_ABORTED_READ -1006 87 | #define ERR_NIFFS_TEST_REF_DATA_MISMATCH -1007 88 | #define ERR_NIFFS_TEST_EOF -1008 89 | #define ERR_NIFFS_TEST_FATAL -1100 90 | 91 | #endif /* TEST_NIFFS_TEST_CONFIG_H_ */ 92 | -------------------------------------------------------------------------------- /src/test/niffs_test_emul.c: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_test_emul.c 3 | * 4 | * Created on: Feb 3, 2015 5 | * Author: petera 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "niffs_test_emul.h" 14 | 15 | u8_t __dbg = NIFFS_DBG_DEFAULT; 16 | static u8_t _flash[(EMUL_SECTORS+EMUL_LIN_SECTORS) * EMUL_SECTOR_SIZE]; 17 | static u8_t buf[EMUL_BUF_SIZE]; 18 | static niffs_file_desc descs[EMUL_FILE_DESCS]; 19 | niffs fs; 20 | 21 | typedef struct fdata_s{ 22 | char name[32]; 23 | u8_t *data; 24 | u32_t len; 25 | struct fdata_s *next; 26 | } fdata; 27 | 28 | static fdata *dhead = 0; 29 | static fdata *dlast = 0; 30 | static u32_t valid_byte_writes = 0; 31 | 32 | static int emul_hal_erase_f(u8_t *addr, u32_t len) { 33 | if (addr < &_flash[0]) { 34 | printf("erasing too low address\n"); 35 | return ERR_NIFFS_TEST_BAD_ADDR; 36 | } 37 | if (addr+len > &_flash[0] + (EMUL_SECTORS+EMUL_LIN_SECTORS) * EMUL_SECTOR_SIZE) { 38 | printf("erasing too high address (addr:%i len:%i, max:%i)\n", (u32_t)((intptr_t)addr - (intptr_t)_flash), len, 39 | (EMUL_SECTORS+EMUL_LIN_SECTORS) * EMUL_SECTOR_SIZE); 40 | return ERR_NIFFS_TEST_BAD_ADDR; 41 | } 42 | if ((addr - &_flash[0]) % EMUL_SECTOR_SIZE) { 43 | printf("erasing unaligned address\n"); 44 | return ERR_NIFFS_TEST_BAD_ADDR; 45 | } 46 | if (len != EMUL_SECTOR_SIZE) return ERR_NIFFS_TEST_BAD_ADDR; 47 | memset(addr, 0xff, len); 48 | return NIFFS_OK; 49 | } 50 | 51 | static int emul_hal_write_f(u8_t *addr, const u8_t *src, u32_t len) { 52 | if (addr < &_flash[0]) { 53 | printf("writing too low address\n"); 54 | return ERR_NIFFS_TEST_BAD_ADDR; 55 | } 56 | if (addr+len > &_flash[0] + (EMUL_SECTORS+EMUL_LIN_SECTORS) * EMUL_SECTOR_SIZE) { 57 | printf("writing too high address (addr:%i len:%i, max:%i)\n", (u32_t)((intptr_t)addr - (intptr_t)_flash), len, 58 | (EMUL_SECTORS+EMUL_LIN_SECTORS) * EMUL_SECTOR_SIZE); 59 | return ERR_NIFFS_TEST_BAD_ADDR; 60 | } 61 | if (len == 0) { 62 | printf("writing nothing\n"); 63 | return ERR_NIFFS_TEST_BAD_ADDR; 64 | } 65 | // if (len % NIFFS_WORD_ALIGN != 0) { 66 | // printf("unaligned write length %08x\n", len); 67 | // return ERR_NIFFS_TEST_UNLIGNED_WRITE_LEN; 68 | // } 69 | #ifdef TEST_CHECK_UNALIGNED_ACCESS 70 | if ((uintptr_t)addr % NIFFS_WORD_ALIGN != 0) { 71 | printf("unaligned write address %p (addr:%i len:%i)\n", addr, (u32_t)((intptr_t)addr - (intptr_t)_flash), len); 72 | return ERR_NIFFS_TEST_UNLIGNED_WRITE_ADDR; 73 | } 74 | #endif 75 | // printf(" WRIT %p : %i\n", addr, len); 76 | int i; 77 | for (i = 0; i < len; i++) { 78 | u8_t b = *src; 79 | #ifdef TEST_CHECK_WRITE_ON_NONERASED_DATA_OTHER_THAN_ZERO 80 | if (b != 0 && *addr != 0xff) { 81 | printf("writing illegally to address %p (addr:%i): %02x @ %02x, ix:%i\n", 82 | addr, (u32_t)((intptr_t)addr - (intptr_t)_flash), b, *addr, i); 83 | return ERR_NIFFS_TEST_WRITE_TO_NONERASED_DATA; 84 | } 85 | #endif 86 | //printf("write %02x to %p [%02x] => ", b, addr, *addr); 87 | *addr &= (b); 88 | //printf("%02x\n", *addr); 89 | addr++; 90 | src++; 91 | if (valid_byte_writes > 0) { 92 | --valid_byte_writes; 93 | if (valid_byte_writes == 0) { 94 | NIFFS_DBG("*** emulated write abort\n"); 95 | return ERR_NIFFS_TEST_ABORTED_WRITE; 96 | } 97 | } 98 | } 99 | return NIFFS_OK; 100 | } 101 | 102 | int niffs_emul_init(void) { 103 | dhead = 0; 104 | dlast = 0; 105 | memset(_flash, 0xff, sizeof(_flash)); 106 | valid_byte_writes = 0; 107 | return NIFFS_init(&fs, (u8_t *)&_flash[0], EMUL_SECTORS, EMUL_SECTOR_SIZE, EMUL_PAGE_SIZE, 108 | buf, sizeof(buf), 109 | descs, EMUL_FILE_DESCS, 110 | emul_hal_erase_f, emul_hal_write_f, EMUL_LIN_SECTORS); 111 | return 0; 112 | } 113 | 114 | void niffs_emul_rand_filesystem(void) { 115 | u32_t i; 116 | for (i = 0; i < sizeof(_flash); i++) { 117 | _flash[i] = rand(); 118 | } 119 | } 120 | 121 | void niffs_emul_set_write_byte_limit(u32_t limit) { 122 | valid_byte_writes = limit; 123 | } 124 | 125 | void memdump(u8_t *addr, u32_t len) { 126 | u8_t *a = addr; 127 | while (a < addr + len) { 128 | int i; 129 | for (i = 0; i < 16; i++) { 130 | if (&a[i] < addr+len) printf("%02x", a[i]); 131 | else printf(" "); 132 | } 133 | printf(" "); 134 | for (i = 0; i < 16; i++) { 135 | if (&a[i] < addr+len) printf("%c", a[i] >= ' ' && a[i] < 0x7f ? a[i] : '.'); 136 | else printf(" "); 137 | } 138 | printf("\n"); 139 | a += 16; 140 | } 141 | } 142 | 143 | void memrand(u8_t *d, u32_t len, u32_t seed) { 144 | u32_t i; 145 | srand(seed); 146 | for (i = 0; i < len; i++){ 147 | d[i] = rand(); 148 | } 149 | } 150 | 151 | 152 | void niffs_emul_dump_pix(niffs *fs, niffs_page_ix pix) { 153 | niffs_page_hdr *phdr = (niffs_page_hdr *)_NIFFS_PIX_2_ADDR(fs, pix); 154 | printf("PIX:%04i @ %p\n", pix, phdr); 155 | printf(" flag:%04x id:%04x oid:%02x spix:%02x\n", 156 | phdr->flag, phdr->id.raw, phdr->id.obj_id, phdr->id.spix); 157 | u8_t *data = (u8_t *)phdr + sizeof(niffs_page_hdr); 158 | u32_t len = _NIFFS_SPIX_2_PDATA_LEN(fs, 1); 159 | if (!_NIFFS_IS_FREE(phdr) && !_NIFFS_IS_DELE(phdr) &&_NIFFS_IS_ID_VALID(phdr) && phdr->id.spix == 0) { 160 | niffs_object_hdr *ohdr = (niffs_object_hdr *)phdr; 161 | printf(" length:%08x name:%s\n", ohdr->len, ohdr->name); 162 | data = (u8_t *)phdr + sizeof(niffs_object_hdr); 163 | len = _NIFFS_SPIX_2_PDATA_LEN(fs, 0); 164 | } 165 | 166 | memdump(data, len); 167 | } 168 | 169 | u8_t *niffs_emul_create_data(char *name, u32_t len) { 170 | fdata *e = malloc(sizeof(fdata)); 171 | NIFFS_ASSERT(e); 172 | strncpy(e->name, name, 32); 173 | 174 | u32_t seed = 0x20050715; 175 | int i; 176 | for(i = 0; i < strlen(e->name); i++) { 177 | seed ^= ((seed & 0xf0000000) >> 28); 178 | seed <<= 4; 179 | seed ^= e->name[i]; 180 | } 181 | 182 | u8_t *d = malloc(len); 183 | NIFFS_ASSERT(d); 184 | e->len = len; 185 | e->data = d; 186 | e->next = 0; 187 | 188 | srand(seed); 189 | for (i = 0; i < len; i++){ 190 | d[i] = rand(); 191 | } 192 | 193 | if (dhead == 0) { 194 | dhead = e; 195 | dlast = e; 196 | } else { 197 | dlast->next = e; 198 | dlast = e; 199 | } 200 | return d; 201 | } 202 | 203 | static fdata *cursor = 0; 204 | 205 | void niffs_emul_reset_data_cursor(void) { 206 | cursor = 0; 207 | } 208 | 209 | char *niffs_emul_get_next_data_name(void) { 210 | if (cursor == 0) { 211 | cursor = dhead; 212 | } else { 213 | cursor = cursor->next; 214 | } 215 | return cursor == 0 ? 0 : cursor->name; 216 | } 217 | 218 | u8_t *niffs_emul_extend_data(char *name, u32_t extra_len, u8_t *extra_data) { 219 | fdata *cur_e = dhead; 220 | fdata *e = 0; 221 | while (cur_e) { 222 | if (strcmp(name, cur_e->name) == 0) { 223 | e = cur_e; 224 | break; 225 | } 226 | } 227 | NIFFS_ASSERT(e); 228 | 229 | u8_t *ndata = malloc(e->len + extra_len); 230 | NIFFS_ASSERT(ndata); 231 | memcpy(ndata, e->data, e->len); 232 | if (extra_data) memcpy(ndata + e->len, extra_data, extra_len); 233 | free(e->data); 234 | e->data = ndata; 235 | e->len = e->len + extra_len; 236 | return e->data; 237 | } 238 | 239 | u8_t *niffs_emul_write_data(char *name, u32_t offs, u8_t *data, u32_t len) { 240 | fdata *cur_e = dhead; 241 | fdata *e = 0; 242 | while (cur_e) { 243 | if (strcmp(name, cur_e->name) == 0) { 244 | e = cur_e; 245 | break; 246 | } 247 | } 248 | NIFFS_ASSERT(e); 249 | 250 | if (e->len < offs+len) { 251 | (void)niffs_emul_extend_data(name, offs+len-e->len, 0); 252 | } 253 | 254 | memcpy(&e->data[offs], data, len); 255 | 256 | return e->data; 257 | } 258 | 259 | u8_t *niffs_emul_write_rand_data(char *name, u32_t offs, u32_t seed, u32_t len) { 260 | fdata *cur_e = dhead; 261 | fdata *e = 0; 262 | while (cur_e) { 263 | if (strcmp(name, cur_e->name) == 0) { 264 | e = cur_e; 265 | break; 266 | } 267 | } 268 | NIFFS_ASSERT(e); 269 | 270 | if (e->len < offs+len) { 271 | (void)niffs_emul_extend_data(name, offs+len-e->len, 0); 272 | } 273 | 274 | memrand(&e->data[offs], len, seed); 275 | 276 | return e->data; 277 | } 278 | 279 | void niffs_emul_destroy_data(char *name) { 280 | fdata *prev_e = 0; 281 | fdata *cur_e = dhead; 282 | while (cur_e) { 283 | if (strcmp(name, cur_e->name) == 0) { 284 | break; 285 | } 286 | prev_e = cur_e; 287 | cur_e = cur_e->next; 288 | } 289 | NIFFS_ASSERT(cur_e); 290 | if (cursor == cur_e) { 291 | cursor = prev_e; 292 | } 293 | 294 | if (dhead == cur_e) { 295 | free(cur_e->data); 296 | dhead = cur_e->next; 297 | free(cur_e); 298 | } else { 299 | free(cur_e->data); 300 | prev_e->next = cur_e->next; 301 | free(cur_e); 302 | } 303 | if (dlast == cur_e) { 304 | dlast = prev_e; 305 | } 306 | } 307 | 308 | void niffs_emul_destroy_all_data(void) { 309 | while (dhead) { 310 | free(dhead->data); 311 | fdata *pdhead = dhead; 312 | dhead = dhead->next; 313 | free(pdhead); 314 | } 315 | dlast = 0; 316 | } 317 | 318 | u8_t *niffs_emul_get_data(char *name, u32_t *len) { 319 | fdata *e = dhead; 320 | while (e) { 321 | if (strcmp(name, e->name) == 0) { 322 | if (len) *len = e->len; 323 | return e->data; 324 | } 325 | e = e->next; 326 | } 327 | NIFFS_ASSERT(0); 328 | return 0; 329 | } 330 | 331 | void niffs_emul_get_sector_erase_count_info(niffs *fs, u32_t *s_era_min, u32_t *s_era_max) { 332 | u32_t s; 333 | *s_era_min = 0xffffffff; 334 | *s_era_max = 0; 335 | for (s = 0; s < fs->sectors; s++) { 336 | niffs_sector_hdr *shdr = (niffs_sector_hdr *)_NIFFS_SECTOR_2_ADDR(fs, s); 337 | if (shdr->era_cnt != (niffs_erase_cnt)-1) { 338 | *s_era_min = MIN(*s_era_min, shdr->era_cnt); 339 | *s_era_max = MAX(*s_era_max, shdr->era_cnt); 340 | } 341 | } 342 | } 343 | 344 | int niffs_emul_create_file(niffs *fs, char *name, u32_t len) { 345 | int res; 346 | int fd = NIFFS_open(fs, name, NIFFS_O_CREAT | NIFFS_O_TRUNC | NIFFS_O_RDWR, 0); 347 | if (fd < 0) return fd; 348 | u8_t *data = niffs_emul_create_data(name, len); 349 | if (data == 0) return ERR_NIFFS_TEST_FATAL; 350 | res = NIFFS_write(fs, fd, data, len); 351 | if (res < 0) return res; 352 | res = NIFFS_lseek(fs, fd, 0, NIFFS_SEEK_SET); 353 | if (res < 0) return res; 354 | niffs_stat s; 355 | res = NIFFS_fstat(fs, fd, &s); 356 | if (s.size != len) { 357 | return ERR_NIFFS_TEST_FATAL; 358 | } 359 | u8_t buf[64]; 360 | u32_t offs = 0; 361 | do { 362 | u32_t rlen = MIN(len - offs, sizeof(buf)); 363 | res = NIFFS_read(fs, fd, &buf[0], rlen); 364 | if (res == 0) return ERR_NIFFS_TEST_EOF; 365 | if (res < 0) return res; 366 | if (res != rlen) { 367 | return ERR_NIFFS_TEST_FATAL; 368 | } 369 | if (memcmp(buf, &data[offs], rlen) != 0) { 370 | u32_t ix; 371 | u32_t mismatch_ix; 372 | memdump(buf, sizeof(buf)); 373 | memdump(&data[offs < 32 ? 0 : offs-32], sizeof(buf)); 374 | for (ix = 0; ix < rlen; ix++) { 375 | if (buf[ix] != data[offs+ix]) { 376 | mismatch_ix = ix; 377 | } 378 | } 379 | NIFFS_DBG("mismatch @ offset %i\n", offs+mismatch_ix); 380 | return ERR_NIFFS_TEST_REF_DATA_MISMATCH; 381 | } 382 | offs += rlen; 383 | } while (offs < len); 384 | (void)NIFFS_close(fs, fd); 385 | return res >= 0 ? NIFFS_OK : res; 386 | } 387 | 388 | int niffs_emul_verify_file(niffs *fs, char *name) { 389 | u32_t dlen; 390 | u8_t *data = niffs_emul_get_data(name, &dlen); 391 | if (data == 0) { 392 | return ERR_NIFFS_TEST_FATAL; 393 | } 394 | return niffs_emul_verify_file_against_data(fs, name, data); 395 | } 396 | 397 | int niffs_emul_verify_file_against_data(niffs *fs, char *name, u8_t *data) { 398 | int fd = NIFFS_open(fs, name, NIFFS_O_RDONLY, 0); 399 | if (fd < 0) return fd; 400 | if (data == 0) { 401 | return ERR_NIFFS_TEST_FATAL; 402 | } 403 | niffs_stat s; 404 | int res = NIFFS_fstat(fs, fd, &s); 405 | if (res != NIFFS_OK) { 406 | return ERR_NIFFS_TEST_FATAL; 407 | } 408 | 409 | u8_t buf[8]; 410 | u32_t offs = 0; 411 | do { 412 | u32_t rlen = MIN(s.size - offs, sizeof(buf)); 413 | res = NIFFS_read(fs, fd, &buf[0], rlen); 414 | if (res == 0) return ERR_NIFFS_TEST_EOF; 415 | if (res < 0) return res; 416 | if (res != rlen) { 417 | return ERR_NIFFS_TEST_FATAL; 418 | } 419 | if (memcmp(buf, &data[offs], rlen) != 0) { 420 | u32_t ix; 421 | u32_t mismatch_ix; 422 | for (ix = 0; ix < rlen; ix++) { 423 | if (buf[ix] != data[offs+ix]) { 424 | mismatch_ix = ix; 425 | } 426 | } 427 | NIFFS_DBG("mismatch @ offset %i\n", offs+mismatch_ix); 428 | return ERR_NIFFS_TEST_REF_DATA_MISMATCH; 429 | } 430 | offs += rlen; 431 | } while (offs < s.size); 432 | (void)NIFFS_close(fs, fd); 433 | return res >= 0 ? NIFFS_OK : res; 434 | } 435 | 436 | int niffs_emul_remove_all_zerosized_files(niffs *fs) { 437 | niffs_DIR d; 438 | struct niffs_dirent e; 439 | struct niffs_dirent *pe = &e; 440 | 441 | NIFFS_opendir(fs, "/", &d); 442 | while ((pe = NIFFS_readdir(&d, pe))) { 443 | if (pe->size == 0) { 444 | int res = NIFFS_remove(fs, pe->name); 445 | if (res != NIFFS_OK) return res; 446 | } 447 | } 448 | NIFFS_closedir(&d); 449 | return NIFFS_OK; 450 | } 451 | 452 | int niffs_emul_read_ptr(niffs *fs, int fd_ix, u8_t **data, u32_t *avail) { 453 | return niffs_read_ptr(fs, fd_ix, data, avail); 454 | } 455 | 456 | -------------------------------------------------------------------------------- /src/test/niffs_test_emul.h: -------------------------------------------------------------------------------- 1 | /* 2 | * niffs_test_emul.h 3 | * 4 | * Created on: Feb 3, 2015 5 | * Author: petera 6 | */ 7 | 8 | #ifndef NIFFS_TEST_EMUL_H_ 9 | #define NIFFS_TEST_EMUL_H_ 10 | 11 | #include "niffs_test_config.h" 12 | #include "niffs.h" 13 | #include "niffs_internal.h" 14 | 15 | extern niffs fs; 16 | 17 | void memrand(u8_t *d, u32_t len, u32_t seed); 18 | void memdump(u8_t *addr, u32_t len); 19 | 20 | int niffs_emul_init(void); 21 | void niffs_emul_rand_filesystem(void); 22 | void niffs_emul_dump_pix(niffs *fs, niffs_page_ix pix); 23 | 24 | u8_t *niffs_emul_create_data(char *name, u32_t len); 25 | void niffs_emul_reset_data_cursor(void); 26 | char *niffs_emul_get_next_data_name(void); 27 | u8_t *niffs_emul_get_data(char *name, u32_t *len); 28 | u8_t *niffs_emul_write_data(char *name, u32_t offs, u8_t *data, u32_t len); 29 | u8_t *niffs_emul_write_rand_data(char *name, u32_t offs, u32_t seed, u32_t len); 30 | u8_t *niffs_emul_extend_data(char *name, u32_t extra_len, u8_t *extra_data); 31 | void niffs_emul_destroy_data(char *name); 32 | void niffs_emul_destroy_all_data(void); 33 | 34 | void niffs_emul_get_sector_erase_count_info(niffs *fs, u32_t *s_era_min, u32_t *s_era_max); 35 | void niffs_emul_set_write_byte_limit(u32_t limit); 36 | int niffs_emul_create_file(niffs *fs, char *name, u32_t len); 37 | int niffs_emul_verify_file(niffs *fs, char *name); 38 | int niffs_emul_verify_file_against_data(niffs *fs, char *name, u8_t *data); 39 | int niffs_emul_remove_all_zerosized_files(niffs *fs); 40 | 41 | int niffs_emul_read_ptr(niffs *fs, int fd_ix, u8_t **data, u32_t *avail); 42 | 43 | #endif /* NIFFS_TEST_EMUL_H_ */ 44 | -------------------------------------------------------------------------------- /src/test/testrunner.c: -------------------------------------------------------------------------------- 1 | /* 2 | * testrunner.c 3 | * 4 | * Created on: Jun 18, 2013 5 | * Author: petera 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "testrunner.h" 20 | 21 | static struct { 22 | test *tests; 23 | test *_last_test; 24 | int test_count; 25 | void (*on_stop)(test *t); 26 | test_res *failed; 27 | test_res *failed_last; 28 | test_res *stopped; 29 | test_res *stopped_last; 30 | FILE *spec; 31 | char incl_filter[256]; 32 | char excl_filter[256]; 33 | } test_main; 34 | 35 | void test_init(void (*on_stop)(test *t)) { 36 | test_main.on_stop = on_stop; 37 | } 38 | 39 | static char check_spec(char *name) { 40 | if (test_main.spec) { 41 | fseek(test_main.spec, 0, SEEK_SET); 42 | char *line = NULL; 43 | size_t sz; 44 | ssize_t read; 45 | while ((read = getline(&line, &sz, test_main.spec)) != -1) { 46 | if (strncmp(line, name, strlen(line)-1) == 0) { 47 | free(line); 48 | return 1; 49 | } 50 | } 51 | free(line); 52 | return 0; 53 | } else { 54 | return 1; 55 | } 56 | } 57 | 58 | static char check_incl_filter(char *name) { 59 | if (strlen(test_main.incl_filter)== 0) return 1; 60 | return strstr(name, test_main.incl_filter) == 0 ? 0 : 1; 61 | } 62 | 63 | static char check_excl_filter(char *name) { 64 | if (strlen(test_main.excl_filter)== 0) return 1; 65 | return strstr(name, test_main.excl_filter) == 0 ? 1 : 0; 66 | } 67 | 68 | void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)) { 69 | if (f == 0) return; 70 | if (!check_spec(name)) return; 71 | if (!check_incl_filter(name)) return; 72 | if (!check_excl_filter(name)) return; 73 | DBGT("adding test %s\n", name); 74 | test *t = malloc(sizeof(test)); 75 | memset(t, 0, sizeof(test)); 76 | t->f = f; 77 | strcpy(t->name, name); 78 | t->setup = setup; 79 | t->teardown = teardown; 80 | if (test_main.tests == 0) { 81 | test_main.tests = t; 82 | } else { 83 | test_main._last_test->_next = t; 84 | } 85 | test_main._last_test = t; 86 | test_main.test_count++; 87 | } 88 | 89 | static void add_res(test *t, test_res **head, test_res **last) { 90 | test_res *tr = malloc(sizeof(test_res)); 91 | memset(tr,0,sizeof(test_res)); 92 | strcpy(tr->name, t->name); 93 | if (*head == 0) { 94 | *head = tr; 95 | } else { 96 | (*last)->_next = tr; 97 | } 98 | *last = tr; 99 | } 100 | 101 | static void dump_res(test_res **head) { 102 | test_res *tr = (*head); 103 | while (tr) { 104 | test_res *next_tr = tr->_next; 105 | printf(" %s\n", tr->name); 106 | free(tr); 107 | tr = next_tr; 108 | } 109 | } 110 | 111 | int run_tests(int argc, char **args) { 112 | memset(&test_main, 0, sizeof(test_main)); 113 | int arg; 114 | int incl_filter = 0; 115 | int excl_filter = 0; 116 | for (arg = 1; arg < argc; arg++) { 117 | if (strlen(args[arg]) == 0) continue; 118 | if (0 == strcmp("-f", args[arg])) { 119 | incl_filter = 1; 120 | continue; 121 | } 122 | if (0 == strcmp("-e", args[arg])) { 123 | excl_filter = 1; 124 | continue; 125 | } 126 | if (incl_filter) { 127 | strcpy(test_main.incl_filter, args[arg]); 128 | incl_filter = 0; 129 | } else if (excl_filter) { 130 | strcpy(test_main.excl_filter, args[arg]); 131 | excl_filter = 0; 132 | } else { 133 | printf("running tests from %s\n", args[arg]); 134 | FILE *fd = fopen(args[1], "r"); 135 | if (fd == NULL) { 136 | printf("%s not found\n", args[arg]); 137 | return -2; 138 | } 139 | test_main.spec = fd; 140 | } 141 | } 142 | 143 | DBGT("adding suites...\n"); 144 | add_suites(); 145 | DBGT("%i tests added\n", test_main.test_count); 146 | if (test_main.spec) { 147 | fclose(test_main.spec); 148 | } 149 | 150 | if (test_main.test_count == 0) { 151 | printf("No tests to run\n"); 152 | return 0; 153 | } 154 | 155 | int fd_success = open("_tests_ok", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); 156 | int fd_bad = open("_tests_fail", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); 157 | 158 | DBGT("running tests...\n"); 159 | int ok = 0; 160 | int failed = 0; 161 | int stopped = 0; 162 | test *cur_t = test_main.tests; 163 | int i = 1; 164 | while (cur_t) { 165 | cur_t->setup(cur_t); 166 | test *next_test = cur_t->_next; 167 | DBGT("TEST %i/%i : running test %s\n", i, test_main.test_count, cur_t->name); 168 | i++; 169 | int res = cur_t->f(cur_t); 170 | cur_t->test_result = res; 171 | cur_t->teardown(cur_t); 172 | int fd = res == TEST_RES_OK ? fd_success : fd_bad; 173 | write(fd, cur_t->name, strlen(cur_t->name)); 174 | write(fd, "\n", 1); 175 | switch (res) { 176 | case TEST_RES_OK: 177 | ok++; 178 | printf(" .. ok\n"); 179 | break; 180 | case TEST_RES_FAIL: 181 | failed++; 182 | printf(" .. FAILED\n"); 183 | if (test_main.on_stop) test_main.on_stop(cur_t); 184 | add_res(cur_t, &test_main.failed, &test_main.failed_last); 185 | break; 186 | case TEST_RES_ASSERT: 187 | stopped++; 188 | printf(" .. ABORTED\n"); 189 | if (test_main.on_stop) test_main.on_stop(cur_t); 190 | add_res(cur_t, &test_main.stopped, &test_main.stopped_last); 191 | break; 192 | } 193 | free(cur_t); 194 | cur_t = next_test; 195 | } 196 | close(fd_success); 197 | close(fd_bad); 198 | DBGT("ran %i tests\n", test_main.test_count); 199 | printf("Test report, %i tests\n", test_main.test_count); 200 | printf("%i succeeded\n", ok); 201 | printf("%i failed\n", failed); 202 | dump_res(&test_main.failed); 203 | printf("%i stopped\n", stopped); 204 | dump_res(&test_main.stopped); 205 | if (ok < test_main.test_count) { 206 | printf("\nFAILED\n"); 207 | return -1; 208 | } else { 209 | printf("\nALL TESTS OK\n"); 210 | return 0; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/test/testrunner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * testrunner.h 3 | * 4 | * Created on: Jun 19, 2013 5 | * Author: petera 6 | */ 7 | 8 | /* 9 | 10 | file mysuite.c: 11 | 12 | SUITE(mysuite) 13 | 14 | static void setup(test *t) {} 15 | 16 | static void teardown(test *t) {} 17 | 18 | TEST(mytest) { 19 | printf("mytest runs now..\n"); 20 | return 0; 21 | } TEST_END 22 | 23 | SUITE_TESTS(mysuite) 24 | ADD_TEST(mytest) 25 | SUITE_END(mysuite) 26 | 27 | 28 | 29 | file mysuite2.c: 30 | 31 | SUITE(mysuite2) 32 | 33 | static void setup(test *t) {} 34 | 35 | static void teardown(test *t) {} 36 | 37 | TEST(mytest2a) { 38 | printf("mytest2a runs now..\n"); 39 | return 0; 40 | } TEST_END 41 | 42 | TEST(mytest2b) { 43 | printf("mytest2b runs now..\n"); 44 | return 0; 45 | } TEST_END 46 | 47 | SUITE_TESTS(mysuite2) 48 | ADD_TEST(mytest2a) 49 | ADD_TEST(mytest2b) 50 | SUITE_END(mysuite2) 51 | 52 | 53 | some other file.c: 54 | 55 | void add_suites() { 56 | ADD_SUITE(mysuite); 57 | ADD_SUITE(mysuite2); 58 | } 59 | */ 60 | 61 | #ifndef TESTRUNNER_H_ 62 | #define TESTRUNNER_H_ 63 | 64 | #define TEST_RES_OK 0 65 | #define TEST_RES_FAIL -1 66 | #define TEST_RES_ASSERT -2 67 | 68 | struct test_s; 69 | 70 | typedef int (*test_f)(struct test_s *t); 71 | 72 | typedef struct test_s { 73 | test_f f; 74 | char name[256]; 75 | void *data; 76 | void (*setup)(struct test_s *t); 77 | void (*teardown)(struct test_s *t); 78 | struct test_s *_next; 79 | unsigned char test_result; 80 | } test; 81 | 82 | typedef struct test_res_s { 83 | char name[256]; 84 | struct test_res_s *_next; 85 | } test_res; 86 | 87 | #define TEST_CHECK(x) if (!(x)) { \ 88 | printf(" TEST FAIL %s:%i\n", __FILE__, __LINE__); \ 89 | goto __fail_stop; \ 90 | } 91 | #define TEST_CHECK_EQ(x, y) if ((x) != (y)) { \ 92 | printf(" TEST FAIL %s:%i, %i != %i\n", __FILE__, (int)__LINE__, (int)(x), (int)(y)); \ 93 | goto __fail_stop; \ 94 | } 95 | #define TEST_CHECK_NEQ(x, y) if ((x) == (y)) { \ 96 | printf(" TEST FAIL %s:%i, %i == %i\n", __FILE__, __LINE__, (x), (y)); \ 97 | goto __fail_stop; \ 98 | } 99 | #define TEST_CHECK_GT(x, y) if ((x) <= (y)) { \ 100 | printf(" TEST FAIL %s:%i, %i <= %i\n", __FILE__, __LINE__, (x), (y)); \ 101 | goto __fail_stop; \ 102 | } 103 | #define TEST_CHECK_LT(x, y) if ((x) >= (y)) { \ 104 | printf(" TEST FAIL %s:%i, %i >= %i\n", __FILE__, __LINE__, (x), (y)); \ 105 | goto __fail_stop; \ 106 | } 107 | #define TEST_CHECK_GE(x, y) if ((x) < (y)) { \ 108 | printf(" TEST FAIL %s:%i, %i < %i\n", __FILE__, __LINE__, (x), (y)); \ 109 | goto __fail_stop; \ 110 | } 111 | #define TEST_CHECK_LE(x, y) if ((x) > (y)) { \ 112 | printf(" TEST FAIL %s:%i, %i > %i\n", __FILE__, __LINE__, (x), (y)); \ 113 | goto __fail_stop; \ 114 | } 115 | #define TEST_ASSERT(x) if (!(x)) { \ 116 | printf(" TEST ASSERT %s:%i\n", __FILE__, __LINE__); \ 117 | goto __fail_assert; \ 118 | } 119 | 120 | #define DBGT(...) printf(__VA_ARGS__) 121 | 122 | #define str(s) #s 123 | 124 | #define SUITE(sui) 125 | 126 | #define SUITE_TESTS(sui) \ 127 | void _add_suite_tests_##sui(void) { 128 | 129 | #define SUITE_END(sui) \ 130 | } 131 | 132 | #define ADD_TEST(tf) \ 133 | _add_test(__test_##tf, str(tf), setup, teardown); 134 | 135 | #define ADD_SUITE(sui) \ 136 | extern void _add_suite_tests_##sui(void); \ 137 | _add_suite_tests_##sui(); 138 | 139 | #define TEST(tf) \ 140 | static int __test_##tf(struct test_s *t) { do 141 | 142 | #define TEST_END \ 143 | while(0); \ 144 | __fail_stop: return TEST_RES_FAIL; \ 145 | __fail_assert: return TEST_RES_ASSERT; \ 146 | } 147 | 148 | void add_suites(); 149 | void test_init(void (*on_stop)(test *t)); 150 | // returns 0 if all tests ok, -1 if any test failed, -2 on badness 151 | int run_tests(int argc, char **args); 152 | void _add_suite(const char *suite_name); 153 | void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)); 154 | 155 | #endif /* TESTRUNNER_H_ */ 156 | -------------------------------------------------------------------------------- /src/test/testsuites.c: -------------------------------------------------------------------------------- 1 | /* 2 | * testsuites.c 3 | * 4 | * Created on: Jun 19, 2013 5 | * Author: petera 6 | */ 7 | 8 | #include "testrunner.h" 9 | 10 | void add_suites() { 11 | ADD_SUITE(niffs_cfg_tests); 12 | ADD_SUITE(niffs_func_tests); 13 | ADD_SUITE(niffs_sys_tests); 14 | ADD_SUITE(niffs_run_tests); 15 | } 16 | --------------------------------------------------------------------------------