Add an image maker tool that generates image files for 2k page * 64 devices
[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
36
37 /*
38  * These are the sizes in the simulator file.
39  */
40 #define PAGE_DATA_SIZE  2048
41 #define PAGE_SPARE_SIZE 64
42 #define PAGE_SIZE       (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
43
44 /* Some stub definitions to get building to work. */
45 int simulate_power_failure = 0;
46 int random_seed = 0;
47
48 static char *input_dir;
49 static char *output_file;
50 static char *working_file;
51
52 static void usage(const char *prog_name)
53 {
54         printf("Usage: %s options\n", prog_name);
55         printf("\t-i name input_directory\n");
56         printf("\t-o name output_file\n");
57         printf("\t-w name working_file\n");
58 }
59
60 static void parse_args(int argc, char *argv[])
61 {
62         int c;
63
64         opterr = 0;
65         while ((c = getopt(argc, argv, "i:o:w:h")) != -1) {
66                 switch (c) {
67                 default:
68                 case 'h': usage(argv[0]); break;
69                 case 'i': input_dir = strdup(optarg); break;
70                 case 'o': output_file = strdup(optarg); break;
71                 case 'w': working_file = strdup(optarg); break;
72                 }
73         }
74 }
75
76
77 static int process_file(const char *from_path, const char *to_path, unsigned mode)
78 {
79         int hin;
80         int hout;
81         unsigned char buffer[8000];
82         int nread;
83         int nwritten;
84         int nbytes = 0;
85         int ret;
86
87         hin = open(from_path, O_RDONLY);
88         if (hin < 0) {
89                 perror ("opening input file");
90                 return -1;
91         }
92         hout = yaffs_open(to_path, O_CREAT | O_TRUNC | O_RDWR, 0666);
93
94         if(hout < 0) {
95                 printf("failed to create yaffs file %s\n", to_path);
96                 return -1;
97         }
98
99         while ((nread = read(hin, buffer, sizeof(buffer))) > 0) {
100                 nwritten = yaffs_write(hout, buffer, nread);
101
102                 if (nwritten != nread) {
103                         printf("Only wrote %d bytes out of %d\n", nwritten, nread);
104                         return -1;
105                 }
106                 nbytes += nwritten;
107         }
108
109         ret = yaffs_fdatasync(hout);
110         if (ret < 0) {
111                 printf("data sytnc failed\n");
112                 return -1;
113         }
114
115         ret = yaffs_fchmod(hout, mode);
116         if (ret < 0) {
117                 printf("chmod failed\n");
118                 return -1;
119         }
120
121         ret = yaffs_close(hout);
122         if (ret < 0) {
123                 printf("close failed\n");
124                 return -1;
125         }
126
127         return nbytes;
128 }
129
130 static int process_directory(const char *from_dir, const char *to_dir)
131 {
132         int error = 0;
133
134         DIR *dir;
135         struct dirent *entry;
136
137         printf("Processing directory %s into %s\n", from_dir, to_dir);
138
139         dir = opendir(from_dir);
140         if(!dir) {
141                 printf("opendir failed on %s", from_dir);
142                 return -1;
143         }
144
145         while((entry = readdir(dir)) != NULL  && error >= 0) {
146                 char from_path[500];
147                 char to_path[500];
148                 struct stat stats;
149                 unsigned  mode;
150                 int ret;
151
152                 //printf("Got entry %s\n", entry->d_name);
153
154                 /* Ignore . and .. */
155                 if(strcmp(entry->d_name, ".") == 0 ||
156                    strcmp(entry->d_name, "..") == 0)
157                    continue;
158
159                 if (snprintf(from_path, sizeof(from_path),
160                             "%s/%s", from_dir,entry->d_name) >= (int)sizeof(from_path)) {
161                         printf("path too long for %s/%s\n", from_dir, entry->d_name);
162                         error = -1;
163                         continue;
164                 }
165                 if (snprintf(to_path, sizeof(to_path),
166                             "%s/%s",to_dir,entry->d_name) >= (int)sizeof(to_path)) {
167                         printf("path too long for %s/%s\n",to_dir,entry->d_name);
168                         error = -1;
169                         continue;
170                 }
171
172                 if (lstat(from_path,&stats) < 0)
173                 {
174                         perror("lstat");
175                         error = -1;
176                         continue;
177                 }
178
179                 mode = stats.st_mode & 0777;
180
181                 if (S_ISDIR(stats.st_mode)) {
182                         printf("Directory create %s, mode %03o\n", to_path, mode);
183                         ret = yaffs_mkdir(to_path, mode);
184                         printf("Directory create %s, mode %03o : result %d\n",
185                                 to_path, mode, ret);
186
187                         if (ret < 0) {
188                                 printf("directory creation failed\n");
189                                 error = -1;
190                         }
191                         process_directory(from_path, to_path);
192                 } else if (S_ISREG(stats.st_mode)) {
193                         ret = process_file(from_path, to_path, mode);
194                         printf("Copy file %s to %s, mode %03o : result %d\n",
195                                 from_path, to_path, mode, ret);
196                         if (ret < 0) {
197                                 printf("file copy failed\n");
198                                 error = -1;
199                         }
200
201                 } else {
202                         printf("Unhandled object type %d\n", stats.st_mode);
203                 }
204         }
205
206         closedir(dir);
207
208         return 0;
209
210 }
211
212 int is_all_ff(unsigned char *buffer, int n)
213 {
214         while (n > 0) {
215                 if (*buffer != 0xff)
216                         return 0;
217                 buffer++;
218                 n--;
219         }
220
221         return 1;
222 }
223
224 /*
225  * Write the data to output, skipping over the spare bytes.
226  * Stop writing when we get to blank flash.
227  */
228 int generate_output_file(const char *working_file, const char *output_file)
229 {
230         unsigned char buffer[PAGE_SIZE];
231         int inh;
232         int outh;
233         int nread;
234         int nwritten;
235         int total = 0;
236
237         inh = open(working_file, O_RDONLY);
238         outh = open(output_file, O_CREAT | O_TRUNC | O_RDWR, 0666);
239
240         while ((nread = read(inh, buffer, PAGE_SIZE)) > 0) {
241                 if (nread != PAGE_SIZE) {
242                         printf("working file not properly sized\n");
243                         return -1;
244                 }
245
246                 if(is_all_ff(buffer, PAGE_DATA_SIZE)) {
247                         printf("End of data found\n");
248                         break;
249                 }
250
251                 nwritten = write(outh, buffer, PAGE_DATA_SIZE);
252
253                 if (nwritten != PAGE_DATA_SIZE) {
254                         printf("short write\n");
255                         return -1;
256                 }
257
258                 total+= nwritten;
259         }
260
261         close(inh);
262         close(outh);
263
264         return total;
265 }
266
267
268 int main(int argc, char *argv[])
269 {
270         struct yaffs_dev * dev;
271         int ret;
272
273         parse_args(argc, argv);
274
275         if (!input_dir || !output_file || !working_file) {
276                 printf("Need input directory , output file and working file\n");
277                 exit(1);
278         }
279
280         /*
281          * Create the Yaffs working file using the simulator.
282          */
283         unlink(working_file);
284         dev = yaffs_nandsim_install_drv("yroot",
285                                         working_file,
286                                         2048,
287                                         10,
288                                         1);
289
290         if (!dev) {
291                 printf("Failed to create yaffs working file\n");
292                 exit(1);
293         }
294
295         /*
296          * Disable checkpointing to create an image without checkpoint data.
297          */
298         dev->param.skip_checkpt_rd = 1;
299         dev->param.skip_checkpt_wr = 1;
300
301         ret = yaffs_mount("yroot");
302
303         printf("yaffs_mount returned %d\n", ret);
304
305         printf("Generating image from %s into file %s using working file %s\n",
306                 input_dir, output_file, working_file);
307         process_directory(input_dir, "yroot");
308
309         yaffs_unmount("yroot");
310
311         ret = generate_output_file(working_file, output_file);
312
313         printf("wrote %d bytes to output\n", ret);
314
315         if (ret < 0)
316                 exit(1);
317
318         return 0;
319 }