• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 - 2020, IBEROXARXA SERVICIOS INTEGRALES, S.L.
3  * Copyright (C) 2015 - 2020, Jaume Olivé Petrus (jolive@whitecatboard.org)
4  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in the
14  *       documentation and/or other materials provided with the distribution.
15  *     * Neither the name of the <organization> nor the
16  *       names of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written permission.
18  *     * The WHITECAT logotype cannot be changed, you can remove it, but you
19  *       cannot change it in any way. The WHITECAT logotype is:
20  *
21  *          /\       /\
22  *         /  \_____/  \
23  *        /_____________\
24  *        W H I T E C A T
25  *
26  *     * Redistributions in binary form must retain all copyright notices printed
27  *       to any local or remote output device. This include any reference to
28  *       Lua RTOS, whitecatboard.org, Lua, and other copyright notices that may
29  *       appear in the future.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
35  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41  *
42  * Lua RTOS, a tool for make a LFS file system image
43  *
44  */
45 
46 #include "lfs.h"
47 
48 #include <ctype.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <errno.h>
54 #include <limits.h>
55 #include <dirent.h>
56 #include <sys/types.h>
57 
58 static struct lfs_config cfg;
59 static lfs_t lfs;
60 static uint8_t *data;
61 
lfs_read(const struct lfs_config * c,lfs_block_t block,lfs_off_t off,void * buffer,lfs_size_t size)62 static int lfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
63 {
64     memcpy(buffer, data + (block * c->block_size) + off, size);
65     return 0;
66 }
67 
lfs_prog(const struct lfs_config * c,lfs_block_t block,lfs_off_t off,const void * buffer,lfs_size_t size)68 static int lfs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
69 {
70     memcpy(data + (block * c->block_size) + off, buffer, size);
71     return 0;
72 }
73 
lfs_erase(const struct lfs_config * c,lfs_block_t block)74 static int lfs_erase(const struct lfs_config *c, lfs_block_t block)
75 {
76     memset(data + (block * c->block_size), 0, c->block_size);
77     return 0;
78 }
79 
lfs_sync(const struct lfs_config * c)80 static int lfs_sync(const struct lfs_config *c)
81 {
82     return 0;
83 }
84 
create_dir(char * src)85 static void create_dir(char *src)
86 {
87     char *path;
88 
89     path = strchr(src, '/');
90     if (path) {
91         int ret;
92         fprintf(stdout, "%s\r\n", path);
93 
94         if ((ret = lfs_mkdir(&lfs, path)) < 0) {
95             fprintf(stderr, "can't create directory %s: error=%d\r\n", path, ret);
96             exit(1);
97         }
98     }
99 }
100 
create_file(char * src)101 static void create_file(char *src)
102 {
103     char *path;
104 
105     path = strchr(src, '/');
106     if (path) {
107         fprintf(stdout, "%s\r\n", path);
108 
109         // Open source file
110         FILE *srcf = fopen(src, "rb");
111         if (!srcf) {
112             fprintf(stderr, "can't open source file %s: errno=%d (%s)\r\n", src, errno, strerror(errno));
113             exit(1);
114         }
115 
116         // Open destination file
117         lfs_file_t dstf;
118         int ret;
119         if ((ret = lfs_file_open(&lfs, &dstf, path, LFS_O_WRONLY | LFS_O_CREAT)) < 0) {
120             fprintf(stderr, "can't open destination file %s: error=%d\r\n", path, ret);
121             exit(1);
122         }
123 
124         char c = fgetc(srcf);
125         while (!feof(srcf)) {
126             ret = lfs_file_write(&lfs, &dstf, &c, 1);
127             if (ret < 0) {
128                 fprintf(stderr, "can't write to destination file %s: error=%d\r\n", path, ret);
129                 exit(1);
130             }
131             c = fgetc(srcf);
132         }
133 
134         // Close destination file
135         ret = lfs_file_close(&lfs, &dstf);
136         if (ret < 0) {
137             fprintf(stderr, "can't close destination file %s: error=%d\r\n", path, ret);
138             exit(1);
139         }
140 
141         // Close source file
142         fclose(srcf);
143     }
144 }
145 static void skip_direct(char *curr_path, struct dirent *ent, char *src);
146 
compact(char * src)147 static void compact(char *src)
148 {
149     DIR *dir;
150 
151     dir = opendir(src);
152     if (dir) {
153         struct dirent *ent;
154         char curr_path[PATH_MAX];
155         while ((ent = readdir(dir))) {
156             // Skip . and .. directories
157             skip_direct(curr_path, ent, src);
158         }
159 
160         closedir(dir);
161     }
162 }
skip_direct(char * curr_path,struct dirent * ent,char * src)163 static void skip_direct(char *curr_path, struct dirent *ent, char *src)
164 {
165     if ((strcmp(ent->d_name, ".") != 0) && (strcmp(ent->d_name, "..") != 0)) {
166         // Update the current path
167         strcpy(curr_path, src);
168         strcat(curr_path, "/");
169         strcat(curr_path, ent->d_name);
170 
171         if (ent->d_type == DT_DIR) {
172             create_dir(curr_path);
173             compact(curr_path);
174         } else if (ent->d_type == DT_REG) {
175             create_file(curr_path);
176         }
177     }
178 }
usage(void)179 void usage(void)
180 {
181     (void)fprintf(stdout,
182             "usage: mklfs -c <pack-dir> -b <block-size> -r <read-size> -p <prog-size> -s <filesystem-size> -n "
183             "<context> -l <lookahead_size> -e <cache_size> -k <block_cycles> -i <image-file-path>\r\n");
184 }
185 
is_number(const char * s)186 static int is_number(const char *s)
187 {
188     const char *c = s;
189 
190     while (*c) {
191         if ((*c < '0') || (*c > '9')) {
192             return 0;
193         }
194         c++;
195     }
196 
197     return 1;
198 }
199 
is_hex(const char * s)200 static int is_hex(const char *s)
201 {
202     const char *c = s;
203 
204     if (*c++ != '0') {
205         return 0;
206     }
207 
208     if (*c++ != 'x') {
209         return 0;
210     }
211 
212     while (*c) {
213         if (((*c < '0') || (*c > '9')) && ((*c < 'A') || (*c > 'F')) && ((*c < 'a') || (*c > 'f'))) {
214             return 0;
215         }
216         c++;
217     }
218 
219     return 1;
220 }
221 
to_int(const char * s)222 static int to_int(const char *s)
223 {
224     if (is_number(s)) {
225         return atoi(s);
226     } else if (is_hex(s)) {
227         return (int)strtol(s, NULL, 0x10);
228     }
229 
230     return -1;
231 }
232 
main(int argc,char ** argv)233 int main(int argc, char **argv)
234 {
235     char *src = NULL;   // Source directory
236     char *dst = NULL;   // Destination image
237     int c;              // Current option
238     int block_size = 0; // Block size
239     int read_size = 0;  // Read size
240     int prog_size = 0;  // Prog size
241     int fs_size = 0;    // File system size
242     int err;
243     int part_no = 0;    // context
244     int blk_cycles = 0; // block_cycles
245     int la_size = 0;    // lookahead_size
246     int ca_size = 0;    // cache_size
247 
248     while ((c = getopt(argc, argv, "c:i:b:p:r:s:n:l:e:k:")) != -1) {
249         switch (c) {
250             case 'c':
251                 src = optarg;
252                 break;
253 
254             case 'i':
255                 dst = optarg;
256                 break;
257 
258             case 'b':
259                 block_size = to_int(optarg);
260                 break;
261 
262             case 'p':
263                 prog_size = to_int(optarg);
264                 break;
265 
266             case 'r':
267                 read_size = to_int(optarg);
268                 break;
269 
270             case 's':
271                 fs_size = to_int(optarg);
272                 break;
273 
274             case 'n':
275                 part_no = to_int(optarg);
276                 break;
277 
278             case 'l':
279                 la_size = to_int(optarg);
280                 break;
281 
282             case 'e':
283                 ca_size = to_int(optarg);
284                 break;
285 
286             case 'k':
287                 blk_cycles = to_int(optarg);
288                 break;
289             default:
290                 break;
291         }
292     }
293 
294     if ((src == NULL) || (dst == NULL) || (block_size <= 0) || (prog_size <= 0) || (read_size <= 0) || (fs_size <= 0)) {
295         usage();
296         exit(1);
297     }
298 
299     // Mount the file system
300     cfg.read = lfs_read;
301     cfg.prog = lfs_prog;
302     cfg.erase = lfs_erase;
303     cfg.sync = lfs_sync;
304 
305     cfg.block_size = block_size;
306     cfg.read_size = read_size;
307     cfg.prog_size = prog_size;
308     cfg.block_count = fs_size / cfg.block_size;
309     cfg.lookahead_size = la_size;
310     cfg.context = (void *)part_no;
311     cfg.block_cycles = blk_cycles;
312     cfg.cache_size = ca_size;
313 
314     data = calloc(1, fs_size);
315     if (!data) {
316         fprintf(stderr, "no memory for mount\r\n");
317         return -1;
318     }
319 
320     err = lfs_format(&lfs, &cfg);
321     if (err < 0) {
322         fprintf(stderr, "format error: error=%d\r\n", err);
323         return -1;
324     }
325 
326     err = lfs_mount(&lfs, &cfg);
327     if (err < 0) {
328         fprintf(stderr, "mount error: error=%d\r\n", err);
329         return -1;
330     }
331 
332     char *last_dir = strrchr(src, '/');
333     if (last_dir) {
334         last_dir++;
335         compact(last_dir);
336     } else {
337         compact(src);
338     }
339 
340     FILE *img = fopen(dst, "wb+");
341 
342     if (!img) {
343         fprintf(stderr, "can't create image file: errno=%d (%s)\r\n", errno, strerror(errno));
344         return -1;
345     }
346 
347     int ret;
348     ret = fwrite(data, 1, fs_size, img);
349     if (ret < 0) {
350         fprintf(stderr, "fwrite(data, 1, fs_size, img): errno=%d (%s)\r\n", errno, strerror(errno));
351     }
352 
353     ret = fclose(img);
354     if (ret < 0) {
355         fprintf(stderr, "fclose(img): errno=%d (%s)\r\n", errno, strerror(errno));
356         return -1;
357     }
358 
359     return 0;
360 }
361