FreeCalypso > hg > fc-magnetite
comparison src/cs/drivers/drv_app/ffs/board/tcases.c @ 0:945cf7f506b2
src/cs: chipsetsw import from tcs211-fcmodem
binary blobs and LCD demo files have been excluded,
all line endings are LF only
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 25 Sep 2016 22:50:11 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:945cf7f506b2 |
---|---|
1 /****************************************************************************** | |
2 * Flash File System (ffs) | |
3 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com | |
4 * | |
5 * ffs test cases | |
6 * | |
7 * $Id: tcases.c 1.13.1.1.1.66 Thu, 08 Jan 2004 15:05:23 +0100 tsj $ | |
8 * | |
9 ******************************************************************************/ | |
10 | |
11 #ifndef TARGET | |
12 #include "ffs.cfg" | |
13 #endif | |
14 | |
15 #include "ffs/ffs_api.h" // Temp | |
16 #include "ffs/ffs.h" | |
17 | |
18 #include "ffs/board/tffs.h" | |
19 #include "ffs/board/core.h" // only for block/object recovery test flags | |
20 #include "ffs/board/tdata.h" | |
21 #include "ffs/board/ffstrace.h" | |
22 #include "ffs/board/drv.h" | |
23 #include "ffs/pcm.h" | |
24 | |
25 #if((TARGET == 1) || (RIV_ENV==1)) | |
26 #include "rvf/rvf_api.h" // this include rv_general.h and rvf_target.h | |
27 #include "rvm/rvm_use_id_list.h" | |
28 | |
29 #endif | |
30 | |
31 #include <stdio.h> | |
32 #include <string.h> | |
33 #include <stdlib.h> | |
34 #include <limits.h> | |
35 #include <assert.h> | |
36 | |
37 #define LUDIR "/europe/sweden" | |
38 #define MFDIR "/pcm" | |
39 | |
40 // TODO: reimplement test case bfull (not valid any more). | |
41 | |
42 // TODO: Cleanup in beginning of each test case for as many cases as | |
43 // possible, so they can be re-run. | |
44 | |
45 // TODO: Make as many cases as possible fully independent of number of | |
46 // blocks and size of blocks in ffs. | |
47 | |
48 // TODO: Every testcase should test if it is applicable to the current | |
49 // environment, e.g. some tests are impossible if e have a 2 or 3 block | |
50 // file system. | |
51 | |
52 // TODO: test case for testing age functionality | |
53 // TODO: Implement case_ren | |
54 // TODO: Implement case_rm | |
55 | |
56 // NOTEME: DO something with test case flags (PC, IT, RND)? | |
57 | |
58 // Should we make a test case where we use case_lsr to make map of objects ( | |
59 // ensuring mapsize is prime). In a loop, we select a random object (object | |
60 // index[rnd%size]) and perform a random operation on that object? | |
61 | |
62 // Should test data (tdata[]) be of sizes 2^n+n or Xn+n where n = 0..15 | |
63 | |
64 // Should all test files have suffix ".<tdata-index>"? This would make very | |
65 // easy data checking! | |
66 | |
67 // Add compiler define: WITH_PCM | |
68 | |
69 //unsigned char ffs_image[4*4*1024]; | |
70 //int ffs_ram_image_address = (int) &ffs_image; | |
71 | |
72 | |
73 /****************************************************************************** | |
74 * Prototypes and Globals | |
75 ******************************************************************************/ | |
76 | |
77 // Helper functions | |
78 int case_cleanup(int min_space); | |
79 int case_mk_rand_file(char *dirname, int max_size, int min_size); | |
80 int ignore_file(char *pathname); | |
81 int case_trace_mask(int p0, int p1); | |
82 int case_reinit(int p0, int p1); | |
83 int case_debug_help(int p0, int p1); | |
84 | |
85 struct object_s { | |
86 char *name; | |
87 struct xstat_s stat; | |
88 }; | |
89 | |
90 const struct testcase_s testcase[]; | |
91 | |
92 // Benchmark (not in use yet) | |
93 struct results_s { | |
94 int w16B; | |
95 int w256B; | |
96 int w4096B; | |
97 int rew4096B; | |
98 int r16B; | |
99 int r256B; | |
100 int r4096B; | |
101 int lfile; | |
102 int ldir; | |
103 int lonef; | |
104 }; | |
105 | |
106 /****************************************************************************** | |
107 * Collective Test Cases | |
108 ******************************************************************************/ | |
109 | |
110 // test cases: all, alot, most, much + specific ones | |
111 | |
112 int case_all(int p0, int p1) | |
113 { | |
114 #if (TARGET == 1) | |
115 UINT32 time_begin, elapsed; | |
116 time_begin = tffs_timer_begin(); | |
117 #endif | |
118 // We have to run test case 'init' after test case 'format'. This is | |
119 // because 'init' test case calls test_ffs_params_get() which | |
120 // initializes variables used in many of the testcases. | |
121 | |
122 error = test_run("ninit;format;i;world;eu;pcm;apiexc;" | |
123 "bigf;open;rw;seek;append;ren;mopen;" | |
124 "jnl;irec;drec;trunc;brec;stat;" | |
125 "lu;fc;root;dirs;frd;bfull;dsync;" | |
126 "ssym;find;ri;x;fwflags;query;octrl"); | |
127 #if (TARGET == 1) | |
128 elapsed = tffs_timer_end(time_begin); | |
129 ttw(ttr(TTrAll, "Time elapsed %ds" NL, elapsed / 1000)); | |
130 #endif | |
131 | |
132 test_statistics_print(); | |
133 | |
134 return error; | |
135 // Not implemented test cases... | |
136 return test_run("rm;pcm;"); | |
137 } | |
138 | |
139 int case_alot(int p0, int p1) | |
140 { | |
141 return test_run("ninit;format;ri;i;ri;world;ri;eu;ri;fwflags;ri;" | |
142 "bigf;ri;open;ri;rw;ri;seek;ri;append;ri;ren;ri;" | |
143 "jnl;ri;irec;ri;brec;ri;stat;ri;trunc;ri;mopen;ri;" | |
144 "lu;ri;fc;ri;root;ri;dirs;ri;frd;ri;bfull;ri;" | |
145 "ssym;ri;find;ri;x;ri;dsync;ri;pcm;ri;query;ri;octrl"); | |
146 } | |
147 | |
148 int case_tall(int p0, int p1) | |
149 { | |
150 return test_run("ninit;format;i;world;eu;fwflags;" | |
151 "bigf;jnl;irec;drec;ren;apiexc;" | |
152 "stat;open;rw;seek;trunc;append;octrl;" | |
153 "lu;fc;root;dirs;frd;bfull;pcm;query;" | |
154 "ssym;find;x;ex;bf;nb;mopen;dsync;brec"); | |
155 } | |
156 | |
157 // Ad hoc test case | |
158 int case_test(int p0, int p1) | |
159 { | |
160 return test_run("format;i;world;eu;ri;mopen1;ri;fwflags;ri;" | |
161 "bigf;ri;jnl;ri;irec;ri;drec;ri;brec;ri;pcm;ri;" | |
162 "trunc1;ri;stat;open1;ri;rw1;ri;seek1;ri;ren;ri;" | |
163 "lu;ri;fc;ri;root;ri;dirs;ri;frd;ri;bfull;ri;" | |
164 "ssym;ri;find;ri;x;ri;append;ri;dsync;ri;"); | |
165 } | |
166 | |
167 extern struct dev_s dev; | |
168 // Agressive all. Run case 'all' for dev.numblocks in the range dev.numblocks..4 | |
169 int case_aall(int p0, int p1) | |
170 { | |
171 char myname[20]; | |
172 | |
173 int i, failed = 0; | |
174 | |
175 if (dev.numblocks * dev.blocksize > 1024*1024) | |
176 strcpy(myname, "/ffs/b999"); | |
177 else | |
178 strcpy(myname, "/ffs/b99"); | |
179 | |
180 /** There's no need to test for i=127,126,125,124..3,2,1. So for i | |
181 * >= 20 we progress a little faster. */ | |
182 for (i = dev.numblocks; i >= 3; i -= (i >= 20 ? i/4 : 1)) | |
183 { | |
184 tw(tr(TR_FUNC, TrTest, "TEST aall. %d\n", i)); | |
185 ttw(ttr(TTrTest, "TEST aall. %d" NL, i)); | |
186 | |
187 error = tffs_preformat(0xDEAD); | |
188 expect(error, EFFS_OK); | |
189 | |
190 sprintf(myname, "/ffs/b%d", i); | |
191 tffs_format(myname, 0x2BAD); | |
192 expect(error, EFFS_OK); | |
193 | |
194 failed += test_run("i;world;eu;bigf;bfull;" | |
195 "jnl;irec;drec;brec;stat;dsync;" | |
196 "open;rw;seek;trunc;ren;mopen;" | |
197 "lu;fc;root;dirs;frd;append;" | |
198 "ssym;find;ri;x"); | |
199 | |
200 } | |
201 return failed; | |
202 } | |
203 | |
204 // This is a collection of all failing testcases to be investigated. | |
205 int case_fail(int p0, int p1) | |
206 { | |
207 int result; | |
208 const char imeifile[] = "/europe/norway/IMEI"; | |
209 | |
210 switch (p0) { | |
211 case 1: | |
212 tw(tr(TR_FUNC, TrTestHigh, | |
213 "remember to run case_fcontrol before this one\n")); | |
214 // Make symlink to imeifile and try to update it | |
215 error = tffs_symlink("/europe/imie", imeifile); | |
216 expect(error, EFFS_ACCESS); | |
217 | |
218 error = tffs_fwrite("/europe/imie", TDATA(1)); | |
219 expect(error, EFFS_ACCESS); | |
220 break; | |
221 case 2: | |
222 if (1) { | |
223 const char bigfile[] = "/iceberg"; | |
224 int bytes_max, file_size; | |
225 char myname[] = "/ffs/b7"; | |
226 | |
227 error = tffs_preformat(0xDEAD); | |
228 expect(error, EFFS_OK); | |
229 | |
230 error = tffs_format(myname, 0x2BAD); | |
231 expect(error, EFFS_OK); | |
232 | |
233 ffs_query(Q_BYTES_FREE, (uint32 *) &bytes_max); | |
234 | |
235 // File the system with this huge file | |
236 file_size = bytes_max; | |
237 | |
238 ttw(ttr(TTrTest, "Bigfile of size %d" NL, file_size)); | |
239 tw(tr(TR_FUNC, TrTestHigh, "Bigfile of size %d\n", file_size)); | |
240 | |
241 error = tffs_fcreate(bigfile, (char *) tdata[TDATA_HUGE], file_size); | |
242 expect(error, EFFS_OK); | |
243 } | |
244 break; | |
245 | |
246 default: | |
247 result = 1; | |
248 } | |
249 return result; | |
250 } | |
251 | |
252 // zzz to easy search ;-) | |
253 // NOTE: Move the below tests | |
254 extern char *tdata_huge; | |
255 // Test that a FFS API blocking call that not is able to send a mail to FFS fails as expected and don't lock the system (it must unlock and delete the mutex). | |
256 int case_okay(int p0, int p1) | |
257 { | |
258 | |
259 error = tffs_fwrite("/test", tdata[TDATA_HUGE], 20); | |
260 expect_ok(error); | |
261 | |
262 error = tffs_fread("/test", bigbuf, 20); | |
263 expect_ok(error); | |
264 | |
265 bigbuf[20] = 0; | |
266 | |
267 tw(tr(TR_FUNC, TrTestHigh, "String '%s'\n", bigbuf)); | |
268 | |
269 return EFFS_OK; | |
270 } | |
271 | |
272 // Run testcases in a random order. Only the test cases in the test case | |
273 // table that are marked as re-runnable, are run. | |
274 int case_rand(int p0, int p1) | |
275 { | |
276 int i, n, seed, max = 0, error = 0; | |
277 const struct testcase_s *p; | |
278 // This is a way to activate trace at a defined test number. If rand | |
279 // test number 134 fail it is possible to activate trace at test number | |
280 // 133 etc. Note we have to change activate_trace_nr manual before compile. | |
281 int activate_trace_nr = 0; | |
282 int trace_mask = 0xFFDFF; | |
283 // NOTE: use p1 as active_trace_nr? or make it | |
284 | |
285 p0 = (p0 == 0 ? 117 : p0); // Number of test cases to run | |
286 p1 = (p1 == 0 ? 567 : p1); // Initial seed | |
287 seed = p1; | |
288 if (seed == 1) { | |
289 ; // TODO: Set seed as a variable of current time | |
290 } | |
291 | |
292 // TODO: Initialize seed from p1. | |
293 | |
294 // First count total number of test cases | |
295 for (p = testcase; p->name; p++) | |
296 max++; | |
297 | |
298 tw(tr(TR_FUNC, TrTestHigh, | |
299 "Number of available random test cases = %d\n", max)); | |
300 | |
301 for (i = 0; i < p0; i++) | |
302 { | |
303 do { | |
304 n = rand() % max; | |
305 } while ((testcase[n].flags & RND) == 0); | |
306 | |
307 if ((i + 1) == activate_trace_nr) { | |
308 #if (TARGET == 0) | |
309 tr_init(trace_mask, 2, 0 ); | |
310 #else | |
311 ttr_init(trace_mask); | |
312 #endif | |
313 tw(tr_bstat()); | |
314 } | |
315 | |
316 tw(tr(TR_FUNC, TrTest, "Nr: %d", i + 1)); | |
317 ttw(ttr(TTrTest, "Nr: %d" NL, i + 1)); | |
318 | |
319 if ((error = test_run(testcase[n].name))) | |
320 break; | |
321 } | |
322 | |
323 if (p1 == 1) | |
324 tw(tr(TR_FUNC, TrTestHigh, "Initial seed = %d\n", seed)); | |
325 | |
326 test_statistics_print(); | |
327 return error; | |
328 } | |
329 | |
330 | |
331 /****************************************************************************** | |
332 * Population Tests | |
333 ******************************************************************************/ | |
334 | |
335 int case_world(int p0, int p1) | |
336 { | |
337 int i; | |
338 const char *dirs[] = { "/antarctica", "/africa", | |
339 "/asia", "/europe", | |
340 "/north-america", "/south-america", | |
341 "/australia" }; | |
342 | |
343 // Cleanup | |
344 for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) { | |
345 tffs_remove(dirs[i]); | |
346 } | |
347 | |
348 for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) { | |
349 error = tffs_mkdir(dirs[i]); | |
350 expect(error, EFFS_OK); | |
351 } | |
352 return 0; | |
353 } | |
354 | |
355 | |
356 int case_europe(int p0, int p1) | |
357 { | |
358 int i; | |
359 const char *dirs[] = { "/europe/denmark", "/europe/sweden", | |
360 "/europe/norway", "/europe/finland" }; | |
361 | |
362 // Cleanup | |
363 for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) { | |
364 error = tffs_remove(dirs[i]); | |
365 } | |
366 | |
367 for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) { | |
368 error = tffs_mkdir(dirs[i]); | |
369 expect(error, EFFS_OK); | |
370 } | |
371 return 0; | |
372 } | |
373 | |
374 int case_denmark(int p0, int p1) | |
375 { | |
376 // Cleanup | |
377 tffs_remove("/europe/denmark/jutland"); | |
378 tffs_remove("/europe/denmark/sealand"); | |
379 | |
380 error = tffs_mkdir("/europe/denmark/jutland"); | |
381 expect(error, EFFS_OK); | |
382 error = tffs_mkdir("/europe/denmark/sealand"); | |
383 expect(error, EFFS_OK); | |
384 | |
385 return 0; | |
386 } | |
387 | |
388 | |
389 /****************************************************************************** | |
390 * Atomic Tests | |
391 ******************************************************************************/ | |
392 | |
393 int case_init(int p0, int p1) | |
394 { | |
395 error = tffs_initialize(); | |
396 // ignore error | |
397 error = test_ffs_params_get(); | |
398 expect(error, EFFS_OK); | |
399 return 0; | |
400 } | |
401 | |
402 int case_exit(int p0, int p1) | |
403 { | |
404 error = tffs_exit(); | |
405 expect(error, EFFS_OK); | |
406 return 0; | |
407 } | |
408 | |
409 int case_only_preformat(int p0, int p1) | |
410 { | |
411 tffs_preformat(0xDEAD); | |
412 expect(error, EFFS_OK); | |
413 return 0; | |
414 } | |
415 | |
416 int case_only_format(int p0, int p1) | |
417 { | |
418 tffs_format("/ffs", 0x2BAD); | |
419 expect(error, EFFS_OK); | |
420 return 0; | |
421 } | |
422 | |
423 int case_reset(int p0, int p1) | |
424 { | |
425 error = tffs_initialize(); | |
426 // ignore result | |
427 error = tffs_preformat(0xDEAD); | |
428 expect(error, EFFS_OK); | |
429 error = tffs_format("/ffs", 0x2BAD); | |
430 expect(error, EFFS_OK); | |
431 error = tffs_exit(); | |
432 expect(error, EFFS_OK); | |
433 return 0; | |
434 } | |
435 | |
436 int case_status(int p0, int p1) | |
437 { | |
438 error = test_run("lsr"); | |
439 return error; | |
440 } | |
441 | |
442 | |
443 /****************************************************************************** | |
444 * Special Tests | |
445 ******************************************************************************/ | |
446 | |
447 // Test FFS with only 2 blocks in device | |
448 int case_twob(int p0, int p1) | |
449 { | |
450 int space_left; | |
451 int size, i; | |
452 char myname[] = "/two_block99"; | |
453 | |
454 // Format ffs to use only 2 block no journal file and no reserved space. | |
455 // Make some directoryes. | |
456 // Fill ffs allmost to the edge and try to write over the edge. | |
457 // Read back all the files. | |
458 error = tffs_preformat(0xDEAD); | |
459 expect(error, EFFS_OK); | |
460 error = tffs_format("/ffs/b2j0m0", 0x2BAD); | |
461 expect(error, EFFS_OK); | |
462 | |
463 error = test_run("i;world;eu;x"); | |
464 if(error) return 1; | |
465 | |
466 // Calculate the amount of space that is left to user data because some space | |
467 // is used to directoryes | |
468 space_left = dev.blocksize - (13 * 20); | |
469 tw(tr(TR_FUNC, TrTestHigh, "Space left: %d\n", space_left)); | |
470 | |
471 size = space_left; | |
472 for(i = 0; i < 6; i++) { | |
473 size = size/2; | |
474 sprintf(myname, "/two_block%d", i); | |
475 error = tffs_fwrite(myname, (char*)tdata[TDATA_HUGE], | |
476 size >= 20 ? size - 20 : 0); | |
477 expect(error, EFFS_OK); | |
478 } | |
479 | |
480 error = tffs_fwrite(myname, (char*)tdata[TDATA_HUGE], space_left/5); | |
481 expect(error, EFFS_NOSPACE); | |
482 | |
483 // 20 is the average space used to the file name + word align. | |
484 size = space_left; | |
485 for(i = 0; i < 6; i++) { | |
486 size = size/2; | |
487 sprintf(myname, "/two_block%d", i); | |
488 error = tffs_fread(myname, bigbuf, bigbuf_size); | |
489 expect(error, size >= 20 ? size - 20 : 0); | |
490 } | |
491 | |
492 //error = ffs_object_control(0, OC_DEV_DEVICE, 0x080D); | |
493 //if (error < 0) return error; | |
494 | |
495 return 0; | |
496 } | |
497 | |
498 // Test FFS with only 3 blocks in device | |
499 int case_threeb(int p0, int p1) | |
500 { | |
501 char mytest[20]; | |
502 | |
503 // Format ffs to use only 3 blocks, make directoryes and run test case | |
504 // rand <p0> number of times. | |
505 error = tffs_preformat(0xDEAD); | |
506 expect(error, EFFS_OK); | |
507 error = tffs_format("/ffs/b3r24", 0x2BAD); | |
508 expect(error, EFFS_OK); | |
509 | |
510 error = test_run("i;world;eu;x"); | |
511 if (error) return 1; | |
512 | |
513 if(p0 == 0) p0 = 233; | |
514 | |
515 sprintf(mytest, "rand%d", p0); | |
516 return test_run(mytest); | |
517 } | |
518 | |
519 | |
520 // Simulate a typical usage of ffs. We expect one part of the data will be | |
521 // what we call 'static' data (calibration files etc) the other part is the | |
522 // 'dynamic' data (wap, sms etc) we do also expect that they don't fill FFS | |
523 // completely thus we have a 'free' part. | |
524 int case_customer(int nblocks, int nloops) | |
525 { | |
526 int free_part = 5, static_part = 47, dynamic_part = 47; | |
527 int free_size, static_size, dynamic_size; | |
528 int bytes_free, bytes_max, bytes_used; | |
529 int file_size_max, file_size_min, file_size_avg; | |
530 int i, j, max_obj_block, num_static_files; | |
531 char myname[] = "/ffs/bxxx/"; | |
532 char file_name[FFS_FILENAME_MAX + 1]; | |
533 char path[FFS_FILENAME_MAX * 2]; | |
534 char static_dir[] ="/READONLY"; | |
535 char dynamic_dir[] = "/rand"; | |
536 struct dir_s dir; | |
537 | |
538 if (nblocks == 0) | |
539 nblocks = 7; | |
540 if (nloops == 0) | |
541 nloops = 300; | |
542 | |
543 error = tffs_preformat(0xDEAD); expect(error, EFFS_OK); | |
544 sprintf(myname, "/ffs/b%d", nblocks); | |
545 error = tffs_format(myname, 0x2BAD); expect(error, EFFS_OK); | |
546 | |
547 tffs_mkdir(dynamic_dir); expect(error, EFFS_OK); | |
548 tffs_mkdir(static_dir); expect(error, EFFS_OK); | |
549 | |
550 ffs_query(Q_BYTES_FREE, &bytes_max); | |
551 free_size = bytes_max * free_part / 100; | |
552 static_size = bytes_max * static_part / 100; | |
553 dynamic_size = bytes_max * dynamic_part / 100; | |
554 tw(tr(TR_FUNC, TrTest, "Free:%d,%dkB. Static:%d,%dkB, Dynamic:%d,%dkB\n", | |
555 free_part, free_size/1024, static_part, static_size/1024, | |
556 dynamic_part, dynamic_size/1024)); | |
557 | |
558 // Find max average objects per block | |
559 max_obj_block = fs.block_files_max; | |
560 if (max_obj_block > fs.objects_max / (dev.numblocks -1 - fs.blocks_free_min)) | |
561 max_obj_block = fs.objects_max / (dev.numblocks -1 - fs.blocks_free_min); | |
562 tw(tr(TR_FUNC, TrTest, "Max average objects per block %d\n", max_obj_block)); | |
563 ttw(ttr(TTrTest, "Max avg obj per block %d" NL, max_obj_block)); | |
564 | |
565 // Average (minimum) file size (avoid to reach block_files_max and | |
566 // objects_max) | |
567 file_size_avg = dev.blocksize / max_obj_block; | |
568 | |
569 ffs_query(Q_BYTES_USED, &bytes_used); | |
570 tw(tr(TR_FUNC, TrTest, "Write static files (avg size %d)\n", file_size_avg)); | |
571 ttw(ttr(TTrTest, "avg size %d" NL, file_size_avg)); | |
572 do { | |
573 i++; | |
574 file_size_min = 5; | |
575 // For each 5 file we make one huge. | |
576 file_size_max = i % 5 ? file_size_avg * 2 : file_size_avg * 15; | |
577 // For each 6 file we make one small. | |
578 file_size_max = i % 6 ? file_size_max : 5; | |
579 | |
580 // Saturate, avoid to make one file that parses the total static_size | |
581 if (file_size_max > static_size - bytes_used) | |
582 file_size_max = file_size_min = static_size - bytes_used; | |
583 | |
584 // For each 7 file we create one dynamic (If the block is full with only | |
585 // valid objects do we risk that this block never will be reclaimed!). | |
586 if (i % 7) | |
587 error = case_mk_rand_file(dynamic_dir, file_size_max, file_size_min); | |
588 else | |
589 error = case_mk_rand_file(static_dir, file_size_max, file_size_min); | |
590 expect_ok(error); | |
591 ffs_query(Q_BYTES_USED, &bytes_used); | |
592 } while (bytes_used < static_size); | |
593 | |
594 num_static_files = tffs_opendir(static_dir, &dir); | |
595 expect_ok(num_static_files); | |
596 tw(tr(TR_FUNC, TrTest, "Written %d files\n", num_static_files)); | |
597 ttw(ttr(TTrTest, "Written %d files" NL, num_static_files)); | |
598 // In a loop we continue to write data until only the wanted free_part is | |
599 // left, after that we remove half of the just created files and then write | |
600 // again and again... | |
601 j = 0; | |
602 tw(tr(TR_FUNC, TrTest, "Write and remove dynamic files\n")); | |
603 ttw(ttr(TTrTest, "Write and remove dynamic files" NL)); | |
604 for (i = 0; i < nloops; i++) { | |
605 if (i % 10 == 0) { | |
606 tw(tr(TR_FUNC, TrTest, "loop %d\n", i)); | |
607 ttw(ttr(TTrTest, "loop %d" NL, i)); | |
608 } | |
609 ffs_query(Q_BYTES_FREE, &bytes_free); | |
610 do { | |
611 j++; | |
612 file_size_min = 5; | |
613 file_size_max = j % 5 ? file_size_avg * 2 : file_size_avg * 15; | |
614 file_size_max = j % 6 ? file_size_max : 5; | |
615 // Saturate, avoid using the free space. | |
616 if (file_size_max > bytes_free - free_size) | |
617 file_size_max = file_size_min = bytes_free - free_size; | |
618 | |
619 if (file_size_max < 0) | |
620 break; | |
621 | |
622 error = case_mk_rand_file(dynamic_dir, file_size_max, file_size_min); | |
623 // NOTE it is very difficult to avoid EFFS_FSFULL because cleanup will | |
624 // sometimes only remove the big files thus there will exist a lot of small | |
625 // that use all the inodes. | |
626 if (error == EFFS_FSFULL) { | |
627 tw(tr(TR_FUNC, TrTest, "Warning no free inodes\n")); | |
628 ttw(ttr(TTrTest, "Warning no free inodes" NL)); | |
629 error = case_cleanup(free_size + dynamic_size); | |
630 } | |
631 else | |
632 expect_ok(error); | |
633 | |
634 ffs_query(Q_BYTES_FREE, &bytes_free); | |
635 } while (bytes_free > free_size); | |
636 | |
637 error = case_cleanup(free_size + dynamic_size / 2); | |
638 expect_ok(error); | |
639 } | |
640 | |
641 error = case_reinit(0, 0); | |
642 expect(EFFS_OK, error); | |
643 | |
644 tw(tr(TR_FUNC, TrTest, "Verify all files\n")); | |
645 ttw(ttr(TTrTest, "Verify all files" NL)); | |
646 for (i = 0; i < 2; i++) { | |
647 if (i == 0) { | |
648 error = tffs_opendir(static_dir, &dir); | |
649 expect_eq(error, num_static_files); | |
650 } | |
651 else { | |
652 error = tffs_opendir(dynamic_dir, &dir); | |
653 expect_ok(error); | |
654 } | |
655 | |
656 while ((error = tffs_readdir(&dir, file_name, sizeof(file_name))) > 0) { | |
657 if (i == 0) | |
658 strcpy(path, static_dir); | |
659 else | |
660 strcpy(path, dynamic_dir); | |
661 strcat(path, "/"); | |
662 strcat(path, file_name); | |
663 | |
664 error = tffs_stat(path, &stat); | |
665 expect_ok(error); | |
666 error = test_expect_file(path, tdata[TDATA_HUGE], stat.size); | |
667 if (error) return 1; | |
668 } | |
669 } | |
670 | |
671 test_statistics_print(); | |
672 return 0; | |
673 } | |
674 | |
675 | |
676 // TODO cleanup this test. Use stat and verify some of the files etc. | |
677 | |
678 // Used to test ConQuest issue FFS_FIX-11368 We fill FFS with a lot of small | |
679 // files. Then by turn remove some files and write new files, always very | |
680 // close to max avaible bytes. | |
681 | |
682 // Note the below test is not able to run in big configuration because it | |
683 // creates a lot of small files thus we reach EFFS_FSFULL 'out of inodes' | |
684 int case_ffull(int p0, int p1) | |
685 { | |
686 int error, i, bytes_free, file_size, max_write_size = 1000; | |
687 char myname[] = "/ffs/bxxx/"; | |
688 | |
689 if (p0 == 0) | |
690 p0 = 100; // Default 100 loops | |
691 if (p1 == 0 || p1 > 999) | |
692 p1 = 3; // Default run in 3 blocks | |
693 | |
694 error = tffs_preformat(0xDEAD); | |
695 expect(error, EFFS_OK); | |
696 | |
697 sprintf(myname, "/ffs/b%d", p1); | |
698 error = tffs_format(myname, 0x2BAD); | |
699 expect(error, EFFS_OK); | |
700 | |
701 tffs_mkdir("/rand"); | |
702 expect(error, EFFS_OK); | |
703 | |
704 tw(tr(TR_FUNC, TrTest, "Fill it with files until it fails\n")); | |
705 ttw(ttr(TTrTest, "Fill it with files until it fails" NL)); | |
706 | |
707 // We have to avoid too many small files or else do we reach objects_max | |
708 ffs_query(Q_BYTES_FREE, &bytes_free); | |
709 max_write_size = bytes_free / fs.objects_max * 2.5; | |
710 | |
711 do { | |
712 error = case_mk_rand_file("/rand", max_write_size, 0); | |
713 } while (error >= 0 ); | |
714 | |
715 tw(tr(TR_FUNC, TrTest, "Fill done (%d)\n" ,error)); | |
716 ttw(ttr(TTrTest, "Fill done (%d)" NL, error)); | |
717 expect(error, EFFS_NOSPACE); // Now are we sure that it is full | |
718 | |
719 tw(tr(TR_FUNC, TrTest, "Cleanup and fill again \n")); | |
720 for (i = 0; i < (1 + p0); i++) { | |
721 tw(tr(TR_FUNC, TrTestHigh, "Loop %d \n", i + 1)); | |
722 ttw(ttr(TTrTest, "Loop %d" NL, i + 1)); | |
723 | |
724 tw(tr_bstat()); | |
725 error = case_cleanup(max_write_size * 3); | |
726 tw(tr_bstat()); | |
727 | |
728 do { | |
729 ffs_query(Q_BYTES_FREE, &bytes_free); | |
730 // Saturate size | |
731 file_size = bytes_free > max_write_size ? max_write_size :bytes_free; | |
732 // Query BYTES_FREE don't count the below data use. | |
733 //file_size -= (FFS_FILENAME_MAX + 1 + dev.atomsize); | |
734 if (file_size < 0) | |
735 break; | |
736 | |
737 error = case_mk_rand_file("/rand", file_size - (FFS_FILENAME_MAX+1), 0); | |
738 | |
739 if (error == EFFS_FSFULL) { // Out of inodes | |
740 error = case_cleanup(max_write_size * 6); | |
741 // Create bigger files to avoid '-11', auto fit :-) | |
742 max_write_size *= 1.1; // Add 10% | |
743 tw(tr(TR_FUNC, TrTestHigh, "Out of inodes, write size: %d \n", | |
744 max_write_size)); | |
745 continue; | |
746 } | |
747 | |
748 expect_ok(error); | |
749 | |
750 } while (file_size != bytes_free); | |
751 } | |
752 | |
753 tw(tr(TR_FUNC, TrTest, "Test finish (%d) \n", error)); | |
754 ttw(ttr(TTrTest, "Test finish (%d)" NL, error)); | |
755 | |
756 if (error >= 0) | |
757 return EFFS_OK; | |
758 | |
759 return error; | |
760 } | |
761 | |
762 int case_rivtype(int p0, int p1) | |
763 { | |
764 // Use the compiler to test if the types are correctly defined. We don't | |
765 // need to run this test just make a compilation. | |
766 T_FFS_OPEN_FLAGS flags = FFS_O_RDONLY; | |
767 T_FFS_SIZE size = 20; | |
768 T_FFS_RET error = -10; | |
769 T_FFS_WHENCE whence = FFS_SEEK_SET; | |
770 T_FFS_STAT stat; | |
771 | |
772 T_FFS_DIR dir; | |
773 T_FFS_FD fd = FFS_FD_OFFSET; | |
774 T_RV_RETURN callback; | |
775 T_FFS_FILE_CNF confirm; | |
776 T_FFS_OBJECT_TYPE objt = OT_FILE; | |
777 | |
778 // Use the defined variables to avoid the boring warning: unused | |
779 // variable 'xx' | |
780 if (flags != FFS_O_RDONLY) return 1; | |
781 if (size != 20) return 1; | |
782 if (error != -10) return 1; | |
783 if (whence != FFS_SEEK_SET) return 1; | |
784 if (fd != FFS_FD_OFFSET) return 1; | |
785 if (objt != OT_FILE) return 1; | |
786 | |
787 stat.type = 1; | |
788 if (stat.type != 1) return 1; | |
789 dir.this = 5; | |
790 if (dir.this != 5) return 1; | |
791 callback.addr_id = 3; | |
792 if (callback.addr_id != 3) return 1; | |
793 confirm.error = -1; | |
794 if (confirm.error != -1) return 1; | |
795 | |
796 return 0; | |
797 } | |
798 | |
799 /****************************************************************************** | |
800 * Pseudo Tests | |
801 ******************************************************************************/ | |
802 | |
803 // Recursively read objects in directory. Does NOT check for buffer | |
804 // overflow! | |
805 int case_dir_list(char *dirname, struct object_s **pplist, char **ppnames) | |
806 { | |
807 struct object_s *plist, *plist_start, *plist_end; | |
808 char pathname[6 * 20]; | |
809 struct dir_s dir; | |
810 char *pnames, *pn; | |
811 int i, pathlen; | |
812 | |
813 //tw(tr(TR_BEGIN, TrTestHigh, "dir_list('%s', %d, 0x%x)\n", | |
814 // dirname, (int)*pplist/sizeof(struct object_s), *ppnames)); | |
815 plist_start = plist = *pplist; | |
816 pnames = *ppnames; | |
817 | |
818 strcpy(pathname, dirname); | |
819 pathlen = strlen(pathname); | |
820 | |
821 // remove trailing slash. It is tiring to handle the root directory | |
822 // differently from other directories. In a future ffs revision, this | |
823 // trailing slash should be allowed! | |
824 if (pathname[pathlen - 1] == '/') { | |
825 pathname[pathlen - 1] = 0; | |
826 pathlen--; | |
827 } | |
828 | |
829 if (strlen(pathname) == 0) | |
830 error = tffs_opendir("/", &dir); | |
831 else | |
832 error = tffs_opendir(pathname, &dir); | |
833 expect_ok(error); | |
834 | |
835 pn = pathname + strlen(pathname); | |
836 *pn++ = '/'; | |
837 *pn = 0; | |
838 | |
839 error = 1; | |
840 for (i = 0; (error = tffs_readdir(&dir, pn, 21)) > 0; i++) | |
841 { | |
842 error = tffs_xlstat(pathname, &plist->stat); | |
843 expect(error, EFFS_OK); | |
844 | |
845 // Copy full object pathname to buffer, working downwards. | |
846 pnames -= strlen(pathname) + 1; | |
847 // Check for buffer overflow (if pnames <= plist) | |
848 expect_gt((int) pnames, (int) plist); | |
849 strcpy(pnames, pathname); | |
850 plist->name = pnames; | |
851 | |
852 plist++; | |
853 } | |
854 *pplist = plist; | |
855 *ppnames = pnames; | |
856 | |
857 // For each directory in the retrieved list, recurse. | |
858 plist_end = plist; | |
859 for (plist = plist_start; plist < plist_end; plist++) { | |
860 if (plist->stat.type == OT_DIR) | |
861 i += case_dir_list(plist->name, pplist, ppnames); | |
862 } | |
863 // tw(tr(TR_END, TrTestHigh, "} %d\n", i)); | |
864 return i; | |
865 } | |
866 | |
867 int case_find(int p0, int p1) | |
868 { | |
869 struct object_s *plist, *plist_start; | |
870 char *pnames, *pnames_start; | |
871 int n, names_used, list_used; | |
872 | |
873 plist = plist_start = (struct object_s *) bigbuf; | |
874 pnames = pnames_start = bigbuf + bigbuf_size; | |
875 n = case_dir_list("/", &plist, &pnames); | |
876 | |
877 list_used = n * sizeof(struct object_s); | |
878 names_used = pnames_start - pnames; | |
879 | |
880 tw(tr(TR_FUNC, TrTestHigh, "Buffer space used: %d + %d = %d\n", | |
881 list_used, names_used, list_used + names_used)); | |
882 ttw(ttr(TTrTest, "Buffer space used: %d + %d = %d" NL, | |
883 list_used, names_used, list_used + names_used)); | |
884 | |
885 return 0; | |
886 } | |
887 | |
888 // TODO: We should accumulate all stat.space and check it vs. the number of | |
889 // bytes used! | |
890 int case_lsr(int p0, int p1) | |
891 { | |
892 struct object_s *plist, *plist_start; | |
893 char *pnames, *pnames_start; | |
894 char of[3]; | |
895 int i, n; | |
896 | |
897 plist = plist_start = (struct object_s *) bigbuf; | |
898 pnames = pnames_start = bigbuf + bigbuf_size; | |
899 n = case_dir_list("/", &plist, &pnames); | |
900 tw(tr(TR_FUNC, TrTestHigh, "Total %d objects.\n", n)); | |
901 ttw(ttr(TTrTest, "Total %d objects" NL, n)); | |
902 | |
903 plist = plist_start; | |
904 for (i = 0; i < n; i++, plist++) { | |
905 strcpy(of, " "); | |
906 switch (plist->stat.type) { | |
907 case OT_FILE: of[0] = ' '; break; | |
908 case OT_DIR: of[0] = 'd'; break; | |
909 case OT_LINK: of[0] = 'l'; break; | |
910 } | |
911 if (plist->stat.flags & OF_READONLY) | |
912 of[1] = 'r'; | |
913 | |
914 #if (TARGET == 0) | |
915 printf("%3d: %s %3d %2d/%04X (%4d,%4d) %5d %s\n", | |
916 i, of, | |
917 plist->stat.inode, plist->stat.block, | |
918 plist->stat.location, plist->stat.sequence, plist->stat.updates, | |
919 plist->stat.size, &plist->name[1]); | |
920 #else | |
921 ttw(ttr(TTrTest, "%3d: %s %3d %2d/%04X (%4d,%4d) %5d %s" NL, | |
922 i, of, | |
923 plist->stat.inode, plist->stat.block, | |
924 plist->stat.location, plist->stat.sequence, plist->stat.updates, | |
925 plist->stat.size, &plist->name[1])); | |
926 #endif | |
927 } | |
928 | |
929 return 0; | |
930 } | |
931 | |
932 | |
933 /****************************************************************************** | |
934 * Normal Tests | |
935 ******************************************************************************/ | |
936 | |
937 int case_format(int p0, int p1) | |
938 { | |
939 error = tffs_preformat(0xD00D); | |
940 expect(error, EFFS_INVALID); | |
941 error = tffs_preformat(0xDEAD); | |
942 expect(error, EFFS_OK); | |
943 error = tffs_format("/ffs/", 0xDEAD); | |
944 expect(error, EFFS_INVALID); | |
945 error = tffs_format("ffs", 0x2BAD); | |
946 expect(error, EFFS_BADNAME); | |
947 error = tffs_format("", 0x2BAD); | |
948 expect(error, EFFS_BADNAME); | |
949 error = tffs_format("/", 0x2BAD); | |
950 expect(error, EFFS_OK); | |
951 error = tffs_format("/ffs", 0x2BAD); | |
952 expect(error, EFFS_NOPREFORMAT); | |
953 error = tffs_preformat(0xDEAD); | |
954 expect(error, EFFS_OK); | |
955 error = tffs_format(0, 0x2BAD); | |
956 //error = tffs_format("/ffs/i256o128", 0x2BAD); | |
957 expect(error, EFFS_OK); | |
958 return 0; | |
959 } | |
960 | |
961 // Test that it is illegal to modify root inode as if it was a normal file | |
962 // or directory | |
963 int case_root(int p0, int p1) | |
964 { | |
965 error = tffs_opendir("/", &dir); | |
966 expect_ok(error); | |
967 error = tffs_fcreate("/", "foo", 3); | |
968 expect(error, EFFS_EXISTS); | |
969 error = tffs_fupdate("/", "bar", 3); | |
970 expect(error, EFFS_NOTAFILE); | |
971 error = tffs_fwrite("/", "foo", 3); | |
972 expect(error, EFFS_NOTAFILE); | |
973 error = tffs_remove("/"); | |
974 expect(error, EFFS_ACCESS); | |
975 return 0; | |
976 } | |
977 | |
978 // Test object lookup, object names etc. | |
979 int case_lookup(int p0, int p1) | |
980 { | |
981 // Swedish Provinces: Blekinge, Smaaland, Halland, Vaermland, Dalarna, | |
982 // Dalsland, Gotland, Gaestrikland, Haelsingland, Bohuslaen, | |
983 // Haerjedalen, Jaemtland, Lappland, Medelpad, Norrbotten, Naerke, | |
984 // Soedermanland, Uppland, Vaesterbotten | |
985 | |
986 // Smaaland Cities: Vetlanda, Bodafors, Rottne, Ljungby, Nybro, | |
987 // Hultsfred, Oskarshamn, Vimmerby, Hyltebruk, Joenkoeping, Vaexjoe | |
988 | |
989 tffs_mkdir("/europe"); | |
990 tffs_mkdir("/europe/sweden"); | |
991 | |
992 // test init | |
993 error = tffs_mkdir(LUDIR "/Smaaland"); | |
994 expect(error, EFFS_OK); | |
995 // test BAD_FILENAME | |
996 error = tffs_fcreate("", TDATA(0)); | |
997 expect(error, EFFS_BADNAME); | |
998 // test EFFS_EXISTS | |
999 error = tffs_fcreate(LUDIR "/Smaaland/vetlanda", TDATA(0)); | |
1000 expect(error, EFFS_OK); | |
1001 error = tffs_fcreate(LUDIR "/Smaaland/vetlanda", TDATA(0)); | |
1002 expect(error, EFFS_EXISTS); | |
1003 error = tffs_mkdir(LUDIR "/Smaaland"); | |
1004 expect(error, EFFS_EXISTS); | |
1005 error = tffs_fwrite(LUDIR "/Smaaland/vetlanda", TDATA(1)); | |
1006 expect(error, EFFS_OK); | |
1007 // test EFFS_BADNAME | |
1008 error = tffs_fcreate(LUDIR "/Smaaland/A_Zaz.0+9-7!", TDATA(2)); | |
1009 expect(error, EFFS_BADNAME); | |
1010 error = tffs_fcreate(LUDIR "/Smaaland/A_Zaz.0+9-7#%$", TDATA(2)); | |
1011 expect(error, EFFS_OK); | |
1012 // test ending slash | |
1013 error = tffs_mkdir(LUDIR "/Smaaland/Vaexjoe/"); | |
1014 expect(error, EFFS_NOTADIR); | |
1015 error = tffs_fcreate(LUDIR "/Smaaland/Vaexjoe/", TDATA(3)); | |
1016 expect(error, EFFS_NOTADIR); | |
1017 // test EFFS_NAMETOOLONG | |
1018 error = tffs_fcreate(LUDIR "/Smaaland/Hultsfred-is-21-chars", TDATA(4)); | |
1019 expect(error, EFFS_NAMETOOLONG); | |
1020 error = tffs_fcreate(LUDIR "/Smaaland/Bodafors-is-20-chars", TDATA(4)); | |
1021 expect(error, EFFS_OK); | |
1022 error = tffs_mkdir(LUDIR "/Vaermland-is-21-chars"); | |
1023 expect(error, EFFS_NAMETOOLONG); | |
1024 error = tffs_mkdir(LUDIR "/Dalsland-is-20-chars"); | |
1025 expect(error, EFFS_OK); | |
1026 // test EFFS_NOTADIR | |
1027 error = tffs_mkdir(LUDIR "/DontMakeSeveral/DirsAt/TheSameTime"); | |
1028 expect(error, EFFS_NOTADIR); | |
1029 error = tffs_fread(LUDIR "/Lappland/Bodafors-is-20-chars", bigbuf, 1024); | |
1030 tw(tr(TR_END, TrApi, "} %d\n", error)); // Avoid wrong indent | |
1031 expect(error, EFFS_NOTADIR); | |
1032 error = tffs_fread(LUDIR "/Lappland/", bigbuf, 1024); | |
1033 tw(tr(TR_END, TrApi, "} %d\n", error)); // Avoid wrong indent | |
1034 expect(error, EFFS_NOTADIR); | |
1035 error = tffs_fread(LUDIR "/Smaaland/Bodafors", TDATA(4)); | |
1036 tw(tr(TR_END, TrApi, "} %d\n", error)); // Avoid wrong indent | |
1037 expect(error, EFFS_NOTFOUND); | |
1038 // test EFFS_PATHTOODEEP | |
1039 error = tffs_mkdir(LUDIR "/Gotland"); // 3. level | |
1040 expect(error, EFFS_OK); | |
1041 error = tffs_mkdir(LUDIR "/Gotland/Visby"); // 4. level | |
1042 expect(error, EFFS_OK); | |
1043 error = tffs_mkdir(LUDIR "/Gotland/Visby/level5"); // 5. level | |
1044 expect(error, EFFS_OK); | |
1045 error = tffs_mkdir(LUDIR "/Gotland/Visby/level5/level6"); // 6. level | |
1046 expect(error, EFFS_OK); | |
1047 error = tffs_mkdir(LUDIR "/Gotland/Visby/level5/level6/level7"); // 7. level | |
1048 expect(error, EFFS_PATHTOODEEP); | |
1049 error = tffs_fcreate(LUDIR "/Gotland/Visby/level5/level6/level7", | |
1050 TDATA(5)); // 7. level | |
1051 expect(error, EFFS_PATHTOODEEP); | |
1052 | |
1053 // final checks | |
1054 error = test_expect_file(LUDIR "/Smaaland/vetlanda", TDATA(1)); | |
1055 if (error) return 1; | |
1056 error = test_expect_file(LUDIR "/Smaaland/Bodafors-is-20-chars", TDATA(4)); | |
1057 if (error) return 1; | |
1058 error = tffs_opendir(LUDIR "/Dalsland-is-20-chars", &dir); | |
1059 expect_ok(error); | |
1060 error = tffs_opendir(LUDIR "/Gotland/Visby/level5/level6", &dir); | |
1061 expect_ok(error); | |
1062 | |
1063 // cleanup | |
1064 error = tffs_remove(LUDIR "/Smaaland/A_Zaz.0+9-7"); | |
1065 return 0; | |
1066 } | |
1067 | |
1068 | |
1069 // Test fcontrol and read-only semantics. TODO: We still need to perform | |
1070 // same tests on a dir and a symlink and thru a symlink. | |
1071 int case_fcontrol(int p0, int p1) | |
1072 { | |
1073 struct ffs_state_s old, new; | |
1074 const char rofile[] = "/europe/norway/rofile"; | |
1075 const char imeifile[] = "/europe/norway/IMEI"; | |
1076 fd_t fdi; | |
1077 | |
1078 // Cleanup | |
1079 tffs_remove(rofile); | |
1080 tffs_remove("/europe/norway"); | |
1081 tffs_remove("/europe"); | |
1082 | |
1083 // Initialize | |
1084 error = tffs_mkdir("/europe"); | |
1085 error = tffs_mkdir("/europe/norway"); | |
1086 error = tffs_fcreate(rofile, TDATA(2)); | |
1087 expect(error, EFFS_OK); | |
1088 error = tffs_stat(rofile, &stat); | |
1089 expect(error, EFFS_OK); | |
1090 expect_eq(stat.flags, 0); | |
1091 | |
1092 test_ffs_state_get(&old); | |
1093 | |
1094 // set read-only flag | |
1095 error = tffs_fcontrol(rofile, OC_FLAGS, OF_READONLY); | |
1096 expect(error, EFFS_OK); | |
1097 error = tffs_stat(rofile, &stat); | |
1098 expect(error, EFFS_OK); | |
1099 expect_eq(stat.flags, OF_READONLY); | |
1100 | |
1101 test_ffs_state_get(&new); | |
1102 expect_eq(new.objects_total, old.objects_total); | |
1103 expect_ne(new.inodes_used, old.inodes_used); | |
1104 test_ffs_state_copy(&old, &new); | |
1105 | |
1106 // Set illegal flags. Try to fupdate file. Then try to set read-only | |
1107 // flag again. | |
1108 error = tffs_fcontrol(rofile, OC_FLAGS, 1<<0); | |
1109 expect(error, EFFS_INVALID); | |
1110 error = tffs_fcontrol(rofile, OC_FLAGS, 1<<3); | |
1111 expect(error, EFFS_INVALID); | |
1112 error = tffs_fcontrol(rofile, OC_FLAGS, 1<<5); | |
1113 expect(error, EFFS_INVALID); | |
1114 error = tffs_fcontrol(rofile, OC_FLAGS, 1<<6); | |
1115 expect(error, EFFS_INVALID); | |
1116 error = tffs_fupdate(rofile, TDATA(3)); | |
1117 expect(error, EFFS_OK); | |
1118 | |
1119 error = tffs_fcreate("/europe/norway/tease", TDATA(2)); | |
1120 expect(error, EFFS_OK); | |
1121 tffs_remove("/europe/norway/tease"); | |
1122 | |
1123 error = tffs_fcontrol(rofile, OC_FLAGS, OF_READONLY); | |
1124 expect(error, EFFS_OK); | |
1125 error = tffs_stat(rofile, &stat); | |
1126 expect(error, EFFS_OK); | |
1127 expect_eq(stat.flags, OF_READONLY); | |
1128 | |
1129 test_ffs_state_get(&new); | |
1130 expect_eq(new.objects_total, old.objects_total); | |
1131 expect_ne(new.inodes_used, old.inodes_used); | |
1132 test_ffs_state_copy(&old, &new); | |
1133 | |
1134 // clear read-only flag (this works because ffs_is_modifiable() by | |
1135 // default returns true for all objects except for object names ending | |
1136 // in "IMEI". | |
1137 error = tffs_fcontrol(rofile, OC_FLAGS, 0); | |
1138 expect(error, EFFS_OK); | |
1139 error = tffs_stat(rofile, &stat); | |
1140 expect(error, EFFS_OK); | |
1141 expect_eq(stat.flags, 0); | |
1142 | |
1143 test_ffs_state_get(&new); | |
1144 expect_eq(new.objects_total, old.objects_total); | |
1145 expect_ne(new.inodes_used, old.inodes_used); | |
1146 test_ffs_state_copy(&old, &new); | |
1147 | |
1148 // Set read-only flag (again) | |
1149 error = tffs_fcontrol(rofile, OC_FLAGS, OF_READONLY); | |
1150 expect(error, EFFS_OK); | |
1151 error = tffs_stat(rofile, &stat); | |
1152 expect(error, EFFS_OK); | |
1153 expect_eq(stat.flags, OF_READONLY); | |
1154 | |
1155 test_ffs_state_get(&new); | |
1156 expect_eq(new.objects_total, old.objects_total); | |
1157 expect_ne(new.inodes_used, old.inodes_used); | |
1158 test_ffs_state_copy(&old, &new); | |
1159 | |
1160 // Set read-only flag of IMEI file | |
1161 error = tffs_fcreate(imeifile, TDATA(2)); | |
1162 expect(error, EFFS_OK); | |
1163 error = tffs_stat(imeifile, &stat); | |
1164 expect(error, EFFS_OK); | |
1165 expect_eq(stat.flags, 0); | |
1166 error = tffs_fcontrol(imeifile, OC_FLAGS, OF_READONLY); | |
1167 expect(error, EFFS_OK); | |
1168 error = tffs_stat(imeifile, &stat); | |
1169 expect(error, EFFS_OK); | |
1170 expect_eq(stat.flags, OF_READONLY); | |
1171 | |
1172 test_ffs_state_get(&new); | |
1173 expect_eq(new.objects_total, old.objects_total + 1); | |
1174 expect_ne(new.inodes_used, old.inodes_used); | |
1175 test_ffs_state_copy(&old, &new); | |
1176 | |
1177 // Try to remove, fupdate, fwrite and fcontrol IMEI file. | |
1178 error = tffs_remove(imeifile); | |
1179 expect(error, EFFS_ACCESS); | |
1180 error = tffs_fupdate(imeifile, TDATA(0)); | |
1181 expect(error, EFFS_ACCESS); | |
1182 error = tffs_fwrite(imeifile, TDATA(0)); | |
1183 expect(error, EFFS_ACCESS); | |
1184 error = tffs_fcontrol(imeifile, OC_FLAGS, 0); | |
1185 expect(error, EFFS_ACCESS); | |
1186 | |
1187 // Try to open IMEI file in write-only and read-only | |
1188 fdi = tffs_open(imeifile, FFS_O_WRONLY | FFS_O_APPEND); | |
1189 expect(fdi, EFFS_ACCESS); | |
1190 | |
1191 fdi = tffs_open(imeifile, FFS_O_RDONLY); | |
1192 expect(fdi, FFS_FD_OFFSET); | |
1193 error = tffs_close(fdi); | |
1194 expect(error, EFFS_OK); | |
1195 | |
1196 return 0; | |
1197 } | |
1198 | |
1199 // Test symlink functionality of simple symlink implementation. | |
1200 // Fixme: add remove file through symlink, stat a dir through a symlink. | |
1201 int case_ssym(int p0, int p1) | |
1202 { | |
1203 int size; | |
1204 fd_t fdi; | |
1205 // two links, read files thru links | |
1206 // link to link to file, open file | |
1207 // link to non-valid object | |
1208 // | |
1209 // make three test files, a link to each of these, one link to dir, one | |
1210 // link to non-existing object, one link to link to file | |
1211 | |
1212 tffs_mkdir("/europe"); | |
1213 tffs_mkdir("/europe/denmark"); | |
1214 | |
1215 error = tffs_fwrite("/europe/denmark/aalborg", TDATA(1)); | |
1216 expect(error, EFFS_OK); | |
1217 error = tffs_symlink("/europe/aal", "/europe/denmark/aalborg"); | |
1218 expect(error, EFFS_OK); | |
1219 error = tffs_symlink("/dk", "/europe/denmark"); | |
1220 expect(error, EFFS_OK); | |
1221 error = tffs_fwrite("/europe/denmark/aarhus", TDATA(2)); | |
1222 expect(error, EFFS_OK); | |
1223 error = tffs_symlink("/europe/aar", "/europe/denmark/aarhus"); | |
1224 expect(error, EFFS_OK); | |
1225 error = tffs_symlink("/europe/se", "/europe/non-existing"); | |
1226 expect(error, EFFS_OK); | |
1227 error = tffs_fwrite("/europe/denmark/billund", TDATA(3)); | |
1228 expect(error, EFFS_OK); | |
1229 error = tffs_symlink("/europe/bil", "/europe/denmark/billund"); | |
1230 expect(error, EFFS_OK); | |
1231 error = tffs_symlink("/lego", "/europe/bil"); | |
1232 expect(error, EFFS_OK); | |
1233 error = tffs_fwrite("/europe/denmark/norresundby", TDATA(2)); | |
1234 expect(error, EFFS_OK); | |
1235 error = tffs_symlink("/europe/nor", "/europe/denmark/norresundby"); | |
1236 expect(error, EFFS_OK); | |
1237 | |
1238 // Test link to dir | |
1239 error = tffs_opendir("/dk", &dir); | |
1240 expect(error, EFFS_NOTAFILE); // TODO: strange error! | |
1241 error = tffs_stat("/dk", &stat); | |
1242 expect(error, EFFS_NOTAFILE); // TODO: strange error! | |
1243 error = tffs_linkstat("/dk", &stat); | |
1244 expect(error, EFFS_OK); | |
1245 | |
1246 // Test link to link to file | |
1247 error = tffs_stat("/lego", &stat); | |
1248 expect(error, EFFS_NOTAFILE); // TODO: strange error?! | |
1249 error = tffs_linkstat("/lego", &stat); | |
1250 expect(error, EFFS_OK); | |
1251 error = tffs_fread("/lego", bigbuf, bigbuf_size); | |
1252 tw(tr(TR_END, TrApi, "} %d\n", error)); // Avoid wrong indent | |
1253 expect(error, EFFS_NOTAFILE); | |
1254 | |
1255 // Test link to non-existing object | |
1256 error = tffs_opendir("/europe/se", &dir); | |
1257 expect(error, EFFS_NOTFOUND); | |
1258 error = tffs_stat("/europe/se", &stat); | |
1259 expect(error, EFFS_NOTFOUND); | |
1260 error = tffs_linkstat("/europe/se", &stat); | |
1261 expect(error, EFFS_OK); | |
1262 | |
1263 // Read files through links | |
1264 error = test_expect_file("/europe/aal", TDATA(1)); | |
1265 if (error) return 1; | |
1266 error = test_expect_file("/europe/aar", TDATA(2)); | |
1267 if (error) return 1; | |
1268 error = test_expect_file("/europe/bil", TDATA(3)); | |
1269 if (error) return 1; | |
1270 | |
1271 // Write files through links | |
1272 error = tffs_fwrite("/europe/aal", TDATA(3)); | |
1273 expect(error, EFFS_OK); | |
1274 error = tffs_fupdate("/europe/aar", TDATA(4)); | |
1275 expect(error, EFFS_OK); | |
1276 error = tffs_fupdate("/europe/bil", TDATA(5)); | |
1277 expect(error, EFFS_OK); | |
1278 | |
1279 // Open file and write and read files through links | |
1280 fdi = tffs_open("/europe/nor", FFS_O_WRONLY | FFS_O_TRUNC | FFS_O_APPEND); | |
1281 expect(fdi, FFS_FD_OFFSET); | |
1282 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 50); | |
1283 expect(size, 50); | |
1284 error = tffs_close(fdi); | |
1285 expect(error, 0); | |
1286 | |
1287 fdi = tffs_open("/europe/nor", FFS_O_RDONLY); | |
1288 expect(fdi, FFS_FD_OFFSET); | |
1289 size = tffs_read(fdi, bigbuf, 62); | |
1290 expect(size, 50); | |
1291 error = test_expect_data((char*)tdata[TDATA_HUGE], bigbuf, 50); | |
1292 if (error) return 1; | |
1293 error = tffs_close(fdi); | |
1294 expect(error, 0); | |
1295 | |
1296 // remove "lego" link, recreate it to link to "billund", read file data | |
1297 // through link, re-write file data through link | |
1298 error = tffs_symlink("/lego", "/europe/denmark/billund"); | |
1299 expect(error, EFFS_NOTAFILE); // TODO: strange error?! | |
1300 error = tffs_fupdate("/lego", "/europe/denmark/billund", | |
1301 strlen("/europe/denmark/billund")); | |
1302 expect(error, EFFS_NOTAFILE); | |
1303 error = tffs_remove("/lego"); | |
1304 expect(error, EFFS_OK); | |
1305 error = tffs_symlink("/lego", "/europe/denmark/billund"); | |
1306 expect(error, EFFS_OK); | |
1307 error = test_expect_file("/lego", TDATA(5)); | |
1308 if (error) return 1; | |
1309 error = tffs_fupdate("/lego", TDATA(2)); | |
1310 expect(error, EFFS_OK); | |
1311 | |
1312 // Re-Read files through links | |
1313 error = test_expect_file("/europe/aal", TDATA(3)); | |
1314 if (error) return 1; | |
1315 error = test_expect_file("/europe/aar", TDATA(4)); | |
1316 if (error) return 1; | |
1317 error = test_expect_file("/europe/bil", TDATA(2)); | |
1318 if (error) return 1; | |
1319 | |
1320 // Clean up | |
1321 error = tffs_remove("/europe/aal"); | |
1322 expect(error, EFFS_OK); | |
1323 error = tffs_remove("/dk"); | |
1324 expect(error, EFFS_OK); | |
1325 error = tffs_remove("/europe/aar"); | |
1326 expect(error, EFFS_OK); | |
1327 error = tffs_remove("/europe/se"); | |
1328 expect(error, EFFS_OK); | |
1329 error = tffs_remove("/europe/bil"); | |
1330 expect(error, EFFS_OK); | |
1331 error = tffs_remove("/lego"); | |
1332 expect(error, EFFS_OK); | |
1333 error = tffs_remove("/europe/nor"); | |
1334 expect(error, EFFS_OK); | |
1335 | |
1336 return 0; | |
1337 } | |
1338 | |
1339 // Test symlink functionality of full symlink implementation | |
1340 int case_fsym(int p0, int p1) | |
1341 { | |
1342 fd_t fdi; | |
1343 // make relative link to directory, stat link and directory | |
1344 error = tffs_symlink("/sa", "/south-america"); // relative link | |
1345 expect(error, EFFS_OK); | |
1346 | |
1347 error = tffs_linkstat("/sa", &stat); | |
1348 expect(error, EFFS_OK); | |
1349 expect_eq(stat.type, OT_LINK); | |
1350 | |
1351 error = tffs_stat("/sa", &stat); | |
1352 expect(error, EFFS_OK); | |
1353 expect_eq(stat.type, OT_DIR); | |
1354 | |
1355 // create directory thru a symlink | |
1356 error = tffs_mkdir("/sa/brazil"); | |
1357 expect(error, EFFS_OK); | |
1358 error = tffs_symlink("/br.ba", "/brazil/buenos-aires"); // relative link | |
1359 expect(error, EFFS_OK); | |
1360 | |
1361 // create file via symlink, stat the new file | |
1362 error = tffs_fcreate("/sa/brazil/buenos-aires", TDATA(2)); | |
1363 expect(error, EFFS_OK); | |
1364 error = tffs_stat("/sa/br.ba", &stat); | |
1365 expect(error, EFFS_OK); | |
1366 expect_eq(stat.type, OT_FILE); | |
1367 | |
1368 fdi = tffs_open("/sa/peru", FFS_O_WRONLY | FFS_O_TRUNC | | |
1369 FFS_O_APPEND | FFS_O_CREATE); | |
1370 expect(fdi, FFS_FD_OFFSET); | |
1371 error = tffs_close(fdi); | |
1372 expect(error, 0); | |
1373 | |
1374 // create file thru a symlink, stat the new file. Will this work? | |
1375 error = tffs_symlink("/br.br", "/brazil/brasilia"); // relative link | |
1376 expect(error, EFFS_OK); | |
1377 error = tffs_fcreate("/sa/br.br", TDATA(3)); // ??? | |
1378 expect(error, EFFS_OK); | |
1379 error = tffs_stat("/sa/br.br", &stat); | |
1380 expect(error, EFFS_OK); | |
1381 expect_eq(stat.type, OT_FILE); | |
1382 | |
1383 // Create symlink that is a link to absolute link path | |
1384 error = tffs_symlink("/south-america/cape-horn", "/sa/ar"); // absolute link | |
1385 expect(error, EFFS_OK); | |
1386 | |
1387 error = tffs_fcreate("/south-america/argentina", TDATA(0)); | |
1388 | |
1389 expect(error, EFFS_OK); | |
1390 error = tffs_symlink("/sa/ar", "/south-america/argentina"); | |
1391 expect(error, EFFS_OK); | |
1392 | |
1393 // TODO: Test very deep path | |
1394 | |
1395 // TODO: Test circular link | |
1396 | |
1397 // TODO: Test if ending slash is allowed on dirs and symlinks | |
1398 | |
1399 tw(tr(TR_FUNC, TrTest, "WARNING: Test case not implemented!\n")); | |
1400 ttw(str(TTrTest, "Test case not implemented!" NL)); | |
1401 | |
1402 return 0; | |
1403 } | |
1404 | |
1405 // Check every combination of name length and data size within the device | |
1406 // atomsize, | |
1407 int case_fread(int p0, int p1) | |
1408 { | |
1409 const char fullname[] = "123456789ABCDEF0123456789ABCDEF"; | |
1410 int i, j, dirlen, mysize; | |
1411 char *mydata; | |
1412 char myname[20+20+32] = "/australia/f"; | |
1413 | |
1414 case_cleanup(0x11 * param.atomsize * param.atomsize); | |
1415 | |
1416 tffs_mkdir("/australia"); | |
1417 | |
1418 mydata = (char *) tdata[TDATA_HUGE]; | |
1419 dirlen = strlen(myname); | |
1420 | |
1421 for (j = 0; j < param.atomsize; j++) { | |
1422 mysize = j * 0x11 /* + 0x100 */; | |
1423 ttw(ttr(TTrTest, "frd: size = %x" NL, mysize)); | |
1424 tw(tr(TR_FUNC, TrTestHigh, "frd: size = %x\n", mysize)); | |
1425 // remove files | |
1426 for (i = 0; i < param.atomsize; i++) { | |
1427 strncpy(&myname[dirlen], fullname, i); | |
1428 myname[dirlen + i] = 0; | |
1429 error = tffs_remove(myname); | |
1430 } | |
1431 // fcreate files with varying name lengths but same alignment. | |
1432 for (i = 0; i < param.atomsize; i++) { | |
1433 strncpy(&myname[dirlen], fullname, i); | |
1434 myname[dirlen + i] = 0; | |
1435 error = tffs_fwrite(myname, mydata, mysize); | |
1436 expect(error, EFFS_OK); | |
1437 } | |
1438 // Now check all the files written | |
1439 for (i = 0; i < param.atomsize; i++) { | |
1440 strncpy(&myname[dirlen], fullname, i); | |
1441 myname[dirlen + i] = 0; | |
1442 //tw(tr(TR_FUNC, TrTestHigh, "frd: txf('f...', %x, %d)\n", | |
1443 // mydata, mysize)); | |
1444 error = test_expect_file(myname, mydata, mysize); | |
1445 if (error) return 1; | |
1446 } | |
1447 mydata += 0x10; | |
1448 } | |
1449 | |
1450 for (i = 0; i < param.atomsize; i++) { | |
1451 strncpy(&myname[dirlen], fullname, i); | |
1452 myname[dirlen + i] = 0; | |
1453 error = tffs_remove(myname); | |
1454 expect(error, EFFS_OK); | |
1455 } | |
1456 return 0; | |
1457 } | |
1458 | |
1459 | |
1460 /****************************************************************************** | |
1461 * Non-finished | |
1462 ******************************************************************************/ | |
1463 | |
1464 // Test Directories | |
1465 int case_dirs(int p0, int p1) | |
1466 { | |
1467 // remove empty dir, non-empty dir | |
1468 // open/readdir empty dir, non-empty dir | |
1469 char name[21]; | |
1470 int i, j; | |
1471 struct dir_s dir[3]; | |
1472 const char *names[3][5] = { | |
1473 { "china", "japan", "korea", "india", 0 }, | |
1474 { "bombay", "newdelhi", 0, 0, 0 }, | |
1475 { "hongkong", "shanghai", "hk", 0, 0 } | |
1476 }; | |
1477 | |
1478 // Cleanup | |
1479 tffs_mkdir("/asia"); | |
1480 tffs_remove("/asia/india/bombay"); | |
1481 tffs_remove("/asia/india/newdelhi"); | |
1482 tffs_remove("/asia/india"); | |
1483 | |
1484 error = tffs_mkdir("/asia/china"); | |
1485 expect(error, EFFS_OK); | |
1486 error = tffs_mkdir("/asia/china/beijing"); | |
1487 expect(error, EFFS_OK); | |
1488 error = tffs_mkdir("/asia/china/hongkong"); | |
1489 expect(error, EFFS_OK); | |
1490 error = tffs_fcreate("/asia/china/hongkong/hkfile1", TDATA(1)); | |
1491 expect(error, EFFS_OK); | |
1492 error = tffs_fcreate("/asia/china/shanghai", TDATA(2)); | |
1493 expect(error, EFFS_OK); | |
1494 error = tffs_symlink("/asia/china/hk", "/asia/china/hongkong"); | |
1495 expect(error, EFFS_OK); | |
1496 error = tffs_mkdir("/asia/japan"); | |
1497 expect(error, EFFS_OK); | |
1498 error = tffs_fcreate("/asia/thailand", TDATA(0)); | |
1499 expect(error, EFFS_OK); | |
1500 error = tffs_fcreate("/asia/korea", TDATA(2)); | |
1501 expect(error, EFFS_OK); | |
1502 error = tffs_fcreate("/asia/japan/tokyo", TDATA(3)); | |
1503 expect(error, EFFS_OK); | |
1504 error = tffs_fupdate("/asia/japan/tokyo", TDATA(4)); | |
1505 expect(error, EFFS_OK); | |
1506 error = tffs_mkdir("/asia/india"); | |
1507 expect(error, EFFS_OK); | |
1508 error = tffs_fcreate("/asia/india/bombay", TDATA(0)); | |
1509 expect(error, EFFS_OK); | |
1510 error = tffs_fcreate("/asia/india/newdelhi", TDATA(1)); | |
1511 expect(error, EFFS_OK); | |
1512 error = tffs_fcreate("/asia/india/calcutta", TDATA(2)); | |
1513 expect(error, EFFS_OK); | |
1514 | |
1515 error = tffs_opendir("/asia", &dir[0]); | |
1516 expect(error, 5); | |
1517 error = tffs_opendir("/asia/india", &dir[1]); | |
1518 expect(error, 3); | |
1519 error = tffs_opendir("/asia/china", &dir[2]); | |
1520 expect(error, 4); | |
1521 | |
1522 // remove first, middle and last entry in a dir | |
1523 error = tffs_remove("/asia/china/beijing"); | |
1524 expect(error, EFFS_OK); | |
1525 error = tffs_remove("/asia/thailand"); | |
1526 expect(error, EFFS_OK); | |
1527 error = tffs_remove("/asia/india/calcutta"); | |
1528 expect(error, EFFS_OK); | |
1529 | |
1530 for (j = 0; j < 5; j++) { | |
1531 for (i = 0; i < 3; i++) { | |
1532 error = tffs_readdir(&dir[i], name, 21); | |
1533 if (names[i][j] == NULL) { | |
1534 expect(error, EFFS_OK); | |
1535 } | |
1536 else { | |
1537 expect_gt(error, EFFS_OK); | |
1538 tw(tr(TR_FUNC, TrTestHigh, "dir[%d]: %10s, expected: %s\n", | |
1539 i, name, names[i][j])); | |
1540 test_expect_data(name, TDATA_STRING(names[i][j])); | |
1541 } | |
1542 } | |
1543 } | |
1544 | |
1545 error = tffs_remove("/asia/china"); | |
1546 expect(error, EFFS_DIRNOTEMPTY); | |
1547 error = tffs_remove("/asia/china/hongkong"); | |
1548 expect(error, EFFS_DIRNOTEMPTY); | |
1549 error = tffs_remove("/asia/china/hongkong/hkfile1"); | |
1550 expect(error, EFFS_OK); | |
1551 error = tffs_remove("/asia/china/shanghai"); | |
1552 expect(error, EFFS_OK); | |
1553 error = tffs_remove("/asia/china/hk"); | |
1554 expect(error, EFFS_OK); | |
1555 error = tffs_remove("/asia/china"); | |
1556 expect(error, EFFS_DIRNOTEMPTY); | |
1557 error = tffs_remove("/asia/china/hongkong"); | |
1558 expect(error, EFFS_OK); | |
1559 error = tffs_opendir("/asia/china", &dir[2]); | |
1560 expect(error, 0); | |
1561 error = tffs_remove("/asia/china"); | |
1562 expect(error, EFFS_OK); | |
1563 | |
1564 error = tffs_remove("/asia/korea"); | |
1565 expect(error, EFFS_OK); | |
1566 error = tffs_remove("/asia/japan/tokyo"); | |
1567 expect(error, EFFS_OK); | |
1568 error = tffs_remove("/asia/japan"); | |
1569 expect(error, EFFS_OK); | |
1570 | |
1571 return 0; | |
1572 } | |
1573 | |
1574 // Check that expected stat data was read | |
1575 int case_expect_stat(const char *name, int n) | |
1576 { | |
1577 error = tffs_stat(name, &stat); | |
1578 expect(error, EFFS_OK); | |
1579 // test type, size, flags, space? | |
1580 // test range of location, inode, block | |
1581 return 0; | |
1582 } | |
1583 | |
1584 // Test stat | |
1585 int case_stat(int p0, int p1) | |
1586 { | |
1587 struct xstat_s xstat; | |
1588 struct stat_s stat; | |
1589 char myname[] = "/Stat_file"; | |
1590 char sym_name[] = "/sf"; | |
1591 char stream_name[] = "/Stat_stream"; | |
1592 fd_t fdi; | |
1593 int size, i, file_size = 0; | |
1594 | |
1595 // test stat on dirs, symlinks and files | |
1596 // check stat.block (by writing two HUGE files) | |
1597 | |
1598 case_cleanup(fs.chunk_size_max / 5 * 20); | |
1599 | |
1600 // NOTEME: this is a very limited test | |
1601 error = tffs_fwrite(myname, (char *)tdata[TDATA_HUGE], 99); | |
1602 expect_ok(error); | |
1603 | |
1604 error = tffs_stat(myname, &stat); | |
1605 expect(error, EFFS_OK); | |
1606 expect(stat.type, OT_FILE); | |
1607 expect(stat.flags, 0); | |
1608 expect_ok(stat.inode); | |
1609 expect(stat.size, 99); | |
1610 | |
1611 // error = tffs_xstat(myname, &xstat); | |
1612 // expect(error, EFFS_OK); | |
1613 | |
1614 // expect(error, EFFS_OK); | |
1615 // expect(xstat.type, OT_FILE); | |
1616 // expect(xstat.flags, 0); | |
1617 // expect_ok(xstat.inode); | |
1618 // expect(xstat.size, 99); | |
1619 | |
1620 // expect(xstat.space, 112); | |
1621 // expect_ok(xstat.location); | |
1622 // expect_ok(xstat.block); | |
1623 // expect_ok(xstat.sequence); | |
1624 // expect_ok(xstat.updates); | |
1625 | |
1626 error = tffs_linkstat(myname, &stat); | |
1627 expect(error, EFFS_OK); | |
1628 | |
1629 expect(error, EFFS_OK); | |
1630 expect(stat.type, OT_FILE); | |
1631 expect(stat.flags, 0); | |
1632 expect_ok(stat.inode); | |
1633 expect(stat.size, 99); | |
1634 | |
1635 error = tffs_xlstat(myname, &xstat); | |
1636 expect(error, EFFS_OK); | |
1637 | |
1638 expect(error, EFFS_OK); | |
1639 expect(xstat.type, OT_FILE); | |
1640 expect(xstat.flags, 0); | |
1641 expect_ok(xstat.inode); | |
1642 expect(xstat.size, 99); | |
1643 | |
1644 expect(xstat.space, 112); | |
1645 expect_ok(xstat.location); | |
1646 expect_ok(xstat.block); | |
1647 expect_ok(xstat.sequence); | |
1648 expect_ok(xstat.updates); | |
1649 | |
1650 // Symlink | |
1651 tffs_symlink(sym_name, myname); | |
1652 | |
1653 error = tffs_xlstat(sym_name, &xstat); | |
1654 expect(error, EFFS_OK); | |
1655 | |
1656 expect(error, EFFS_OK); | |
1657 expect(xstat.type, OT_LINK); | |
1658 expect(xstat.flags, 0); | |
1659 expect_ok(xstat.inode); | |
1660 expect(xstat.size, sizeof(myname)); | |
1661 | |
1662 expect(xstat.space, 16); | |
1663 expect_ok(xstat.location); | |
1664 expect_ok(xstat.block); | |
1665 expect_ok(xstat.sequence); | |
1666 expect_ok(xstat.updates); | |
1667 | |
1668 // Stream stat test | |
1669 // Use xstat to return the size of the file | |
1670 fdi = tffs_open(stream_name, FFS_O_WRONLY | FFS_O_CREATE | | |
1671 FFS_O_TRUNC | FFS_O_APPEND); | |
1672 expect(fdi, FFS_FD_OFFSET); | |
1673 | |
1674 for (i = 0; i < 20; i++) { | |
1675 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], | |
1676 fs.chunk_size_max / 5); | |
1677 | |
1678 expect(size, fs.chunk_size_max / 5); | |
1679 file_size +=size; | |
1680 | |
1681 error = tffs_xlstat(stream_name, &xstat); | |
1682 expect(error, EFFS_OK); | |
1683 expect_eq(xstat.size, file_size); | |
1684 | |
1685 error = tffs_fstat(fdi, &stat); | |
1686 expect(error, EFFS_OK); | |
1687 expect_eq(stat.size, file_size); | |
1688 } | |
1689 | |
1690 error = tffs_close(fdi); | |
1691 expect(error, EFFS_OK); | |
1692 | |
1693 // Test if the file size is right if opened in read-only | |
1694 fdi = tffs_open(stream_name, FFS_O_RDONLY); | |
1695 expect(fdi, FFS_FD_OFFSET); | |
1696 | |
1697 error = tffs_xlstat(stream_name, &xstat); | |
1698 expect(error, EFFS_OK); | |
1699 expect_eq(xstat.size, file_size); | |
1700 | |
1701 // Test a lot of difference fdi | |
1702 for (i = -3; i < FFS_FD_OFFSET + fs.fd_max + 3; i++) { | |
1703 error = tffs_fstat(i, &stat); | |
1704 if (i == FFS_FD_OFFSET) { | |
1705 expect(error, EFFS_OK); | |
1706 } | |
1707 else expect(error, EFFS_BADFD); | |
1708 } | |
1709 error = tffs_close(fdi); | |
1710 expect(error, EFFS_OK); | |
1711 | |
1712 return 0; | |
1713 } | |
1714 | |
1715 int case_remove(int p0, int p1) | |
1716 { | |
1717 tw(tr(TR_FUNC, TrTest, "WARNING: Test case not implemented!\n")); | |
1718 ttw(str(TTrTest, "Test case not implemented!" NL)); | |
1719 | |
1720 return 0; | |
1721 } | |
1722 | |
1723 int case_rename(int p0, int p1) | |
1724 { | |
1725 fd_t fdi; | |
1726 int size, i; | |
1727 struct dir_s dir; | |
1728 // create file A | |
1729 // rename A to B | |
1730 // check file A is gone | |
1731 // check file B is same as file A | |
1732 // do all the same for directory | |
1733 // do all the same for symlink | |
1734 // test and ensure that dir rename "foo" to "foo/bar" is impossible! | |
1735 | |
1736 // Cleanup before run | |
1737 tffs_remove("/Walt_Disney/RUP"); | |
1738 tffs_remove("/Uncle_Scrooge"); | |
1739 tffs_remove("/Walt_Disney/Minnie"); | |
1740 tffs_remove("/Walt_Disney"); | |
1741 tffs_remove("/Duck"); | |
1742 | |
1743 // Init | |
1744 tffs_mkdir("/Disney"); | |
1745 tffs_mkdir("/Hell"); | |
1746 | |
1747 error = tffs_fwrite("/IMEI", TDATA(2)); | |
1748 if (error < 0 && error != EFFS_ACCESS) return 1; | |
1749 error = tffs_fcontrol("/IMEI", OC_FLAGS, OF_READONLY); | |
1750 if (error < 0 && error != EFFS_ACCESS) return 1; | |
1751 | |
1752 tw(tr(TR_FUNC, TrTestHigh, "Rename file\n")); /* Rename file */ | |
1753 | |
1754 error = tffs_fwrite("/Mickey", TDATA(3)); | |
1755 expect(error, EFFS_OK); | |
1756 | |
1757 error = tffs_fwrite("/Pluto", TDATA(2)); | |
1758 expect(error, EFFS_OK); | |
1759 | |
1760 error = tffs_rename("/Pluto", "/Dog"); | |
1761 expect(error, EFFS_OK); | |
1762 | |
1763 error = tffs_fupdate("/Pluto", TDATA(2)); | |
1764 expect(error, EFFS_NOTFOUND); | |
1765 | |
1766 error = test_expect_file("/Dog", TDATA(2)); | |
1767 if (error) return 1; | |
1768 | |
1769 error = tffs_rename("/Dog", "/Hell/RIP"); | |
1770 expect(error, EFFS_OK); | |
1771 | |
1772 error = tffs_rename("/Hell/RIP", "/RAP"); | |
1773 expect(error, EFFS_OK); | |
1774 | |
1775 error = tffs_rename("/RAP", "/Disney/RUP"); | |
1776 expect(error, EFFS_OK); | |
1777 | |
1778 error = test_expect_file("/Disney/RUP", TDATA(2)); | |
1779 if (error) return 1; | |
1780 | |
1781 // Rename a file to an existing file | |
1782 error = tffs_rename("/Mickey", "/Disney/RUP"); | |
1783 expect(error, EFFS_OK); | |
1784 | |
1785 // Have the data changed? | |
1786 error = test_expect_file("/Disney/RUP", TDATA(3)); | |
1787 if (error) return 1; | |
1788 | |
1789 // Try rename a file to an exisitng read-only file | |
1790 error = tffs_rename("/Disney/RUP", "/IMEI"); | |
1791 expect(error, EFFS_ACCESS); | |
1792 | |
1793 // Try rename a file to an existing dir | |
1794 error = tffs_rename("/Disney/RUP", "/Hell"); | |
1795 expect(error, EFFS_NOTAFILE); | |
1796 | |
1797 error = tffs_rename("/Disney/RUP", "/BADNAME?"); | |
1798 expect(error, EFFS_BADNAME); | |
1799 | |
1800 error = tffs_remove("/Hell"); | |
1801 expect(error, EFFS_OK); | |
1802 | |
1803 tw(tr(TR_FUNC, TrTestHigh, "Rename symlink\n")); /* Rename symlink */ | |
1804 | |
1805 tffs_symlink("/Goose", "/Disney/RUP"); // 5 | |
1806 | |
1807 error = tffs_rename("/Goose", "/Duck"); | |
1808 expect(error, EFFS_OK); | |
1809 | |
1810 error = tffs_fupdate("/Goose", TDATA(2)); | |
1811 expect(error, EFFS_NOTFOUND); | |
1812 | |
1813 error = test_expect_file("/Duck", TDATA(3)); | |
1814 if (error) return 1; | |
1815 | |
1816 error = test_expect_file("/Disney/RUP", TDATA(3)); | |
1817 if (error) return 1; | |
1818 | |
1819 tw(tr(TR_FUNC, TrTestHigh, "Rename dir\n")); /* Rename dir */ | |
1820 | |
1821 // * FIXME BUG * FIXME BUG * FIXME BUG * The below test to not fail instead | |
1822 // the directory is removed | |
1823 // error = tffs_rename("/Disney", "/Disney/foo"); | |
1824 // expect(error, EFFS_OK); | |
1825 | |
1826 tffs_mkdir("/Disney/Donald_Duck"); | |
1827 expect(error, EFFS_OK); | |
1828 error = ffs_rename("/Disney/Donald_Duck", "/Uncle_Scrooge"); | |
1829 expect(error, EFFS_OK); | |
1830 error = tffs_opendir("/Uncle_Scrooge", &dir); | |
1831 expect(error, EFFS_OK); | |
1832 error = tffs_opendir("/Disney/Donald_Duck", &dir); | |
1833 expect(error, EFFS_NOTFOUND); | |
1834 | |
1835 error = tffs_rename("/Disney", "/Walt_Disney"); | |
1836 expect(error, EFFS_OK); | |
1837 | |
1838 tffs_mkdir("/Disney"); // Create 'Disney' dir again | |
1839 expect(error, EFFS_OK); | |
1840 | |
1841 // Try rename to existing dir | |
1842 error = tffs_rename("/Disney", "/Walt_Disney"); | |
1843 expect(error, EFFS_EXISTS); | |
1844 | |
1845 // Try rename to existing file | |
1846 error = tffs_rename("/Disney", "/Walt_Disney/RUP"); | |
1847 expect(error, EFFS_EXISTS); | |
1848 | |
1849 tw(tr(TR_FUNC, TrTestHigh, "Rename seghead\n")); /* Rename seghead */ | |
1850 | |
1851 fdi = tffs_open("/Walt_Disney/Mickey", FFS_O_WRONLY | FFS_O_CREATE); | |
1852 expect(fdi, FFS_FD_OFFSET); | |
1853 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max + 1); | |
1854 expect(size, fs.chunk_size_max + 1); | |
1855 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + size, fs.chunk_size_max); | |
1856 expect(size, fs.chunk_size_max); | |
1857 | |
1858 error = tffs_rename("/Walt_Disney/Mickey", "/Walt_Disney/Minnie"); | |
1859 expect(error, EFFS_LOCKED); | |
1860 tffs_close(fdi); | |
1861 | |
1862 error = tffs_rename("/Walt_Disney/Mickey", "/Walt_Disney/Minnie"); | |
1863 expect(error, EFFS_OK); | |
1864 | |
1865 fdi = tffs_open("/Walt_Disney/Minnie", FFS_O_RDONLY); | |
1866 expect(fdi, FFS_FD_OFFSET); | |
1867 i = 0; | |
1868 do { | |
1869 size = tffs_read(fdi, bigbuf, bigbuf_size); | |
1870 error = test_expect_data((char*)tdata[TDATA_HUGE] + i, bigbuf, size); | |
1871 if (error) return 1; | |
1872 i += size; | |
1873 } while (size); | |
1874 error = tffs_close(fdi); | |
1875 expect(error, 0); | |
1876 | |
1877 error = test_expect_file("/Walt_Disney/Minnie", (char *)tdata[TDATA_HUGE], | |
1878 2 * fs.chunk_size_max + 1); | |
1879 if (error) return 1; | |
1880 | |
1881 // Rename a big file to an existing big file | |
1882 error = tffs_fwrite("/Mickey", (char *)tdata[TDATA_HUGE] + 5, | |
1883 2.5 * fs.chunk_size_max); | |
1884 expect(error, EFFS_OK); | |
1885 | |
1886 error = tffs_rename("/Mickey", "/Walt_Disney/Minnie"); | |
1887 expect(error, EFFS_OK); | |
1888 | |
1889 error = test_expect_file("/Walt_Disney/Minnie", (char *)tdata[TDATA_HUGE] + 5, | |
1890 2.5 * fs.chunk_size_max); | |
1891 if (error) return 1; | |
1892 | |
1893 error = tffs_fread("/Mickey", 0 , 0); | |
1894 expect(error, EFFS_NOTFOUND); | |
1895 | |
1896 return 0; | |
1897 } | |
1898 | |
1899 // One of the problems with the rename function is that we need to copy the | |
1900 // data part from the old obj to the new obj. When we allocate data for the | |
1901 // new obj we risk that the data alloc caused a data reclaim which relocated | |
1902 // the old obj thus the source have been moved! | |
1903 int case_rename_extended(int p0, int p1) | |
1904 { | |
1905 int i, old_drec_most_lost, rename_file_relocated = 0; | |
1906 int fsize, offset; | |
1907 char myname1[] = "/rename1/rename1/foo"; | |
1908 char myname2[] = "/rename2/rename2/bar"; | |
1909 | |
1910 if (p0 == 0) p0 = 100; | |
1911 if (p1 == 0) p1 = 5; | |
1912 | |
1913 error = tffs_preformat(0xDEAD); | |
1914 expect(error, EFFS_OK); | |
1915 error = tffs_format("/ffs/b3r24", 0x2BAD); | |
1916 expect(error, EFFS_OK); | |
1917 | |
1918 fsize = 2.5 * fs.chunk_size_max; // Test with more than one chunk | |
1919 | |
1920 tffs_mkdir("/rename1"); | |
1921 tffs_mkdir("/rename1/rename1"); | |
1922 tffs_mkdir("/rename2"); | |
1923 tffs_mkdir("/rename2/rename2"); | |
1924 | |
1925 error = tffs_file_write(myname1, (char*)tdata[TDATA_HUGE], fsize, | |
1926 FFS_O_CREATE | FFS_O_TRUNC); | |
1927 | |
1928 // Test if rename can handle when the objects are relocaded while the | |
1929 // rename is in progress | |
1930 for (i = 0; i < p0; i++) { | |
1931 tw(tr(TR_FUNC, TrTest, "Rename number %d\n", i)); | |
1932 | |
1933 offset = i % 2 ? 3 : 9; | |
1934 error = tffs_file_write(myname2, (char*)tdata[TDATA_HUGE] + offset, fsize, | |
1935 FFS_O_CREATE | FFS_O_TRUNC); | |
1936 | |
1937 // Get data reclaim candidate most_lost | |
1938 old_drec_most_lost = stats.drec.most_lost; | |
1939 error = tffs_rename(myname2, myname1); | |
1940 expect(error, EFFS_OK); | |
1941 | |
1942 error = test_expect_file(myname1, tdata[TDATA_HUGE] + offset, fsize); | |
1943 expect(error, EFFS_OK); | |
1944 | |
1945 error = tffs_fread(myname2, 0, 0); | |
1946 expect(error, EFFS_NOTFOUND); | |
1947 | |
1948 // Has the rename triggered a data_reclaim()? | |
1949 if (old_drec_most_lost != stats.drec.most_lost) { | |
1950 rename_file_relocated++; | |
1951 tw(tr(TR_FUNC, TrTest, "Rename objects relocated %d\n", | |
1952 rename_file_relocated)); | |
1953 if (rename_file_relocated >= p1) | |
1954 return EFFS_OK; | |
1955 } | |
1956 } | |
1957 | |
1958 return 1; | |
1959 } | |
1960 | |
1961 | |
1962 // Test Big files | |
1963 int case_bigfile(int p0, int p1) | |
1964 { | |
1965 struct ffs_state_s old, new; | |
1966 const char bigfile[] = "/antarctica/iceberg"; | |
1967 int bytes_max, file_size; | |
1968 | |
1969 #if 1 | |
1970 ttw(ttr(TTrTest, "WARNING: We need to re-implement this test. Skip test" NL)); | |
1971 tw(tr(TR_FUNC, TrTest, "WARNING: We need to re-implement this test. Skip test\n")); | |
1972 return 0; | |
1973 #endif | |
1974 | |
1975 if (param.data_blocks <= 1) { | |
1976 ttw(ttr(TTrTest, "WARNING: Too few blocks to run. Skip test" NL)); | |
1977 tw(tr(TR_FUNC, TrTest, "WARNING: Too few blocks to run. Skip test\n")); | |
1978 return 0; | |
1979 } | |
1980 | |
1981 error = case_cleanup(fs.filesize_max); | |
1982 expect(error, EFFS_NOSPACE); // We can not cleanup this amount. | |
1983 | |
1984 ffs_query(Q_BYTES_FREE, (uint32 *) &bytes_max); | |
1985 test_ffs_state_get(&old); | |
1986 | |
1987 // We don't have enough space for this amount because the name dos also | |
1988 // use some space | |
1989 file_size = bytes_max + 1; | |
1990 | |
1991 // Try to make a file of a size that is bigger than the total free space | |
1992 // in the file system. | |
1993 ttw(ttr(TTrTest, "Bigfile of size %d" NL, file_size)); | |
1994 tw(tr(TR_FUNC, TrTestHigh, "Bigfile of size %d\n", file_size)); | |
1995 error = tffs_fcreate(bigfile, | |
1996 (char *) tdata[TDATA_HUGE], file_size); | |
1997 expect(error, EFFS_NOSPACE); | |
1998 | |
1999 test_ffs_state_get(&new); | |
2000 expect_eq(old.bytes_free, new.bytes_free); | |
2001 | |
2002 // File the system with this huge file | |
2003 file_size = bytes_max - FFS_FILENAME_MAX - dev.atomsize; | |
2004 ttw(ttr(TTrTest, "Bigfile of size %d" NL, file_size)); | |
2005 tw(tr(TR_FUNC, TrTestHigh, "Bigfile of size %d\n", file_size)); | |
2006 error = tffs_fcreate(bigfile, | |
2007 (char *) tdata[TDATA_HUGE], file_size); | |
2008 expect(error, EFFS_OK); | |
2009 | |
2010 error = test_expect_file((char *) bigfile, | |
2011 (char *) tdata[TDATA_HUGE], file_size); | |
2012 if (error) return 1; | |
2013 | |
2014 test_ffs_state_get(&new); | |
2015 expect_gt(old.bytes_free, new.bytes_free - file_size); | |
2016 | |
2017 tffs_remove(bigfile); | |
2018 | |
2019 return 0; | |
2020 } | |
2021 | |
2022 | |
2023 /****************************************************************************** | |
2024 * Reclaim Test Cases | |
2025 ******************************************************************************/ | |
2026 | |
2027 // Test that ffs internal state is same after a re-ffs_init() | |
2028 int case_reinit(int p0, int p1) | |
2029 { | |
2030 struct ffs_state_s old, new; | |
2031 | |
2032 test_ffs_state_get(&old); | |
2033 error = tffs_initialize(); | |
2034 expect(error, EFFS_OK); | |
2035 test_ffs_state_get(&new); | |
2036 error = test_expect_state(&old, &new); | |
2037 if (error) return 1; | |
2038 | |
2039 return 0; | |
2040 } | |
2041 | |
2042 // Test inodes reclaim | |
2043 int case_irec(int p0, int p1) | |
2044 { | |
2045 // African states: kenya, egypt, marocco, namibia, nigeria, mozambique, | |
2046 // tanzania, ghana, togo, liberia, mali, congo | |
2047 struct ffs_state_s old, new; | |
2048 int i, j, updates; | |
2049 | |
2050 if (p0 == 0) | |
2051 p0 = 7; | |
2052 | |
2053 tffs_mkdir("/africa"); | |
2054 | |
2055 // Initialize | |
2056 tffs_fwrite("/africa/kenya", TDATA(0)); // 1 | |
2057 tffs_mkdir("/africa/east"); // 2 | |
2058 tffs_fwrite("/africa/tanzania", TDATA(1)); // 3 | |
2059 tffs_fwrite("/africa/east/egypt", TDATA(2)); // 4 | |
2060 tffs_symlink("/africa/et", "africa/east/egypt"); // 5 | |
2061 tffs_mkdir("/africa/west"); // 7 | |
2062 tffs_fupdate("/africa/et", TDATA(3)); // 6 | |
2063 tffs_fwrite("/africa/west/liberia", TDATA(0)); // 8 | |
2064 | |
2065 for (j = 0; j < p0; j++) { | |
2066 test_ffs_state_get(&old); | |
2067 updates = param.inodes_max - old.inodes_used; | |
2068 ttw(ttr(TTrTest, "loop %d: updates = %d" NL, j, updates)); | |
2069 tw(tr(TR_FUNC, TrTestHigh, "loop %d: updates = %d\n", j, updates)); | |
2070 for (i = 0; i < (updates / 10) + 10; i++) { | |
2071 // cleanup... | |
2072 error = tffs_remove("/africa/east/egypt"); | |
2073 expect(error, EFFS_OK); | |
2074 error = tffs_remove("/africa/east"); | |
2075 expect(error, EFFS_OK); | |
2076 error = tffs_remove("/africa/et"); | |
2077 expect(error, EFFS_OK); | |
2078 error = tffs_remove("/africa/west/liberia"); | |
2079 expect(error, EFFS_OK); | |
2080 error = tffs_remove("/africa/west"); | |
2081 expect(error, EFFS_OK); | |
2082 // use 10 inodes... | |
2083 error = tffs_fwrite("/africa/kenya", TDATA(0)); // 1 | |
2084 expect(error, EFFS_OK); | |
2085 error = tffs_mkdir("/africa/east"); // 2 | |
2086 expect(error, EFFS_OK); | |
2087 error = tffs_fwrite("/africa/tanzania", (char *) tdata[0], 0); // 3 | |
2088 expect(error, EFFS_OK); | |
2089 error = tffs_fcreate("/africa/east/egypt", TDATA(2)); // 4 | |
2090 expect(error, EFFS_OK); | |
2091 error = tffs_symlink("/africa/et", "/africa/east/egypt"); // 5 | |
2092 expect(error, EFFS_OK); | |
2093 error = tffs_mkdir("/africa/west"); // 7 | |
2094 expect(error, EFFS_OK); | |
2095 error = tffs_fupdate("/africa/et", TDATA(3)); // 6 | |
2096 expect(error, EFFS_OK); | |
2097 error = tffs_fcreate("/africa/west/liberia", TDATA(0)); // 8 | |
2098 expect(error, EFFS_OK); | |
2099 error = tffs_fupdate("/africa/west/liberia", TDATA(1)); // 9 | |
2100 expect(error, EFFS_OK); | |
2101 error = tffs_fupdate("/africa/tanzania", TDATA(2)); // 10 | |
2102 expect(error, EFFS_OK); | |
2103 } | |
2104 test_ffs_state_get(&new); | |
2105 expect_eq(old.objects_total, new.objects_total); | |
2106 error = test_expect_file("/africa/tanzania", TDATA(2)); | |
2107 if (error) return 1; | |
2108 error = test_expect_file("/africa/west/liberia", TDATA(1)); | |
2109 if (error) return 1; | |
2110 error = test_expect_file("/africa/east/egypt", TDATA(3)); | |
2111 if (error) return 1; | |
2112 error = test_expect_file("/africa/kenya", TDATA(0)); | |
2113 if (error) return 1; | |
2114 } | |
2115 | |
2116 return 0; | |
2117 } | |
2118 | |
2119 #if 1 | |
2120 // FIXME: Is this test case still valid after the new ffs_file_write() which | |
2121 // makes several chunks instead of on big? | |
2122 | |
2123 // Test data reclaim. Use up to maximum half the total space available. | |
2124 // drec params: percentage of avail to use, numupdates. We must not have too | |
2125 // big files due to fragmentation problems | |
2126 #define DREC_DIR "/north-america/usa" | |
2127 #define DREC_CHUNKS 6 | |
2128 int case_drec(int p0, int p1) | |
2129 { | |
2130 static struct test_file_s files[] = | |
2131 { | |
2132 { DREC_DIR "/alaska", 0, 0 }, | |
2133 { DREC_DIR "/arkansas", 0, 0 }, | |
2134 { DREC_DIR "/california", 0, 0 }, | |
2135 { DREC_DIR "/colorado", 0, 0 }, | |
2136 { DREC_DIR "/dakota", 0, 0 }, // north, south? | |
2137 { DREC_DIR "/DistrictOfColumbia", 0, 0 }, // state? | |
2138 { DREC_DIR "/florida", 0, 0 }, | |
2139 { DREC_DIR "/Georgia", 0, 0 }, | |
2140 { DREC_DIR "/hawaii", 0, 0 }, | |
2141 { DREC_DIR "/Idaho", 0, 0 }, | |
2142 { DREC_DIR "/Illinois", 0, 0 }, | |
2143 { DREC_DIR "/Iowa", 0, 0 }, | |
2144 { DREC_DIR "/kentucky", 0, 0 }, | |
2145 { DREC_DIR "/maine", 0, 0 }, | |
2146 { DREC_DIR "/Massachusettes", 0, 0 }, // spelling? | |
2147 { DREC_DIR "/michigan", 0, 0 }, | |
2148 { DREC_DIR "/minnesota", 0, 0 }, | |
2149 { DREC_DIR "/mississippi", 0, 0 }, | |
2150 { DREC_DIR "/missouri", 0, 0 }, | |
2151 { DREC_DIR "/Montana", 0, 0 }, | |
2152 { DREC_DIR "/Nevada", 0, 0 }, | |
2153 { DREC_DIR "/NewHampshire", 0, 0 }, | |
2154 { DREC_DIR "/NewJersey", 0, 0 }, | |
2155 { DREC_DIR "/NewMexico", 0, 0 }, | |
2156 { DREC_DIR "/NewYork", 0, 0 }, // state? | |
2157 { DREC_DIR "/north-carolina", 0, 0 }, | |
2158 { DREC_DIR "/ohio", 0, 0 }, | |
2159 { DREC_DIR "/oklahoma", 0, 0 }, | |
2160 { DREC_DIR "/Oregon", 0, 0 }, | |
2161 { DREC_DIR "/Pensylvania", 0, 0 }, | |
2162 { DREC_DIR "/RhodeIsland", 0, 0 }, // state? | |
2163 { DREC_DIR "/south-carolina", 0, 0 }, | |
2164 { DREC_DIR "/Tennesee", 0, 0 }, | |
2165 { DREC_DIR "/texas", 0, 0 }, | |
2166 { DREC_DIR "/utah", 0, 0 }, | |
2167 { DREC_DIR "/Vermont", 0, 0 }, | |
2168 { DREC_DIR "/virginia", 0, 0 }, | |
2169 { DREC_DIR "/washington", 0, 0 }, | |
2170 { DREC_DIR "/Wyoming", 0, 0 }, | |
2171 | |
2172 { DREC_DIR "/40", 0, 0 }, | |
2173 { DREC_DIR "/41", 0, 0 }, | |
2174 { DREC_DIR "/42", 0, 0 }, | |
2175 { DREC_DIR "/43", 0, 0 }, | |
2176 { DREC_DIR "/44", 0, 0 }, | |
2177 { DREC_DIR "/45", 0, 0 }, | |
2178 { DREC_DIR "/46", 0, 0 }, | |
2179 { DREC_DIR "/47", 0, 0 }, | |
2180 { DREC_DIR "/48", 0, 0 }, | |
2181 { DREC_DIR "/49", 0, 0 }, | |
2182 { DREC_DIR "/50", 0, 0 }, | |
2183 { DREC_DIR "/51", 0, 0 }, | |
2184 { DREC_DIR "/52", 0, 0 }, | |
2185 }; | |
2186 struct chunk_s { | |
2187 int ratio; | |
2188 int high; | |
2189 int low; | |
2190 }; | |
2191 const struct chunk_s chunk[DREC_CHUNKS] = { | |
2192 { 15, 65536, 32768 }, | |
2193 { 15, 32768, 16384 }, | |
2194 { 25, 16384, 8192 }, | |
2195 { 20, 8192, 4096 }, | |
2196 { 15, 4096, 2048 }, | |
2197 { 10, 2048, 0 } | |
2198 }; | |
2199 | |
2200 int i, j, n, num_files; | |
2201 int num, pct; | |
2202 int size_used, size_max, size_chunk; | |
2203 int size_chunk_used, size_chunk_low, size_chunk_high; | |
2204 | |
2205 num = (p0 == 0 ? 11 : p0); | |
2206 pct = (p1 == 0 ? 50 : p1); | |
2207 | |
2208 tffs_mkdir("/north-america"); | |
2209 tffs_mkdir("/north-america/usa"); | |
2210 | |
2211 size_max = pct * param.bytes_avail / 100; | |
2212 size_used = 0; | |
2213 num_files = sizeof(files) / sizeof(struct test_file_s); | |
2214 n = 0; | |
2215 | |
2216 tw(tr(TR_FUNC, TrTestHigh, "pct = %d%% = %dk\n", pct, size_max/1024)); | |
2217 | |
2218 for (i = 0; i < DREC_CHUNKS; i++) { | |
2219 size_chunk = chunk[i].ratio * size_max / 100; | |
2220 size_chunk_low = chunk[i].low / 256 * fs.filesize_max / 256; | |
2221 size_chunk_high = chunk[i].high / 256 * fs.filesize_max / 256; | |
2222 tw(tr(TR_FUNC, TrTestHigh, "%4dk of [%d..%d]: ", | |
2223 size_chunk/1024, size_chunk_high, size_chunk_low)); | |
2224 ttw(ttr(TTrTest, "%4dk of [%d..%d]: ", | |
2225 size_chunk/1024, size_chunk_high, size_chunk_low)); | |
2226 size_chunk_used = 0; | |
2227 // If the total chunk size can guaranteeable be contained... | |
2228 if (size_chunk >= chunk[i].high) { | |
2229 for (j = 0; j < size_chunk / size_chunk_high; j++) { | |
2230 if (n >= num_files) { | |
2231 tw(tr(TR_FUNC, TrTestHigh, "j too big\n")); | |
2232 ttw(str(TTrTest, "j too big" NL)); | |
2233 break; | |
2234 } | |
2235 files[n].size = size_chunk_low + | |
2236 rand() % (size_chunk_high - size_chunk_low); | |
2237 #ifdef WIN32 | |
2238 /* due to limitation in MS Visual C */ | |
2239 if( files[n].size > 65535 ) | |
2240 files[n].size = 65535; | |
2241 #endif //WIN32 | |
2242 files[n].data = (char *) tdata[TDATA_HUGE] + n; | |
2243 tw(tr(TR_NULL, TrTestHigh, "%d:%s ", | |
2244 files[n].size, &files[n].name[strlen(DREC_DIR)+1])); | |
2245 ttw(ttr(TTrTest, "%d:%s " NL, | |
2246 files[n].size, &files[n].name[strlen(DREC_DIR)+1])); | |
2247 size_chunk_used += files[n].size; | |
2248 n++; | |
2249 // FIXME: We should let all the unused bytes from this | |
2250 // chunk spill over into the next chunk so we use the | |
2251 // full percentage specified by p1. | |
2252 } | |
2253 size_used += size_chunk_used; | |
2254 } | |
2255 tw(tr(TR_NULL, TrTestHigh, "(%dk)\n", size_chunk_used/1024)); | |
2256 ttw(ttr(TTrTest, "(%dk)" NL, size_chunk_used/1024)); | |
2257 } | |
2258 tw(tr(TR_FUNC, TrTestHigh, "pct = %d%% = %dk\n", | |
2259 100 * size_used/param.bytes_avail, size_used/1024)); | |
2260 ttw(ttr(TTrTest, "pct = %d%% = %dk" NL, | |
2261 100 * size_used/param.bytes_avail, size_used/1024)); | |
2262 | |
2263 for (j = 0; j < num; j++) { | |
2264 ttw(ttr(TTrTest, "drec: %d. write" NL, j+1)); | |
2265 tw(tr(TR_FUNC, TrTestHigh, "drec: %d. write\n", j+1)); | |
2266 for (i = 0; i < n; i++) { | |
2267 error = tffs_fwrite(files[i].name, files[i].data, files[i].size); | |
2268 expect(error, EFFS_OK); | |
2269 } | |
2270 } | |
2271 | |
2272 for (i = 0; i < n; i++) { | |
2273 error = test_expect_file(files[i].name, files[i].data, files[i].size); | |
2274 if (error) | |
2275 return 1; | |
2276 error = tffs_remove(files[i].name); | |
2277 expect(error, EFFS_OK); | |
2278 } | |
2279 tffs_remove("/north-america/usa"); | |
2280 tffs_remove("/north-america"); | |
2281 | |
2282 return 0; | |
2283 } | |
2284 | |
2285 #else | |
2286 | |
2287 // Test data reclaim. Use up to maximum half the total space available. | |
2288 // drec params: percentage of avail to use, numupdates. We must not have too | |
2289 // big files due to fragmentation problems | |
2290 int case_drec(int p0, int p1) | |
2291 { | |
2292 struct blabla_s { | |
2293 int ratio; | |
2294 int high; | |
2295 int low; | |
2296 }; | |
2297 | |
2298 struct blabla_s sizes[4] = | |
2299 { | |
2300 { 10, 65536, 32768 }, | |
2301 { 40, 21800, 16384 }, | |
2302 { 45, 16384, 2048 }, | |
2303 { 5, 2048, 0 } | |
2304 }; | |
2305 | |
2306 static struct test_file_s files[] = | |
2307 { | |
2308 { DRECDIR "/alaska", 0, 0 }, | |
2309 { DRECDIR "/arkansas", 0, 0 }, | |
2310 { DRECDIR "/california", 0, 0 }, | |
2311 { DRECDIR "/colorado", 0, 0 }, | |
2312 { DRECDIR "/dakota", 0, 0 }, // north, south? | |
2313 { DRECDIR "/DistrictOfColumbia", 0, 0 }, // state? | |
2314 { DRECDIR "/florida", 0, 0 }, | |
2315 { DRECDIR "/Georgia", 0, 0 }, | |
2316 { DRECDIR "/hawaii", 0, 0 }, | |
2317 { DRECDIR "/Idaho", 0, 0 }, | |
2318 { DRECDIR "/Illinois", 0, 0 }, | |
2319 { DRECDIR "/Iowa", 0, 0 }, | |
2320 { DRECDIR "/kentucky", 0, 0 }, | |
2321 { DRECDIR "/maine", 0, 0 }, | |
2322 { DRECDIR "/Massachusettes", 0, 0 }, // spelling? | |
2323 { DRECDIR "/michigan", 0, 0 }, | |
2324 { DRECDIR "/minnesota", 0, 0 }, | |
2325 { DRECDIR "/mississippi", 0, 0 }, | |
2326 { DRECDIR "/missouri", 0, 0 }, | |
2327 { DRECDIR "/Montana", 0, 0 }, | |
2328 { DRECDIR "/Nevada", 0, 0 }, | |
2329 { DRECDIR "/NewHampshire", 0, 0 }, | |
2330 { DRECDIR "/NewJersey", 0, 0 }, | |
2331 { DRECDIR "/NewMexico", 0, 0 }, | |
2332 { DRECDIR "/NewYork", 0, 0 }, // state? | |
2333 { DRECDIR "/north-carolina", 0, 0 }, | |
2334 { DRECDIR "/ohio", 0, 0 }, | |
2335 { DRECDIR "/oklahoma", 0, 0 }, | |
2336 { DRECDIR "/Oregon", 0, 0 }, | |
2337 { DRECDIR "/Pensylvania", 0, 0 }, | |
2338 { DRECDIR "/RhodeIsland", 0, 0 }, // state? | |
2339 { DRECDIR "/south-carolina", 0, 0 }, | |
2340 { DRECDIR "/Tennesee", 0, 0 }, | |
2341 { DRECDIR "/texas", 0, 0 }, | |
2342 { DRECDIR "/utah", 0, 0 }, | |
2343 { DRECDIR "/Vermont", 0, 0 }, | |
2344 { DRECDIR "/virginia", 0, 0 }, | |
2345 { DRECDIR "/washington", 0, 0 }, | |
2346 { DRECDIR "/Wyoming", 0, 0 }, | |
2347 | |
2348 { DRECDIR "/40", 0, 0 }, | |
2349 { DRECDIR "/41", 0, 0 }, | |
2350 { DRECDIR "/42", 0, 0 }, | |
2351 { DRECDIR "/43", 0, 0 }, | |
2352 { DRECDIR "/44", 0, 0 }, | |
2353 { DRECDIR "/45", 0, 0 }, | |
2354 { DRECDIR "/46", 0, 0 }, | |
2355 { DRECDIR "/47", 0, 0 }, | |
2356 { DRECDIR "/48", 0, 0 }, | |
2357 { DRECDIR "/49", 0, 0 }, | |
2358 { DRECDIR "/50", 0, 0 }, | |
2359 { DRECDIR "/51", 0, 0 }, | |
2360 { DRECDIR "/52", 0, 0 }, | |
2361 }; | |
2362 | |
2363 int i, j, n, size, size_target; | |
2364 int num, percentage; | |
2365 | |
2366 error = tffs_mkdir("/north-america"); | |
2367 | |
2368 percentage = (p1 == 0 ? 50 : p1); | |
2369 n = sizeof(files)/sizeof(struct test_file_s); | |
2370 size_target = percentage * param.bytes_avail / 100; | |
2371 size = 0; | |
2372 for (i = 0; i < 4; i++) { | |
2373 sizes[i].ratio = sizes[i].ratio * size_target / 100; | |
2374 sizes[i].high = sizes[i].high / 256 * fs.filesize_max / 256; | |
2375 sizes[i].low = sizes[i].low / 256 * fs.filesize_max / 256; | |
2376 size += sizes[i].ratio; | |
2377 } | |
2378 ttw(ttr(TTrTest, "%4dk in total" NL, size / 1024)); | |
2379 tw(tr(TR_FUNC, TrTestHigh, "%4dk in total\n", size / 1024)); | |
2380 | |
2381 j = 0; | |
2382 size = size_target = 0; | |
2383 for (i = 0; i < 4; i++) { | |
2384 ttw(ttr(TTrTest, "%4dk: %d..%d = ", | |
2385 sizes[i].ratio / 1024, sizes[i].high, sizes[i].low)); | |
2386 tw(tr(TR_FUNC, TrTestHigh, "%4dk: %d..%d = ", | |
2387 sizes[i].ratio / 1024, sizes[i].high, sizes[i].low)); | |
2388 size_target += sizes[i].ratio; | |
2389 while (size < size_target) { | |
2390 files[j].data = (char *) tdata[TDATA_HUGE] + j; | |
2391 files[j].size = rand() % (sizes[i].high - sizes[i].low) | |
2392 + sizes[i].low; | |
2393 size += files[j].size; | |
2394 ttw(ttr(TTrTest, "%d:%s, ", | |
2395 files[j].size, &files[j].name[strlen(DRECDIR)+1])); | |
2396 tw(tr(TR_NULL, TrTestHigh, "%d:%s, ", | |
2397 files[j].size, &files[j].name[strlen(DRECDIR)+1])); | |
2398 j++; | |
2399 if (j >= n) { | |
2400 // TODO: better error handling? | |
2401 ttw(str(TTrTest, "j too big" NL)); | |
2402 tw(tr(TR_FUNC, TrTestHigh, "j too big\n")); | |
2403 return -1; | |
2404 } | |
2405 } | |
2406 ttw(str(TTrTest, "" NL)); | |
2407 tw(tr(TR_NULL, TrTestHigh, "\n")); | |
2408 } | |
2409 n = j; | |
2410 | |
2411 error = tffs_mkdir(DRECDIR); | |
2412 | |
2413 num = (p0 == 0 ? 5 : p0); | |
2414 for (j = 0; j < num; j++) { | |
2415 ttw(ttr(TTrTest, "drec: %d. write" NL, j+1)); | |
2416 tw(tr(TR_FUNC, TrTestHigh, "drec: %d. write\n", j+1)); | |
2417 for (i = 0; i < n; i++) { | |
2418 error = tffs_fwrite(files[i].name, files[i].data, files[i].size); | |
2419 expect(error, EFFS_OK); | |
2420 } | |
2421 // error = test_run("ri"); | |
2422 // if (error) return 1; | |
2423 } | |
2424 | |
2425 for (i = 0; i < n; i++) { | |
2426 error = test_expect_file(files[i].name, files[i].data, files[i].size); | |
2427 if (error) return 1; | |
2428 error = tffs_remove(files[i].name); | |
2429 expect(error, EFFS_OK); | |
2430 } | |
2431 | |
2432 return 0; | |
2433 } | |
2434 | |
2435 #endif | |
2436 | |
2437 void save_block_ages(int *age) | |
2438 { | |
2439 int i; | |
2440 struct block_header_s *bhp; | |
2441 | |
2442 for (i = 0; i < dev.numblocks; i++) | |
2443 { | |
2444 bhp = (struct block_header_s *) offset2addr(dev.binfo[i].offset); | |
2445 age[i] = bhp->age; | |
2446 tw(tr(TR_FUNC, TrTestHigh, "b,age(%d,%d)\n", i, age[i])); | |
2447 } | |
2448 } | |
2449 | |
2450 // NOTE: This chech includes the inode block thus the inode block also needs | |
2451 // to be reclaimed before this functions returns ok | |
2452 int has_all_block_ages_changed(int *age) | |
2453 { | |
2454 int i; | |
2455 struct block_header_s *bhp; | |
2456 | |
2457 for (i = 0; i < dev.numblocks; i++) | |
2458 { | |
2459 bhp = (struct block_header_s *) offset2addr(dev.binfo[i].offset); | |
2460 if (age[i] == bhp->age) | |
2461 return 0; // Age have not changed | |
2462 } | |
2463 | |
2464 return 1; | |
2465 } | |
2466 | |
2467 #define chunkalign(size) (((size) + fs.chunk_size_max-1) & ~(fs.chunk_size_max-1)) | |
2468 | |
2469 // Fill a data blocks with the maximum possible numbers of objects | |
2470 int fill_block_with_max_objects(void) | |
2471 { | |
2472 static int n = 1000; // Avoid white spaces in the filename | |
2473 int fsize, i, b, nobjects, bfree_space; | |
2474 char myname[] = "Fb_max-xxxx"; | |
2475 char *mydata = (char *) tdata[TDATA_HUGE]; | |
2476 | |
2477 // Find an approximate objects size | |
2478 fsize = dev.blocksize / fs.block_files_max - sizeof(myname) - 1; | |
2479 | |
2480 // Fill approximate 75% of a data block | |
2481 for (i = 0; i < fs.block_files_max / 4 * 3; i++, n++) { | |
2482 sprintf(myname, "/Fb_max-%4d", n); | |
2483 error = tffs_file_write(myname,(char*) mydata, fsize, FFS_O_CREATE); | |
2484 expect_ok(error); | |
2485 } | |
2486 | |
2487 // Find the block we currently are filling with objects. | |
2488 error = tffs_xlstat(myname, &xstat); | |
2489 expect_ok(error); | |
2490 | |
2491 b = xstat.block; | |
2492 bfree_space = dev.blocksize - bstat[b].used; | |
2493 tw(tr(TR_FUNC, TrTestHigh, "Block: %d, Free space:%dkB\n", b ,bfree_space>>10)); | |
2494 | |
2495 // Calculate the exact file size to fill a block with max number of files | |
2496 nobjects = fs.block_files_max - bstat[b].objects - fs.block_files_reserved; | |
2497 | |
2498 fsize = bfree_space / nobjects - sizeof(myname); | |
2499 fsize &= ~dev.atomnotmask; // Avoid padding | |
2500 tw(tr(TR_FUNC, TrTestHigh, "Exact file size (%d)\n", fsize)); | |
2501 | |
2502 // Fill the rest of the block | |
2503 for (i = 0; i < nobjects; i++, n++) { | |
2504 sprintf(myname, "/Fb_max-%4d", n); | |
2505 error = tffs_file_write(myname, (char*) mydata, fsize, FFS_O_CREATE); | |
2506 expect_ok(error); | |
2507 } | |
2508 | |
2509 tw(tr(TR_FUNC, TrTest, "Filled block %d done\n", b)); | |
2510 | |
2511 return EFFS_OK; | |
2512 } | |
2513 | |
2514 // Stress test data reclaim and test wearleveling. | |
2515 // NOTE: This test can not run in less than 7 blocks | |
2516 int case_adrec(int nwrites, int nage_change) | |
2517 { | |
2518 int i, j, n, inodes_reserved, nobjects, bytes_max; | |
2519 int blocks, fsize; | |
2520 int dynamic_fsize = 1000; | |
2521 char static_name[] = "/Static-xxxx"; | |
2522 char dynamic_name[] = "/Dynamic"; | |
2523 int *age = (int*) smallbuf; | |
2524 | |
2525 /* Flow: | |
2526 Format ffs. | |
2527 Fill N number of blocks with the maximum possible numbers of objects. | |
2528 Fill the rest of FFS except from a few kbytes. Use almost all the inodes. | |
2529 Trigger data reclaim by continue to update a file. | |
2530 Test if all flash blocks are used for wearleveling. | |
2531 */ | |
2532 if (nwrites == 0) // Number of updates of the dynamic file (timeout) | |
2533 nwrites = 1000000; | |
2534 if (nage_change == 0) // | |
2535 nage_change = 2; | |
2536 | |
2537 error = tffs_preformat(0xDEAD); | |
2538 expect(error, EFFS_OK); | |
2539 error = tffs_format("/ffs", 0x2BAD); | |
2540 expect(error, EFFS_OK); | |
2541 | |
2542 // Major hack, disable journal and reserved space or else there will be | |
2543 // created new journals inside the blocks where we wish to have only | |
2544 // static objects | |
2545 fs.ijournal = 0; | |
2546 fs.reserved_space = 0; | |
2547 | |
2548 // Minimum amount of inodes to fill FFS: | |
2549 ffs_query(Q_BYTES_FREE, &bytes_max); | |
2550 inodes_reserved = bytes_max / fs.chunk_size_max; | |
2551 | |
2552 // We need to calculate the amount of inodes we can use and still | |
2553 // garanti that we have enough inodes to fill all data blocks with data. | |
2554 nobjects = fs.objects_max - inodes_reserved; | |
2555 | |
2556 // How many blocks can we fill? | |
2557 blocks = nobjects / fs.block_files_max; | |
2558 | |
2559 // Fill N number of data blocks with the maximum possible numbers of objects | |
2560 tw(tr(TR_FUNC, TrTest, "Fill %d blocks with max obj \n", blocks)); | |
2561 n = 1000; // Avoid white spaces in the filename | |
2562 for (j = 0; j < blocks; j++) { | |
2563 error = fill_block_with_max_objects(); | |
2564 expect_ok(error); | |
2565 } | |
2566 | |
2567 // Restore journal and reserved space | |
2568 error = tffs_initialize(); | |
2569 expect_ok(error); | |
2570 | |
2571 // Fill the rest of FFS except from 3 times the dynamic size, futhermore | |
2572 // keep 4 objects 'free' | |
2573 ffs_query(Q_OBJECTS_FREE, &nobjects); | |
2574 tw(tr(TR_FUNC, TrTest, "Fill almost the rest of FFS\n")); | |
2575 n = 1000; // Avoid white spaces in the filename | |
2576 while (nobjects - 4 > 0) { | |
2577 ffs_query(Q_BYTES_FREE, &bytes_max); | |
2578 fsize = (bytes_max - dynamic_fsize * 3) / (nobjects - 4); | |
2579 | |
2580 tw(tr(TR_FUNC, TrTestHigh, "space,obj,fsize (%dk,%d,%d)\n", | |
2581 bytes_max/1024, nobjects, fsize)); | |
2582 | |
2583 if (fsize > fs.chunk_size_max) { | |
2584 // Roundup to the closet complete chunk or else we use to many inodes | |
2585 fsize = chunkalign(fsize); | |
2586 tw(tr(TR_FUNC, TrTestHigh, "Chunkalign %d\n", fsize)); | |
2587 } | |
2588 sprintf(static_name, "/Static-%4d", n++); | |
2589 error = tffs_file_write(static_name, (char*)tdata[TDATA_HUGE], fsize, | |
2590 FFS_O_CREATE); | |
2591 if (error == EFFS_NOSPACE) { | |
2592 tw(tr(TR_FUNC, TrTest, "WARNING: Fill failed with out of data space\n")); | |
2593 break; | |
2594 } | |
2595 else | |
2596 expect_ok(error); | |
2597 | |
2598 ffs_query(Q_OBJECTS_FREE, &nobjects); | |
2599 } | |
2600 tw(tr(TR_FUNC, TrTest, "Fill done, all static objects are written\n")); | |
2601 | |
2602 case_debug_help(2,0); // bstat trace | |
2603 | |
2604 // Save the age of all blocks | |
2605 save_block_ages(age); | |
2606 | |
2607 tw(tr(TR_FUNC, TrTest, "Update the dynamic file max %d times\n", nwrites)); | |
2608 | |
2609 for (i = 0, j = 0; i < nwrites; i++) { | |
2610 error = tffs_file_write(dynamic_name, (char*)tdata[TDATA_HUGE], | |
2611 dynamic_fsize, | |
2612 FFS_O_CREATE | FFS_O_TRUNC); | |
2613 expect_ok(error); | |
2614 | |
2615 if (i%1000 == 0) | |
2616 tw(tr(TR_FUNC, TrTest, "Write number %d\n", i)); | |
2617 | |
2618 if (has_all_block_ages_changed(age) == 1) { | |
2619 tw(tr(TR_FUNC, TrTest,"All block ages have changed %d\n", j)); | |
2620 j++; | |
2621 save_block_ages(age); | |
2622 } | |
2623 | |
2624 if (j >= nage_change) | |
2625 break; | |
2626 } | |
2627 | |
2628 test_statistics_print(); | |
2629 | |
2630 case_debug_help(2,0); // bstat trace | |
2631 | |
2632 if (j >= nage_change) | |
2633 return 0; | |
2634 | |
2635 return 1; //Error | |
2636 } | |
2637 | |
2638 /****************************************************************************** | |
2639 * Journalling and Recover Test Cases | |
2640 ******************************************************************************/ | |
2641 | |
2642 // Test journalling. Both for normal objects but also for journal file | |
2643 // itself! The following operations are tested for proper recovery: fcreate, | |
2644 // fupdate, relocate, delete, clean, fcontrol | |
2645 int case_journal(int p0, int p1) | |
2646 { | |
2647 struct test_file_s tf; | |
2648 struct ffs_state_s old, new; | |
2649 struct xstat_s stat_old, stat_new; | |
2650 int i, myspace = 0, mytmpspace, offset; | |
2651 char mytmpname[] = "/test-journal-tmp"; | |
2652 int testflags[] = { | |
2653 JOURNAL_TEST_EMPTY, // object not committed | |
2654 JOURNAL_TEST_WRITING, // object not committed | |
2655 JOURNAL_TEST_READY, // object ok | |
2656 JOURNAL_TEST_COMMITTING, // object ok | |
2657 JOURNAL_TEST_COMMITTED, // object ok | |
2658 JOURNAL_TEST_DONE, // object ok | |
2659 }; | |
2660 | |
2661 tf.name = "/test-journal"; | |
2662 tf.data = (char *) tdata[2]; | |
2663 tf.size = sdata[2]; | |
2664 | |
2665 #if 1 | |
2666 // NOTEME: Workaround, the below use of state_get can not handle if we | |
2667 // create a new journal while we run the test. Instead we create a | |
2668 // new journal before the test if we are close to full. | |
2669 if (fs.journal_pos >= fs.journal_size - (FFS_JOURNAL_MARGIN + 12) * | |
2670 sizeof(struct journal_s)) { | |
2671 tw(tr(TR_FUNC, TrTest, "Journal file (near) full!\n")); | |
2672 journal_create(fs.ijournal); | |
2673 } | |
2674 | |
2675 // NOTEME: Workaround, this test is unabel to handle a | |
2676 // block_alloc(). The 'extra' amount of lost space caused by a | |
2677 // block_alloc() and its block header dos cheat the test to fail. | |
2678 offset = data_prealloc(1024); | |
2679 expect_gt(offset, 0); | |
2680 #endif | |
2681 | |
2682 // init | |
2683 #if 1 | |
2684 error = tffs_fwrite(mytmpname, tf.data, tf.size); | |
2685 expect(error, EFFS_OK); | |
2686 error = tffs_xlstat(mytmpname, &stat_old); | |
2687 expect(error, EFFS_OK); | |
2688 mytmpspace = stat_old.space; | |
2689 ttw(ttr(TTrTest, "file '%s' uses %d bytes" NL, mytmpname, mytmpspace)); | |
2690 tw(tr(TR_FUNC, TrTestHigh, "file '%s' uses %d bytes\n", mytmpname, mytmpspace)); | |
2691 #endif | |
2692 error = tffs_fcreate(tf.name, tf.data, tf.size); | |
2693 expect(error, EFFS_OK); | |
2694 error = tffs_xlstat(tf.name, &stat_old); | |
2695 expect(error, EFFS_OK); | |
2696 myspace = stat_old.space; | |
2697 error = tffs_fcreate("/dummy", 0, 0); | |
2698 expect(error, EFFS_OK); | |
2699 ttw(ttr(TTrTest, "file '%s' uses %d bytes" NL, tf.name, myspace)); | |
2700 tw(tr(TR_FUNC, TrTestHigh, "file '%s' uses %d bytes\n", tf.name, myspace)); | |
2701 | |
2702 ttw(str(TTrTest, "fcreate:" NL)); | |
2703 tw(tr(TR_BEGIN, TrTestHigh, "fcreate:\n")); | |
2704 stat_old.inode = 0; | |
2705 for (i = 0; i < sizeof(testflags)/sizeof(int); i++) | |
2706 { | |
2707 // clean up from operation being tested | |
2708 tffs_remove(tf.name); | |
2709 | |
2710 ttw(ttr(TTrTest, "fs.testflags = 0x%x" NL, testflags[i])); | |
2711 tw(tr(TR_FUNC, TrTestHigh, "fs.testflags = 0x%x\n", testflags[i])); | |
2712 test_ffs_state_get(&old); | |
2713 | |
2714 error = tffs_fcontrol("/dummy", OC_FS_TESTFLAGS, testflags[i]); | |
2715 expect(error, EFFS_OK); | |
2716 | |
2717 error = tffs_fcreate(tf.name, tf.data, tf.size); | |
2718 expect(error, EFFS_OK); | |
2719 | |
2720 error = tffs_initialize(); | |
2721 expect(error, EFFS_OK); | |
2722 | |
2723 test_ffs_state_get(&new); | |
2724 | |
2725 tw(tr(TR_FUNC, TrTestHigh, | |
2726 "bytes_used new = %7d, old = %7d, diff = %d\n", | |
2727 new.bytes_used, old.bytes_used, new.bytes_used - old.bytes_used)); | |
2728 tw(tr(TR_FUNC, TrTestHigh, | |
2729 "bytes_lost new = %7d, old = %7d, diff = %d\n", | |
2730 new.bytes_lost, old.bytes_lost, | |
2731 new.bytes_lost - old.bytes_lost)); | |
2732 | |
2733 expect_eq(new.bytes_used, old.bytes_used + myspace); | |
2734 | |
2735 error = tffs_xlstat(tf.name, &stat_new); | |
2736 if (i < 2) { | |
2737 // object was not committed, so object must not exist | |
2738 expect(error, EFFS_NOTFOUND); | |
2739 expect_eq(new.objects_total, old.objects_total); | |
2740 expect_eq(new.bytes_lost, old.bytes_lost + myspace); | |
2741 } | |
2742 else { | |
2743 // object was committed, so object must exist | |
2744 expect(error, EFFS_OK); | |
2745 expect_ne(stat_old.inode, stat_new.inode); | |
2746 expect_eq(new.objects_total, old.objects_total + 1); | |
2747 expect_eq(new.bytes_lost, old.bytes_lost); | |
2748 } | |
2749 } | |
2750 ttw(str(TTrTest, "" NL)); | |
2751 tw(tr(TR_END, TrTestHigh, "")); | |
2752 | |
2753 ttw(str(TTrTest, "fupdate:" NL)); | |
2754 tw(tr(TR_BEGIN, TrTestHigh, "fupdate:\n")); | |
2755 error = tffs_xlstat(tf.name, &stat_old); | |
2756 expect(error, EFFS_OK); | |
2757 for (i = 0; i < sizeof(testflags)/sizeof(int); i++) | |
2758 { | |
2759 ttw(ttr(TTrTest, "fs.testflags = 0x%x" NL, testflags[i])); | |
2760 tw(tr(TR_FUNC, TrTestHigh, "fs.testflags = 0x%x\n", testflags[i])); | |
2761 test_ffs_state_get(&old); | |
2762 | |
2763 error = tffs_fcontrol("/dummy", OC_FS_TESTFLAGS, testflags[i]); | |
2764 expect(error, EFFS_OK); | |
2765 | |
2766 error = tffs_fupdate(tf.name, tf.data, tf.size); | |
2767 | |
2768 error = tffs_initialize(); | |
2769 expect(error, EFFS_OK); | |
2770 | |
2771 error = tffs_xlstat(tf.name, &stat_new); | |
2772 expect(error, EFFS_OK); | |
2773 | |
2774 if (i < 2) { | |
2775 // object was not committed, so stats must be equal | |
2776 error = test_expect_data(&stat_new, &stat_old, sizeof(stat)); | |
2777 if (error) return 1; | |
2778 } | |
2779 else { | |
2780 // object was committed, so inodes must not be equal | |
2781 expect_ne(stat_old.inode, stat_new.inode); | |
2782 } | |
2783 | |
2784 test_ffs_state_get(&new); | |
2785 | |
2786 tw(tr(TR_FUNC, TrTestHigh, | |
2787 "bytes_used new = %7d, old = %7d, diff = %d\n", | |
2788 new.bytes_used, old.bytes_used, new.bytes_used - old.bytes_used)); | |
2789 tw(tr(TR_FUNC, TrTestHigh, | |
2790 "bytes_lost new = %7d, old = %7d, diff = %d\n", | |
2791 new.bytes_lost, old.bytes_lost, | |
2792 new.bytes_lost - old.bytes_lost)); | |
2793 | |
2794 expect_eq(new.objects_total, old.objects_total); | |
2795 expect_eq(new.bytes_used, old.bytes_used + myspace); | |
2796 expect_eq(new.bytes_lost, old.bytes_lost + myspace); | |
2797 } | |
2798 ttw(str(TTrTest, "" NL)); | |
2799 tw(tr(TR_END, TrTestHigh, "")); | |
2800 | |
2801 ttw(str(TTrTest, "rename:" NL)); | |
2802 tw(tr(TR_BEGIN, TrTestHigh, "rename:\n")); | |
2803 error = tffs_fwrite(tf.name, tf.data, tf.size); | |
2804 expect(error, EFFS_OK); | |
2805 error = tffs_xlstat(tf.name, &stat_old); | |
2806 expect(error, EFFS_OK); | |
2807 | |
2808 for (i = 0; i < sizeof(testflags)/sizeof(int); i++) | |
2809 { | |
2810 ttw(ttr(TTrTest, "fs.testflags = 0x%x" NL, testflags[i])); | |
2811 tw(tr(TR_FUNC, TrTestHigh, "fs.testflags = 0x%x\n", testflags[i])); | |
2812 | |
2813 error = tffs_fwrite(mytmpname, tf.data, tf.size); | |
2814 expect_ok(error); | |
2815 error = tffs_fcontrol("/dummy", OC_FS_TESTFLAGS, testflags[i]); | |
2816 expect(error, EFFS_OK); | |
2817 | |
2818 test_ffs_state_get(&old); | |
2819 error = tffs_rename(mytmpname, tf.name); | |
2820 expect_ok(error); | |
2821 error = tffs_initialize(); | |
2822 expect(error, EFFS_OK); | |
2823 test_ffs_state_get(&new); | |
2824 | |
2825 // tf.name MUST always exist | |
2826 error = tffs_xlstat(tf.name, &stat_new); | |
2827 expect(error, EFFS_OK); | |
2828 | |
2829 tw(tr(TR_FUNC, TrTestHigh, | |
2830 "bytes_used new = %7d, old = %7d, diff = %d\n", | |
2831 new.bytes_used, old.bytes_used, new.bytes_used - old.bytes_used)); | |
2832 tw(tr(TR_FUNC, TrTestHigh, | |
2833 "bytes_lost new = %7d, old = %7d, diff = %d\n", | |
2834 new.bytes_lost, old.bytes_lost, | |
2835 new.bytes_lost - old.bytes_lost)); | |
2836 | |
2837 error = tffs_xlstat(mytmpname, &stat_new); | |
2838 if (i < 2) { | |
2839 // Journal not READY, so test-journal-tmp must exist | |
2840 expect(error, EFFS_OK); | |
2841 expect_eq(new.objects_total, old.objects_total); | |
2842 expect_eq(new.bytes_used, old.bytes_used + myspace); | |
2843 expect_eq(new.bytes_lost, old.bytes_lost + myspace); | |
2844 } | |
2845 else { | |
2846 // Journal ready, so test-journal-tmp must not exist | |
2847 expect(error, EFFS_NOTFOUND); | |
2848 expect_eq(new.objects_total, old.objects_total - 1); | |
2849 expect_eq(new.bytes_used, old.bytes_used + myspace); | |
2850 expect_eq(new.bytes_lost, old.bytes_lost + myspace + mytmpspace); | |
2851 expect_ne(stat_old.inode, stat_new.inode); | |
2852 } | |
2853 } | |
2854 | |
2855 ttw(str(TTrTest, "" NL)); | |
2856 tw(tr(TR_END, TrTestHigh, "")); | |
2857 | |
2858 // cleanup | |
2859 tffs_remove(tf.name); | |
2860 tffs_remove("/dummy"); | |
2861 | |
2862 return 0; | |
2863 } | |
2864 | |
2865 // Test block recovery | |
2866 int case_brecover(int p0, int p1) | |
2867 { | |
2868 struct test_file_s tf; | |
2869 struct ffs_state_s old, new; | |
2870 int j, inodes_block_old = 0, inodes_block_new = 0; | |
2871 int i, error; | |
2872 uint16 free_blocks; | |
2873 | |
2874 int testflags[] = { | |
2875 BLOCK_COMMIT_BEFORE, | |
2876 BLOCK_COMMIT_NO_VALID, | |
2877 BLOCK_COMMIT_OLD_FREE, | |
2878 BLOCK_COMMIT_AFTER | |
2879 }; | |
2880 | |
2881 int testflags_2[] = { | |
2882 BLOCK_RECLAIM_ALLOC, | |
2883 BLOCK_RECLAIM_CLEANING, | |
2884 BLOCK_RECLAIM_NO_CLEAN, | |
2885 }; | |
2886 | |
2887 tf.name = "/dummy4fctrl"; | |
2888 tf.data = (char *) tdata[0]; | |
2889 tf.size = sdata[0]; | |
2890 | |
2891 error = tffs_fwrite(tf.name, tf.data, tf.size); | |
2892 expect(error, EFFS_OK); | |
2893 | |
2894 for (j = 0; j < 3; j++) | |
2895 { | |
2896 test_ffs_state_get(&old); | |
2897 //case_lsr(0, 0); // temp | |
2898 | |
2899 error = ffs_query(Q_FS_INODES, (uint16 *) &inodes_block_old); | |
2900 expect(error, EFFS_OK); | |
2901 | |
2902 // Trigger block_commit() to fail | |
2903 error = tffs_fcontrol(tf.name, OC_FS_TESTFLAGS, testflags[j]); | |
2904 expect(error, EFFS_OK); | |
2905 | |
2906 inodes_reclaim(); | |
2907 | |
2908 error = tffs_initialize(); | |
2909 expect(error, EFFS_OK); | |
2910 | |
2911 error = ffs_query(Q_FS_INODES, (uint16 *) &inodes_block_new); | |
2912 expect(error, EFFS_OK); | |
2913 | |
2914 ttw(ttr(TTrTest, "inodes block %d -> %d" NL, | |
2915 inodes_block_old, inodes_block_new)); | |
2916 tw(tr(TR_FUNC, TrTestHigh, "inodes block %d -> %d\n", | |
2917 inodes_block_old, inodes_block_new)); | |
2918 | |
2919 switch (j) { | |
2920 case 0: expect(inodes_block_old, inodes_block_new); break; | |
2921 case 1: expect_ne(inodes_block_old, inodes_block_new); break; | |
2922 case 2: expect_ne(inodes_block_old, inodes_block_new); break; | |
2923 case 3: expect_ne(inodes_block_old, inodes_block_new); break; | |
2924 } | |
2925 | |
2926 test_ffs_state_get(&new); | |
2927 | |
2928 if (test_expect_objects(&old, &new)) | |
2929 return 1; | |
2930 | |
2931 } | |
2932 | |
2933 // FIXME: The below test often fails (recalaim data block and create new | |
2934 // jouranl file makes it to fail) | |
2935 if (p0 == 9) { | |
2936 // Test BLOCK_RECLAIM Fill up all data blocks until only one is | |
2937 // free. | |
2938 tw(tr(TR_FUNC, TrTest, "Test Block reclaim\n")); | |
2939 ttw(ttr(TTrTest, "Test Block reclaim..." )); | |
2940 tffs_mkdir("/rand"); | |
2941 | |
2942 ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks); | |
2943 while (free_blocks > 1) { | |
2944 error = case_mk_rand_file("/rand", 10000, 0); | |
2945 if (error < 0) { | |
2946 tw(tr(TR_FUNC, TrTest, "ERROR: case_mk_rand_file failed\n")); | |
2947 return 1; | |
2948 } | |
2949 ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks); | |
2950 } | |
2951 | |
2952 // case_mk_rand_file() will trigger a block_reclaim which will be | |
2953 // interruptet by the activated testflags. This will cause the FFS to | |
2954 // use the last free block! After a new init of ffs must it have | |
2955 // recovered. | |
2956 | |
2957 ttw(ttr(TTrTest, "use last block...")); | |
2958 for (i = 0; i < sizeof(testflags_2)/sizeof(int); i++) | |
2959 { | |
2960 error = tffs_fcontrol(tf.name, OC_FS_TESTFLAGS, testflags_2[i]); | |
2961 expect(error, EFFS_OK); | |
2962 | |
2963 do { | |
2964 case_cleanup(20000); | |
2965 error = case_mk_rand_file("/rand", 7000, 0); | |
2966 } while (error >= 0); | |
2967 expect(error, EFFS_NOSPACE); | |
2968 | |
2969 ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks); | |
2970 if (free_blocks != 0) { | |
2971 tw(tr(TR_FUNC, TrTestHigh, "ERROR: We still have free blocks!\n")); | |
2972 return 1; | |
2973 } | |
2974 | |
2975 error = tffs_initialize();// NOTE: error "WARNING: block_alloc failed" is okay. | |
2976 expect_ok(error); | |
2977 | |
2978 ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks); | |
2979 if (free_blocks != 1) { | |
2980 tw(tr(TR_FUNC, TrTestHigh, | |
2981 "ERROR: Wrong number of blocks free: %d\n", free_blocks)); | |
2982 return 1; | |
2983 } | |
2984 } | |
2985 // NOTE: We have to make this clenaup because we can not run if FFS is | |
2986 // near full | |
2987 case_cleanup(dev.blocksize); | |
2988 | |
2989 // This test will make data_block_reclaim() to fail before it has | |
2990 // relocated all objects | |
2991 ttw(ttr(TTrTest, "interrupt block_reclaim()...")); | |
2992 for (i = 0; i < 4; i++) | |
2993 { | |
2994 error = tffs_fcontrol(tf.name, OC_FS_TESTFLAGS, BLOCK_RECOVER_OBJECTS); | |
2995 expect(error, EFFS_OK); | |
2996 | |
2997 do { | |
2998 case_cleanup(20000); | |
2999 error = case_mk_rand_file("/rand", 7000, 0); | |
3000 } while (error >= 0); | |
3001 expect(error, EFFS_NOSPACE); | |
3002 // NOTE: error "WARNING: block_alloc failed" is okay. | |
3003 error = tffs_initialize(); | |
3004 expect_ok(error); | |
3005 } | |
3006 | |
3007 // Free up some space to the next test case. | |
3008 case_cleanup(dev.blocksize * 4); | |
3009 | |
3010 ttw(ttr(TTrTest, "Done" NL)); | |
3011 } | |
3012 | |
3013 return 0; | |
3014 } | |
3015 | |
3016 | |
3017 /****************************************************************************** | |
3018 * Specific/Special Test Cases | |
3019 ******************************************************************************/ | |
3020 | |
3021 // FIXME: Is this test case still valid after the new ffs_file_write() which | |
3022 // makes seveal chunks instead of on big? | |
3023 | |
3024 // Test filling a block to the full block size. We write N files of | |
3025 // decreasing powers of two, starting at half the block size. At the end we | |
3026 // are guaranteed to have at least one completelt full block. Also, we know | |
3027 // we have used at least <block_size> bytes of storage. | |
3028 int case_bfull(int p0, int p1) | |
3029 { | |
3030 struct ffs_state_s old, new; | |
3031 char myname[40] = "/antarctica/ice-"; | |
3032 int i, size, mysize, dirlen, space; | |
3033 | |
3034 if (param.data_blocks <= 1) { | |
3035 ttw(ttr(TTrTest, "WARNING: Too few blocks to run. Skip test" NL)); | |
3036 tw(tr(TR_FUNC, TrTest, "WARNING: Too few blocks to run. Skip test\n")); | |
3037 return 0; | |
3038 } | |
3039 | |
3040 error = tffs_mkdir("/antarctica"); | |
3041 | |
3042 error = case_cleanup(param.block_size + 10000); | |
3043 expect_ok(error); | |
3044 | |
3045 test_ffs_state_get(&old); | |
3046 dirlen = strlen(myname); | |
3047 space = 0; | |
3048 | |
3049 size = param.block_size/2; | |
3050 for (i = 0; size > 0; i++) { | |
3051 mysize = size - param.atomsize; | |
3052 if (mysize < 0) | |
3053 mysize = size; | |
3054 sprintf(&myname[dirlen], "%d", size); | |
3055 error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], mysize); | |
3056 expect(error, EFFS_OK); | |
3057 error = tffs_xlstat(myname, &xstat); | |
3058 expect(error, EFFS_OK); | |
3059 ttw(ttr(TTrTest, "%6d: %s" NL, xstat.space, myname)); | |
3060 tw(tr(TR_FUNC, TrTestHigh, "%6d: %s\n", xstat.space, myname)); | |
3061 space += xstat.space; | |
3062 size >>= 1; | |
3063 } | |
3064 | |
3065 test_ffs_state_get(&new); | |
3066 // Check space used. We have used a little more than <space> because we | |
3067 // have probably allocated one or two new blocks, and that is | |
3068 // dev.atomsize more bytes per block. | |
3069 tw(tr(TR_FUNC, TrTestHigh, | |
3070 "old.free = %d, new.free = %d, space used in test = %d\n", | |
3071 old.bytes_free, new.bytes_free, space)); | |
3072 expect_gt(old.bytes_free, new.bytes_free + space - 1); | |
3073 | |
3074 // remove half of the files | |
3075 size = param.block_size/2; | |
3076 for (i = 0; size > 0; i++) { | |
3077 if (i & 1) { | |
3078 sprintf(&myname[dirlen], "%d", size); | |
3079 error = tffs_remove(myname); | |
3080 expect(error, EFFS_OK); | |
3081 } | |
3082 size >>= 1; | |
3083 } | |
3084 | |
3085 return 0; | |
3086 } | |
3087 | |
3088 | |
3089 int case_list(int p0, int p1) | |
3090 { | |
3091 const struct testcase_s *p; | |
3092 | |
3093 tw(tr(TR_FUNC, TrTestHigh, "bigbuf = 0x%X, %d\n", bigbuf, bigbuf_size)); | |
3094 tw(tr(TR_FUNC, TrTestHigh, "smallbuf = 0x%X, %d\n", smallbuf, smallbuf_size)); | |
3095 | |
3096 ttw(ttr(TTrTest, "bigbuf = 0x%X, %d" NL, bigbuf, bigbuf_size)); | |
3097 ttw(ttr(TTrTest, "smallbuf = 0x%X, %d" NL, smallbuf, smallbuf_size)); | |
3098 | |
3099 ttw(str(TTrTest, "Test Cases:" NL)); | |
3100 for (p = testcase; p->name != 0; p++) { | |
3101 tw(tr(TR_FUNC, TrTest, "%8s: %s\n", p->name, p->comment)); | |
3102 ttw(ttr(TTrTest, "%8s: %s" NL, p->name, p->comment)); | |
3103 } | |
3104 return 0; | |
3105 } | |
3106 | |
3107 // Stress test the target. | |
3108 // p0 is number of times to run. Default is 10. | |
3109 // p1 is number of milli-seconds to wait between each file update. | |
3110 int case_stress(int p0, int p1) | |
3111 { | |
3112 char myname[20]; | |
3113 int i, mysize; | |
3114 char *mydata; | |
3115 | |
3116 mydata = (char *) tdata[TDATA_HUGE]; | |
3117 mysize = 9 * param.block_size / 16; | |
3118 | |
3119 if (p0 == 0) p0 = 10; | |
3120 if (p1 == 0) p1 = 1000; | |
3121 | |
3122 for (i = 0; i < p0; i++) { | |
3123 sprintf(myname, "/stress-%d", i); | |
3124 ttw(ttr(TTrTest, "/stress %d" NL, i)); | |
3125 error = tffs_fcreate(myname, (char *)mydata, mysize); | |
3126 expect(error, EFFS_OK); | |
3127 tffs_delay(p1); | |
3128 error = tffs_remove(myname); | |
3129 expect(error, EFFS_OK); | |
3130 } | |
3131 | |
3132 return 0; | |
3133 } | |
3134 | |
3135 // Test ffs with many (small) files. p0 is number of times to write all the | |
3136 // files. Default is two e.g. one create and one update | |
3137 int case_mfiles(int p0, int p1) | |
3138 { | |
3139 char myname[40]; | |
3140 int i, j; | |
3141 | |
3142 static struct test_file_s tf[] = | |
3143 { | |
3144 { MFDIR "/MSCAP", 0, 6 }, | |
3145 { MFDIR "/IMEI", 0, 8 }, | |
3146 { MFDIR "/CLASS2", 0, 3 }, | |
3147 { MFDIR "/CLASS3", 0, 2 }, | |
3148 { MFDIR "/MSSUP", 0, 5 }, | |
3149 { MFDIR "/MSSET", 0, 83 }, | |
3150 { MFDIR "/UPN", 0, 165 }, | |
3151 { MFDIR "/CTIM", 0, 92 }, | |
3152 { MFDIR "/CCNT", 0, 52 }, | |
3153 { MFDIR "/ECC", 0, 15 }, | |
3154 { MFDIR "/ORG", 0, 2650 }, | |
3155 { MFDIR "/BCCHINF", 0, 54 }, | |
3156 { MFDIR "/CCP", 0, 7 }, | |
3157 { MFDIR "/EXT1", 0, 13 }, | |
3158 { MFDIR "/SIMLCK", 0, 62 }, | |
3159 { MFDIR "/SIMLCKEXT",0, 172 }, | |
3160 { MFDIR "/SECURITY", 0, 8 }, | |
3161 { MFDIR "/MAIN", 0, 8 }, | |
3162 { MFDIR "/SFK", 0, 8 }, | |
3163 { MFDIR "/FAULT", 0, 8 }, | |
3164 { MFDIR "/DEBUG", 0, 8 }, | |
3165 { MFDIR "/POWER", 0, 8 }, | |
3166 { MFDIR "/KEYB", 0, 64 }, | |
3167 { MFDIR "/RADIO", 0, 8 }, | |
3168 { MFDIR "/CGMI", 0, 20 }, | |
3169 { MFDIR "/CGMM", 0, 20 }, | |
3170 { MFDIR "/CGMR", 0, 20 }, | |
3171 { MFDIR "/CGSN", 0, 20 }, | |
3172 { MFDIR "/SMSPRFL", 0, 206 }, | |
3173 { MFDIR "/PLMN", 0, 68 }, | |
3174 { MFDIR "/ATRADIO", 0, 2700 }, | |
3175 { MFDIR "/GROUP", 0, 1122 } | |
3176 }; | |
3177 | |
3178 error = tffs_preformat(0xDEAD); | |
3179 expect(error, EFFS_OK); | |
3180 error = tffs_format("/ffs/i2048o1024", 0x2BAD); | |
3181 expect(error, EFFS_OK); | |
3182 error = tffs_mkdir(MFDIR); | |
3183 expect(error, EFFS_OK); | |
3184 | |
3185 if (p0 == 0) p0 = 2; | |
3186 | |
3187 for (j = 0; j < p0; j++) { | |
3188 tw(tr(TR_FUNC, TrTestHigh, "mf: Writing many files, loop %d\n", j)); | |
3189 | |
3190 tw(tr(TR_FUNC, TrTestHigh, "SMS000..SMS099\n")); | |
3191 for (i = 0; i < 100; i++) { | |
3192 sprintf(myname, MFDIR "/SMS%03d", i); | |
3193 error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 176); | |
3194 expect(error, EFFS_OK); | |
3195 } | |
3196 | |
3197 tw(tr(TR_FUNC, TrTestHigh, "LDN/LRN/LMN000..LDN/LRN/LMN009\n")); | |
3198 for (i = 0; i < 10; i++) { | |
3199 sprintf(myname, MFDIR "/LDN%03d", i); | |
3200 error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 31); | |
3201 expect(error, EFFS_OK); | |
3202 sprintf(myname, MFDIR "/LRN%03d", i); | |
3203 error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 32); | |
3204 expect(error, EFFS_OK); | |
3205 sprintf(myname, MFDIR "/LMN%03d", i); | |
3206 error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 30); | |
3207 expect(error, EFFS_OK); | |
3208 } | |
3209 | |
3210 tw(tr(TR_FUNC, TrTestHigh, "ADN000..ADN149\n")); | |
3211 for (i = 0; i < 150; i++) { | |
3212 sprintf(myname, MFDIR "/ADN%03d", i); | |
3213 error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 43); | |
3214 expect(error, EFFS_OK); | |
3215 } | |
3216 | |
3217 tw(tr(TR_FUNC, TrTestHigh, "PCM Files...\n")); | |
3218 for (i = 0; i < sizeof(tf)/sizeof(struct test_file_s); i++) { | |
3219 error = tffs_fwrite(tf[i].name, | |
3220 (char *) tdata[TDATA_HUGE], tf[i].size); | |
3221 expect(error, EFFS_OK); | |
3222 } | |
3223 } | |
3224 | |
3225 error = tffs_exit(); | |
3226 expect(error, EFFS_OK); | |
3227 | |
3228 return 0; | |
3229 } | |
3230 | |
3231 | |
3232 int case_open(int p0, int p1) | |
3233 { | |
3234 fd_t fdi; | |
3235 char myname[20]; | |
3236 int i, size; | |
3237 | |
3238 #define RDONLY FFS_O_RDONLY | |
3239 #define WRONLY FFS_O_WRONLY | |
3240 #define APPEND FFS_O_APPEND | |
3241 #define CREATE FFS_O_CREATE | |
3242 #define EXCL FFS_O_EXCL | |
3243 #define TRUNC FFS_O_TRUNC | |
3244 | |
3245 ffs_options_t non_exist_invalid[] = { | |
3246 ( 0 ), | |
3247 ( RDONLY | CREATE ), | |
3248 ( RDONLY | CREATE | EXCL ), | |
3249 ( RDONLY | CREATE | TRUNC ), | |
3250 ( RDONLY | CREATE | EXCL | TRUNC ), | |
3251 ( RDONLY | EXCL ), | |
3252 ( RDONLY | EXCL | TRUNC ), | |
3253 ( RDONLY | TRUNC ), | |
3254 ( EXCL ), | |
3255 ( EXCL | TRUNC ), | |
3256 ( TRUNC ), | |
3257 ( CREATE | TRUNC ), | |
3258 ( CREATE | EXCL | TRUNC ), | |
3259 ( CREATE | EXCL ), | |
3260 ( CREATE ), | |
3261 ( APPEND ), | |
3262 ( APPEND | EXCL ), | |
3263 ( APPEND | EXCL | TRUNC ), | |
3264 ( APPEND | TRUNC ), | |
3265 ( APPEND | CREATE | TRUNC ), | |
3266 ( APPEND | CREATE | EXCL ), | |
3267 ( APPEND | CREATE | EXCL ), | |
3268 ( APPEND | CREATE ), | |
3269 ( RDONLY | APPEND ), | |
3270 ( RDONLY | APPEND | EXCL ), | |
3271 ( RDONLY | APPEND | EXCL | TRUNC ), | |
3272 ( RDONLY | APPEND | TRUNC ), | |
3273 ( RDONLY | APPEND | CREATE | TRUNC ), | |
3274 ( RDONLY | APPEND | CREATE | EXCL | TRUNC ), | |
3275 ( RDONLY | APPEND | CREATE | EXCL ), | |
3276 ( RDONLY | APPEND | CREATE ) | |
3277 }; | |
3278 | |
3279 ffs_options_t non_exist_notfound[] = { | |
3280 ( WRONLY | APPEND ), | |
3281 ( WRONLY | APPEND | EXCL ), | |
3282 ( WRONLY | APPEND | EXCL | TRUNC ), | |
3283 ( WRONLY | APPEND | TRUNC ), | |
3284 ( WRONLY ), | |
3285 ( WRONLY | EXCL ), | |
3286 ( WRONLY | EXCL | TRUNC ), | |
3287 ( WRONLY | TRUNC ), | |
3288 ( RDONLY | WRONLY ), | |
3289 ( RDONLY | WRONLY | EXCL ), | |
3290 ( RDONLY | WRONLY | EXCL | TRUNC ), | |
3291 ( RDONLY | WRONLY | TRUNC ), | |
3292 ( RDONLY | WRONLY | APPEND ), | |
3293 ( RDONLY | WRONLY | APPEND | EXCL ), | |
3294 ( RDONLY | WRONLY | APPEND | EXCL | TRUNC ), | |
3295 ( RDONLY | WRONLY | APPEND | TRUNC ), | |
3296 ( RDONLY ) | |
3297 }; | |
3298 | |
3299 ffs_options_t non_exist_fd_offset[] = { | |
3300 ( WRONLY | APPEND | CREATE | TRUNC ), | |
3301 ( WRONLY | APPEND | CREATE | EXCL | TRUNC ), | |
3302 ( WRONLY | APPEND | CREATE | EXCL ), | |
3303 ( WRONLY | APPEND | CREATE ), | |
3304 ( WRONLY | CREATE | TRUNC ), | |
3305 ( WRONLY | CREATE | EXCL | TRUNC ), | |
3306 ( WRONLY | CREATE | EXCL ), | |
3307 ( WRONLY | CREATE ), | |
3308 ( RDONLY | WRONLY | CREATE | TRUNC ), | |
3309 ( RDONLY | WRONLY | CREATE | EXCL | TRUNC ), | |
3310 ( RDONLY | WRONLY | CREATE | EXCL ), | |
3311 ( RDONLY | WRONLY | CREATE ), | |
3312 | |
3313 ( RDONLY | WRONLY | APPEND | CREATE | TRUNC ), | |
3314 ( RDONLY | WRONLY | APPEND | CREATE | EXCL | TRUNC ), | |
3315 ( RDONLY | WRONLY | APPEND | CREATE | EXCL ), | |
3316 ( RDONLY | WRONLY | APPEND | CREATE ) | |
3317 }; | |
3318 | |
3319 ffs_options_t exist_invalid[] = { | |
3320 ( EXCL ), | |
3321 ( EXCL | TRUNC ), | |
3322 ( TRUNC ), | |
3323 ( CREATE | TRUNC ), | |
3324 ( CREATE | EXCL | TRUNC ), | |
3325 ( CREATE | EXCL ), | |
3326 ( CREATE ), | |
3327 ( APPEND ), | |
3328 ( APPEND | EXCL ), | |
3329 ( APPEND | EXCL | TRUNC ), | |
3330 ( APPEND | TRUNC ), | |
3331 ( APPEND | CREATE | TRUNC ), | |
3332 ( APPEND | CREATE | EXCL | TRUNC ), | |
3333 ( APPEND | CREATE | EXCL ), | |
3334 ( APPEND | CREATE ), | |
3335 ( RDONLY | APPEND ), | |
3336 ( RDONLY | APPEND | EXCL ), | |
3337 ( RDONLY | APPEND | EXCL | TRUNC ), | |
3338 ( RDONLY | APPEND | TRUNC ), | |
3339 ( RDONLY | APPEND | CREATE | TRUNC ), | |
3340 ( RDONLY | APPEND | CREATE | EXCL | TRUNC ), | |
3341 ( RDONLY | APPEND | CREATE | EXCL ), | |
3342 ( RDONLY | APPEND | CREATE ), | |
3343 ( RDONLY | EXCL ), | |
3344 ( RDONLY | EXCL | TRUNC ), | |
3345 ( RDONLY | TRUNC ), | |
3346 ( RDONLY | CREATE | TRUNC ), | |
3347 ( RDONLY | CREATE | EXCL | TRUNC ), | |
3348 ( RDONLY | CREATE | EXCL ), | |
3349 ( RDONLY | CREATE ) | |
3350 }; | |
3351 | |
3352 ffs_options_t exist_exist[] = { | |
3353 ( WRONLY | APPEND | CREATE | EXCL | TRUNC ), | |
3354 ( WRONLY | APPEND | CREATE | EXCL ), | |
3355 ( WRONLY | CREATE | EXCL | TRUNC ), | |
3356 ( WRONLY | CREATE | EXCL ), | |
3357 ( RDONLY | WRONLY | CREATE | EXCL | TRUNC ), | |
3358 ( RDONLY | WRONLY | CREATE | EXCL ), | |
3359 ( RDONLY | WRONLY | APPEND | CREATE | EXCL | TRUNC ), | |
3360 ( RDONLY | WRONLY | APPEND | CREATE | EXCL ) | |
3361 }; | |
3362 | |
3363 ffs_options_t exist_fd_offset[] = { | |
3364 ( WRONLY | APPEND ), | |
3365 ( WRONLY | APPEND | EXCL ), | |
3366 ( WRONLY | APPEND | EXCL | TRUNC ), | |
3367 ( WRONLY | APPEND | TRUNC ), | |
3368 ( WRONLY | APPEND | CREATE | TRUNC ), | |
3369 ( WRONLY | APPEND | CREATE ), | |
3370 ( RDONLY ), | |
3371 ( RDONLY | WRONLY ), | |
3372 ( RDONLY | WRONLY | EXCL ), | |
3373 ( RDONLY | WRONLY | EXCL | TRUNC ), | |
3374 ( RDONLY | WRONLY | TRUNC ), | |
3375 ( RDONLY | WRONLY | CREATE | TRUNC ), | |
3376 ( RDONLY | WRONLY | CREATE ), | |
3377 ( RDONLY | WRONLY | APPEND ), | |
3378 ( RDONLY | WRONLY | APPEND | EXCL ), | |
3379 ( RDONLY | WRONLY | APPEND | EXCL | TRUNC ), | |
3380 ( RDONLY | WRONLY | APPEND | TRUNC ), | |
3381 ( RDONLY | WRONLY | APPEND | CREATE | TRUNC ), | |
3382 ( RDONLY | WRONLY | APPEND | CREATE ), | |
3383 ( WRONLY ), | |
3384 ( WRONLY | EXCL ), | |
3385 ( WRONLY | EXCL | TRUNC ), | |
3386 ( WRONLY | TRUNC ), | |
3387 ( WRONLY | CREATE | TRUNC ), | |
3388 ( WRONLY | CREATE ) | |
3389 | |
3390 }; | |
3391 | |
3392 // Cleanup | |
3393 for (i = 0; i < 20; i++) { | |
3394 sprintf(myname, "/stream%d", i); | |
3395 tffs_remove(myname); | |
3396 } | |
3397 | |
3398 tw(tr(TR_FUNC, TrTestHigh, "Various open options, file non-existing\n")); | |
3399 ttw(str(TTrTest, "Various open options, file non-existing" NL)); | |
3400 | |
3401 for (i = 0; i < sizeof(non_exist_invalid)/sizeof(ffs_options_t); i++) { | |
3402 sprintf(myname, "/stream%d", i - i/20 * 20); | |
3403 fdi = tffs_open(myname, non_exist_invalid[i]); | |
3404 expect(fdi, EFFS_INVALID); | |
3405 } | |
3406 | |
3407 for (i = 0; i < sizeof(non_exist_notfound)/sizeof(ffs_options_t); i++) { | |
3408 sprintf(myname, "/stream%d", i - i/20 * 20); | |
3409 fdi = tffs_open(myname, non_exist_notfound[i]); | |
3410 expect(fdi, EFFS_NOTFOUND); | |
3411 } | |
3412 | |
3413 for (i = 0; i < sizeof(non_exist_fd_offset)/sizeof(ffs_options_t); i++) { | |
3414 sprintf(myname, "/stream%d", i - i/20 * 20); | |
3415 fdi = tffs_open(myname, non_exist_fd_offset[i]); | |
3416 expect(fdi, FFS_FD_OFFSET); | |
3417 tffs_close(fdi); | |
3418 } | |
3419 | |
3420 // Make FFS_FD_MAX number of files and write some data for later use | |
3421 tw(tr(TR_FUNC, TrTestHigh, "Create %d files with data \n", fs.fd_max)); | |
3422 for (i = 0; i < fs.fd_max; i++) { | |
3423 sprintf(myname, "/stream%d", i); | |
3424 fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC); | |
3425 expect(fdi, i + FFS_FD_OFFSET); | |
3426 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31); | |
3427 expect(size, 31); | |
3428 } | |
3429 | |
3430 // Try to open one more file, this will make a error! | |
3431 sprintf(myname, "/stream%d", i++); | |
3432 fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC); | |
3433 expect(fdi, EFFS_NUMFD); | |
3434 | |
3435 for (i = 0; i < fs.fd_max; i++) { | |
3436 error = tffs_close(i + FFS_FD_OFFSET); | |
3437 expect(error, EFFS_OK); | |
3438 } | |
3439 | |
3440 tw(tr(TR_FUNC, TrTestHigh, | |
3441 "Open same file multiple times in RDONLY mode\n")); | |
3442 for (i = 0; i < fs.fd_max; i++) { | |
3443 fdi = tffs_open("/stream2", FFS_O_RDONLY); | |
3444 expect(fdi, i + FFS_FD_OFFSET); | |
3445 } | |
3446 | |
3447 for (i = 0; i < fs.fd_max; i++) { | |
3448 error = tffs_close(i + FFS_FD_OFFSET); | |
3449 expect(error, 0); | |
3450 } | |
3451 | |
3452 tw(tr(TR_FUNC, TrTestHigh, | |
3453 "Open in WRONLY and try to open same file in WR or RD\n")); | |
3454 fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND); | |
3455 expect(fdi, FFS_FD_OFFSET); | |
3456 fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND); | |
3457 expect(fdi, EFFS_LOCKED); | |
3458 fdi = tffs_open("/stream1", FFS_O_RDONLY ); | |
3459 expect(fdi, EFFS_LOCKED); | |
3460 error = tffs_close(FFS_FD_OFFSET); | |
3461 expect(error, 0); | |
3462 | |
3463 tw(tr(TR_FUNC, TrTestHigh, | |
3464 "Open in READONLY and try to open same file WRONLY\n")); | |
3465 fdi = tffs_open("/stream1", FFS_O_RDONLY); | |
3466 expect(fdi, FFS_FD_OFFSET); | |
3467 fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND); | |
3468 expect(fdi, EFFS_LOCKED); | |
3469 error = tffs_close(FFS_FD_OFFSET); | |
3470 expect(error, 0); | |
3471 | |
3472 tw(tr(TR_FUNC, TrTestHigh, "Various open options, file exists\n")); | |
3473 ttw(str(TTrTest, "Various open options, file exists" NL)); | |
3474 | |
3475 for (i = 0; i < sizeof(exist_invalid)/sizeof(ffs_options_t); i++) { | |
3476 sprintf(myname, "/stream%d", i - i/20 * 20); | |
3477 fdi = tffs_open(myname, exist_invalid[i]); | |
3478 expect(fdi, EFFS_INVALID); | |
3479 } | |
3480 | |
3481 for (i = 0; i < sizeof(exist_exist)/sizeof(ffs_options_t); i++) { | |
3482 sprintf(myname, "/stream%d", i - i/20 * 20); | |
3483 fdi = tffs_open(myname, exist_exist[i]); | |
3484 expect(fdi, EFFS_EXISTS); | |
3485 tffs_close(fdi); | |
3486 } | |
3487 | |
3488 for (i = 0; i < sizeof(exist_fd_offset)/sizeof(ffs_options_t); i++) { | |
3489 sprintf(myname, "/stream%d", i - i/10 * 10); | |
3490 fdi = tffs_open(myname, exist_fd_offset[i]); | |
3491 expect(fdi, FFS_FD_OFFSET); | |
3492 tffs_close(fdi); | |
3493 } | |
3494 | |
3495 tw(tr(TR_FUNC, TrTestHigh, "Try to create a file with a dir name\n")); | |
3496 error = tffs_mkdir("/streams"); | |
3497 | |
3498 fdi = tffs_open("/streams", FFS_O_WRONLY | FFS_O_APPEND | FFS_O_CREATE); | |
3499 expect(fdi, EFFS_NOTAFILE); | |
3500 | |
3501 tw(tr(TR_FUNC, TrTestHigh, | |
3502 "Try to use fwrite, fcreate, fread and remove on a open file\n")); | |
3503 fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND); | |
3504 expect(fdi, FFS_FD_OFFSET); | |
3505 | |
3506 error = tffs_fcreate("/stream1", TDATA(2)); | |
3507 expect(error, EFFS_EXISTS); | |
3508 | |
3509 error = tffs_file_write("/stream1", (char *) tdata[TDATA_HUGE], 31, | |
3510 FFS_O_CREATE | FFS_O_TRUNC); | |
3511 expect(error, EFFS_LOCKED); | |
3512 | |
3513 error = tffs_file_read("/stream1", bigbuf, 31); | |
3514 expect(error, EFFS_LOCKED); | |
3515 | |
3516 error = tffs_remove("/stream1"); | |
3517 expect(error, EFFS_LOCKED); | |
3518 | |
3519 error = tffs_close(fdi); | |
3520 expect(error, 0); | |
3521 | |
3522 #undef RDONLY | |
3523 #undef WRONLY | |
3524 #undef APPEND | |
3525 #undef CREATE | |
3526 #undef EXCL | |
3527 #undef TRUNC | |
3528 | |
3529 return 0; | |
3530 } | |
3531 | |
3532 int twrite_seek(fd_t fdi, offset_t offset, int whence) | |
3533 { | |
3534 int size; | |
3535 | |
3536 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + 10, 100); | |
3537 if (test_expect(size, 100) < 0) return -1; | |
3538 | |
3539 offset = tffs_seek(fdi, offset, whence); | |
3540 if (test_expect_ok(offset)) return -1; | |
3541 | |
3542 return offset; | |
3543 } | |
3544 | |
3545 int tseek_read(fd_t fdi, offset_t offset, int whence, offset_t src_offset) | |
3546 { | |
3547 int size; | |
3548 | |
3549 offset = tffs_seek(fdi, offset, whence); | |
3550 if (test_expect_ok(offset)) return -1; | |
3551 | |
3552 size = tffs_read(fdi, bigbuf, 100); | |
3553 if (test_expect(size, 100) < 0) return -1; | |
3554 | |
3555 error = test_expect_data((char*)tdata[TDATA_HUGE] + src_offset, bigbuf, size); | |
3556 if (error) return error; | |
3557 | |
3558 return offset; | |
3559 } | |
3560 | |
3561 int tseek_write(fd_t fdi, offset_t offset, int whence, offset_t src_offset) | |
3562 { | |
3563 int size; | |
3564 | |
3565 offset = tffs_seek(fdi, offset, whence); | |
3566 if (test_expect_ok(offset)) return -1; | |
3567 | |
3568 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + src_offset + offset, | |
3569 fs.chunk_size_max / 2); | |
3570 if (test_expect(size, fs.chunk_size_max / 2) < 0) return -1; | |
3571 | |
3572 return offset; | |
3573 } | |
3574 | |
3575 int case_rw(int p0, int p1) | |
3576 { | |
3577 int i, size, offset; | |
3578 fd_t fdi; | |
3579 | |
3580 const char *dirs[] = { "/streams", "/streams/rw", "/streams/rw/multi", | |
3581 "/streams/rw/multi/write" }; | |
3582 | |
3583 error = case_cleanup(5 * fs.chunk_size_max); | |
3584 expect_ok(error); | |
3585 | |
3586 for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) { | |
3587 error = tffs_mkdir(dirs[i]); | |
3588 } | |
3589 | |
3590 tw(tr(TR_FUNC, TrTestHigh, | |
3591 "Test create and append of file, small and huge\n")); | |
3592 ttw(str(TTrTest, "Test create and append of file, small and huge" NL)); | |
3593 | |
3594 fdi = tffs_open("/streams/rw_test", | |
3595 FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC); | |
3596 expect(fdi, FFS_FD_OFFSET); | |
3597 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31); | |
3598 expect(size, 31); | |
3599 error = tffs_close(fdi); expect(error, EFFS_OK); | |
3600 | |
3601 fdi = tffs_open("/streams/rw_test", FFS_O_WRONLY | FFS_O_APPEND); | |
3602 expect(fdi, FFS_FD_OFFSET); | |
3603 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + 31, 2 * fs.chunk_size_max); | |
3604 expect(size, 2 * fs.chunk_size_max); | |
3605 | |
3606 error = tffs_close(fdi); expect(error, EFFS_OK); | |
3607 | |
3608 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
3609 ttw(ttr(TTrTest, "Validate data" NL)); | |
3610 size = tffs_fread("/streams/rw_test", bigbuf, bigbuf_size); | |
3611 expect(size, 31 + 2 * fs.chunk_size_max); | |
3612 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size); | |
3613 if (error) return 1; | |
3614 | |
3615 // Provoke EFFS_FILETOOBIG | |
3616 error = tffs_fread("/streams/rw_test", bigbuf, size - 1); | |
3617 expect(error, EFFS_FILETOOBIG); | |
3618 error = tffs_fread("/streams/rw_test", bigbuf, size + 1); | |
3619 expect_ok(error); | |
3620 error = tffs_fread("/streams/rw_test", bigbuf, size); | |
3621 expect_ok(error); | |
3622 | |
3623 // Update file from zero, middle (between to chunks) and end. File with | |
3624 // and without data in seghead. Update the first 100 bytes (new data | |
3625 // have a offset of 10 so the data not is identical with the existing | |
3626 // ones). | |
3627 fdi = tffs_open("/streams/rw_test", FFS_O_RDWR); | |
3628 expect(fdi, FFS_FD_OFFSET); | |
3629 | |
3630 // write 100 bytes and seek to 50 bytes before end of the first chunk | |
3631 expect_ok(twrite_seek(fdi, fs.chunk_size_max - 50, FFS_SEEK_SET)); | |
3632 | |
3633 // write 100 bytes, seek to 50 bytes from the end of the file | |
3634 expect_ok(twrite_seek(fdi, -50, FFS_SEEK_END)); | |
3635 | |
3636 // Write 100 bytes. This will update the last 19 bytes of second chunk, | |
3637 // update and append data to the last chunk. Read the last data but | |
3638 // only 80 bytes because they are in the buffer | |
3639 expect_ok(twrite_seek(fdi, -80, FFS_SEEK_CUR)); | |
3640 | |
3641 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
3642 ttw(ttr(TTrTest, "Validate data" NL)); | |
3643 | |
3644 size = tffs_read(fdi, bigbuf, 100); | |
3645 expect(size, 80); | |
3646 error = test_expect_data((char *)tdata[TDATA_HUGE] + 10 + 20, bigbuf, size); | |
3647 if (error) return 1; | |
3648 | |
3649 // Seek to start of file and read the first 100 bytes that was updated | |
3650 offset = tseek_read(fdi, 0, FFS_SEEK_SET, 10); | |
3651 expect_ok(offset); | |
3652 | |
3653 // Read 100 bytes more to make sure that the old data still is valid | |
3654 offset = tseek_read(fdi, 0, FFS_SEEK_CUR, 100); | |
3655 expect_ok(offset); | |
3656 | |
3657 // Seek to 50 bytes before end of the first chunk and read 100 bytes | |
3658 offset = tseek_read(fdi, fs.chunk_size_max - 50, FFS_SEEK_SET, 10); | |
3659 expect_ok(offset); | |
3660 | |
3661 // Read 100 bytes more to make sure that the old data still is valid | |
3662 offset = tseek_read(fdi, 0, FFS_SEEK_CUR, offset + 100); | |
3663 expect_ok(offset); | |
3664 | |
3665 // Read the last 100 bytes (updated data from 2 chunks) | |
3666 offset = tseek_read(fdi, -100, FFS_SEEK_END, 10); | |
3667 expect_ok(offset); | |
3668 | |
3669 error = tffs_close(fdi); | |
3670 expect(error, EFFS_OK); | |
3671 | |
3672 // Test where there is data in the seghead | |
3673 size = tffs_file_write("/streams/rw_test", (char*) tdata[TDATA_HUGE], | |
3674 2 * fs.chunk_size_max, FFS_O_CREATE | FFS_O_TRUNC); | |
3675 | |
3676 fdi = tffs_open("/streams/rw_test", FFS_O_RDWR); | |
3677 expect(fdi, FFS_FD_OFFSET); | |
3678 | |
3679 // Update the last half of the last chunk | |
3680 expect_ok(tseek_write(fdi, -fs.chunk_size_max / 2, FFS_SEEK_END, 10)); | |
3681 | |
3682 // Update the first half of the last chunk | |
3683 expect_ok(tseek_write(fdi, fs.chunk_size_max, FFS_SEEK_SET, 10)); | |
3684 | |
3685 // Update the first half of the seghead | |
3686 expect_ok(tseek_write(fdi, 0, FFS_SEEK_SET, 10)); | |
3687 | |
3688 // Update the last half of the seghead, but flush the buffer so it have | |
3689 // to write and read the previous updated data | |
3690 error = tffs_fdatasync(fdi); | |
3691 expect(error, EFFS_OK); | |
3692 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + 10 + fs.chunk_size_max/2, | |
3693 fs.chunk_size_max/2); | |
3694 expect(size, fs.chunk_size_max/2); | |
3695 | |
3696 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
3697 ttw(ttr(TTrTest, "Validate data" NL)); | |
3698 // Read the complete file, all the data should have a offset of 10 bytes now! | |
3699 offset = tffs_seek(fdi, 0, FFS_SEEK_SET); | |
3700 expect_ok(offset); | |
3701 | |
3702 size = tffs_read(fdi, bigbuf, bigbuf_size); | |
3703 expect(size, 2 * fs.chunk_size_max); | |
3704 error = test_expect_data((char *)tdata[TDATA_HUGE] + 10, bigbuf, size); | |
3705 if (error) return 1; | |
3706 | |
3707 error = tffs_close(fdi); expect(error, 0); | |
3708 | |
3709 // Test bad fdi, write in RDONLY and read from WRONLY | |
3710 fdi = tffs_open("/streams/rw_test", FFS_O_RDONLY); | |
3711 expect(fdi, FFS_FD_OFFSET); | |
3712 size = tffs_read(fdi + 1, bigbuf, 31); | |
3713 expect(size, EFFS_BADFD); | |
3714 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31); | |
3715 tw(tr(TR_END, TrApi, "} %d\n", size)); // Avoid wrong indent | |
3716 expect(size, EFFS_INVALID); | |
3717 error = tffs_close(fdi); expect(error, 0); | |
3718 | |
3719 fdi = tffs_open("/streams/rw_test", FFS_O_WRONLY | FFS_O_APPEND); | |
3720 expect(fdi, FFS_FD_OFFSET); | |
3721 size = tffs_read(fdi, bigbuf, 31); | |
3722 expect(size, EFFS_INVALID); | |
3723 error = tffs_close(fdi); expect(error, 0); | |
3724 | |
3725 // Test for bad file name | |
3726 fdi = tffs_open("/stream&!'*", FFS_O_WRONLY | FFS_O_CREATE); | |
3727 expect(fdi, EFFS_BADNAME); | |
3728 | |
3729 // Test for bad file name | |
3730 fdi = tffs_open("/%$#.+-_,Z19", FFS_O_WRONLY | FFS_O_CREATE); | |
3731 expect(fdi, FFS_FD_OFFSET); | |
3732 tffs_close(fdi); | |
3733 | |
3734 return 0; | |
3735 } | |
3736 | |
3737 int case_multi_open(int p0, int p1) | |
3738 { | |
3739 int i, j, size; | |
3740 fd_t fdi; | |
3741 | |
3742 const char *dirs[] = { "/streams", "/streams/rw", "/streams/rw/multi", | |
3743 "/streams/rw/multi/write" }; | |
3744 | |
3745 const char *file[] = { "/x-rw", "/streams/rw/x-rw", | |
3746 "/streams/rw/multi/x-rw", | |
3747 "/streams/rw/multi/write/x-rw" }; | |
3748 | |
3749 error = case_cleanup(fs.fd_max * 50 * 10 + 5000); | |
3750 expect_ok(error); | |
3751 | |
3752 for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) { | |
3753 error = tffs_mkdir(dirs[i]); | |
3754 } | |
3755 | |
3756 // Open multiply files from difference subdirectorys | |
3757 // and write/read X times to/from file (this also test truncate option) | |
3758 for (i = 0; i < fs.fd_max; i++) { | |
3759 fdi = tffs_open( file[i], FFS_O_WRONLY | FFS_O_APPEND | | |
3760 FFS_O_CREATE | FFS_O_TRUNC); | |
3761 expect(fdi, i + FFS_FD_OFFSET); | |
3762 } | |
3763 | |
3764 for (i = 0; i < fs.fd_max; i++) { | |
3765 for (j = 0; j < 10; j++) { | |
3766 size = tffs_write(i + FFS_FD_OFFSET, (char *) tdata[TDATA_HUGE], 50); | |
3767 expect(size, 50); | |
3768 } | |
3769 } | |
3770 // Run test with p0 != 0 to stress the test | |
3771 if (p0) { error = test_run("irec;drec;"); if (error > 0) return 1; } | |
3772 | |
3773 for (i = 0; i < fs.fd_max; i++) { | |
3774 error = tffs_close(i + FFS_FD_OFFSET); | |
3775 expect(error, 0); | |
3776 } | |
3777 | |
3778 for (i = 0; i < fs.fd_max; i++) { | |
3779 fdi = tffs_open( file[i], FFS_O_RDONLY); | |
3780 expect(fdi, i + FFS_FD_OFFSET); | |
3781 } | |
3782 | |
3783 if(p0) { error = test_run("irec;drec;"); if (error > 0) return 1; } | |
3784 | |
3785 for (i = 0; i < fs.fd_max; i++) { | |
3786 for (j = 0; j < 10; j++) { | |
3787 size = tffs_read(i + FFS_FD_OFFSET, bigbuf, 50); | |
3788 expect(size, 50); | |
3789 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size); | |
3790 if (error) return 1; | |
3791 } | |
3792 } | |
3793 | |
3794 for (i = 0; i < fs.fd_max; i++) { | |
3795 error = tffs_close(i + FFS_FD_OFFSET); | |
3796 expect(error, 0); | |
3797 } | |
3798 | |
3799 return 0; | |
3800 } | |
3801 | |
3802 | |
3803 int case_seek(int p0, int p1) | |
3804 { | |
3805 fd_t fdi; | |
3806 int size, offset; | |
3807 | |
3808 error = case_cleanup(3 * fs.chunk_size_max); | |
3809 expect_ok(error); | |
3810 | |
3811 // The seek function itself don't care if the file is open in read or | |
3812 // write mode. | |
3813 error = tffs_mkdir("/streams"); | |
3814 | |
3815 offset = tffs_seek(FFS_FD_OFFSET, 0, FFS_SEEK_SET); | |
3816 expect(offset, EFFS_BADFD); | |
3817 | |
3818 /* Make file to seek on */ | |
3819 fdi = tffs_open("/streams/seek", FFS_O_RDWR | FFS_O_CREATE | FFS_O_TRUNC); | |
3820 expect(fdi, FFS_FD_OFFSET); | |
3821 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 3 * fs.chunk_size_max); | |
3822 expect(size, 3 * fs.chunk_size_max); | |
3823 | |
3824 /* Simple test in RDWR without any writes. Test good and bad offset */ | |
3825 tw(tr(TR_FUNC, TrTestHigh, "seek and RDWR \n")); | |
3826 ttw(str(TTrTest, "seek and RDWR" NL)); | |
3827 | |
3828 offset = ffs_seek(fdi, 0, 5); | |
3829 expect(offset, EFFS_INVALID ); | |
3830 | |
3831 tw(tr(TR_FUNC, TrTestHigh, "ffs_seek(FFS_SEEK_SET)\n")); | |
3832 ttw(str(TTrTest, "ffs_seek(FFS_SEEK_SET)" NL)); | |
3833 offset = tffs_seek(fdi, -1, FFS_SEEK_SET); | |
3834 expect(offset, EFFS_INVALID); | |
3835 offset = tffs_seek(fdi, 3 * fs.chunk_size_max + 1, FFS_SEEK_SET); | |
3836 expect(offset, EFFS_INVALID); | |
3837 | |
3838 offset = tffs_seek(fdi, 15, FFS_SEEK_SET); | |
3839 expect(offset, 15); | |
3840 size = tffs_read(fdi, bigbuf, fs.chunk_size_max/10); | |
3841 expect(size, fs.chunk_size_max/10); | |
3842 error = test_expect_data((char *)tdata[TDATA_HUGE] + 15, | |
3843 bigbuf, fs.chunk_size_max/10); | |
3844 if (error) return 1; | |
3845 | |
3846 offset = tffs_seek(fdi, 0, FFS_SEEK_SET); | |
3847 expect(offset, 0); | |
3848 | |
3849 size = tffs_read(fdi, bigbuf, bigbuf_size); | |
3850 error = test_expect_data((char*)tdata[TDATA_HUGE], bigbuf, size); | |
3851 if (error) return 1; | |
3852 | |
3853 tw(tr(TR_FUNC, TrTestHigh, "ffs_seek(FFS_SEEK_CUR)\n")); | |
3854 ttw(str(TTrTest, "ffs_seek(FFS_SEEK_CUR)" NL)); | |
3855 offset = tffs_seek(fdi, -(3 * fs.chunk_size_max + 1), FFS_SEEK_CUR); | |
3856 expect(offset, EFFS_INVALID); | |
3857 offset = tffs_seek(fdi, 1, FFS_SEEK_CUR); | |
3858 expect(offset, EFFS_INVALID); | |
3859 offset = tffs_seek(fdi, 0, FFS_SEEK_CUR); | |
3860 expect(offset, 3 * fs.chunk_size_max); | |
3861 offset = tffs_seek(fdi, -30, FFS_SEEK_CUR); | |
3862 expect(offset, 3 * fs.chunk_size_max - 30); | |
3863 offset = tffs_seek(fdi, 20, FFS_SEEK_CUR); | |
3864 expect(offset, 3 * fs.chunk_size_max - 30 + 20); | |
3865 size = tffs_read(fdi, bigbuf, 3 * fs.chunk_size_max); | |
3866 expect(size, 10); | |
3867 error = test_expect_data((char *)tdata[TDATA_HUGE] + | |
3868 (3 * fs.chunk_size_max - 10), bigbuf, 10); | |
3869 if (error) return 1; | |
3870 | |
3871 tw(tr(TR_FUNC, TrTestHigh, "ffs_seek(FFS_SEEK_END)\n")); | |
3872 ttw(str(TTrTest, "ffs_seek(FFS_SEEK_END)" NL)); | |
3873 offset = tffs_seek(fdi, -(3 * fs.chunk_size_max + 1), FFS_SEEK_END); | |
3874 expect(offset, EFFS_INVALID); | |
3875 offset = tffs_seek(fdi, 1, FFS_SEEK_END); | |
3876 expect(offset, EFFS_INVALID); | |
3877 offset = tffs_seek(fdi, 0, FFS_SEEK_END); | |
3878 expect(offset, 3 * fs.chunk_size_max); | |
3879 offset = tffs_seek(fdi, -15, FFS_SEEK_END); | |
3880 expect(offset, 3 * fs.chunk_size_max - 15); | |
3881 size = tffs_read(fdi, bigbuf, 20); | |
3882 expect(size, 15); | |
3883 error = test_expect_data((char *)tdata[TDATA_HUGE] + | |
3884 (3 * fs.chunk_size_max - 15), bigbuf, size); | |
3885 if (error) return 1; | |
3886 | |
3887 error = tffs_close(fdi); | |
3888 expect(error, 0); | |
3889 | |
3890 // Seek in write-mode with write in different places of the file. Test | |
3891 // on the dirty flag to se if the buffer is flushed ad the rigth time | |
3892 tw(tr(TR_FUNC, TrTestHigh, "seek and WRONLY \n")); | |
3893 ttw(str(TTrTest, "seek and WRONLY" NL)); | |
3894 | |
3895 fdi = tffs_open("/streams/seek", FFS_O_WRONLY); | |
3896 | |
3897 // Write and seek in the last chunk, buffer must be dirty so long the fp | |
3898 // not have been moved away from that chunk! | |
3899 | |
3900 offset = tffs_seek(fdi, -20, FFS_SEEK_END); expect_ok(offset); | |
3901 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0); | |
3902 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10); | |
3903 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3904 | |
3905 offset = tffs_seek(fdi, -100, FFS_SEEK_CUR); expect_ok(offset); | |
3906 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3907 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10); | |
3908 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3909 | |
3910 offset = tffs_seek(fdi, -fs.chunk_size_max/4, FFS_SEEK_CUR); expect_ok(offset); | |
3911 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3912 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10); | |
3913 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3914 | |
3915 offset = tffs_seek(fdi, offset + 10, FFS_SEEK_SET); expect_ok(offset); | |
3916 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3917 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10); | |
3918 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3919 | |
3920 // Write and seek across several chunks, the buffer must be flushed after | |
3921 // leaving a 'dirty' chunk. | |
3922 | |
3923 offset = tffs_seek(fdi, 10, FFS_SEEK_SET); expect_ok(offset); | |
3924 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0); | |
3925 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10); | |
3926 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3927 | |
3928 offset = tffs_seek(fdi, -50, FFS_SEEK_END); expect_ok(offset); | |
3929 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0); | |
3930 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 100); expect(size, 100); | |
3931 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3932 | |
3933 offset = tffs_seek(fdi, -fs.chunk_size_max, FFS_SEEK_CUR); expect_ok(offset); | |
3934 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0); | |
3935 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], fs.chunk_size_max / 2); | |
3936 expect(size, fs.chunk_size_max / 2); | |
3937 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3938 | |
3939 offset = tffs_seek(fdi, fs.chunk_size_max, FFS_SEEK_SET); expect_ok(offset); | |
3940 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0); | |
3941 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 50); expect(size, 50); | |
3942 expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1); | |
3943 | |
3944 error = tffs_close(fdi); | |
3945 expect(error, 0); | |
3946 | |
3947 return 0; | |
3948 } | |
3949 | |
3950 // NOTEME: move to other place later | |
3951 int case_trunc(int p0, int p1) | |
3952 { | |
3953 fd_t fdi; | |
3954 int size, f_size, trunc_size, i; | |
3955 T_FFS_STAT stat; | |
3956 char fname[] = "/truncate/normal_file"; | |
3957 char sname[] = "/truncate/stream_file"; | |
3958 char imeifile[] = "/truncate/IMEI"; | |
3959 | |
3960 tffs_remove(fname); | |
3961 tffs_remove(sname); | |
3962 | |
3963 error = case_cleanup(5 * fs.chunk_size_max); | |
3964 expect_ok(error); | |
3965 | |
3966 tffs_mkdir("/truncate"); | |
3967 | |
3968 // Try to truncate a non existing file | |
3969 error = tffs_truncate(fname, 0); | |
3970 expect(error, EFFS_NOTFOUND); | |
3971 | |
3972 // Try to truncate a directory | |
3973 error = tffs_truncate("/truncate", 0); | |
3974 expect(error, EFFS_NOTAFILE); | |
3975 | |
3976 f_size = fs.chunk_size_max + 100; | |
3977 error = tffs_file_write(fname, (char *)tdata[TDATA_HUGE], f_size, | |
3978 FFS_O_TRUNC | FFS_O_WRONLY | FFS_O_CREATE); | |
3979 expect(error, EFFS_OK); | |
3980 | |
3981 /* Test truncate from file size + 3 to file size - 3 */ | |
3982 for (i = 0; i < 6; i++) { | |
3983 trunc_size = f_size + 3 - i; | |
3984 tw(tr(TR_FUNC, TrTestLow, "TRUNC file to size %d \n", trunc_size)); | |
3985 error = tffs_truncate(fname, trunc_size); | |
3986 expect(error, EFFS_OK); | |
3987 error = tffs_lstat(fname, &stat); | |
3988 expect(error, EFFS_OK); | |
3989 expect_eq(stat.size, (f_size < trunc_size ? f_size : trunc_size)); | |
3990 } | |
3991 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
3992 size = tffs_fread(fname, bigbuf, f_size); | |
3993 expect(size, trunc_size); // ++ because of the last -- in for() | |
3994 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size); | |
3995 if (error) return 1; | |
3996 | |
3997 tw(tr(TR_FUNC, TrTestLow, "Truncate file while it is open \n")); | |
3998 fdi = tffs_open(fname, FFS_O_WRONLY | FFS_O_APPEND); | |
3999 expect(fdi, FFS_FD_OFFSET); | |
4000 size = tffs_write(fdi, (char *) &tdata[TDATA_HUGE][trunc_size], 31); | |
4001 expect(size, 31); | |
4002 f_size = trunc_size + 31; | |
4003 | |
4004 // Truncate to a size less than fp, this will fail | |
4005 error = tffs_ftruncate(fdi, f_size - 1); | |
4006 expect(error, EFFS_INVALID); | |
4007 | |
4008 // Move fp otherwise it will not be possible to truncate | |
4009 error = ffs_seek(fdi, 0, FFS_SEEK_SET); | |
4010 expect(error, 0); | |
4011 | |
4012 // Test truncate from file size + 3 to file size - 3 | |
4013 for (i = 0; i < 6; i++) { | |
4014 trunc_size = f_size + 3 - i; | |
4015 tw(tr(TR_FUNC, TrTestLow, "TRUNC file to size %d \n", trunc_size)); | |
4016 error = tffs_ftruncate(fdi, trunc_size); | |
4017 expect(error, EFFS_OK); | |
4018 error = tffs_lstat(fname, &stat); | |
4019 expect(error, EFFS_OK); | |
4020 expect_eq(stat.size, (f_size < trunc_size ? f_size : trunc_size)); | |
4021 } | |
4022 | |
4023 error = tffs_close(fdi); | |
4024 expect(error, EFFS_OK); | |
4025 | |
4026 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
4027 size = tffs_fread(fname, bigbuf, f_size); | |
4028 expect(size, trunc_size); | |
4029 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size); | |
4030 if (error) return 1; | |
4031 | |
4032 // We need to test ftruncate with a size less than the first chunk | |
4033 fdi = tffs_open(fname, FFS_O_WRONLY); | |
4034 expect(fdi, FFS_FD_OFFSET); | |
4035 | |
4036 error = tffs_ftruncate(fdi, 10); | |
4037 expect(error, EFFS_OK); | |
4038 error = tffs_ftruncate(fdi, 10); // same size twice to complicate it | |
4039 expect(error, EFFS_OK); | |
4040 error = tffs_lstat(fname, &stat); | |
4041 expect(error, EFFS_OK); | |
4042 expect_eq(stat.size, 10); | |
4043 error = tffs_ftruncate(fdi, 0); | |
4044 expect(error, EFFS_OK); | |
4045 error = tffs_ftruncate(fdi, 0); | |
4046 expect(error, EFFS_OK); | |
4047 error = tffs_lstat(fname, &stat); | |
4048 expect(error, EFFS_OK); | |
4049 expect_eq(stat.size, 0); | |
4050 error = tffs_close(fdi); | |
4051 expect(error, EFFS_OK); | |
4052 | |
4053 // Stream file test, make 2 segments and test around the end of segment | |
4054 // 1 (file closed) | |
4055 fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC | |
4056 | FFS_O_APPEND); | |
4057 expect(fdi, FFS_FD_OFFSET); | |
4058 | |
4059 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max + 1); | |
4060 expect(size, fs.chunk_size_max + 1); | |
4061 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31); | |
4062 expect(size, 31); | |
4063 error = tffs_close(fdi); | |
4064 expect(error, EFFS_OK); | |
4065 | |
4066 f_size = fs.chunk_size_max + 1 + 31; | |
4067 | |
4068 for (i = 0; i < 6; i++) { | |
4069 trunc_size = fs.chunk_size_max + 1 + 3 - i; | |
4070 tw(tr(TR_FUNC, TrTestLow, "TRUNC stream to size %d \n", trunc_size)); | |
4071 error = tffs_truncate(sname, trunc_size); | |
4072 expect(error, EFFS_OK); | |
4073 error = tffs_lstat(sname, &stat); | |
4074 expect(error, EFFS_OK); | |
4075 expect_eq(stat.size, trunc_size); | |
4076 } | |
4077 | |
4078 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
4079 size = tffs_fread(sname, bigbuf, f_size); | |
4080 expect(size, trunc_size); | |
4081 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size); | |
4082 if (error) return 1; | |
4083 | |
4084 // Try to enlarge the file. | |
4085 tw(tr(TR_FUNC, TrTestLow, "Try to enlarge the file \n")); | |
4086 error = tffs_truncate(sname, trunc_size + 1); | |
4087 expect(error, EFFS_OK); | |
4088 error = tffs_lstat(sname, &stat); | |
4089 expect(error, EFFS_OK); | |
4090 expect_eq(stat.size, trunc_size); | |
4091 | |
4092 fdi = tffs_open(sname, FFS_O_WRONLY); | |
4093 expect(fdi, FFS_FD_OFFSET); | |
4094 error = tffs_ftruncate(fdi, trunc_size + 1); | |
4095 expect(error, EFFS_OK); | |
4096 error = tffs_lstat(sname, &stat); | |
4097 expect(error, EFFS_OK); | |
4098 expect_eq(stat.size, trunc_size); | |
4099 error = tffs_close(fdi); | |
4100 expect(error, EFFS_OK); | |
4101 | |
4102 // Make a file with 2 segments + some data in the buffer, test around | |
4103 // end of segment 2 and the begining of segment 1 (file open). | |
4104 tw(tr(TR_FUNC, TrTestLow, "Truncate stream while it is open \n")); | |
4105 // Make segment 1 | |
4106 fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_APPEND | FFS_O_TRUNC); | |
4107 expect(fdi, FFS_FD_OFFSET); | |
4108 f_size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], | |
4109 2 * fs.chunk_size_max + 1); | |
4110 expect(f_size, 2 * fs.chunk_size_max + 1); | |
4111 | |
4112 // Move fp otherwise it will not be possible to truncate | |
4113 error = ffs_seek(fdi, 0, FFS_SEEK_SET); | |
4114 expect(error, 0); | |
4115 | |
4116 // Test around end of segment 2 | |
4117 for (i = 0; i < 16; i++) { | |
4118 trunc_size = f_size + 3 - i; | |
4119 tw(tr(TR_FUNC, TrTestLow, "TRUNC stream to size %d \n", | |
4120 trunc_size)); | |
4121 error = tffs_ftruncate(fdi, trunc_size); | |
4122 expect(error, EFFS_OK); | |
4123 error = tffs_lstat(sname, &stat); expect(error, EFFS_OK); | |
4124 expect_eq(stat.size, (f_size < trunc_size ? f_size : trunc_size)); | |
4125 } | |
4126 | |
4127 // Test around begining of segment 1 | |
4128 for (i = 0; i < 6; i++) { | |
4129 trunc_size = 3 - i; | |
4130 tw(tr(TR_FUNC, TrTestLow, "TRUNC stream to size %d \n", | |
4131 trunc_size)); | |
4132 error = tffs_ftruncate(fdi, trunc_size); | |
4133 if (trunc_size >= 0) { | |
4134 expect(error, EFFS_OK); | |
4135 } | |
4136 else { | |
4137 expect(error, EFFS_INVALID); | |
4138 break; | |
4139 } | |
4140 error = tffs_lstat(sname, &stat); | |
4141 expect(error, EFFS_OK); | |
4142 expect_eq(stat.size, (trunc_size)); | |
4143 } | |
4144 | |
4145 error = tffs_close(fdi); | |
4146 expect(error, EFFS_OK); | |
4147 | |
4148 // Make, truncate and append to a file (use ffs_ftruncate()) | |
4149 fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC | |
4150 | FFS_O_APPEND); | |
4151 expect(fdi, FFS_FD_OFFSET); | |
4152 | |
4153 f_size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max); | |
4154 expect(f_size, fs.chunk_size_max ); | |
4155 | |
4156 tw(tr(TR_FUNC, TrTestLow, "write 1/2 buf size, trunc 1/4 buf size\n")); | |
4157 // write 1/2 buf size and truncate 1/4 buf size x times | |
4158 for (i = 0; i < 8; i++) { | |
4159 size = tffs_write(fdi, (char *) &tdata[TDATA_HUGE][f_size], | |
4160 fs.chunk_size_max / 2); | |
4161 if (size < 0) return size; | |
4162 f_size += size; | |
4163 size = tffs_seek(fdi, - fs.chunk_size_max / 4, FFS_SEEK_CUR); | |
4164 expect(size, f_size - fs.chunk_size_max / 4); | |
4165 | |
4166 error = tffs_ftruncate(fdi, f_size - fs.chunk_size_max / 4); | |
4167 expect(error, EFFS_OK); | |
4168 f_size -= fs.chunk_size_max / 4; | |
4169 | |
4170 error = tffs_lstat(sname, &stat); | |
4171 expect(error, EFFS_OK); | |
4172 expect_eq(stat.size, f_size); | |
4173 } | |
4174 error = tffs_close(fdi); | |
4175 expect(error, EFFS_OK); | |
4176 | |
4177 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
4178 size = tffs_fread(sname, bigbuf, bigbuf_size); | |
4179 expect(size, f_size); | |
4180 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size); | |
4181 if (error) return 1; | |
4182 | |
4183 // backwards trunc 1/2 write 1/4 x times | |
4184 tw(tr(TR_FUNC, TrTestLow, "trunc 1/2 buf size, write 1/4 buf size\n")); | |
4185 fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_APPEND); | |
4186 expect(fdi, FFS_FD_OFFSET); | |
4187 | |
4188 for (i = 0; i < 8; i++) { | |
4189 size = tffs_seek(fdi, - fs.chunk_size_max / 2, FFS_SEEK_CUR); | |
4190 expect(size, f_size - fs.chunk_size_max / 2); | |
4191 | |
4192 error = tffs_ftruncate(fdi, f_size - fs.chunk_size_max / 2); | |
4193 expect(error, EFFS_OK); | |
4194 f_size -= fs.chunk_size_max / 2; | |
4195 | |
4196 f_size += tffs_write(fdi, (char *) &tdata[TDATA_HUGE][f_size], | |
4197 fs.chunk_size_max / 4); | |
4198 error = tffs_lstat(sname, &stat); | |
4199 expect(error, EFFS_OK); | |
4200 expect_eq(stat.size, f_size); | |
4201 } | |
4202 | |
4203 if (p0) { error = test_run("irec"); if (error > 0) return 1; } | |
4204 | |
4205 error = tffs_close(fdi); | |
4206 expect(error, EFFS_OK); | |
4207 | |
4208 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
4209 size = tffs_fread(sname, bigbuf, bigbuf_size); | |
4210 expect(size, f_size); | |
4211 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size); | |
4212 if (error) return 1; | |
4213 | |
4214 tw(tr(TR_FUNC, TrTestLow, "Make 2 segments, truncate to zero and append\n")); | |
4215 fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC | |
4216 | FFS_O_APPEND); | |
4217 expect(fdi, FFS_FD_OFFSET); | |
4218 size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 2 * fs.chunk_size_max + 10); | |
4219 expect(size, 2 * fs.chunk_size_max + 10); | |
4220 | |
4221 // Move fp otherwise it will not be possible to truncate | |
4222 error = ffs_seek(fdi, 0, FFS_SEEK_SET); | |
4223 expect(error, 0); | |
4224 | |
4225 error = tffs_ftruncate(fdi, 0); | |
4226 expect(error, EFFS_OK); | |
4227 | |
4228 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 150); | |
4229 expect(size, 150 ); | |
4230 | |
4231 error = tffs_close(fdi); | |
4232 expect(error, EFFS_OK); | |
4233 | |
4234 if (p0) { error = test_run("irec;brec"); if (error > 0) return 1; } | |
4235 | |
4236 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
4237 f_size = tffs_fread(sname, bigbuf, bigbuf_size); | |
4238 expect(f_size, size); | |
4239 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size); | |
4240 if (error) return 1; | |
4241 | |
4242 // Truncate through a symlink | |
4243 error = tffs_symlink("/str", sname); | |
4244 expect(error, EFFS_OK); | |
4245 error = tffs_truncate("/str", 100); | |
4246 expect(error, EFFS_OK); | |
4247 f_size = tffs_fread(sname, bigbuf, bigbuf_size); | |
4248 expect(f_size, 100); | |
4249 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size); | |
4250 if (error) return 1; | |
4251 tffs_remove("/str"); | |
4252 | |
4253 // truncate a file which only have data in the stream buffer | |
4254 fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC | |
4255 | FFS_O_APPEND); | |
4256 expect(fdi, FFS_FD_OFFSET); | |
4257 | |
4258 f_size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 3); | |
4259 expect(f_size, 3); | |
4260 | |
4261 // Move fp otherwise it will not be possible to truncate | |
4262 error = ffs_seek(fdi, 0, FFS_SEEK_SET); | |
4263 expect(error, 0); | |
4264 | |
4265 tw(tr(TR_FUNC, TrTestLow, "Truncate in buffer\n")); | |
4266 for (i = 0; i < 4; i++) { | |
4267 error = tffs_ftruncate(fdi, --f_size); | |
4268 if (f_size >= 0) { | |
4269 expect(error, EFFS_OK); | |
4270 | |
4271 error = tffs_lstat(sname, &stat); | |
4272 expect(error, EFFS_OK); | |
4273 expect_eq(stat.size, f_size); | |
4274 } | |
4275 else { | |
4276 expect(error, EFFS_INVALID); | |
4277 } | |
4278 } | |
4279 error = tffs_close(fdi); | |
4280 expect(error, EFFS_OK); | |
4281 | |
4282 // Try to truncate a read-only file | |
4283 error = tffs_fwrite(imeifile, TDATA(0)); | |
4284 // The file is maybe already created! | |
4285 error = tffs_fcontrol(imeifile, OC_FLAGS, OF_READONLY); | |
4286 error = tffs_truncate(imeifile, 0); | |
4287 expect(error, EFFS_ACCESS); | |
4288 | |
4289 // Use ffs_truncate() on a file open in read mode | |
4290 fdi = tffs_open(fname, FFS_O_RDONLY); | |
4291 error = tffs_truncate(fname, 0); | |
4292 expect(error, EFFS_LOCKED); | |
4293 error = tffs_ftruncate(fdi, 0); | |
4294 expect(error, EFFS_INVALID); | |
4295 error = tffs_close(fdi); | |
4296 expect_ok(error); | |
4297 | |
4298 return 0; | |
4299 } | |
4300 | |
4301 | |
4302 int case_append(int p0, int p1) | |
4303 { | |
4304 fd_t fdi; | |
4305 int size, fsize; | |
4306 char sname[] = "/stream/append1"; | |
4307 char fname[] = "/stream/append2"; | |
4308 int offset = 0; | |
4309 | |
4310 if (param.data_blocks <= 1) { | |
4311 ttw(ttr(TTrTest, "WARNING: Too few blocks to run. Skip test" NL)); | |
4312 tw(tr(TR_FUNC, TrTest, "WARNING: Too few blocks to run. Skip test\n")); | |
4313 return 0; | |
4314 } | |
4315 | |
4316 case_cleanup(fs.chunk_size_max * 5); | |
4317 | |
4318 tffs_mkdir("/stream"); | |
4319 | |
4320 fdi = tffs_open(sname, FFS_O_RDWR | FFS_O_APPEND | FFS_O_TRUNC | | |
4321 FFS_O_CREATE); | |
4322 expect(fdi, FFS_FD_OFFSET); | |
4323 | |
4324 // Write data in buf and seek in the buf | |
4325 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max / 2); | |
4326 expect_gt(size, 0); | |
4327 | |
4328 offset = ffs_seek(fdi, -fs.chunk_size_max / 4, FFS_SEEK_CUR); | |
4329 expect_gt(offset, 0); | |
4330 expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty); | |
4331 | |
4332 // Append data and seek in the buffer ad the end of the last chunk | |
4333 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + | |
4334 fs.fd[fdi - FFS_FD_OFFSET].size, fs.chunk_size_max); | |
4335 expect_gt(size, 0); | |
4336 | |
4337 offset = ffs_seek(fdi, -fs.chunk_size_max / 4, FFS_SEEK_END); | |
4338 expect_gt(offset, 0); | |
4339 | |
4340 size = tffs_read(fdi, bigbuf, fs.chunk_size_max / 4); | |
4341 expect(size, fs.chunk_size_max / 4); | |
4342 expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty); | |
4343 | |
4344 // Append data and seek away from buf | |
4345 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + | |
4346 fs.fd[fdi - FFS_FD_OFFSET].size, fs.chunk_size_max * 1.5); | |
4347 expect_gt(size, 0); | |
4348 | |
4349 offset = ffs_seek(fdi, -fs.chunk_size_max * 2, FFS_SEEK_END); | |
4350 expect_gt(offset, 0); | |
4351 | |
4352 size = tffs_read(fdi, bigbuf, fs.chunk_size_max / 4); | |
4353 expect(size, fs.chunk_size_max / 4); | |
4354 | |
4355 // Append again and validate the data | |
4356 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + | |
4357 fs.fd[fdi - FFS_FD_OFFSET].size, fs.chunk_size_max / 2); | |
4358 expect_gt(size, 0); | |
4359 | |
4360 offset = ffs_seek(fdi, 0, FFS_SEEK_SET); | |
4361 expect(0, offset); | |
4362 | |
4363 size = tffs_read(fdi, bigbuf, fs.fd[fdi - FFS_FD_OFFSET].size); | |
4364 expect_gt(size, 0); | |
4365 | |
4366 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size); | |
4367 if (error) return 1; | |
4368 | |
4369 error = tffs_close(fdi); | |
4370 expect_ok(error); | |
4371 | |
4372 // Append on a file with data in the seghead | |
4373 fsize = fs.chunk_size_max / 4; | |
4374 error = tffs_file_write(fname, (char *)tdata[TDATA_HUGE], fsize, | |
4375 FFS_O_TRUNC | FFS_O_WRONLY | FFS_O_CREATE); | |
4376 expect(error, EFFS_OK); | |
4377 | |
4378 fdi = tffs_open(fname, FFS_O_RDWR | FFS_O_APPEND); | |
4379 expect(fdi, FFS_FD_OFFSET); | |
4380 | |
4381 // Write data in buf and seek in the buf | |
4382 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + fsize, | |
4383 fs.chunk_size_max / 2); | |
4384 expect_gt(size, 0); | |
4385 fsize += size; | |
4386 | |
4387 offset = ffs_seek(fdi, 0, FFS_SEEK_SET); | |
4388 expect(offset, 0); | |
4389 expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty); | |
4390 | |
4391 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + fsize, | |
4392 fs.chunk_size_max / 2); | |
4393 expect_gt(size, 0); | |
4394 fsize += size; | |
4395 | |
4396 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, fsize); | |
4397 if (error) return 1; | |
4398 | |
4399 error = tffs_close(fdi); | |
4400 expect_ok(error); | |
4401 | |
4402 return 0; | |
4403 } | |
4404 | |
4405 int case_datasync(int p0, int p1) | |
4406 { | |
4407 fd_t fdi; | |
4408 int size, fsize, offset, i; | |
4409 char myname[] = "/datasync"; | |
4410 | |
4411 error = case_cleanup(4 * fs.chunk_size_max); | |
4412 expect_ok(error); | |
4413 | |
4414 fdi = tffs_open(myname, FFS_O_RDWR | FFS_O_TRUNC | FFS_O_CREATE); | |
4415 expect(fdi, FFS_FD_OFFSET); | |
4416 | |
4417 fsize = 0; | |
4418 for (i = 0; i < 10; i++) { | |
4419 // Write data in buf and use datasync | |
4420 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + fsize, | |
4421 fs.chunk_size_max / 3); | |
4422 expect_gt(size, 0); | |
4423 fsize += size; | |
4424 | |
4425 error = tffs_fdatasync(fdi); | |
4426 expect(error, EFFS_OK); | |
4427 expect(0, fs.fd[fdi - FFS_FD_OFFSET].dirty); | |
4428 } | |
4429 | |
4430 error = tffs_fdatasync(fdi + 1); | |
4431 expect(error, EFFS_BADFD); | |
4432 | |
4433 // Seek to chunk 2, write data, seek, use fdatasync | |
4434 offset = tffs_seek(fdi, fs.chunk_size_max * 2.5, FFS_SEEK_SET); | |
4435 expect_gt(offset, 0); | |
4436 | |
4437 size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + offset, | |
4438 fs.chunk_size_max / 4); | |
4439 expect_gt(size, 0); | |
4440 | |
4441 offset = tffs_seek(fdi, -fs.chunk_size_max / 2, FFS_SEEK_CUR); | |
4442 expect_gt(offset, 0); | |
4443 | |
4444 error = tffs_fdatasync(fdi); | |
4445 expect(error, EFFS_OK); | |
4446 expect(0, fs.fd[fdi - FFS_FD_OFFSET].dirty); | |
4447 | |
4448 error = tffs_close(fdi); | |
4449 expect_ok(error); | |
4450 | |
4451 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
4452 size = tffs_fread(myname, bigbuf, fsize); | |
4453 tw(tr(TR_FUNC, TrTestLow, "size: %d fsize: %d \n", size, fsize)); | |
4454 expect(size, fsize); | |
4455 error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size); | |
4456 if (error) return 1; | |
4457 | |
4458 return 0; | |
4459 } | |
4460 | |
4461 int case_fw_flags(int p0, int p1) | |
4462 { | |
4463 int i; | |
4464 char myname[] = "/file_write"; | |
4465 | |
4466 tffs_remove(myname); | |
4467 | |
4468 tw(tr(TR_FUNC, TrTestHigh, "Test ffs_file_write() flags, file non-exist\n")); | |
4469 for (i = 0; i < 0xFE; i++) { | |
4470 error = tffs_file_write(myname, 0,0, i); | |
4471 | |
4472 if (is_open_option(i, FFS_O_CREATE)) { | |
4473 expect_ok(error); | |
4474 error = tffs_remove(myname); | |
4475 expect_ok(error); | |
4476 } | |
4477 else | |
4478 expect(EFFS_NOTFOUND, error); | |
4479 } | |
4480 | |
4481 tw(tr(TR_FUNC, TrTestHigh, "Test ffs_file_write() flags, file exist\n")); | |
4482 error = tffs_file_write(myname, 0,0, FFS_O_CREATE); | |
4483 expect_ok(error); | |
4484 | |
4485 for (i = 0; i < 0xFF; i++) { | |
4486 error = tffs_file_write(myname, 0,0, i); | |
4487 | |
4488 if (is_open_option(i, FFS_O_EXCL) && is_open_option(i, FFS_O_CREATE)) { | |
4489 expect(error, EFFS_EXISTS); | |
4490 } | |
4491 | |
4492 else | |
4493 expect_ok(error); | |
4494 } | |
4495 | |
4496 return 0; | |
4497 } | |
4498 | |
4499 | |
4500 drv_Return_Type pcm_init(void); | |
4501 | |
4502 int case_pcm(int p0, int p1) | |
4503 { | |
4504 UBYTE version; | |
4505 UBYTE imei[] = "12345678"; | |
4506 int size; | |
4507 | |
4508 ffs_mkdir("/pcm"); | |
4509 | |
4510 // Write imei file to ffs. Run init (this reads the imei file), remove | |
4511 // the file from flash, write the imei to flash from pcm and validate | |
4512 // data. | |
4513 error = ffs_file_write("/pcm/IMEI", &imei, sizeof(imei), FFS_O_CREATE); | |
4514 expect_ok(error); | |
4515 | |
4516 error = pcm_init(); | |
4517 expect(PCM_INITIALIZED, error); | |
4518 | |
4519 error = pcm_ReadFile((UBYTE *) EF_IMEI_ID, SIZE_EF_IMEI, imei, &version); | |
4520 expect(PCM_OK, error); | |
4521 | |
4522 error = ffs_remove("/pcm/IMEI"); | |
4523 expect_ok(error); | |
4524 | |
4525 error = pcm_WriteFile((UBYTE *) EF_IMEI_ID, SIZE_EF_IMEI, imei); | |
4526 expect(PCM_OK, error); | |
4527 | |
4528 tw(tr(TR_FUNC, TrTestLow, "Validate data \n")); | |
4529 size = tffs_fread("/pcm/IMEI", bigbuf, bigbuf_size); | |
4530 expect(size, SIZE_EF_IMEI); | |
4531 error = test_expect_data(imei, bigbuf, size); | |
4532 if (error) return 1; | |
4533 | |
4534 // TODO: test pcm_WriteRecord and pcm_ReadRecord. | |
4535 return 0; | |
4536 } | |
4537 | |
4538 | |
4539 int case_api_exceptions(int p0, int p1) | |
4540 { | |
4541 int i; | |
4542 T_FFS_DIR dir; | |
4543 T_FFS_FD myfdi; | |
4544 char myname[] = "/BAD"; | |
4545 char mydir[] = "/tdir"; | |
4546 char mylink[] = "/tlink"; | |
4547 char mytfile[] = "/tfile"; | |
4548 char buf[] = "foobar"; | |
4549 | |
4550 // Create test file and dir | |
4551 error = tffs_file_write(mytfile, buf, sizeof(buf), FFS_O_CREATE); | |
4552 expect_ok(error); | |
4553 | |
4554 error = tffs_mkdir(mydir); | |
4555 if (error < 0 && error != EFFS_EXISTS) return 1; | |
4556 | |
4557 error = tffs_symlink(mytfile, mylink); | |
4558 if (error < 0 && error != EFFS_EXISTS) return 1; | |
4559 | |
4560 error = tffs_opendir(mydir, &dir); | |
4561 expect_ok(error); | |
4562 | |
4563 myfdi = tffs_open("/tsream", FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC); | |
4564 expect(myfdi, FFS_FD_OFFSET); | |
4565 | |
4566 expect(tffs_write(myfdi, buf, sizeof(buf)), sizeof(buf)); | |
4567 | |
4568 // Test all API functions for pathname with null pointers. | |
4569 for (i = 0; i < 17; i++) { | |
4570 switch (i) { | |
4571 case 0: error = tffs_open(0, FFS_O_WRONLY | FFS_O_CREATE); break; | |
4572 case 1: error = tffs_truncate(0, 1); break; | |
4573 case 2: error = tffs_file_write(0, buf, sizeof(buf), FFS_O_CREATE); break; | |
4574 case 3: error = tffs_stat(0, &stat); break; | |
4575 case 4: error = tffs_lstat(0, &stat); break; | |
4576 case 5: error = tffs_xlstat(0, &xstat); break; | |
4577 case 6: error = tffs_remove(0); break; | |
4578 case 7: error = tffs_mkdir(0); break; | |
4579 case 8: error = tffs_opendir(0, &dir); break; | |
4580 case 9: error = tffs_symlink(0, myname); break; | |
4581 case 10: error = tffs_symlink("/link", 0); break; | |
4582 case 11: error = tffs_readlink(0, buf, sizeof(buf)); break; | |
4583 case 12: error = tffs_rename(0, "/test"); break; | |
4584 case 13: error = tffs_rename(mytfile, 0); break; | |
4585 case 14: error = tffs_file_write(0, buf, sizeof(buf), FFS_O_CREATE); break; | |
4586 case 15: error = tffs_file_read(0, buf, sizeof(buf)); break; | |
4587 case 16: error = tffs_fcontrol(0, OC_FLAGS, OF_READONLY); break; | |
4588 default: error = EFFS_INVALID; | |
4589 } | |
4590 expect(error, EFFS_BADNAME); | |
4591 } | |
4592 | |
4593 // Test all API functions with buffer null pointers. | |
4594 for (i = 0; i < 13; i++) { | |
4595 switch (i) { | |
4596 case 0: error = tffs_file_write(myname, 0, 100, FFS_O_CREATE); break; | |
4597 case 1: error = tffs_file_read(mytfile, 0, 40); break; | |
4598 case 2: error = tffs_opendir(mydir, 0); break; | |
4599 case 3: error = ffs_readdir (0, buf, sizeof(buf)); break; | |
4600 case 4: error = ffs_readdir (&dir, 0, 100); break; | |
4601 case 5: error = tffs_readlink(mylink, 0, 1); break; | |
4602 case 6: error = tffs_stat(mytfile, 0); break; | |
4603 case 7: error = tffs_lstat(mylink, 0); break; | |
4604 case 8: error = tffs_xlstat(mylink, 0); break; | |
4605 case 9: error = tffs_query(Q_BYTES_FREE, 0); break; | |
4606 case 10: error = tffs_fstat(myfdi, 0); break; | |
4607 case 11: error = tffs_write(myfdi, 0, 10); break; | |
4608 case 12: error = tffs_read(myfdi, 0, 40); break; | |
4609 default: error = 0; | |
4610 } | |
4611 expect(error, EFFS_INVALID); | |
4612 } | |
4613 expect_ok(tffs_close(myfdi)); | |
4614 | |
4615 // Make sure we still can create empty files! | |
4616 error = tffs_file_write("/empty_file", 0, 0, FFS_O_CREATE); | |
4617 expect_ok(error); | |
4618 | |
4619 // Open file for test of negative size | |
4620 myfdi = tffs_open(myname, FFS_O_RDWR | FFS_O_CREATE | | |
4621 FFS_O_TRUNC | FFS_O_APPEND); | |
4622 expect(myfdi, FFS_FD_OFFSET); | |
4623 | |
4624 // Test all API 'size' parameters with a negative size | |
4625 for (i = 0; i < 11; i++) { | |
4626 switch (i) { | |
4627 // Try modify | |
4628 case 0: error = tffs_write(myfdi, buf, -1); break; | |
4629 case 1: error = tffs_truncate(myname, -1); break; | |
4630 case 2: error = tffs_fwrite(myname, buf, -2); break; | |
4631 case 3: error = tffs_fcreate(myname, buf, -3); break; | |
4632 case 4: error = tffs_fupdate(myname, buf, -56); break; | |
4633 case 5: error = tffs_file_write(myname, buf, -100, FFS_O_CREATE); break; | |
4634 // Try read | |
4635 case 6: error = tffs_fread(mytfile, bigbuf, -1); break; | |
4636 case 7: error = tffs_file_read(mytfile, bigbuf, -2); break; | |
4637 case 8: error = tffs_readdir(&dir, bigbuf, -3); break; | |
4638 case 9: error = tffs_readlink(mytfile, bigbuf, -4); break; | |
4639 case 10: error = tffs_read(myfdi, bigbuf, -5); break; | |
4640 default: error = 0; | |
4641 } | |
4642 expect(error, EFFS_INVALID); | |
4643 } | |
4644 | |
4645 error = tffs_close(myfdi); | |
4646 expect_ok(error); | |
4647 | |
4648 return EFFS_OK; | |
4649 } | |
4650 | |
4651 int case_api_notformated(int p0, int p1) | |
4652 { | |
4653 int i; | |
4654 struct dir_s dir; | |
4655 fd_t fdi; | |
4656 char buf[20]; | |
4657 uint16 q_out; | |
4658 struct xstat_s xstat; | |
4659 | |
4660 error = tffs_preformat(0xDEAD); | |
4661 expect(error, EFFS_OK); | |
4662 | |
4663 for(i=1; i<24; i++) | |
4664 { | |
4665 switch(i) | |
4666 { | |
4667 case 1: error = tffs_open("apinf", FFS_O_WRONLY); break; | |
4668 case 2: error = tffs_close(fdi); break; | |
4669 case 3: error = tffs_write(fdi, "abcdefghij", 10); break; | |
4670 case 4: error = tffs_read(fdi, buf, 2); break; | |
4671 case 5: error = tffs_seek(fdi, 0, FFS_SEEK_SET); break; | |
4672 case 6: error = tffs_truncate("apinf", 0); break; | |
4673 case 7: error = tffs_fdatasync(fdi); break; | |
4674 case 8: error = tffs_stat("apinf", &stat); break; | |
4675 case 9: error = tffs_fstat(fdi, &stat); break; | |
4676 case 10: error = tffs_lstat("apinf", &stat); break; | |
4677 case 11: error = tffs_xlstat("apinf", &xstat); break; | |
4678 case 12: error = ffs_remove("/apinf"); break; | |
4679 case 13: error = ffs_mkdir("/apinf"); break; | |
4680 case 14: error = ffs_opendir("/apinf", &dir); break; | |
4681 case 15: error = tffs_readdir(&dir, "/ffs", 21); break; | |
4682 case 16: error = tffs_symlink("/europe/imie", "imei"); break; | |
4683 case 17: error = ffs_rename("/Pluto", "/Dog"); break; | |
4684 case 18: error = ffs_file_write("/non-exist", "1234567890", 10, FFS_O_TRUNC); break; | |
4685 case 19: error = tffs_file_read("/stream1", buf, 10); break; | |
4686 case 20: error = tffs_fcreate("/", "apinf", 3); break; | |
4687 case 21: error = tffs_fupdate("/", "bar", 3); break; | |
4688 case 22: error = tffs_fwrite("/europe/imie","0123456789", 10); break; | |
4689 case 23: error = tffs_fcontrol("/apinf", OC_FLAGS, OF_READONLY); break; | |
4690 } | |
4691 | |
4692 expect(error, EFFS_NOFORMAT); | |
4693 | |
4694 } | |
4695 /* query must return information even if the device isnt formated */ | |
4696 error = tffs_query(Q_FS_INODES, (uint16 *) &q_out); | |
4697 expect(error, EFFS_OK); | |
4698 | |
4699 return 0; | |
4700 } | |
4701 | |
4702 int case_query(int p0, int p1) | |
4703 { | |
4704 int i; | |
4705 uint32 ret_val32; | |
4706 uint16 ret_val16; | |
4707 | |
4708 for(i=1; i<27; i++) | |
4709 { | |
4710 switch(i) | |
4711 { | |
4712 case 1: error = ffs_query(Q_TM_BUFADDR, (uint32 *)&ret_val32); break; | |
4713 case 2: error = ffs_query(Q_TM_BUFSIZE, (uint32 *)&ret_val32); break; | |
4714 case 3: error = ffs_query(Q_DEV_BASE, (uint32 *)&ret_val32); break; | |
4715 case 4: error = ffs_query(Q_FFS_API_VERSION, (uint16 *)&ret_val16); break; | |
4716 case 5: error = ffs_query(Q_FFS_DRV_VERSION, (uint16 *)&ret_val16); break; | |
4717 case 6: error = ffs_query(Q_FFS_REVISION, (uint16 *)&ret_val16); break; | |
4718 case 7: error = ffs_query(Q_FFS_FORMAT_WRITE, (uint16 *)&ret_val16); break; | |
4719 case 8: error = ffs_query(Q_FFS_FORMAT_READ, (uint16 *)&ret_val16); break; | |
4720 case 9: error = ffs_query(Q_FFS_LASTERROR, (uint16 *)&ret_val16); break; | |
4721 case 10: error = ffs_query(Q_FFS_TM_VERSION, (uint16 *)&ret_val16); break; | |
4722 case 11: error = ffs_query(Q_OBJECTS_MAX, (uint16 *)&ret_val16); break; | |
4723 case 12: error = ffs_query(Q_CHUNK_SIZE_MAX, (uint16 *)&ret_val16); break; | |
4724 case 13: error = ffs_query(Q_FD_BUF_SIZE, (uint32 *)&ret_val32); break; | |
4725 case 14: error = ffs_query(Q_FD_MAX, (uint16 *)&ret_val16); break; | |
4726 case 15: error = ffs_query(Q_DEV_MANUFACTURER, (uint16 *)&ret_val16); break; | |
4727 case 16: error = ffs_query(Q_DEV_DEVICE, (uint16 *)&ret_val16); break; | |
4728 case 17: error = ffs_query(Q_DEV_DRIVER, (uint16 *)&ret_val16); break; | |
4729 case 18: error = ffs_query(Q_LOST_HIGH, (uint16 *)&ret_val16); break; | |
4730 case 19: error = ffs_query(Q_FS_FLAGS, (uint16 *)&ret_val16); break; | |
4731 case 20: error = ffs_query(Q_FS_ROOT, (uint16 *)&ret_val16); break; | |
4732 case 21: error = ffs_query(Q_STATS_DRECLAIMS, (uint32 *)&ret_val32); break; | |
4733 case 22: error = ffs_query(Q_STATS_IRECLAIMS, (uint32 *)&ret_val32); break; | |
4734 case 23: error = ffs_query(Q_STATS_DATA_RECLAIMED, (uint32 *)&ret_val32); break; | |
4735 case 24: error = ffs_query(Q_STATS_INODES_RECLAIMED, (uint32 *)&ret_val32); break; | |
4736 case 25: error = ffs_query(Q_STATS_DATA_ALLOCATED, (uint32 *)&ret_val32); break; | |
4737 case 26: error = ffs_query(Q_REQUEST_ID_LAST, (uint32 *)&ret_val32); break; | |
4738 } | |
4739 | |
4740 expect(error, EFFS_OK); | |
4741 | |
4742 } | |
4743 | |
4744 return 0; | |
4745 } | |
4746 | |
4747 extern uint16 ffs_flash_device; | |
4748 extern uint16 ffs_flash_manufact; | |
4749 | |
4750 int case_octrl(int p0, int p1) | |
4751 { | |
4752 int org_fsflags = fs.flags, org_manufact = ffs_flash_manufact; | |
4753 int org_device = ffs_flash_device, org_testf = fs.testflags; | |
4754 | |
4755 error = object_control(0, OC_FS_FLAGS, 0x02); | |
4756 expect(error, EFFS_OK); | |
4757 error = object_control(0, OC_DEV_MANUFACT, 'T'); | |
4758 expect(error, EFFS_OK); | |
4759 error = object_control(0, OC_DEV_DEVICE, 0x0F12); | |
4760 expect(error, EFFS_OK); | |
4761 error = object_control(0, OC_DEBUG_0, 0xAFFE); | |
4762 expect(error, EFFS_OK); | |
4763 | |
4764 error = object_control(0, OC_DEBUG_LAST+1, 0); | |
4765 expect(error, EFFS_INVALID); | |
4766 | |
4767 // Restore the values or else it mess up the other tests | |
4768 fs.flags = org_fsflags; | |
4769 fs.testflags = org_testf; | |
4770 ffs_flash_manufact = org_manufact; | |
4771 ffs_flash_device = org_device; | |
4772 | |
4773 return 0; | |
4774 } | |
4775 | |
4776 /***************************************************************************/ | |
4777 /* Examples from RIV111 */ | |
4778 /***************************************************************************/ | |
4779 #if (TARGET == 0) | |
4780 int case_examples(int p0, int p1) | |
4781 { | |
4782 return 0; | |
4783 } | |
4784 #else | |
4785 | |
4786 static req_id_t my_request_id; | |
4787 static int removed_greeting; | |
4788 | |
4789 static void my_callback(T_FFS_FILE_CNF *confirm) | |
4790 { | |
4791 ttw(ttr(TTrTest, "my_callback(%d, %s, %d)" NL, | |
4792 confirm->error, confirm->path, confirm->request_id)); | |
4793 | |
4794 if (my_request_id != confirm->request_id) { | |
4795 ttw(ttr(TTrFatal, "error (%d, %d)" NL, confirm->request_id, my_request_id)); | |
4796 return; | |
4797 } | |
4798 | |
4799 if (confirm->error < 0) { | |
4800 ttw(ttr(TTrTest, "FATAL: my_callback error: %d" NL, confirm->error)); | |
4801 } | |
4802 else { | |
4803 ttw(ttr(TTrTest, "Remove 'greeting'" NL)); | |
4804 ffs_remove_nb("/greeting", 0); | |
4805 removed_greeting = 1; | |
4806 } | |
4807 | |
4808 error = rvf_free_buf(confirm); | |
4809 if (error < 0) | |
4810 ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); | |
4811 } | |
4812 | |
4813 // Using Function Callback | |
4814 T_RV_RETURN my_fc_cnfpath = {0, (CALLBACK_FUNC)my_callback}; | |
4815 | |
4816 // Using Mail Callback | |
4817 #define MY_TASK_ID (MAX_RVF_TASKS - 1 - 1) // same as FFS_TEST_TASK_ID | |
4818 T_RV_RETURN my_mail_cnfpath = {MY_TASK_ID, 0}; | |
4819 | |
4820 int case_examples(int p0, int p1) | |
4821 { | |
4822 if(1) { | |
4823 // MMI Configuration scenario | |
4824 struct { | |
4825 int volume; | |
4826 uint32 ringtype; | |
4827 } mmi; | |
4828 | |
4829 int temp; | |
4830 ttw(ttr(TTrTest, "Run MMI conf." NL)); | |
4831 mmi.volume = temp = 3; | |
4832 mmi.ringtype = 1111; | |
4833 ffs_mkdir("/mmi"); | |
4834 ffs_fwrite("/mmi/volume", &mmi.volume, sizeof(mmi.volume)); | |
4835 error = ffs_file_read("/mmi/volume", &mmi.volume, sizeof(mmi.volume)); | |
4836 if (error < 0) | |
4837 return 1; | |
4838 error = test_expect_data(&temp, &mmi.volume, sizeof(mmi.volume)); | |
4839 if (error < 0) | |
4840 return 1; | |
4841 } | |
4842 | |
4843 if(1) { | |
4844 // Using Mail Callback | |
4845 T_FFS_FILE_CNF *confirm_file; | |
4846 T_FFS_STREAM_CNF *confirm_stream; | |
4847 T_FFS_RET error; | |
4848 T_FFS_FD fdi; | |
4849 char hello[] = "Hello, world"; | |
4850 T_FFS_SIZE size; | |
4851 | |
4852 ttw(ttr(TTrTest, "Use Mail Callback" NL)); | |
4853 if ((my_request_id = ffs_open_nb("/mmi/sound", | |
4854 FFS_O_WRONLY | FFS_O_CREATE | | |
4855 FFS_O_APPEND | FFS_O_TRUNC, | |
4856 &my_mail_cnfpath)) < 0) | |
4857 return my_request_id; | |
4858 | |
4859 ttw(ttr(TTrTest, "Wait..." NL)); | |
4860 rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0); | |
4861 | |
4862 ttw(ttr(TTrTest, "Get mail" NL)); | |
4863 confirm_file = (T_FFS_FILE_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0); | |
4864 | |
4865 fdi = confirm_file->error; | |
4866 expect(FFS_FD_OFFSET, fdi); | |
4867 expect(my_request_id, confirm_file->request_id); | |
4868 expect(FFS_MESSAGE_OFFSET, confirm_file->header.msg_id); | |
4869 ttw(ttr(TTrTest, "Path '%s'" NL, confirm_file->path)); | |
4870 | |
4871 error = rvf_free_buf(confirm_file); | |
4872 if (error < 0) | |
4873 ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); | |
4874 | |
4875 if ((my_request_id = ffs_write_nb(fdi, hello, strlen(hello) , | |
4876 &my_mail_cnfpath)) < 0) | |
4877 return my_request_id; | |
4878 | |
4879 ttw(ttr(TTrTest, "Wait..." NL)); | |
4880 rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0); | |
4881 | |
4882 ttw(ttr(TTrTest, "Get mail" NL)); | |
4883 confirm_stream = (T_FFS_STREAM_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0); | |
4884 size = confirm_stream->error; | |
4885 expect(strlen(hello), size); | |
4886 expect(my_request_id, confirm_stream->request_id); | |
4887 ttw(ttr(TTrTest, "fdi: %d" NL, confirm_stream->fdi)); | |
4888 error = rvf_free_buf(confirm_stream); | |
4889 if (error < 0) | |
4890 ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); | |
4891 | |
4892 ttw(ttr(TTrTest, "Close file" NL)); | |
4893 if ((error = ffs_close(fdi)) < 0) | |
4894 return error; | |
4895 } | |
4896 | |
4897 if(1) { | |
4898 // Using Function Callback | |
4899 char hello[] = "Hello, world"; | |
4900 T_FFS_STAT stat; | |
4901 | |
4902 ttw(ttr(TTrTest, "Use Function Callback" NL)); | |
4903 | |
4904 if ((my_request_id = ffs_fcreate_nb("/greeting", hello, strlen(hello), | |
4905 &my_fc_cnfpath)) < 0) | |
4906 return my_request_id; | |
4907 | |
4908 // Wait until my_callback() has removed the file "greeting" | |
4909 removed_greeting = 0; | |
4910 while (removed_greeting == 0) | |
4911 tffs_delay(10); | |
4912 // NOTE: This is importent because if the test brec runs immediately | |
4913 // after his one will the brec test fail because the "greeting" file | |
4914 // is removed inside the brec test which don't expect that files is | |
4915 // removed. | |
4916 } | |
4917 | |
4918 return 0; | |
4919 } | |
4920 #endif | |
4921 /****************************************************************************** | |
4922 * Non blocking test ffs_xx_nb() | |
4923 ******************************************************************************/ | |
4924 | |
4925 #if (TARGET == 0) | |
4926 int case_nonblock(int p0, int p1) | |
4927 { | |
4928 tw(tr(TR_FUNC, TrTest, | |
4929 "WARNING: This test can only run in target. Skip test\n")); | |
4930 return 0; | |
4931 } | |
4932 | |
4933 #else | |
4934 extern int request_id_last; // from task.c | |
4935 | |
4936 #define WAIT_GET_TEST ttw(ttr(TTrTest, "Wait..." NL)); rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0); ttw(ttr(TTrTest, "Get mail" NL)); confirm_file = (T_FFS_FILE_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0); ttw(ttr(TTrTest, "Path '%s'" NL, confirm_file->path)); expect(FFS_MESSAGE_OFFSET, confirm_file->header.msg_id); expect(my_id, confirm_file->request_id); | |
4937 | |
4938 #define WAIT_GET_TEST_FDI ttw(ttr(TTrTest, "Wait..." NL)); rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0); confirm_stream = (T_FFS_STREAM_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0); ttw(ttr(TTrTest, "Get mail" NL)); ttw(ttr(TTrTest, "fdi: %d" NL, confirm_stream->fdi)); expect(FFS_MESSAGE_OFFSET, confirm_stream->header.msg_id); expect(FFS_FD_OFFSET, confirm_stream->fdi); expect(my_id, confirm_stream->request_id); | |
4939 | |
4940 #define FREE error = rvf_free_buf(confirm_file); if (error < 0) { ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); return 1;} | |
4941 | |
4942 #define FREE_FDI error = rvf_free_buf(confirm_stream); if (error < 0) { ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); return 1;} | |
4943 | |
4944 int case_nonblock(int p0, int p1) | |
4945 { | |
4946 T_FFS_FILE_CNF *confirm_file; | |
4947 T_FFS_STREAM_CNF *confirm_stream; | |
4948 T_FFS_RET error; | |
4949 T_FFS_FD fdi; | |
4950 char hello[] = "Hello, world"; | |
4951 char myfname[] = "/non_block/file"; | |
4952 char mysname[] = "/non_block/stream"; | |
4953 T_FFS_SIZE size; | |
4954 int i; | |
4955 T_FFS_REQ_ID my_id; | |
4956 // mail confirm | |
4957 T_RV_RETURN cnfpath = {MY_TASK_ID, 0}; | |
4958 | |
4959 // Test wrap arround in request_id_get(). Set id to 5 from max, the following | |
4960 // function calls will trigger the wrap arround | |
4961 request_id_last = 0x7FFFFFFF - 5; | |
4962 ttw(ttr(TTrTest, "request :%d" NL, request_id_last)); | |
4963 | |
4964 // preformat, format, mkdir | |
4965 // open, write, ftruncate, close, remove, | |
4966 // file_write, symlink, rename, truncate, fcontrol | |
4967 | |
4968 my_id = ffs_preformat_nb(0xDEAD, &cnfpath); | |
4969 expect_gt(my_id, -1); | |
4970 WAIT_GET_TEST; FREE; | |
4971 | |
4972 my_id = ffs_format_nb("/ffs", 0x2BAD, &cnfpath); | |
4973 expect_gt(my_id, -1); | |
4974 WAIT_GET_TEST; FREE; | |
4975 | |
4976 my_id = ffs_mkdir_nb("/non_block", &cnfpath); | |
4977 expect_gt(my_id, -1); | |
4978 WAIT_GET_TEST; FREE; | |
4979 | |
4980 if ((my_id = ffs_open_nb(mysname, FFS_O_WRONLY | FFS_O_CREATE, | |
4981 &cnfpath)) < 0) | |
4982 return my_id; | |
4983 WAIT_GET_TEST; | |
4984 fdi = confirm_file->error; | |
4985 expect(FFS_FD_OFFSET, fdi); | |
4986 FREE; | |
4987 | |
4988 if ((my_id = ffs_write_nb(fdi, hello, strlen(hello), &cnfpath)) < 0) | |
4989 return my_id; | |
4990 WAIT_GET_TEST_FDI; FREE_FDI; | |
4991 | |
4992 expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty); | |
4993 if ((my_id = ffs_fdatasync_nb(fdi, &cnfpath)) < 0) | |
4994 return my_id; | |
4995 WAIT_GET_TEST_FDI; FREE_FDI; | |
4996 expect(0, fs.fd[fdi - FFS_FD_OFFSET].dirty); | |
4997 | |
4998 if ((my_id = ffs_seek_nb(fdi, 2, FFS_SEEK_SET, &cnfpath)) < 0) | |
4999 return my_id; | |
5000 WAIT_GET_TEST_FDI; FREE_FDI; | |
5001 expect(2, fs.fd[fdi - FFS_FD_OFFSET].fp); | |
5002 | |
5003 if ((my_id = ffs_ftruncate_nb(fdi, 3, &cnfpath)) < 0) | |
5004 return my_id; | |
5005 WAIT_GET_TEST_FDI; | |
5006 expect(EFFS_OK, confirm_stream->error); | |
5007 FREE_FDI; | |
5008 | |
5009 if ((my_id = ffs_close_nb(fdi, &cnfpath)) < 0) | |
5010 return my_id; | |
5011 WAIT_GET_TEST_FDI; | |
5012 expect(EFFS_OK, confirm_stream->error); | |
5013 FREE_FDI; | |
5014 | |
5015 if ((my_id = ffs_remove_nb(mysname, &cnfpath)) < 0) | |
5016 return my_id; | |
5017 WAIT_GET_TEST; | |
5018 expect(EFFS_OK, confirm_file->error); | |
5019 FREE; | |
5020 | |
5021 if ((my_id = ffs_file_write_nb(myfname, hello, strlen(hello), | |
5022 FFS_O_WRONLY | FFS_O_CREATE, &cnfpath)) < 0) | |
5023 return my_id; | |
5024 WAIT_GET_TEST; | |
5025 expect(EFFS_OK, confirm_file->error); | |
5026 FREE; | |
5027 | |
5028 if ((my_id = ffs_symlink_nb("/nb_file", myfname, &cnfpath)) < 0) | |
5029 return my_id; | |
5030 WAIT_GET_TEST; | |
5031 expect(EFFS_OK, confirm_file->error); | |
5032 FREE; | |
5033 | |
5034 if ((my_id = ffs_rename_nb("/nb_file", "/nbf", &cnfpath)) < 0) | |
5035 return my_id; | |
5036 WAIT_GET_TEST; | |
5037 expect(EFFS_OK, confirm_file->error); | |
5038 FREE; | |
5039 | |
5040 if ((my_id = ffs_truncate_nb(myfname, 0, &cnfpath)) < 0) | |
5041 return my_id; | |
5042 WAIT_GET_TEST; | |
5043 expect(EFFS_OK, confirm_file->error); | |
5044 FREE; | |
5045 | |
5046 if ((my_id = ffs_fcontrol_nb(myfname, OC_FLAGS, OF_READONLY, &cnfpath)) < 0) | |
5047 return my_id; | |
5048 WAIT_GET_TEST; | |
5049 expect(EFFS_OK, confirm_file->error); | |
5050 FREE; | |
5051 | |
5052 ttw(ttr(TTrTest, "request :%d" NL, request_id_last)); | |
5053 | |
5054 // This should make a EFFS_MEMORY fail | |
5055 for(i = 0; i < 10000; i++) { | |
5056 my_id = ffs_fwrite_nb("/mem_test", TDATA(0), 0); | |
5057 if (my_id < 0) | |
5058 break; | |
5059 } | |
5060 ttw(ttr(TTrTest, "write nr: %d my_id: %d" NL, i, my_id)); | |
5061 expect(my_id, EFFS_MEMORY); | |
5062 // All memory has been used so wait a while (let some of the writes finish) | |
5063 tffs_delay(50); | |
5064 // Make a call to a blocking function will make it possible for ffs to | |
5065 // finish all the non blocking writes. | |
5066 error = ffs_fwrite("/mem_test", TDATA(0)); | |
5067 expect_ok(error); | |
5068 | |
5069 return 0; | |
5070 } | |
5071 #endif | |
5072 | |
5073 /****************************************************************************** | |
5074 * Blocking test | |
5075 ******************************************************************************/ | |
5076 | |
5077 #if (TARGET == 0) | |
5078 int case_blocking(int p0, int p1) | |
5079 { | |
5080 tw(tr(TR_FUNC, TrTest, | |
5081 "WARNING: This test can only run in target. Skip test\n")); | |
5082 return 0; | |
5083 } | |
5084 #else | |
5085 | |
5086 #include "ffs/board/task.h" | |
5087 void my_mb_callback(T_RVF_MB_ID id) | |
5088 { // Dummy callback function | |
5089 } | |
5090 | |
5091 | |
5092 // Test that a FFS API blocking call that not is able to send a mail to FFS fails as expected and don't lock the system (it must unlock and delete the mutex). | |
5093 int case_blocking(int p0, int p1) | |
5094 { | |
5095 UINT32 mem_unused; | |
5096 T_RVF_MB_STATUS status; | |
5097 char *buf; | |
5098 extern T_OS_MB_ID ffs_mb_id; | |
5099 | |
5100 // Later when all the memory is used the memory bank will be marked as | |
5101 // RED by Riviera. The RED flag is erased when the buffer is freed but | |
5102 // only if a callback function is applied. | |
5103 rvf_set_callback_func(ffs_mb_id, my_mb_callback); // Ignore error | |
5104 | |
5105 mem_unused = rvf_get_mb_unused_mem(ffs_mb_id); | |
5106 ttw(ttr(TTrTest,"Unused memory: %d" NL, mem_unused)); | |
5107 | |
5108 // When all the memory is used the blocking functions will not be able | |
5109 // to allocate memory to the FFS mail thus it must fail. After the | |
5110 // buffer has been freed the block call must again be fully functional. | |
5111 if ((buf = (char *) target_malloc(mem_unused)) == 0) | |
5112 return EFFS_MEMORY; | |
5113 | |
5114 error = tffs_fwrite("/blocking_test", (char*)tdata[TDATA_HUGE], 20); | |
5115 | |
5116 target_free(buf); | |
5117 | |
5118 expect(error, EFFS_MEMORY); | |
5119 | |
5120 error = tffs_fwrite("/blocking_test", (char*)tdata[TDATA_HUGE], 20); | |
5121 expect_ok(error); | |
5122 | |
5123 return EFFS_OK; | |
5124 } | |
5125 #endif | |
5126 | |
5127 /****************************************************************************** | |
5128 * Test erase_suspend and erase_resume | |
5129 ****************************************************************************** | |
5130 * Test erase suspend and resume by making a call to ffs_begin() followed by | |
5131 * an ffs_read() while we are erasing. We trigger the erase by sending | |
5132 * several write mails to FFS. We let FFS get the CPU for less time than an | |
5133 * erase, which will guarantee that we interrupt the erase when we call | |
5134 * ffs_begin(). | |
5135 ******************************************************************************/ | |
5136 #if (TARGET == 1) | |
5137 static int write_mails_left; | |
5138 | |
5139 static void driver_callback(T_FFS_FILE_CNF *confirm) | |
5140 { | |
5141 if (confirm->error < 0) { | |
5142 ttw(ttr(TTrTest, "FATAL: driver_callback error: %d" NL, confirm->error)); | |
5143 } | |
5144 | |
5145 error = rvf_free_buf(confirm); | |
5146 if (error < 0) | |
5147 ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); | |
5148 | |
5149 write_mails_left--; | |
5150 } | |
5151 #endif | |
5152 | |
5153 #if (TARGET == 0) | |
5154 int case_erase_suspend(int p0, int p1) | |
5155 { | |
5156 tw(tr(TR_FUNC, TrTestHigh, "Erase_suspend test not supported on PC sim\n")); | |
5157 return 1; | |
5158 } | |
5159 #else | |
5160 // TEST erase_suspend and erase_resume | |
5161 int case_erase_suspend(int p0, int p1) | |
5162 { | |
5163 int i, j, error, nsuspend; | |
5164 char myname[] = "/ffs/b4"; // Run test with only 4 block. | |
5165 char myfname[] = "/driver_test"; | |
5166 int file_size = 1024; | |
5167 | |
5168 T_RV_RETURN cnfpath = {0, (CALLBACK_FUNC)driver_callback}; | |
5169 | |
5170 ttw(ttr(TTrTest, "Erase suspend-resume test" NL)); | |
5171 | |
5172 // To minimize the numbers of required writes before we are guarantied an | |
5173 // erase we run this test in only 4 blocks | |
5174 error = tffs_preformat(0xDEAD); | |
5175 expect(error, EFFS_OK); | |
5176 error = tffs_format(myname, 0x2BAD); | |
5177 expect(error, EFFS_OK); | |
5178 | |
5179 if (p0 == 0) p0 = 1; | |
5180 for (j = 0; j < p0; j++) { | |
5181 write_mails_left = 0; | |
5182 // Write 2 blocks of data (must trigger an erase) | |
5183 for (i = 0; i < 2 * (dev.blocksize/file_size); i++) | |
5184 { | |
5185 // Non blockin write | |
5186 if ((error = ffs_file_write_nb(myfname, (char *) tdata[TDATA_HUGE], | |
5187 file_size, | |
5188 FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC, | |
5189 &cnfpath)) < 0) | |
5190 return error; | |
5191 write_mails_left++; | |
5192 } | |
5193 ttw(ttr(TTrTest, "Finish write calls(%d)" NL, i)); | |
5194 | |
5195 // NOTE only tested with AMD MB driver | |
5196 switch (dev.driver) { | |
5197 case FFS_DRIVER_AMD: | |
5198 case FFS_DRIVER_SST: | |
5199 case FFS_DRIVER_INTEL: | |
5200 case FFS_DRIVER_AMD_SB: | |
5201 ttw(ttr(TTrTest, "Start read test" NL)); | |
5202 nsuspend = 0; | |
5203 do { | |
5204 // NOTEME: We can also test if we get the CPU and not is delay | |
5205 // by the erase | |
5206 | |
5207 // This will change state to ERASE_SUSPEND if we are in | |
5208 // ERASE mode (only valid for MB driver) | |
5209 error = ffs_begin(); | |
5210 expect(error, EFFS_OK); | |
5211 | |
5212 if (dev.state == DEV_ERASE_SUSPEND) { | |
5213 nsuspend++; | |
5214 // Read... Note it will also resume the erase (MB driver). | |
5215 error = tffs_file_read(myfname, bigbuf, file_size/4); | |
5216 expect(error, EFFS_FILETOOBIG); | |
5217 } | |
5218 rvf_delay(5); // Let FFS get the CPU for some time | |
5219 } while (write_mails_left > 0); | |
5220 | |
5221 if (nsuspend <= 0) { | |
5222 ttw(ttr(TTrTest, "Arg no erase suspend" NL)); | |
5223 return 1; | |
5224 } | |
5225 ttw(ttr(TTrTest, "Erase suspended %d times" NL, nsuspend)); | |
5226 break; | |
5227 | |
5228 case FFS_DRIVER_SST_SB: | |
5229 case FFS_DRIVER_INTEL_SB: | |
5230 default: | |
5231 ttw(ttr(TTrTest, "Driver not supported by this test" NL)); | |
5232 // Do not return before the cnfpath resource not is used anymore | |
5233 while (write_mails_left > 0) rvf_delay(100); | |
5234 return 1; | |
5235 } | |
5236 } | |
5237 return 0; | |
5238 } | |
5239 #endif // TARGET == 0 | |
5240 | |
5241 /****************************************************************************** | |
5242 * The 3 below testh_.. function is helper function used for the low level | |
5243 * driver tests. | |
5244 ******************************************************************************/ | |
5245 #if (TARGET == 1) | |
5246 | |
5247 uint32 int_disable(void); | |
5248 void int_enable(uint32 tmp); | |
5249 | |
5250 // Only start an erase, don't wait until it is finish | |
5251 // Note to use this function with SB drivers require a multi bank flash device | |
5252 int testh_nb_erase(uint8 block) | |
5253 { | |
5254 volatile char *flash = dev.base; | |
5255 volatile char *addr; | |
5256 uint32 cpsr; | |
5257 | |
5258 ttw(ttr(TTrTest, "e(%d)" NL, block)); | |
5259 | |
5260 addr = block2addr(block); | |
5261 cpsr = int_disable(); | |
5262 switch (dev.driver) { | |
5263 case FFS_DRIVER_AMD: | |
5264 case FFS_DRIVER_AMD_SB: | |
5265 case FFS_DRIVER_AMD_PSEUDO_SB: | |
5266 flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 | |
5267 flash[0x5555] = 0x55; // AMD unlock cycle 2 | |
5268 flash[0xAAAA] = 0x80; | |
5269 flash[0xAAAA] = 0xAA; // AMD unlock cycle 1 | |
5270 flash[0x5555] = 0x55; // AMD unlock cycle 2 | |
5271 *addr = 0x30; // AMD erase sector command | |
5272 int_enable(cpsr); | |
5273 break; | |
5274 default: | |
5275 return -1; // Not yet supported | |
5276 } | |
5277 return 0; | |
5278 } | |
5279 | |
5280 // Note to use this function with SB drivers require a multi bank flash device | |
5281 int testh_erase_suspend(uint8 block) | |
5282 { | |
5283 volatile char *flash = dev.base; | |
5284 volatile char *addr; | |
5285 | |
5286 ttw(ttr(TTrTest, "esusp(%d)" NL, block)); | |
5287 | |
5288 addr = block2addr(block); | |
5289 switch (dev.driver) { | |
5290 case FFS_DRIVER_AMD: | |
5291 case FFS_DRIVER_AMD_SB: | |
5292 case FFS_DRIVER_AMD_PSEUDO_SB: | |
5293 *addr = 0xB0; // AMD erase suspend command | |
5294 break; | |
5295 default: | |
5296 return -1; // Not yet supported | |
5297 } | |
5298 return 0; | |
5299 } | |
5300 | |
5301 int testh_get_free_block(void) | |
5302 { | |
5303 uint8 b; | |
5304 | |
5305 for (b = 0; b < dev.numblocks; b++) | |
5306 { | |
5307 if (is_block(b, BF_IS_FREE) || is_block(b, BF_IS_EMPTY)) | |
5308 return b; | |
5309 } | |
5310 return -1; | |
5311 } | |
5312 #endif // TARGET == 1 | |
5313 | |
5314 // NOTEME: The below test have not been used in this FFS version | |
5315 // NOTEME: We don't have an AMD init function | |
5316 /****************************************************************************** | |
5317 * Test drv.init (low level driver test) | |
5318 ****************************************************************************** | |
5319 * Test drv.init by start an erase, call drv.init and make sure that the | |
5320 * erase is finish after we return from drv.init. | |
5321 * | |
5322 * Test drv.init by start erase, suspend the erase and make sure that the | |
5323 * erase is resumed and finish before we return from drv.init. The test is | |
5324 * valid for both AMD SB and MB driver | |
5325 ******************************************************************************/ | |
5326 | |
5327 #if (TARGET == 0) | |
5328 int case_drv_init(int p0, int p1) | |
5329 { | |
5330 tw(tr(TR_FUNC, TrTestHigh, "drv_init test not supported on PC sim\n")); | |
5331 return 1; | |
5332 } | |
5333 #else | |
5334 int case_drv_init(int p0, int p1) | |
5335 { | |
5336 volatile char *flash = dev.base; | |
5337 volatile char *addr; | |
5338 char myname[] = "/drv_init"; | |
5339 uint32 cpsr; | |
5340 uint8 block; | |
5341 int free_b, i, j, command; | |
5342 enum command { ERASE, WRITE, READ }; | |
5343 char action[6][3] = | |
5344 { | |
5345 { WRITE, READ, ERASE }, | |
5346 { WRITE, ERASE, READ }, | |
5347 { READ, WRITE, ERASE }, | |
5348 { READ, ERASE, WRITE }, | |
5349 { ERASE, READ, WRITE }, | |
5350 { ERASE, WRITE, READ } | |
5351 }; | |
5352 | |
5353 ttw(ttr(TTrTest, "Test ffsdrv.init()" NL)); | |
5354 | |
5355 // Test drv.init 6 times there the flash is in erase mode and 6 times | |
5356 // there the flash is in erase suspend mode. | |
5357 for (i = 0; i < 12; i++) | |
5358 { | |
5359 free_b = testh_get_free_block(); | |
5360 expect_ok(free_b); | |
5361 | |
5362 fs.debug[0] = 0; | |
5363 fs.debug[1] = 0; | |
5364 | |
5365 // Start erase, run driver init. | |
5366 error = testh_nb_erase(free_b); | |
5367 expect_ok(error); | |
5368 rvf_delay(20); // Make sure that the erase has started | |
5369 | |
5370 if (i > 6) { | |
5371 error = testh_erase_suspend(free_b); | |
5372 expect_ok(error); | |
5373 rvf_delay(20); // Make sure that the erase is suspended | |
5374 } | |
5375 | |
5376 error = ffsdrv.init(); // Call ffsdrv_init() instead? (inc. autodetect) | |
5377 expect_ok(error); | |
5378 | |
5379 if (i > 6) { | |
5380 expect(fs.debug[0], 1); // Test that the erase was resumed | |
5381 expect_gt(fs.debug[1], 0); // Test what we did wait for erase to finish | |
5382 } | |
5383 else { | |
5384 expect(fs.debug[0], 0); // Erase not resumed | |
5385 expect_gt(fs.debug[1], 0); // We did wait for an erase to finish | |
5386 } | |
5387 | |
5388 // To test that any combination of erase, read or write can be | |
5389 // performed after drv.init do we make the test below. The first | |
5390 // complete drv.init test will be like this: Start an erase, call | |
5391 // drv.init(), write a file, read the file and erase a free block. | |
5392 for (j = 0; j < 3; j++) { | |
5393 if (i < 6) | |
5394 command = action[i][j]; | |
5395 else | |
5396 command = action[i-6][j]; | |
5397 switch (command) { | |
5398 case ERASE: | |
5399 free_b = testh_get_free_block(); | |
5400 expect_ok(free_b); | |
5401 ffsdrv.erase(free_b); | |
5402 break; | |
5403 case READ: | |
5404 error = test_expect_file(myname, TDATA(2)); | |
5405 if (error) return 1; | |
5406 break; | |
5407 case WRITE: | |
5408 error = tffs_fwrite(myname, TDATA(2)); | |
5409 expect(error, EFFS_OK); | |
5410 break; | |
5411 default: | |
5412 return 1; | |
5413 } | |
5414 } | |
5415 } | |
5416 return 0; | |
5417 } | |
5418 #endif | |
5419 | |
5420 uint32 get_cpsr(void); | |
5421 | |
5422 // Test disable and enable of interrupt (Note only valid for MB drivers) | |
5423 int case_interrupt(int p0, int p1) | |
5424 { | |
5425 extern void int_enable(uint32 tmp); | |
5426 extern uint32 int_disable(void); | |
5427 uint32 cpsr; | |
5428 int i; | |
5429 uint32 xcpsr; | |
5430 | |
5431 switch (dev.driver) { | |
5432 case FFS_DRIVER_AMD: | |
5433 case FFS_DRIVER_INTEL: | |
5434 break; | |
5435 default: | |
5436 return 1; // Not supported | |
5437 } | |
5438 | |
5439 p0 *= 100; | |
5440 | |
5441 ttw(ttr(TTrTest, "Test interrupt code" NL)); | |
5442 | |
5443 for (i = 0; i < p0; i++) { | |
5444 cpsr = int_disable(); | |
5445 xcpsr = get_cpsr(); | |
5446 if ((xcpsr & 0xC0) != 0xC0) { | |
5447 ttw(ttr(TTrTest, "FATAL int not disablet!" NL)); | |
5448 return 1; | |
5449 } | |
5450 int_enable(cpsr); | |
5451 xcpsr = get_cpsr(); | |
5452 if ((xcpsr & 0xC0) != 0) { | |
5453 ttw(ttr(TTrTest, "FATAL int not enablet!" NL)); | |
5454 return 1; | |
5455 } | |
5456 if ((i % 1000) == 0) | |
5457 ttw(ttr(TTrTest, "loop (%d)" NL, i)); | |
5458 } | |
5459 | |
5460 return 0; | |
5461 } | |
5462 | |
5463 | |
5464 /****************************************************************************** | |
5465 * Benchmarking | |
5466 ******************************************************************************/ | |
5467 // Below define only for PC compile | |
5468 #if (TARGET == 0) | |
5469 #define UINT32 int | |
5470 #define tffs_timer_begin() 0 | |
5471 #define tffs_timer_end(time) 5000 - time | |
5472 #endif | |
5473 | |
5474 const struct results_s old_results[] = | |
5475 { | |
5476 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | |
5477 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } | |
5478 }; | |
5479 | |
5480 // NOTEME: Bencmark_results() not finished. | |
5481 int bencmark_results(int manufact, int driver, int sample, | |
5482 struct results_s *meas_res) | |
5483 { | |
5484 switch(manufact) { | |
5485 case MANUFACT_AMD: | |
5486 switch(driver) { | |
5487 // case FFS_DRIVER_AMD: | |
5488 case FFS_DRIVER_AMD_SB: | |
5489 default: return 0; | |
5490 } | |
5491 case MANUFACT_FUJITSU: | |
5492 switch(driver) { | |
5493 // case FFS_DRIVER_AMD: | |
5494 case FFS_DRIVER_AMD_SB: | |
5495 default: return 0; | |
5496 } | |
5497 default: return 0; | |
5498 } | |
5499 } | |
5500 | |
5501 // Benchmark write and read operation. Measure write throughput as kBps in | |
5502 // idle and loopback mode. Both for an empty ffs where we don't have to | |
5503 // reclaim blocks and for a full ffs where block reclaims/erasures affect | |
5504 // the overall throughput. For SB flash driver as well as for DB driver. For | |
5505 // files of size:16, 256, 4096, bytes. | |
5506 int case_bm_stream_rw(int p0, int p1) | |
5507 { | |
5508 #if (TARGET == 1) | |
5509 UINT32 time_begin, elapsed, bytes_max; | |
5510 char myname[] = "/Benchmark0"; | |
5511 int i, j, k, nm_files, file_size; | |
5512 int size, write_size[] = {16, 256, 4096}; | |
5513 fd_t fdi; | |
5514 | |
5515 //ttw(ttr(TTrTest, "RVF_POOL_0_SIZE: %d" NL, RVF_POOL_0_SIZE)); | |
5516 | |
5517 // 1 block is used for inodes, 1 have to be free, 1/4 is used for | |
5518 // journal and 1/2 is used as a margin | |
5519 | |
5520 // FIXME: changed to 4.75 because the SW TCS2.1 dos make some files and | |
5521 // because of this is there not enough data space left to this test. | |
5522 // NOTEME: Instead of hardwire this value then query it | |
5523 bytes_max = (dev.numblocks - 4.75) * dev.blocksize; | |
5524 file_size = bytes_max / dev.numblocks; | |
5525 ttw(ttr(TTrTest, "bytes_max: %d(- 2.75 block)" NL, bytes_max)); | |
5526 | |
5527 // Format, measure write of 16B. | |
5528 // Format, measure write of 256B. | |
5529 // Format, measure write of 4096B. | |
5530 | |
5531 for (j = 0; j < 3; j++) { | |
5532 ttw(ttr(TTrTest, "Format, measure write of %dB" NL, write_size[j])); | |
5533 | |
5534 error = tffs_preformat(0xDEAD); | |
5535 expect(error, EFFS_OK); | |
5536 error = tffs_format("/foo", 0x2BAD); | |
5537 expect(error, EFFS_OK); | |
5538 | |
5539 time_begin = tffs_timer_begin(); | |
5540 for (i = 0; i < dev.numblocks; i++) { | |
5541 myname[10] = i + (i <= 9 ? '0': 'A' -10); | |
5542 | |
5543 fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE); | |
5544 expect(fdi, FFS_FD_OFFSET); | |
5545 | |
5546 size = 0; | |
5547 do { | |
5548 size += error = tffs_write(fdi, (char*)tdata[TDATA_HUGE], | |
5549 write_size[j]); | |
5550 if (error < 0) { | |
5551 if (error == EFFS_NOSPACE) { | |
5552 ttw(ttr(TTrTest, "Aarg out of space" NL)); | |
5553 bytes_max = size; | |
5554 break; | |
5555 } | |
5556 else | |
5557 expect_ok(error); | |
5558 } | |
5559 } while (size < file_size); | |
5560 | |
5561 error = tffs_close(fdi); | |
5562 expect_ok(error); | |
5563 } | |
5564 | |
5565 elapsed = tffs_timer_end(time_begin); | |
5566 // FFS has used the CPU for a long time so let the trace task get | |
5567 // the CPU for a while | |
5568 tffs_delay(50); | |
5569 ttw(ttr(TTrTest, "Write %dBytes %d times in %dms, %dkBps" NL NL, | |
5570 write_size[j], file_size/write_size[j], elapsed, | |
5571 (bytes_max * 1000) / (elapsed * 1024))); | |
5572 } | |
5573 | |
5574 | |
5575 ttw(ttr(TTrTest, "Rm all files, measure write of 4kB" NL)); | |
5576 for (i = 0; i < dev.numblocks; i++) { | |
5577 myname[10] = i + (i <= 9 ? '0': 'A' -10); | |
5578 error = tffs_remove(myname); | |
5579 expect_ok(error); | |
5580 } | |
5581 | |
5582 time_begin = tffs_timer_begin(); | |
5583 for (i = 0; i < dev.numblocks; i++) { | |
5584 myname[10] = i + (i <= 9 ? '0': 'A' -10); | |
5585 fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE); | |
5586 expect(fdi, FFS_FD_OFFSET); | |
5587 | |
5588 size = 0; | |
5589 do { | |
5590 size += tffs_write(fdi, (char*)tdata[TDATA_HUGE], write_size[2]); | |
5591 } while (size < file_size); | |
5592 | |
5593 error = tffs_close(fdi); | |
5594 expect_ok(error); | |
5595 } | |
5596 | |
5597 elapsed = tffs_timer_end(time_begin); | |
5598 tffs_delay(50); | |
5599 ttw(ttr(TTrTest, "Write %dBytes %d times in %dms, %dkBps" NL NL, | |
5600 write_size[2], file_size/write_size[2], elapsed, | |
5601 (bytes_max * 1000) / (elapsed * 1024))); | |
5602 | |
5603 | |
5604 // Read all files with 16B at a time | |
5605 for (j = 0; j < 3; j++) { | |
5606 ttw(ttr(TTrTest, "Read all files with %dB at a time" NL, write_size[j])); | |
5607 time_begin = tffs_timer_begin(); | |
5608 | |
5609 for (i = 0; i < dev.numblocks; i++) { | |
5610 myname[10] = i + (i <= 9 ? '0': 'A' -10); | |
5611 fdi = tffs_open(myname, FFS_O_RDONLY); | |
5612 expect(fdi, FFS_FD_OFFSET); | |
5613 size = 0; | |
5614 do { | |
5615 size += tffs_read(fdi, bigbuf, write_size[j]); | |
5616 } while (size < file_size); | |
5617 | |
5618 error = tffs_close(fdi); | |
5619 expect(error, 0); | |
5620 } | |
5621 elapsed = tffs_timer_end(time_begin); | |
5622 | |
5623 ttw(ttr(TTrTest, "Read %d files of %dkB in %dms, %dkBps," NL NL, | |
5624 dev.numblocks, size/1024, elapsed, | |
5625 (dev.numblocks * size * 1000) / (elapsed * 1024))); | |
5626 } | |
5627 | |
5628 | |
5629 // Measure write and read of one big file | |
5630 ttw(ttr(TTrTest, "Format, Write and read one big file" NL)); | |
5631 | |
5632 error = tffs_preformat(0xDEAD); | |
5633 expect(error, EFFS_OK); | |
5634 error = tffs_format("/foo", 0x2BAD); | |
5635 expect(error, EFFS_OK); | |
5636 | |
5637 time_begin = tffs_timer_begin(); | |
5638 | |
5639 fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE); | |
5640 | |
5641 size = 0; | |
5642 do { | |
5643 size += tffs_write(fdi, bigbuf, write_size[2]); | |
5644 } while (size < bytes_max); | |
5645 | |
5646 error = tffs_close(fdi); | |
5647 expect(error, 0); | |
5648 | |
5649 elapsed = tffs_timer_end(time_begin); | |
5650 | |
5651 ttw(ttr(TTrTest, "Write %dkB in %dms, %dkBps" NL, | |
5652 size/1024 , elapsed, (size * 1000) / (elapsed * 1024))); | |
5653 | |
5654 | |
5655 time_begin = tffs_timer_begin(); | |
5656 | |
5657 // read one big file (reading one big file take more time than reading | |
5658 // many files of the same total size because there is a lot more inode | |
5659 // to look through) | |
5660 fdi = tffs_open(myname, FFS_O_RDONLY); | |
5661 expect(fdi, FFS_FD_OFFSET); | |
5662 size = 0; | |
5663 do { | |
5664 size += tffs_read(fdi, bigbuf, write_size[2]); | |
5665 } while (size < bytes_max); | |
5666 | |
5667 error = tffs_close(fdi); | |
5668 expect(error, 0); | |
5669 | |
5670 elapsed = tffs_timer_end(time_begin); | |
5671 | |
5672 ttw(ttr(TTrTest, "Read %dkB in %dms, %dkBps," NL, | |
5673 size/1024, elapsed, (size * 1000) / (elapsed * 1024))); | |
5674 | |
5675 // Make a data base of old measurements her? compare with old data and | |
5676 // make a warning if the performance has decreased? | |
5677 | |
5678 return 0; | |
5679 #else | |
5680 return 1; | |
5681 #endif | |
5682 } | |
5683 | |
5684 // Benchmark ffs_file_write() and ffs_file_read() | |
5685 int case_bm_file_rw(int p0, int p1) | |
5686 { | |
5687 UINT32 time_begin, elapsed; | |
5688 char myname[] = "/Benchmark"; | |
5689 int i, j; | |
5690 | |
5691 struct test_info_s { | |
5692 int fsize; | |
5693 int fnumber; | |
5694 }; | |
5695 | |
5696 struct test_info_s tinfo[] = { | |
5697 { 16, 500 }, | |
5698 { 256, 200 }, | |
5699 { 4096, 200 }, | |
5700 {32768, 10 } | |
5701 }; | |
5702 | |
5703 for (j = 0; j < 4; j++) { | |
5704 ttw(ttr(TTrTest, "Format, measure write of %dB" NL, tinfo[j].fsize)); | |
5705 | |
5706 error = tffs_preformat(0xDEAD); | |
5707 expect(error, EFFS_OK); | |
5708 error = tffs_format("/foo", 0x2BAD); | |
5709 expect(error, EFFS_OK); | |
5710 | |
5711 time_begin = tffs_timer_begin(); | |
5712 for (i = 0; i < tinfo[j].fnumber; i++) { | |
5713 error = tffs_file_write(myname, (char*)tdata[TDATA_HUGE], | |
5714 tinfo[j].fsize, FFS_O_CREATE); | |
5715 expect_ok(error); | |
5716 } | |
5717 elapsed = tffs_timer_end(time_begin); | |
5718 | |
5719 // FFS has used the CPU for a long time so let the trace task get | |
5720 // the CPU for a while | |
5721 tffs_delay(50); | |
5722 ttw(ttr(TTrTest, "Write %dBytes %d times in %dms, %dkBps" NL NL, | |
5723 tinfo[j].fsize, i, elapsed, | |
5724 (i * tinfo[j].fsize * 1000) / (elapsed * 1024))); | |
5725 | |
5726 time_begin = tffs_timer_begin(); | |
5727 for (i = 0; i < tinfo[j].fnumber; i++) { | |
5728 error = tffs_file_read(myname, bigbuf, tinfo[j].fsize); | |
5729 expect_ok(error); | |
5730 } | |
5731 elapsed = tffs_timer_end(time_begin); | |
5732 | |
5733 ttw(ttr(TTrTest, "Read %dBytes %d times in %dms, %dkBps" NL NL, | |
5734 tinfo[j].fsize, i, elapsed, | |
5735 (i * tinfo[j].fsize * 1000) / (elapsed * 1024))); | |
5736 } | |
5737 tffs_delay(3000); | |
5738 | |
5739 return 0; | |
5740 } | |
5741 | |
5742 // We banchmark lookups by using ffs_stat() | |
5743 int case_bm_lookup(int p0, int p1) | |
5744 { | |
5745 //format, update file x times, measure lookup with ffs_stat() | |
5746 //format, make x difference files, measure lookup with ffs_stat() | |
5747 //format, make a file in max directory depth, measure lookup with ffs_stat() | |
5748 //format, make one file, measure lookup with ffs_stat() (no traverse) | |
5749 //format, make x dirs with x files, measure lookup of last file in last dir | |
5750 #if (TARGET == 1) | |
5751 UINT32 time_begin, elapsed; | |
5752 int i, j; | |
5753 char myname[] = "/benchmark"; | |
5754 char mydir[100] = ""; | |
5755 char depth[] = "/depth99"; | |
5756 char mypath[100] = ""; | |
5757 | |
5758 //format, update file 100 times, measure lookup with ffs_stat() | |
5759 error = tffs_preformat(0xDEAD); | |
5760 expect(error, EFFS_OK); | |
5761 error = tffs_format("/foo", 0x2BAD); | |
5762 expect(error, EFFS_OK); | |
5763 | |
5764 for (i = 0; i < 100; i++) { | |
5765 error = tffs_file_write(myname, 0,0, FFS_O_CREATE); | |
5766 expect_ok(error); | |
5767 } | |
5768 | |
5769 time_begin = tffs_timer_begin(); | |
5770 for (i = 0; i < 100; i++) { | |
5771 error = tffs_stat(myname, &stat); | |
5772 expect_ok(error); | |
5773 } | |
5774 elapsed = tffs_timer_end(time_begin); | |
5775 | |
5776 ttw(ttr(TTrTest, "Lookup through 100 deleted objects 100 times in %dms(%d obj/s)" NL, elapsed, 100 * 1000 / elapsed)); | |
5777 | |
5778 //format, make 100 difference files, measure lookup with ffs_stat() | |
5779 error = tffs_preformat(0xDEAD); | |
5780 expect(error, EFFS_OK); | |
5781 error = tffs_format("/foo", 0x2BAD); | |
5782 expect(error, EFFS_OK); | |
5783 | |
5784 for (i = 0; i < 100; i++) { | |
5785 sprintf(myname, "/benchm%d", i); | |
5786 error = tffs_file_write(myname, 0,0, FFS_O_CREATE); | |
5787 expect_ok(error); | |
5788 } | |
5789 | |
5790 time_begin = tffs_timer_begin(); | |
5791 for (i = 0; i < 100; i++) { | |
5792 error = tffs_stat(myname, &stat); | |
5793 expect_ok(error); | |
5794 } | |
5795 elapsed = tffs_timer_end(time_begin); | |
5796 | |
5797 ttw(ttr(TTrTest, "Lookup through 100 difference objects 100 times in %dms(%d obj/s)" | |
5798 NL, elapsed, 100 * 1000 / elapsed)); | |
5799 | |
5800 //format, make a file in max directory depth, measure lookup with ffs_stat() | |
5801 error = tffs_preformat(0xDEAD); | |
5802 expect(error, EFFS_OK); | |
5803 error = tffs_format("/foo", 0x2BAD); | |
5804 expect(error, EFFS_OK); | |
5805 | |
5806 for (i = 0; i < fs.path_depth_max - 1; i++) { | |
5807 sprintf(depth, "/depth%d", i + 1); | |
5808 strcat(mydir, depth); | |
5809 error = tffs_mkdir(mydir); | |
5810 expect_ok(error); | |
5811 } | |
5812 | |
5813 strcat(mydir, myname); | |
5814 error = tffs_file_write(mydir, 0,0, FFS_O_CREATE); | |
5815 expect_ok(error); | |
5816 | |
5817 time_begin = tffs_timer_begin(); | |
5818 for (i = 0; i < 1000; i++) { | |
5819 error = tffs_stat(mydir, &stat); | |
5820 expect_ok(error); | |
5821 } | |
5822 elapsed = tffs_timer_end(time_begin); | |
5823 | |
5824 ttw(ttr(TTrTest, "Lookup througt %d directorys 1000 times in %dms(%d obj/s)" | |
5825 NL, fs.path_depth_max, elapsed, 1000 * 1000 / elapsed)); | |
5826 | |
5827 //format, make x files in each directory, measure lookup with ffs_stat() | |
5828 error = tffs_preformat(0xDEAD); | |
5829 expect(error, EFFS_OK); | |
5830 error = tffs_format("/foo", 0x2BAD); | |
5831 expect(error, EFFS_OK); | |
5832 | |
5833 mydir[0] = 0; // Reset/empty buffer | |
5834 | |
5835 for (i = 0; i < fs.path_depth_max - 1; i++) { | |
5836 sprintf(depth, "/depth%d", i + 1); | |
5837 strcat(mydir, depth); | |
5838 error = tffs_mkdir(mydir); | |
5839 expect_ok(error); | |
5840 | |
5841 for (j = 0; j < 5; j++){ | |
5842 sprintf(myname, "/benchm%d", j); | |
5843 strcpy(mypath, mydir); | |
5844 strcat(mypath, myname); | |
5845 error = tffs_file_write(mypath, 0,0, FFS_O_CREATE); | |
5846 expect_ok(error); | |
5847 } | |
5848 } | |
5849 | |
5850 time_begin = tffs_timer_begin(); | |
5851 for (i = 0; i < 100; i++) { | |
5852 error = tffs_stat(mypath, &stat); | |
5853 expect_ok(error); | |
5854 } | |
5855 elapsed = tffs_timer_end(time_begin); | |
5856 | |
5857 ttw(ttr(TTrTest, "Lookup througt %d directorys with %d files in each times in %dms(%d obj/s)" | |
5858 NL, fs.path_depth_max, j, elapsed, 100 * 1000 / elapsed)); | |
5859 | |
5860 //format, make one file, measure lookup with ffs_stat() (no traverse) | |
5861 error = tffs_preformat(0xDEAD); | |
5862 expect(error, EFFS_OK); | |
5863 error = tffs_format("/foo", 0x2BAD); | |
5864 expect(error, EFFS_OK); | |
5865 | |
5866 error = tffs_file_write(myname, 0,0, FFS_O_CREATE); | |
5867 expect_ok(error); | |
5868 | |
5869 time_begin = tffs_timer_begin(); | |
5870 for (i = 0; i < 10000; i++) { | |
5871 error = tffs_stat(myname, &stat); | |
5872 expect_ok(error); | |
5873 } | |
5874 elapsed = tffs_timer_end(time_begin); | |
5875 | |
5876 ttw(ttr(TTrTest, "Lookup one file 10000 times in %dms(%d obj/s)" | |
5877 NL, elapsed, 1000 * 10000 / elapsed)); | |
5878 | |
5879 //format, make x dirs with x files, measure lookup of last file in last dir | |
5880 error = tffs_preformat(0xDEAD); | |
5881 expect(error, EFFS_OK); | |
5882 error = tffs_format("/foo", 0x2BAD); | |
5883 expect(error, EFFS_OK); | |
5884 return 0; | |
5885 #else | |
5886 return 1; | |
5887 #endif | |
5888 } | |
5889 | |
5890 int case_bm_seek(int p0, int p1) | |
5891 { | |
5892 UINT32 time_begin, elapsed; | |
5893 int i, pos, fsize = 20000; | |
5894 char myname[] = "/benchmark"; | |
5895 fd_t fdi; | |
5896 | |
5897 //format, update file 100 times, measure lookup with ffs_stat() | |
5898 error = tffs_preformat(0xDEAD); | |
5899 expect(error, EFFS_OK); | |
5900 error = tffs_format("/foo", 0x2BAD); | |
5901 expect(error, EFFS_OK); | |
5902 | |
5903 // Create test file | |
5904 error = tffs_file_write(myname, (char*)tdata[TDATA_HUGE], fsize, FFS_O_CREATE); | |
5905 expect_ok(error); | |
5906 | |
5907 fdi = tffs_open(myname, FFS_O_RDWR); | |
5908 expect(fdi, FFS_FD_OFFSET); | |
5909 | |
5910 tw(tr(TR_FUNC, TrTest, "Run read reference\n")); | |
5911 ttw(ttr(TTrTest, "Run read reference" NL)); | |
5912 | |
5913 // Reference | |
5914 time_begin = tffs_timer_begin(); | |
5915 for (i = 0; i < fsize/4; i++) { | |
5916 error = tffs_read(fdi, bigbuf, 4); | |
5917 expect_ok(error); | |
5918 } | |
5919 elapsed = tffs_timer_end(time_begin); | |
5920 | |
5921 tw(tr(TR_FUNC, TrTest, "Read %d entries of 4 bytes (bytes/s %d)\n", | |
5922 fsize/4, (fsize * 1000 / elapsed))); | |
5923 | |
5924 ttw(ttr(TTrTest, "Read %d entries of 4 bytes in %dms (bytes/s %d)" NL, | |
5925 fsize/4, elapsed, (fsize * 1000 / elapsed))); | |
5926 | |
5927 tw(tr(TR_FUNC, TrTest, "Benchmark seek\n")); | |
5928 ttw(ttr(TTrTest, "Benchmark seek" NL)); | |
5929 | |
5930 error = tffs_seek(fdi, 0, FFS_SEEK_SET); | |
5931 expect_ok(error); | |
5932 pos = 0; | |
5933 | |
5934 // Benchmark seek | |
5935 time_begin = tffs_timer_begin(); | |
5936 for (i = 0; i < fsize/4; i++) { | |
5937 error = tffs_seek(fdi, pos, FFS_SEEK_SET); | |
5938 expect_ok(error); | |
5939 pos += 4; | |
5940 error = tffs_read(fdi, bigbuf, 4); | |
5941 expect_ok(error); | |
5942 } | |
5943 elapsed = tffs_timer_end(time_begin); | |
5944 | |
5945 tw(tr(TR_FUNC, TrTest, "Seek and Read %d entries of 4 bytes (bytes/s %d)\n", | |
5946 fsize/4, (fsize * 1000 / elapsed))); | |
5947 | |
5948 ttw(ttr(TTrTest, "Seek and Read %d entries of 4 bytes in %dms (bytes/s %d)" NL, | |
5949 fsize/4, elapsed, (fsize * 1000 / elapsed))); | |
5950 | |
5951 error = tffs_close(fdi); | |
5952 expect_ok(error); | |
5953 | |
5954 return EFFS_OK; | |
5955 } | |
5956 | |
5957 // Benchmark the blocking 'system'. Make n number of calls to ffs_format() | |
5958 // with bad magic. | |
5959 int case_bm_blocking(int p0, int p1) | |
5960 { | |
5961 int i; | |
5962 int time_begin, elapsed; | |
5963 | |
5964 time_begin = tffs_timer_begin(); | |
5965 for (i = 0; i < 10000; i++) | |
5966 tffs_format("/ffs", 0); | |
5967 elapsed = tffs_timer_end(time_begin); | |
5968 | |
5969 ttw(ttr(TTrTest, "Made %d blocking calls in %dms (ms/call %d)" NL, | |
5970 i, elapsed, elapsed / i)); | |
5971 | |
5972 // Make sure that it did fail as we expected | |
5973 error = tffs_format("/ffs", 0); | |
5974 expect(error, EFFS_INVALID); | |
5975 | |
5976 return EFFS_OK; | |
5977 } | |
5978 /****************************************************************************** | |
5979 * Core test case | |
5980 ******************************************************************************/ | |
5981 | |
5982 int case_seekfile(int p0, int p1) | |
5983 { | |
5984 // NOTEME: this is only a visual test add some expect() to finish it. | |
5985 char *name; | |
5986 iref_t i, dir, i_out; | |
5987 int length, flength; | |
5988 int segment_offset; | |
5989 fd_t fdi; | |
5990 | |
5991 error = tffs_fwrite("/File_seg", (char*)tdata[TDATA_HUGE], 50); | |
5992 expect(error, EFFS_OK); | |
5993 | |
5994 if ((i = object_lookup("/File_seg", &name, &dir)) < 0) | |
5995 return i; | |
5996 | |
5997 for (length = 52; length > 48; length--) { | |
5998 flength = segfile_seek(i, length, &i_out, &segment_offset); | |
5999 tw(tr(TR_FUNC, TrTest, | |
6000 "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n", | |
6001 length, flength, segment_offset, i_out)); | |
6002 } | |
6003 | |
6004 fdi = tffs_open("/Stream_seg", FFS_O_WRONLY | FFS_O_CREATE); | |
6005 tffs_write(fdi, (char*)tdata[TDATA_HUGE], 55); | |
6006 tffs_close(fdi); | |
6007 | |
6008 fdi = tffs_open("/Stream_seg", FFS_O_WRONLY | FFS_O_APPEND); | |
6009 tffs_write(fdi, (char*)tdata[TDATA_HUGE], 50); | |
6010 tffs_close(fdi); | |
6011 | |
6012 fdi = tffs_open("/Stream_seg", FFS_O_WRONLY | FFS_O_APPEND); | |
6013 tffs_write(fdi, (char*)tdata[TDATA_HUGE], 45); | |
6014 tffs_close(fdi); | |
6015 | |
6016 if ((i = object_lookup("/Stream_seg", &name, &dir)) < 0) | |
6017 return i; | |
6018 | |
6019 for (length = 153; length > 148; length--) { | |
6020 flength = segfile_seek(i, length, &i_out, &segment_offset); | |
6021 tw(tr(TR_FUNC, TrTest, | |
6022 "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n", | |
6023 length, flength, segment_offset, i_out)); | |
6024 } | |
6025 | |
6026 for (length = 107; length > 103; length--) { | |
6027 flength = segfile_seek(i, length, &i_out, &segment_offset); | |
6028 tw(tr(TR_FUNC, TrTest, | |
6029 "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n", | |
6030 length, flength, segment_offset, i_out)); | |
6031 } | |
6032 | |
6033 for (length = 58; length > 53; length--) { | |
6034 flength = segfile_seek(i, length, &i_out, &segment_offset); | |
6035 tw(tr(TR_FUNC, TrTest, | |
6036 "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n", | |
6037 length, flength, segment_offset, i_out)); | |
6038 } | |
6039 | |
6040 return 0; | |
6041 } | |
6042 | |
6043 void display_fs_params(void) | |
6044 { | |
6045 int numdatablocks; | |
6046 | |
6047 numdatablocks = dev.numblocks - fs.blocks_free_min - 1; | |
6048 | |
6049 // Note expect only one free block! | |
6050 tw(tr(TR_FUNC, TrTest, "Data blocks %d, size %dkB\n", | |
6051 numdatablocks, dev.blocksize / 1024)); | |
6052 tw(tr(TR_FUNC, TrTest, " User data: %dkB\n", | |
6053 (numdatablocks * dev.blocksize - fs.reserved_space) / 1024)); | |
6054 tw(tr(TR_FUNC, TrTest, " reserved_space: %dkB\n", fs.reserved_space/ 1024)); | |
6055 tw(tr(TR_FUNC, TrTest, " inodes_max: %d\n", fs.inodes_max)); | |
6056 tw(tr(TR_FUNC, TrTest, " journal_size: %d\n", fs.journal_size)); | |
6057 tw(tr(TR_FUNC, TrTest, " objects_max: %d\n", fs.objects_max)); | |
6058 tw(tr(TR_FUNC, TrTest, " block_files_max: %d\n", fs.block_files_max)); | |
6059 tw(tr(TR_FUNC, TrTest, " chunk_size: %d\n\n", fs.chunk_size_max)); | |
6060 } | |
6061 | |
6062 // NOTE only visual test | |
6063 int case_param_init(int p0, int p1) | |
6064 { | |
6065 char myname[] = "/ffs/xx/xx/xx"; | |
6066 int numblocks[] = { 8, 3, 7, 15, 31, 63, 96, 127, 61, 127}; | |
6067 int i; | |
6068 | |
6069 for (i = 0; i < sizeof(numblocks) / sizeof(int); i++) | |
6070 { | |
6071 dev.numblocks = numblocks[i]; | |
6072 | |
6073 if (i == 0) | |
6074 dev.blocksize = 1024 * 8; | |
6075 else if (i > 0 && i < 8) | |
6076 dev.blocksize = 1024 * 64; | |
6077 else | |
6078 dev.blocksize = 1024 * 128; | |
6079 | |
6080 fs_params_init(myname); | |
6081 display_fs_params(); | |
6082 | |
6083 // TODO add some checks, test format("/ffs/bx/ox") etc. | |
6084 } | |
6085 | |
6086 error = tffs_initialize(); // Use the 'real' blocksize | |
6087 expect(error, EFFS_OK); | |
6088 | |
6089 // Test param input from the format string | |
6090 error = tffs_preformat(0xDEAD); | |
6091 expect(error, EFFS_OK); | |
6092 tffs_format("/ffs/i4000/o3000", 0x2BAD); | |
6093 expect(error, EFFS_OK); | |
6094 | |
6095 display_fs_params(); | |
6096 | |
6097 // Test small conf. | |
6098 tw(tr(TR_FUNC, TrTest, "Test small conf\n")); | |
6099 error = tffs_preformat(0xDEAD); | |
6100 expect(error, EFFS_OK); | |
6101 tffs_format("/ffs/b3/j8/r24/f100/o100", 0x2BAD); | |
6102 expect(error, EFFS_OK); | |
6103 display_fs_params(); | |
6104 | |
6105 return 0; | |
6106 } | |
6107 | |
6108 /****************************************************************************** | |
6109 * Trace mask | |
6110 ******************************************************************************/ | |
6111 | |
6112 // This is not a test case but a way to change the trace mask on the fly | |
6113 int case_trace_mask(int p0, int p1) | |
6114 { | |
6115 unsigned int temp; | |
6116 | |
6117 // Because p0 and p1 only is of the type int and trace_mask is a | |
6118 // unsigned int is p0 bit 1-28 and p1 is bit 29-32 | |
6119 temp = p1 << 28; | |
6120 temp |= p0; | |
6121 | |
6122 #if (TARGET == 0) | |
6123 tr_init(temp, 2, NULL ); | |
6124 tw(tr(TR_FUNC, TrAll, "trace mask = %x\n", temp)); | |
6125 #else | |
6126 ttr_init(temp); | |
6127 ttw(ttr(TTrTest, "trase mask = %x" NL, temp)); | |
6128 #endif | |
6129 return 0; | |
6130 } | |
6131 | |
6132 /****************************************************************************** | |
6133 * Helper function | |
6134 ******************************************************************************/ | |
6135 | |
6136 #define CLEANUP_MIN_SIZE 1 | |
6137 | |
6138 int ignore_file(char *pathname) | |
6139 { | |
6140 int i; | |
6141 const char *ignore[] = { | |
6142 "/.journal", "/.ffs-stats", "/.ffs-bstat.old","/dummy4fctrl" , | |
6143 "/truncate/IMEI", "/truncate/stream_file", "/gsm/com/rfcap", | |
6144 "/var/dbg/dar" }; | |
6145 const char readonly[] = "/READONLY"; | |
6146 | |
6147 for (i = 0; i < sizeof(ignore)/sizeof(char *); i++) { | |
6148 if (ffs_strcmp(pathname, ignore[i]) == 0) { | |
6149 return 0; | |
6150 } | |
6151 } | |
6152 | |
6153 // Special case, we have one directory where we don't delete any objects | |
6154 if (memcmp(pathname, readonly, sizeof(readonly) - 1) == 0) | |
6155 return 0; | |
6156 | |
6157 return 1; | |
6158 } | |
6159 | |
6160 // Remove files in FFS until there is min_space left. Ignore all files that | |
6161 // are listed in the ignore string above. | |
6162 int case_cleanup(int min_space) | |
6163 { | |
6164 int free, i, n, error; | |
6165 struct object_s *plist, *plist_start; | |
6166 char *pnames, *pnames_start; | |
6167 | |
6168 tw(tr(TR_FUNC, TrTestLow, "case_cleanup(%d)?\n", min_space)); | |
6169 | |
6170 ffs_query(Q_BYTES_FREE, (uint32 *) &free); | |
6171 if (free > min_space) { | |
6172 tw(tr(TR_FUNC, TrTestLow, "Total data free: %d\n", free)); | |
6173 return free; // Nothing to do | |
6174 } | |
6175 | |
6176 plist = plist_start = (struct object_s *) bigbuf; | |
6177 pnames = pnames_start = bigbuf + bigbuf_size; | |
6178 n = case_dir_list("/", &plist, &pnames); | |
6179 plist = plist_start; | |
6180 | |
6181 for (i = 0; i < n; i++, plist++) | |
6182 { | |
6183 ffs_query(Q_BYTES_FREE, (uint32 *) &free); | |
6184 if (free > min_space) { | |
6185 tw(tr(TR_FUNC, TrTestLow, "Total data free: %d\n", free)); | |
6186 return free; | |
6187 } | |
6188 | |
6189 if (plist->stat.size > CLEANUP_MIN_SIZE && ignore_file(plist->name)) { | |
6190 if ((error = ffs_remove(plist->name)) < 0) | |
6191 return error; | |
6192 } | |
6193 } | |
6194 return EFFS_NOSPACE; | |
6195 } | |
6196 | |
6197 // Make a random file. Random filename length, random filename, random filesize. | |
6198 // Note it is up to the caller that the directory exists. | |
6199 int case_mk_rand_file(char *dirname, int max_size, int min_size) | |
6200 { | |
6201 int size, diff, filenamelen, pathlen = 0, i, error; | |
6202 char pathname[(FFS_FILENAME_MAX + 1) * FFS_PATH_DEPTH_MAX]; | |
6203 // All valid filename chars | |
6204 char tabel[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
6205 "abcdefghijklmnopqrtsuvwyz_-.,+%$#"; | |
6206 | |
6207 diff = max_size - min_size; | |
6208 if (diff < 0) | |
6209 return EFFS_INVALID; | |
6210 else if (diff == 0) | |
6211 size = max_size; | |
6212 else | |
6213 size = (rand() % diff) + min_size; | |
6214 | |
6215 filenamelen = (rand() % (FFS_FILENAME_MAX - 1)) + 1; // We need min one char | |
6216 tw(tr(TR_FUNC, TrTestLow, "size:%5d, filenamelen:%3d,",size, filenamelen)); | |
6217 | |
6218 if (dirname != 0) { | |
6219 strcpy(pathname, dirname); | |
6220 pathlen = strlen(pathname); | |
6221 } | |
6222 | |
6223 pathname[pathlen++] = '/'; | |
6224 | |
6225 for (i = 0; i < filenamelen; pathlen++, i++) { | |
6226 pathname[pathlen] = tabel[rand() % strlen(tabel)]; | |
6227 } | |
6228 pathname[pathlen] = 0; // Zero terminate | |
6229 | |
6230 tw(tr(TR_FUNC, TrTestLow, "pathname:'%s'\n", pathname, size)); | |
6231 | |
6232 error = tffs_file_write(pathname, (char *) tdata[TDATA_HUGE], size, | |
6233 FFS_O_CREATE | FFS_O_TRUNC); | |
6234 return error; | |
6235 | |
6236 } | |
6237 | |
6238 // Various helper functions for debug | |
6239 int case_debug_help(int p0, int p1) | |
6240 { | |
6241 int tr_mask; | |
6242 | |
6243 switch(p0) { | |
6244 case 1: | |
6245 { | |
6246 // Write rfcap file | |
6247 char rfcap_data[] = { 0, 0xf, 0x41, 0x10, 0, 0, 0, 0, 0x50, 0, | |
6248 0, 0xa5, 0x5, 0, 0xc0, 0 }; | |
6249 | |
6250 ttw(ttr(TTrTest, "Write rfcap file...")); | |
6251 tffs_mkdir("/gsm"); // ignore error | |
6252 tffs_mkdir("/gsm/com"); | |
6253 error = tffs_file_write("/gsm/com/rfcap", rfcap_data, | |
6254 sizeof(rfcap_data), FFS_O_CREATE | FFS_O_TRUNC); | |
6255 expect_ok(error); | |
6256 ttw(ttr(TTrTest, "done" NL)); | |
6257 } | |
6258 break; | |
6259 case 2: | |
6260 tr_mask = tr_query(INT_MAX); | |
6261 #if (TARGET == 0) | |
6262 tr_init(TrBstat, 2, NULL ); | |
6263 tr_bstat(); | |
6264 tr_init(tr_mask, 2, NULL ); | |
6265 #else | |
6266 ttr_init(TTrBstat); | |
6267 tr_bstat(); | |
6268 ttr_init(tr_mask); | |
6269 #endif | |
6270 break; | |
6271 | |
6272 case 3: | |
6273 // Make mem dump to screen | |
6274 #if (TARGET == 1) | |
6275 rvf_dump_mem(); | |
6276 break; | |
6277 #else | |
6278 tw(tr(TR_FUNC, TrTestLow, "Not supported on PC\n")); | |
6279 return 1; | |
6280 #endif | |
6281 | |
6282 case 4: | |
6283 #if (TARGET == 1) | |
6284 rvf_dump_tasks(); break; | |
6285 #else | |
6286 tw(tr(TR_FUNC, TrTestLow, "Not supported on PC\n")); | |
6287 return 1; | |
6288 #endif | |
6289 case 5: | |
6290 #if (TARGET == 1) | |
6291 rvf_dump_pool(); break; | |
6292 #else | |
6293 tw(tr(TR_FUNC, TrTestLow, "Not supported on PC\n")); | |
6294 return 1; | |
6295 #endif | |
6296 default: | |
6297 tw(tr(TR_FUNC, TrTest, "Available helper functions:\n")); | |
6298 tw(tr(TR_FUNC, TrTest, " 1: Write rfcap file\n")); | |
6299 tw(tr(TR_FUNC, TrTest, " 2: Display bstat trace\n")); | |
6300 | |
6301 ttw(ttr(TTrTest, "Available helper functions:" NL)); | |
6302 ttw(ttr(TTrTest, " 1: Write rfcap file" NL)); | |
6303 ttw(ttr(TTrTest, " 2: Display bstat trace" NL)); | |
6304 ttw(ttr(TTrTest, " 3: Memory dump to screen" NL)); | |
6305 ttw(ttr(TTrTest, " 4: Tasks dump to screen" NL)); | |
6306 ttw(ttr(TTrTest, " 5: Pool dump to screen" NL)); | |
6307 return 0; | |
6308 } | |
6309 | |
6310 return 0; | |
6311 } | |
6312 | |
6313 /****************************************************************************** | |
6314 * Hexdumping | |
6315 ******************************************************************************/ | |
6316 #if 0 | |
6317 void hexdump(const char *buf, int size, unsigned int address, int unitsize) | |
6318 { | |
6319 char string[(8+1+1) + (1+16+1+1) + (3*16) + 1]; | |
6320 int n, i; | |
6321 char *s; | |
6322 | |
6323 while (size > 0) | |
6324 { | |
6325 s = string; | |
6326 s += sprintf(s, "%8x: ", address); // print offset | |
6327 | |
6328 n = (size > 16 ? 16 : size); | |
6329 | |
6330 // print the textual representation | |
6331 for (i = 0; i < n; i++) { | |
6332 if (buf[i] >= ' ' && buf[i] < 127) | |
6333 *s++ = buf[i]; | |
6334 else | |
6335 *s++ = '.'; | |
6336 } | |
6337 // pad textual representation with spaces | |
6338 for (i = 0; i < 16 - n; i++) { | |
6339 *s++ = ' '; | |
6340 } | |
6341 *s++ = ' '; | |
6342 | |
6343 // print hexedecimal representation | |
6344 for (i = 0; i < n; i += unitsize) { | |
6345 switch (unitsize) { | |
6346 case 1: s += sprintf(s, "%02x ", *(unsigned char *) (buf+i)); break; | |
6347 case 2: s += sprintf(s, "%04x ", *(unsigned short *) (buf+i)); break; | |
6348 case 4: s += sprintf(s, "%08x ", *(unsigned int *) (buf+i)); break; | |
6349 } | |
6350 } | |
6351 buf += 16; | |
6352 address += 16; | |
6353 size -= 16; | |
6354 puts(string); | |
6355 } | |
6356 } | |
6357 #endif | |
6358 | |
6359 /****************************************************************************** | |
6360 * Test Cases | |
6361 ******************************************************************************/ | |
6362 | |
6363 const struct testcase_s testcase[] = | |
6364 { | |
6365 // Collective test cases | |
6366 { "all", PC , case_all, "All" }, | |
6367 { "alot", PC , case_alot, "Almost all" }, | |
6368 { "tall", IT , case_tall, "Target all" }, | |
6369 { "aall", PC , case_aall, "Agressive all" }, | |
6370 { "list", PC|IT , case_list, "List all testcases" }, | |
6371 { "lsr", PC|IT , case_lsr, "Recursively list all objects" }, | |
6372 { "test", PC|IT , case_test, "Ad hoc test" }, | |
6373 { "rand", PC|IT , case_rand, "Random tests (NOT FINISHED)" }, | |
6374 { "fail", PC|IT , case_fail, "Fail (just fail)" }, | |
6375 { "okay", PC|IT , case_okay, "Okay (just succeed)" }, | |
6376 | |
6377 // Atomic/small test cases | |
6378 { "s", PC|IT , case_status, "Status: ffs_init(), lsr" }, | |
6379 { "r", PC|IT , case_reset, "preformat(), format(), init(), exit()" }, | |
6380 { "i", PC|IT , case_init, "ffs_init()" }, | |
6381 { "x", PC|IT , case_exit, "ffs_exit()" }, | |
6382 { "p", PC|IT , case_only_preformat, "ffs_preformat()" }, | |
6383 { "f", PC|IT , case_only_format, "ffs_format()" }, | |
6384 | |
6385 // Populate test cases | |
6386 { "world", PC|IT , case_world, "Make world" }, | |
6387 { "eu", PC|IT , case_europe, "Make europe" }, | |
6388 { "dk", PC|IT , case_denmark, "Make denmark" }, | |
6389 | |
6390 // Special test cases | |
6391 { "mf", PC|IT , case_mfiles, "Test FFS with many (small) files" }, | |
6392 { "threeb", PC|IT , case_threeb, "Test ffs in only three blocks" }, | |
6393 { "twob", PC|IT , case_twob, "Test ffs in only two blocks" }, | |
6394 { "pcm", PC|IT , case_pcm, "Test PCM interface" }, | |
6395 { "stress", IT , case_stress, "Stress test erase/write" }, | |
6396 { "find", PC|IT|RND, case_find, "Recursively traverse all objects" }, | |
6397 { "nb", IT , case_nonblock, "Test non block functions" }, | |
6398 { "bf", IT|RND , case_blocking, "Test blocking function" }, | |
6399 { "cust", PC , case_customer, "Test customer typical use"}, | |
6400 { "esus", IT , case_erase_suspend, "Test erase suspend and resume" }, | |
6401 | |
6402 // Driver test cases | |
6403 { "int", IT , case_interrupt, "Test INT disable and enable" }, | |
6404 | |
6405 // Benchmark test cases | |
6406 { "bmsrw", IT , case_bm_stream_rw, "Benchmark stream read and writes" }, | |
6407 { "bmfrw", IT , case_bm_file_rw, "Benchmark file read and writes" }, | |
6408 { "bmlu", IT , case_bm_lookup, "Benchmark lookups" }, | |
6409 { "bmsk", PC|IT , case_bm_seek, "Benchmark ffs_seek()" }, | |
6410 { "bmbl", PC|IT , case_bm_blocking, "Benchmark blocking 'system'" }, | |
6411 | |
6412 // Normal test cases | |
6413 { "format", PC , case_format, "Test ffs_pre/format()" }, | |
6414 { "lu", PC|IT , case_lookup, "Test object_lookup()" }, | |
6415 { "fc", PC|IT , case_fcontrol, "Test fcontrol() and read-only" }, | |
6416 { "root", PC|IT|RND, case_root, "Test root inode is non-modifiable" }, | |
6417 { "dirs", PC|IT|RND, case_dirs, "Test Directories" }, | |
6418 { "frd", PC|IT|RND, case_fread, "Test fread() with varying sizes/names" }, | |
6419 { "bfull", PC|IT , case_bfull, "Test filling a block completely" }, | |
6420 { "ffull", PC|IT , case_ffull, "Test filling ffs completely" }, | |
6421 { "bigf", PC , case_bigfile, "Test big files" }, | |
6422 { "stat", PC|IT|RND, case_stat, "Test ffs_stat()" }, | |
6423 { "rm", PC|IT , case_remove, "Test ffs_remove()" }, | |
6424 { "ren", PC|IT|RND, case_rename, "Test ffs_rename()" }, | |
6425 { "renext", PC|IT , case_rename_extended, "Extended test of ffs_rename()" }, | |
6426 | |
6427 { "irec", PC|IT , case_irec, "Test inodes reclaim" }, | |
6428 { "drec", PC , case_drec, "Test data reclaim" }, | |
6429 { "adrec", PC , case_adrec, "Test xxxx reclaim" }, | |
6430 | |
6431 { "jnl", PC|IT , case_journal, "Test journalling" }, | |
6432 { "brec", PC|IT|RND, case_brecover, "Test block recovery" }, | |
6433 | |
6434 { "ssym", PC|IT|RND, case_ssym, "Test Simple Symlinks" }, | |
6435 { "fsym", PC|IT , case_fsym, "Test Full Symlinks (NOT IMPLEMENTED)" }, | |
6436 { "ri", PC|IT|RND, case_reinit, "Test re-ffs_init()" }, | |
6437 { "open", PC|IT|RND, case_open, "Test open flags" }, | |
6438 { "rw", PC|IT|RND, case_rw, "Test read and write files" }, | |
6439 { "mopen", PC|IT|RND, case_multi_open, "Test open of multiply files" }, | |
6440 { "seek", PC|IT|RND, case_seek, "Test seek on files " }, | |
6441 { "trunc", PC|IT|RND, case_trunc, "Test ffs_truncate() " }, | |
6442 { "append", PC|IT|RND, case_append, "Test append on a open file" }, | |
6443 { "dsync", PC|IT|RND, case_datasync, "Test ffs_fdatasync" }, | |
6444 { "ex", IT|RND, case_examples, "Test examples from RIV111 " }, | |
6445 { "fwflags",PC|IT|RND, case_fw_flags, "Test ffs_file_write() flags" }, | |
6446 { "pcm" ,PC|IT|RND, case_pcm, "Test pcm interface" }, | |
6447 { "apiexc" ,PC|IT, case_api_exceptions, "Test API exceptions" }, | |
6448 { "ninit" ,PC|IT, case_api_notformated, "Test API on a nformated flash"}, | |
6449 { "query" ,PC|IT|RND, case_query, "Test query function" }, | |
6450 { "octrl" ,PC|IT, case_octrl, "Test of object control" }, | |
6451 | |
6452 // Core test cases | |
6453 { "seekf", PC, case_seekfile, "Test core segfile_seek" }, | |
6454 { "param", PC, case_param_init,"Test core param_init" }, | |
6455 | |
6456 // Helper test case | |
6457 { "tr", PC|IT , case_trace_mask, "Change trace mask on the fly " }, | |
6458 { "dh", PC|IT , case_debug_help, "Difference help functions " }, | |
6459 { 0, 0, 0, 0 } | |
6460 }; | |
6461 | |
6462 #if (TARGET == 1) | |
6463 // Note like the interrupt functions in drv.c this asm needs to be places ad | |
6464 // the buttom of the file or else it crach! | |
6465 uint32 get_cpsr(void) | |
6466 { | |
6467 asm(" .state16"); | |
6468 asm(" adr A2, get_cpsr32"); | |
6469 asm(" bx A2"); | |
6470 asm(" .state32"); | |
6471 asm("get_cpsr32"); | |
6472 asm(" mrs A1,cpsr ; get current CPSR"); | |
6473 } | |
6474 #else | |
6475 uint32 get_cpsr(void){return 0;} | |
6476 #endif | |
6477 | |
6478 | |
6479 | |
6480 | |
6481 | |
6482 | |
6483 | |
6484 | |
6485 | |
6486 | |
6487 | |
6488 |