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