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