yaffs_image_maker: Add ability to handle oob tags and no tags ecc
[yaffs2.git] / direct / test-framework / yaffs2_image_maker / yaffs2_image_maker.c
1 /*
2  * An image maker that creates a file that creates a Yaffs2 image file
3  * can be programmed into NAND.
4  * This assumes that the device has the following properties:
5  * * 2k bytes per page
6  * * 64  pages per block
7  * * Yaffs is using inband tags.
8  *
9  * Note that this utility first generates a "working file" which is
10  * a simulation of the NAND. It then generates an output file which
11  * can be programmed into flash.
12  *
13  */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <dirent.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <assert.h>
25
26 #if 1
27 #undef CONFIG_YAFFS_PROVIDE_DEFS
28 #undef CONFIG_YAFFSFS_PROVIDE_VALUES
29 #endif
30
31 #include "yaffsfs.h"
32
33 #include "yaffs_nandsim_file.h"
34 #include "yaffs_guts.h"
35 #include "yaffs_trace.h"
36 #include "yaffs_packedtags2.h"
37
38
39 /*
40  * These are the sizes in the simulator file.
41  */
42 #define PAGE_DATA_SIZE  2048
43 #define PAGE_SPARE_SIZE 64
44 #define PAGE_SIZE       (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
45
46
47 /* Some stub definitions to get building to work. */
48 int simulate_power_failure = 0;
49 int random_seed = 0;
50
51 static char *input_dir;
52 static char *output_file;
53 static char *working_file;
54 static char endian = 'l';
55 static int no_tags_ecc = 0;
56 static int inband_tags = 0;
57
58 static int tags_size;
59 static int record_size;
60 static int total_written;
61
62 static void usage(const char *prog_name)
63 {
64         printf("Usage: %s options\n", prog_name);
65         printf("\t-i name input_directory\n");
66         printf("\t-o name output_file\n");
67         printf("\t-w name working_file\n");
68         printf("\t-b      big endian output\n");
69         printf("\t-I      strore tags in flash data area (inband_tags)\n");
70         printf("\t-N      do not apply ECC to tags in OOB area (no_tags_ecc)\n");
71         exit(1);
72 }
73
74 static void parse_args(int argc, char *argv[])
75 {
76         int c;
77
78         opterr = 0;
79         while ((c = getopt(argc, argv, "bi:o:w:hIN")) != -1) {
80                 switch (c) {
81                 default:
82                 case 'h': usage(argv[0]); break;
83                 case 'i': input_dir = strdup(optarg); break;
84                 case 'o': output_file = strdup(optarg); break;
85                 case 'w': working_file = strdup(optarg); break;
86                 case 'b': endian = 'b'; break;
87                 case 'I': inband_tags = 1; break;
88                 case 'N': no_tags_ecc = 1; break;
89                 }
90         }
91 }
92
93
94 static int process_file(const char *from_path, const char *to_path, unsigned mode)
95 {
96         int hin;
97         int hout;
98         unsigned char buffer[8000];
99         int nread;
100         int nwritten;
101         int nbytes = 0;
102         int ret;
103
104         hin = open(from_path, O_RDONLY);
105         if (hin < 0) {
106                 perror ("opening input file");
107                 return -1;
108         }
109         hout = yaffs_open(to_path, O_CREAT | O_TRUNC | O_RDWR, 0666);
110
111         if(hout < 0) {
112                 printf("failed to create yaffs file %s\n", to_path);
113                 return -1;
114         }
115
116         while ((nread = read(hin, buffer, sizeof(buffer))) > 0) {
117                 nwritten = yaffs_write(hout, buffer, nread);
118
119                 if (nwritten != nread) {
120                         printf("Only wrote %d bytes out of %d\n", nwritten, nread);
121                         return -1;
122                 }
123                 nbytes += nwritten;
124         }
125
126         ret = yaffs_fdatasync(hout);
127         if (ret < 0) {
128                 printf("data sytnc failed\n");
129                 return -1;
130         }
131
132         ret = yaffs_fchmod(hout, mode);
133         if (ret < 0) {
134                 printf("chmod failed\n");
135                 return -1;
136         }
137
138         ret = yaffs_close(hout);
139         if (ret < 0) {
140                 printf("close failed\n");
141                 return -1;
142         }
143
144         return nbytes;
145 }
146
147 static int process_directory(const char *from_dir, const char *to_dir)
148 {
149         int error = 0;
150
151         DIR *dir;
152         struct dirent *entry;
153
154         printf("Processing directory %s into %s\n", from_dir, to_dir);
155
156         dir = opendir(from_dir);
157         if(!dir) {
158                 printf("opendir failed on %s", from_dir);
159                 return -1;
160         }
161
162         while((entry = readdir(dir)) != NULL  && error >= 0) {
163                 char from_path[500];
164                 char to_path[500];
165                 struct stat stats;
166                 unsigned  mode;
167                 int ret;
168
169                 //printf("Got entry %s\n", entry->d_name);
170
171                 /* Ignore . and .. */
172                 if(strcmp(entry->d_name, ".") == 0 ||
173                    strcmp(entry->d_name, "..") == 0)
174                    continue;
175
176                 if (snprintf(from_path, sizeof(from_path),
177                             "%s/%s", from_dir,entry->d_name) >= (int)sizeof(from_path)) {
178                         printf("path too long for %s/%s\n", from_dir, entry->d_name);
179                         error = -1;
180                         continue;
181                 }
182                 if (snprintf(to_path, sizeof(to_path),
183                             "%s/%s",to_dir,entry->d_name) >= (int)sizeof(to_path)) {
184                         printf("path too long for %s/%s\n",to_dir,entry->d_name);
185                         error = -1;
186                         continue;
187                 }
188
189                 if (lstat(from_path,&stats) < 0)
190                 {
191                         perror("lstat");
192                         error = -1;
193                         continue;
194                 }
195
196                 mode = stats.st_mode & 0777;
197
198                 if (S_ISDIR(stats.st_mode)) {
199                         printf("Directory create %s, mode %03o\n", to_path, mode);
200                         ret = yaffs_mkdir(to_path, mode);
201                         printf("Directory create %s, mode %03o : result %d\n",
202                                 to_path, mode, ret);
203
204                         if (ret < 0) {
205                                 printf("directory creation failed\n");
206                                 error = -1;
207                         }
208                         process_directory(from_path, to_path);
209                 } else if (S_ISREG(stats.st_mode)) {
210                         ret = process_file(from_path, to_path, mode);
211                         printf("Copy file %s to %s, mode %03o : result %d\n",
212                                 from_path, to_path, mode, ret);
213                         if (ret < 0) {
214                                 printf("file copy failed\n");
215                                 error = -1;
216                         }
217
218                 } else {
219                         printf("Unhandled object type %d\n", stats.st_mode);
220                 }
221         }
222
223         closedir(dir);
224
225         return 0;
226
227 }
228
229 int is_all_ff(unsigned char *buffer, int n)
230 {
231         while (n > 0) {
232                 if (*buffer != 0xff)
233                         return 0;
234                 buffer++;
235                 n--;
236         }
237
238         return 1;
239 }
240
241 /*
242  * Write the data to output, skipping over the spare bytes.
243  * Stop writing when we get to blank flash.
244  */
245 int generate_output_file(const char *working_file, const char *output_file)
246 {
247         unsigned char buffer[PAGE_SIZE];
248         int inh;
249         int outh;
250         int nread;
251         int nwritten;
252
253         inh = open(working_file, O_RDONLY);
254         outh = open(output_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
255
256         while ((nread = read(inh, buffer, PAGE_SIZE)) > 0) {
257                 if (nread != PAGE_SIZE) {
258                         printf("working file not properly sized\n");
259                         return -1;
260                 }
261
262                 if(is_all_ff(buffer, PAGE_DATA_SIZE)) {
263                         printf("End of data found\n");
264                         break;
265                 }
266
267                 /* Write the data part. */
268                 nwritten = write(outh, buffer, PAGE_DATA_SIZE);
269
270                 if (nwritten != PAGE_DATA_SIZE) {
271                         printf("short write\n");
272                         return -1;
273                 }
274
275                 total_written += nwritten;
276
277                 /* Now if there are OOB tags then write the OOB tags part too */
278                 if (tags_size > 0) {
279                         /* Read the oob bytes. In the simulator these are
280                          * stored at offset 26 in the 64-byte spare area.
281                          * We must therefore copy them from this location to
282                          * the output file.
283                          */
284                         nwritten = write(outh, buffer + PAGE_DATA_SIZE + 26, tags_size);
285
286                         if (nwritten != tags_size) {
287                                 printf("short write\n");
288                                 return -1;
289                         }
290
291                         total_written += nwritten;
292                 }
293         }
294
295         close(inh);
296         close(outh);
297
298         return total_written;
299 }
300
301
302 int main(int argc, char *argv[])
303 {
304         struct yaffs_dev * dev;
305         int ret;
306
307         yaffs_trace_mask = 0;
308
309         parse_args(argc, argv);
310
311         if (!input_dir || !output_file || !working_file) {
312                 printf("Need input directory , output file and working file\n");
313                 exit(1);
314         }
315
316         printf("Generating image from %s into file %s using working file %s\n",
317                 input_dir, output_file, working_file);
318         printf("Output file is in %s endian\n",
319                 (endian == 'l') ? "little" : "big");
320
321         /*
322          * Determine oob tags_size.
323          */
324         if (inband_tags)
325                 tags_size = 0;
326         else if (no_tags_ecc)
327                 tags_size = sizeof(struct yaffs_packed_tags2_tags_only);
328         else
329                 tags_size = sizeof(struct yaffs_packed_tags2);
330
331         record_size = PAGE_DATA_SIZE + tags_size;
332
333         printf("\n");
334         /*
335          * Create the Yaffs working file using the simulator.
336          */
337         unlink(working_file);
338         dev = yaffs_nandsim_install_drv("yroot",
339                                         working_file,
340                                         2048,
341                                         10,
342                                         inband_tags);
343
344         if (!dev) {
345                 printf("Failed to create yaffs working file\n");
346                 exit(1);
347         }
348
349         /*
350          * Disable checkpointing to create an image without checkpoint data.
351          */
352         dev->param.skip_checkpt_rd = 1;
353         dev->param.skip_checkpt_wr = 1;
354
355         /*
356          * Set up stored endian: 1 = little endian, 2 = big endian.
357          * Set no_tags_ecc
358          */
359         dev->param.stored_endian = (endian == 'l') ? 1 : 2;
360         dev->param.no_tags_ecc = no_tags_ecc;
361
362
363         ret = yaffs_mount("yroot");
364
365         printf("yaffs_mount returned %d\n", ret);
366
367         process_directory(input_dir, "yroot");
368
369         yaffs_unmount("yroot");
370
371         printf("Generating output file\n");
372
373         ret = generate_output_file(working_file, output_file);
374
375         printf("Done\n\n");
376         printf("Wrote %d bytes (%d pages of %d bytes each) to output\n",
377                 total_written, total_written/record_size, record_size);
378         if (inband_tags) {
379                 printf("The image has inband tags.\n");
380                 printf("This means it is structured a records of %d bytes per page\n", record_size);
381                 printf("This should be written to the data portion of the page\n");
382         } else {
383                 printf("The image has out of band tags with%s ECC on the tags\n",
384                         no_tags_ecc ? " NO" : "");
385                 printf("This means it has %d tags bytes per record to be written in the oob area\n", tags_size);
386                 printf("Each record is %d bytes.\n"
387                         "The first %d bytes are data for the data datea and\n"
388                         "the last %d bytes are tags for the oob (spare) area\n",
389                         record_size, PAGE_DATA_SIZE, tags_size);
390         }
391         if (ret < 0)
392                 exit(1);
393
394         return 0;
395 }