1 /* 2 This file is part of UFFS, the Ultra-low-cost Flash File System. 3 4 Copyright (C) 2005-2009 Ricky Zheng <[email protected]> 5 6 UFFS is free software; you can redistribute it and/or modify it under 7 the GNU Library General Public License as published by the Free Software 8 Foundation; either version 2 of the License, or (at your option) any 9 later version. 10 11 UFFS is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 or GNU Library General Public License, as applicable, for more details. 15 16 You should have received a copy of the GNU General Public License 17 and GNU Library General Public License along with UFFS; if not, write 18 to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 21 As a special exception, if other files instantiate templates or use 22 macros or inline functions from this file, or you compile this file 23 and link it with other works to produce a work based on this file, 24 this file does not by itself cause the resulting work to be covered 25 by the GNU General Public License. However the source code for this 26 file must still be made available in accordance with section (3) of 27 the GNU General Public License v2. 28 29 This exception does not invalidate any other reasons why a work based 30 on this file might be covered by the GNU General Public License. 31 */ 32 33 /** 34 * \file test_cmds.c 35 * \brief commands for test uffs 36 * \author Ricky Zheng 37 */ 38 #include <stdio.h> 39 #include <string.h> 40 #include <stdlib.h> 41 #include "uffs_config.h" 42 #include "uffs/uffs_public.h" 43 #include "uffs/uffs_fd.h" 44 #include "uffs/uffs_utils.h" 45 #include "uffs/uffs_core.h" 46 #include "uffs/uffs_mtb.h" 47 #include "uffs/uffs_find.h" 48 #include "uffs/uffs_badblock.h" 49 #include "cmdline.h" 50 #include "api_test.h" 51 52 #define PFX "test: " 53 54 #define MAX_TEST_BUF_LEN 8192 55 56 #define SEQ_INIT 10 57 #define SEQ_MOD_LEN 120 58 59 #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__) 60 #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__) 61 62 63 static void memcp_seq(void *des, int size, int start_pos) 64 { 65 int i; 66 u8 *p = (u8 *)des; 67 68 for (i = 0; i < size; i++, p++) { 69 *p = (start_pos + SEQ_INIT + i) % SEQ_MOD_LEN; 70 } 71 } 72 73 static UBOOL check_entry_exist(const char *name) 74 { 75 struct uffs_stat sb; 76 77 return uffs_stat(name, &sb) < 0 ? U_FALSE : U_TRUE; 78 } 79 80 static URET do_write_test_file(int fd, int size) 81 { 82 long pos; 83 unsigned char buf[100]; 84 int len; 85 86 while (size > 0) { 87 pos = uffs_seek(fd, 0, USEEK_CUR); 88 len = (size > sizeof(buf) ? sizeof(buf) : size); 89 memcp_seq(buf, len, pos); 90 if (uffs_write(fd, buf, len) != len) { 91 MSGLN("Write file failed, size %d at %d", len, pos); 92 return U_FAIL; 93 } 94 size -= len; 95 } 96 97 return U_SUCC; 98 } 99 100 static URET test_write_file(const char *file_name, int pos, int size) 101 { 102 int ret = U_FAIL; 103 int fd = -1; 104 105 if ((fd = uffs_open(file_name, UO_RDWR|UO_CREATE)) < 0) { 106 MSGLN("Can't open file %s for write.", file_name); 107 goto test_exit; 108 } 109 110 if (uffs_seek(fd, pos, USEEK_SET) != pos) { 111 MSGLN("Can't seek file %s at pos %d", file_name, pos); 112 goto test_failed; 113 } 114 115 if (do_write_test_file(fd, size) == U_FAIL) { 116 MSGLN("Write file %s failed.", file_name); 117 goto test_failed; 118 } 119 ret = U_SUCC; 120 121 test_failed: 122 uffs_close(fd); 123 124 test_exit: 125 126 return ret; 127 } 128 129 130 static URET test_verify_file(const char *file_name, UBOOL noecc) 131 { 132 int fd; 133 int ret = U_FAIL; 134 unsigned char buf[100]; 135 int i, pos, len; 136 u8 x; 137 138 if ((fd = uffs_open(file_name, (noecc ? UO_RDONLY|UO_NOECC : UO_RDONLY))) < 0) { 139 MSGLN("Can't open file %s for read.", file_name); 140 goto test_exit; 141 } 142 143 pos = 0; 144 while (!uffs_eof(fd)) { 145 len = uffs_read(fd, buf, sizeof(buf)); 146 if (len <= 0) 147 goto test_failed; 148 for (i = 0; i < len; i++) { 149 x = (SEQ_INIT + pos + i) % SEQ_MOD_LEN; 150 if (buf[i] != x) { 151 MSGLN("Verify file %s failed at: %d, expect 0x%02x but got 0x%02x", file_name, pos + i, x, buf[i]); 152 goto test_failed; 153 } 154 } 155 pos += len; 156 } 157 158 if (pos != uffs_seek(fd, 0, USEEK_END)) { 159 MSGLN("Verify file %s failed. invalid file length.", file_name); 160 goto test_failed; 161 } 162 163 MSGLN("Verify file %s succ.", file_name); 164 ret = U_SUCC; 165 166 test_failed: 167 uffs_close(fd); 168 169 test_exit: 170 171 return ret; 172 } 173 174 static URET test_append_file(const char *file_name, int size) 175 { 176 int ret = U_FAIL; 177 int fd = -1; 178 179 if ((fd = uffs_open(file_name, UO_RDWR|UO_APPEND|UO_CREATE)) < 0) { 180 MSGLN("Can't open file %s for append.", file_name); 181 goto test_exit; 182 } 183 184 uffs_seek(fd, 0, USEEK_END); 185 186 if (do_write_test_file(fd, size) == U_FAIL) { 187 MSGLN("Write file %s failed.", file_name); 188 goto test_failed; 189 } 190 ret = U_SUCC; 191 192 test_failed: 193 uffs_close(fd); 194 195 test_exit: 196 197 return ret; 198 } 199 200 201 /* test create file, write file and read back */ 202 static int cmd_t1(int argc, char *argv[]) 203 { 204 int fd; 205 URET ret; 206 char buf[100]; 207 const char *name; 208 209 if (argc < 2) { 210 return CLI_INVALID_ARG; 211 } 212 213 name = argv[1]; 214 215 fd = uffs_open(name, UO_RDWR|UO_CREATE|UO_TRUNC); 216 if (fd < 0) { 217 MSGLN("Can't open %s", name); 218 goto fail; 219 } 220 221 sprintf(buf, "123456789ABCDEF"); 222 ret = uffs_write(fd, buf, strlen(buf)); 223 MSGLN("write %d bytes to file, content: %s", ret, buf); 224 225 ret = uffs_seek(fd, 3, USEEK_SET); 226 MSGLN("new file position: %d", ret); 227 228 memset(buf, 0, sizeof(buf)); 229 ret = uffs_read(fd, buf, 5); 230 MSGLN("read %d bytes, content: %s", ret, buf); 231 232 uffs_close(fd); 233 234 return 0; 235 fail: 236 237 return -1; 238 } 239 240 241 static URET DoTest2(void) 242 { 243 int fd = -1; 244 URET ret = U_FAIL; 245 char buf[100], buf_1[100]; 246 247 fd = uffs_open("/abc/", UO_RDWR|UO_DIR); 248 if (fd < 0) { 249 MSGLN("Can't open dir abc, err: %d", uffs_get_error()); 250 MSGLN("Try to create a new one..."); 251 fd = uffs_open("/abc/", UO_RDWR|UO_CREATE|UO_DIR); 252 if (fd < 0) { 253 MSGLN("Can't create new dir /abc/"); 254 goto exit_test; 255 } 256 else { 257 uffs_close(fd); 258 } 259 } 260 else { 261 uffs_close(fd); 262 } 263 264 fd = uffs_open("/abc/test.txt", UO_RDWR|UO_CREATE); 265 if (fd < 0) { 266 MSGLN("Can't open /abc/test.txt"); 267 goto exit_test; 268 } 269 270 sprintf(buf, "123456789ABCDEF"); 271 ret = uffs_write(fd, buf, strlen(buf)); 272 MSGLN("write %d bytes to file, content: %s", ret, buf); 273 274 ret = uffs_seek(fd, 3, USEEK_SET); 275 MSGLN("new file position: %d", ret); 276 277 memset(buf_1, 0, sizeof(buf_1)); 278 ret = uffs_read(fd, buf_1, 5); 279 MSGLN("read %d bytes, content: %s", ret, buf_1); 280 281 if (memcmp(buf + 3, buf_1, 5) != 0) { 282 ret = U_FAIL; 283 } 284 else { 285 ret = U_SUCC; 286 } 287 288 uffs_close(fd); 289 290 exit_test: 291 292 return ret; 293 } 294 295 296 static int cmd_t2(int argc, char *argv[]) 297 { 298 URET ret; 299 MSGLN("Test return: %s !", (ret = DoTest2()) == U_SUCC ? "succ" : "failed"); 300 301 return (ret == U_SUCC) ? 0 : -1; 302 } 303 304 305 static int cmd_VerifyFile(int argc, char *argv[]) 306 { 307 const char *name; 308 UBOOL noecc = U_FALSE; 309 310 if (argc < 2) { 311 return CLI_INVALID_ARG; 312 } 313 314 name = argv[1]; 315 if (argc > 2 && strcmp(argv[2], "noecc") == 0) { 316 noecc = U_TRUE; 317 } 318 319 MSGLN("Check file %s ... ", name); 320 if (test_verify_file(name, noecc) != U_SUCC) { 321 MSGLN("Verify file %s failed.", name); 322 return -1; 323 } 324 325 return 0; 326 } 327 328 /* Test file append and 'random' write */ 329 static int cmd_t3(int argc, char *argv[]) 330 { 331 const char *name; 332 int i; 333 UBOOL noecc = U_FALSE; 334 int write_test_seq[] = { 20, 10, 500, 40, 1140, 900, 329, 4560, 352, 1100 }; 335 336 if (argc < 2) { 337 return CLI_INVALID_ARG; 338 } 339 340 name = argv[1]; 341 if (argv[2] && strcmp(argv[2], "noecc") == 0) { 342 noecc = U_TRUE; 343 } 344 345 if (check_entry_exist(name)) { 346 MSGLN("Check file %s ... ", name); 347 if (test_verify_file(name, noecc) != U_SUCC) { 348 MSGLN("Verify file %s failed.", name); 349 return -1; 350 } 351 } 352 353 MSGLN("Test append file %s ...", name); 354 for (i = 1; i < 500; i += 29) { 355 if (test_append_file(name, i) != U_SUCC) { 356 MSGLN("Append file %s test failed at %d !", name, i); 357 return -1; 358 } 359 } 360 361 MSGLN("Check file %s ... ", name); 362 if (test_verify_file(name, noecc) != U_SUCC) { 363 MSGLN("Verify file %s failed.", name); 364 return -1; 365 } 366 367 MSGLN("Test write file ..."); 368 for (i = 0; i < sizeof(write_test_seq) / sizeof(int) - 1; i++) { 369 if (test_write_file(name, write_test_seq[i], write_test_seq[i+1]) != U_SUCC) { 370 MSGLN("Test write file failed !"); 371 return -1; 372 } 373 } 374 375 MSGLN("Check file %s ... ", name); 376 if (test_verify_file(name, noecc) != U_SUCC) { 377 MSGLN("Verify file %s failed.", name); 378 return -1; 379 } 380 381 MSGLN("Test succ !"); 382 383 return 0; 384 } 385 386 /* open two files and test write */ 387 static int cmd_t4(int argc, char *argv[]) 388 { 389 int fd1 = -1, fd2 = -1; 390 391 MSGLN("open /a ..."); 392 if ((fd1 = uffs_open("/a", UO_RDWR | UO_CREATE)) < 0) { 393 MSGLN("Can't open /a"); 394 goto fail_exit; 395 } 396 397 MSGLN("open /b ..."); 398 if ((fd2 = uffs_open("/b", UO_RDWR | UO_CREATE)) < 0) { 399 MSGLN("Can't open /b"); 400 uffs_close(fd1); 401 goto fail_exit; 402 } 403 404 MSGLN("write (1) to /a ..."); 405 uffs_write(fd1, "Hello,", 6); 406 MSGLN("write (1) to /b ..."); 407 uffs_write(fd2, "Hello,", 6); 408 MSGLN("write (2) to /a ..."); 409 uffs_write(fd1, "World.", 6); 410 MSGLN("write (2) to /b ..."); 411 uffs_write(fd2, "World.", 6); 412 MSGLN("close /a ..."); 413 uffs_close(fd1); 414 MSGLN("close /b ..."); 415 uffs_close(fd2); 416 417 return 0; 418 419 fail_exit: 420 return -1; 421 } 422 423 /* test appending file */ 424 static int cmd_t5(int argc, char *argv[]) 425 { 426 int fd = -1; 427 URET ret; 428 char buf[100]; 429 const char *name; 430 431 if (argc < 2) { 432 return CLI_INVALID_ARG; 433 } 434 435 name = argv[1]; 436 437 fd = uffs_open(name, UO_RDWR|UO_APPEND); 438 if (fd < 0) { 439 MSGLN("Can't open %s", name); 440 goto fail; 441 } 442 443 sprintf(buf, "append test..."); 444 ret = uffs_write(fd, buf, strlen(buf)); 445 if (ret != strlen(buf)) { 446 MSGLN("write file failed, %d/%d", ret, strlen(buf)); 447 ret = -1; 448 } 449 else { 450 MSGLN("write %d bytes to file, content: %s", ret, buf); 451 ret = 0; 452 } 453 454 uffs_close(fd); 455 456 return ret; 457 fail: 458 return -1; 459 } 460 461 462 /* usage: t_pgrw 463 * 464 * This test case test page read/write 465 */ 466 static int cmd_TestPageReadWrite(int argc, char *argv[]) 467 { 468 TreeNode *node = NULL; 469 uffs_Device *dev; 470 uffs_Tags local_tag; 471 uffs_Tags *tag = &local_tag; 472 int ret; 473 u16 block; 474 u16 page; 475 uffs_Buf *buf = NULL; 476 477 u32 i; 478 int rc = -1; 479 480 dev = uffs_GetDeviceFromMountPoint("/"); 481 if (!dev) 482 goto ext; 483 484 buf = uffs_BufClone(dev, NULL); 485 if (!buf) 486 goto ext; 487 488 node = uffs_TreeGetErasedNode(dev); 489 if (!node) { 490 MSGLN("no free block ?"); 491 goto ext; 492 } 493 494 for (i = 0; i < dev->com.pg_data_size; i++) { 495 buf->data[i] = i & 0xFF; 496 } 497 498 block = node->u.list.block; 499 page = 1; 500 501 TAG_DIRTY_BIT(tag) = TAG_DIRTY; 502 TAG_VALID_BIT(tag) = TAG_VALID; 503 TAG_DATA_LEN(tag) = dev->com.pg_data_size; 504 TAG_TYPE(tag) = UFFS_TYPE_DATA; 505 TAG_PAGE_ID(tag) = 3; 506 TAG_PARENT(tag) = 100; 507 TAG_SERIAL(tag) = 10; 508 TAG_BLOCK_TS(tag) = 1; 509 SEAL_TAG(tag); 510 511 ret = uffs_FlashWritePageCombine(dev, block, page, buf, tag); 512 if (UFFS_FLASH_HAVE_ERR(ret)) { 513 MSGLN("Write page error: %d", ret); 514 goto ext; 515 } 516 517 ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE); 518 if (UFFS_FLASH_HAVE_ERR(ret)) { 519 MSGLN("Read page error: %d", ret); 520 goto ext; 521 } 522 523 for (i = 0; i < dev->com.pg_data_size; i++) { 524 if (buf->data[i] != (i & 0xFF)) { 525 MSGLN("Data verify fail at: %d", i); 526 goto ext; 527 } 528 } 529 530 ret = uffs_FlashReadPageTag(dev, block, page, tag); 531 if (UFFS_FLASH_HAVE_ERR(ret)) { 532 MSGLN("Read tag (page spare) error: %d", ret); 533 goto ext; 534 } 535 536 // verify tag: 537 if (!TAG_IS_SEALED(tag)) { 538 MSGLN("not sealed ? Tag verify fail!"); 539 goto ext; 540 } 541 542 if (!TAG_IS_DIRTY(tag)) { 543 MSGLN("not dirty ? Tag verify fail!"); 544 goto ext; 545 } 546 547 if (!TAG_IS_VALID(tag)) { 548 MSGLN("not valid ? Tag verify fail!"); 549 goto ext; 550 } 551 552 if (TAG_DATA_LEN(tag) != dev->com.pg_data_size || 553 TAG_TYPE(tag) != UFFS_TYPE_DATA || 554 TAG_PAGE_ID(tag) != 3 || 555 TAG_PARENT(tag) != 100 || 556 TAG_SERIAL(tag) != 10 || 557 TAG_BLOCK_TS(tag) != 1) { 558 559 MSGLN("Tag verify fail!"); 560 goto ext; 561 } 562 563 MSGLN("Page read/write test succ."); 564 rc = 0; 565 566 ext: 567 if (node) { 568 uffs_FlashEraseBlock(dev, node->u.list.block); 569 if (HAVE_BADBLOCK(dev)) 570 uffs_BadBlockProcess(dev, node); 571 else 572 uffs_TreeInsertToErasedListTail(dev, node); 573 } 574 575 if (dev) 576 uffs_PutDevice(dev); 577 578 if (buf) 579 uffs_BufFreeClone(dev, buf); 580 581 return rc; 582 } 583 584 /* t_format : test format partition */ 585 static int cmd_TestFormat(int argc, char *argv[]) 586 { 587 URET ret; 588 const char *mount = "/"; 589 uffs_Device *dev; 590 UBOOL force = U_FALSE; 591 const char *test_file = "/a.txt"; 592 int fd; 593 int rc = -1; 594 595 if (argc > 1) { 596 mount = argv[1]; 597 if (argc > 2 && strcmp(argv[2], "-f") == 0) 598 force = U_TRUE; 599 } 600 601 fd = uffs_open(test_file, UO_RDWR | UO_CREATE); 602 if (fd < 0) { 603 MSGLN("can't create test file %s", test_file); 604 goto ext; 605 } 606 607 MSGLN("Formating %s ... ", mount); 608 609 dev = uffs_GetDeviceFromMountPoint(mount); 610 if (dev == NULL) { 611 MSGLN("Can't get device from mount point."); 612 goto ext; 613 } 614 else { 615 ret = uffs_FormatDevice(dev, force); 616 if (ret != U_SUCC) { 617 MSGLN("Format fail."); 618 } 619 else { 620 MSGLN("Format succ."); 621 rc = 0; 622 } 623 uffs_PutDevice(dev); 624 } 625 626 uffs_close(fd); // this should fail on signature check ! 627 ext: 628 return rc; 629 } 630 631 632 633 /** 634 * usage: t_pfs <start> <n> 635 * 636 * for example: t_pfs /x/ 100 637 * 638 * This test case performs: 639 * 1) create <n> files under <start>, write full file name as file content 640 * 2) list files under <start>, check files are all listed once 641 * 3) check file content aganist file name 642 * 4) delete files on success 643 */ 644 static int cmd_TestPopulateFiles(int argc, char *argv[]) 645 { 646 const char *start = "/"; 647 int count = 80; 648 int i, fd, num; 649 char name[128]; 650 char buf[128]; 651 uffs_DIR *dirp; 652 struct uffs_dirent *ent; 653 unsigned long bitmap[50] = {0}; // one bit per file, maximu 32*50 = 1600 files 654 UBOOL succ = U_TRUE; 655 656 #define SBIT(n) bitmap[(n)/(sizeof(bitmap[0]) * 8)] |= (1 << ((n) % (sizeof(bitmap[0]) * 8))) 657 #define GBIT(n) (bitmap[(n)/(sizeof(bitmap[0]) * 8)] & (1 << ((n) % (sizeof(bitmap[0]) * 8)))) 658 659 if (argc > 1) { 660 start = argv[1]; 661 if (argc > 2) { 662 count = strtol(argv[2], NULL, 10); 663 } 664 } 665 666 if (count > sizeof(bitmap) * 8) 667 count = sizeof(bitmap) * 8; 668 669 for (i = 0, fd = -1; i < count; i++) { 670 sprintf(name, "%sFile%03d", start, i); 671 fd = uffs_open(name, UO_RDWR|UO_CREATE|UO_TRUNC); 672 if (fd < 0) { 673 MSGLN("Create file %s failed", name); 674 break; 675 } 676 if (uffs_write(fd, name, strlen(name)) != strlen(name)) { // write full path name to file 677 MSGLN("Write to file %s failed", name); 678 uffs_close(fd); 679 break; 680 } 681 uffs_close(fd); 682 } 683 684 if (i < count) { 685 // not success, need to clean up 686 for (; i >= 0; i--) { 687 sprintf(name, "%sFile%03d", start, i); 688 if (uffs_remove(name) < 0) 689 MSGLN("Delete file %s failed", name); 690 } 691 succ = U_FALSE; 692 goto ext; 693 } 694 695 MSGLN("%d files created.", count); 696 697 // list files 698 dirp = uffs_opendir(start); 699 if (dirp == NULL) { 700 MSGLN("Can't open dir %s !", start); 701 succ = U_FALSE; 702 goto ext; 703 } 704 ent = uffs_readdir(dirp); 705 while (ent && succ) { 706 707 if (!(ent->d_type & FILE_ATTR_DIR) && // not a dir 708 ent->d_namelen == strlen("File000") && // check file name length 709 memcmp(ent->d_name, "File", strlen("File")) == 0) { // file name start with "File" 710 711 MSGLN("List entry %s", ent->d_name); 712 713 num = strtol(ent->d_name + 4, NULL, 10); 714 if (GBIT(num)) { 715 // file already listed ? 716 MSGLN("File %d listed twice !", ent->d_name); 717 succ = U_FALSE; 718 break; 719 } 720 SBIT(num); 721 722 // check file content 723 sprintf(name, "%s%s", start, ent->d_name); 724 fd = uffs_open(name, UO_RDONLY); 725 if (fd < 0) { 726 MSGLN("Open file %d for read failed !", name); 727 } 728 else { 729 memset(buf, 0, sizeof(buf)); 730 num = uffs_read(fd, buf, sizeof(buf)); 731 if (num != strlen(name)) { 732 MSGLN("%s Read data length expect %d but got %d !", name, strlen(name), num); 733 succ = U_FALSE; 734 } 735 else { 736 if (memcmp(name, buf, num) != 0) { 737 MSGLN("File %s have wrong content '%s' !", name, buf); 738 succ = U_FALSE; 739 } 740 } 741 uffs_close(fd); 742 } 743 } 744 ent = uffs_readdir(dirp); 745 } 746 uffs_closedir(dirp); 747 748 // check absent files 749 for (i = 0; i < count; i++) { 750 if (GBIT(i) == 0) { 751 sprintf(name, "%sFile%03d", start, i); 752 MSGLN("File %s not listed !", name); 753 succ = U_FALSE; 754 } 755 } 756 757 // delete files if pass the test 758 for (i = 0; succ && i < count; i++) { 759 sprintf(name, "%sFile%03d", start, i); 760 if (uffs_remove(name) < 0) { 761 MSGLN("Delete file %s failed", name); 762 succ = U_FALSE; 763 } 764 } 765 766 ext: 767 MSGLN("Populate files test %s !", succ ? "SUCC" : "FAILED"); 768 return succ ? 0 : -1; 769 770 } 771 772 /** 773 * Open <file> with <oflag>, save fd to $1 774 * 775 * t_open <oflag> <file> 776 */ 777 static int cmd_topen(int argc, char *argv[]) 778 { 779 int fd; 780 const char *name; 781 char *p; 782 int oflag = 0; 783 784 CHK_ARGC(3, 3); 785 786 name = argv[2]; 787 p = argv[1]; 788 while(*p) { 789 switch(*p++) { 790 case 'a': 791 oflag |= UO_APPEND; 792 break; 793 case 'c': 794 oflag |= UO_CREATE; 795 break; 796 case 't': 797 oflag |= UO_TRUNC; 798 break; 799 case 'w': 800 oflag |= UO_RDWR; 801 break; 802 case 'r': 803 oflag |= UO_RDONLY; 804 break; 805 } 806 } 807 808 fd = uffs_open(name, oflag); 809 810 if (fd >= 0) { 811 cli_env_set('1', fd); 812 return 0; 813 } 814 else { 815 return -1; 816 } 817 } 818 819 /** 820 * seek file pointer 821 * t_seek <fd> <offset> [<origin>] 822 * if success, $1 = file position after seek 823 */ 824 static int cmd_tseek(int argc, char *argv[]) 825 { 826 int origin = USEEK_SET; 827 int offset; 828 int fd; 829 int ret; 830 831 CHK_ARGC(3, 4); 832 833 if (sscanf(argv[1], "%d", &fd) != 1 || 834 sscanf(argv[2], "%d", &offset) != 1) 835 { 836 return CLI_INVALID_ARG; 837 } 838 839 if (argc > 3) { 840 switch(argv[3][0]) { 841 case 's': 842 origin = USEEK_SET; 843 break; 844 case 'c': 845 origin = USEEK_CUR; 846 break; 847 case 'e': 848 origin = USEEK_END; 849 break; 850 default: 851 return CLI_INVALID_ARG; 852 } 853 } 854 855 ret = uffs_seek(fd, offset, origin); 856 if (ret >= 0) { 857 cli_env_set('1', ret); 858 return 0; 859 } 860 else { 861 return -1; 862 } 863 } 864 865 /** 866 * close file 867 * t_close <fd> 868 */ 869 static int cmd_tclose(int argc, char *argv[]) 870 { 871 int fd; 872 873 CHK_ARGC(2, 2); 874 875 if (sscanf(argv[1], "%d", &fd) == 1) { 876 return uffs_close(fd); 877 } 878 else 879 return -1; 880 } 881 882 /** 883 * write file 884 * t_write <fd> <txt> [..] 885 */ 886 static int cmd_twrite(int argc, char *argv[]) 887 { 888 int fd; 889 int i, len = 0; 890 int ret = 0; 891 892 CHK_ARGC(3, 0); 893 if (sscanf(argv[1], "%d", &fd) != 1) { 894 return -1; 895 } 896 else { 897 for (i = 2; i < argc; i++) { 898 len = strlen(argv[i]); 899 if (uffs_write(fd, argv[i], len) != len) { 900 ret = -1; 901 break; 902 } 903 } 904 } 905 906 if (ret == 0) 907 cli_env_set('1', len); 908 909 return ret; 910 } 911 912 /** 913 * read and check seq file 914 * t_check_seq <fd> <size> 915 */ 916 static int cmd_tcheck_seq(int argc, char *argv[]) 917 { 918 int fd; 919 int len, size; 920 int ret = 0, r_ret = 0; 921 long pos; 922 u8 buf[MAX_TEST_BUF_LEN]; 923 int i; 924 u8 x; 925 926 CHK_ARGC(3, 3); 927 928 if (sscanf(argv[1], "%d", &fd) != 1) { 929 return -1; 930 } 931 932 if (sscanf(argv[2], "%d", &len) != 1) { 933 return -1; 934 } 935 936 pos = uffs_tell(fd); 937 while (len > 0) { 938 size = (len > sizeof(buf) ? sizeof(buf) : len); 939 if ((r_ret = uffs_read(fd, buf, size)) < 0) { 940 MSGLN("Read fail! fd = %d, size = %d, pos = %ld", fd, size, pos); 941 ret = -1; 942 break; 943 } 944 945 // check seq 946 for (i = 0; i < r_ret; i++) { 947 x = (pos + SEQ_INIT + i) % SEQ_MOD_LEN; 948 if (buf[i] != x) { 949 MSGLN("Check fail! fd = %d, pos = %ld (expect 0x%02x but 0x%02x)\n", fd, pos + i, x, buf[i]); 950 ret = -1; 951 break; 952 } 953 } 954 955 if (ret < 0) 956 break; 957 958 len -= r_ret; 959 pos += r_ret; 960 } 961 962 return ret; 963 } 964 965 966 967 /** 968 * write random seq to file 969 * t_write_seq <fd> <size> 970 */ 971 static int cmd_twrite_seq(int argc, char *argv[]) 972 { 973 int fd; 974 int len = 0, size = 0; 975 long pos = 0; 976 int ret = 0, w_ret = 0; 977 u8 buf[MAX_TEST_BUF_LEN]; 978 979 CHK_ARGC(3, 3); 980 if (sscanf(argv[1], "%d", &fd) != 1) { 981 return -1; 982 } 983 984 if (sscanf(argv[2], "%d", &len) != 1) { 985 return -1; 986 } 987 988 pos = uffs_tell(fd); 989 while (len > 0) { 990 size = (len < sizeof(buf) ? len : sizeof(buf)); 991 memcp_seq(buf, size, pos); 992 if ((w_ret = uffs_write(fd, buf, size)) < 0) { 993 MSGLN("write fail! fd = %d, size = %d, pos = %ld", fd, size, pos); 994 ret = -1; 995 break; 996 } 997 pos += w_ret; 998 len -= w_ret; 999 } 1000 1001 if (ret == 0) 1002 cli_env_set('1', len); 1003 1004 return ret; 1005 } 1006 1007 1008 /** 1009 * read and check file 1010 * t_read <fd> <txt> 1011 */ 1012 static int cmd_tread(int argc, char *argv[]) 1013 { 1014 int fd; 1015 int len, n; 1016 int ret = 0; 1017 char buf[64]; 1018 char *p; 1019 1020 CHK_ARGC(3, 3); 1021 1022 if (sscanf(argv[1], "%d", &fd) != 1) { 1023 return -1; 1024 } 1025 else { 1026 len = strlen(argv[2]); 1027 n = 0; 1028 p = argv[2]; 1029 while (n < len) { 1030 n = (len > sizeof(buf) ? sizeof(buf) : len); 1031 if (uffs_read(fd, buf, n) != n || 1032 memcmp(buf, p, n) != 0) { 1033 ret = -1; 1034 break; 1035 } 1036 len -= n; 1037 p += n; 1038 } 1039 } 1040 1041 return ret; 1042 } 1043 1044 1045 static void do_dump_page(uffs_Device *dev, uffs_Buf *buf) 1046 { 1047 int i, j; 1048 const int line = 16; 1049 struct uffs_MiniHeaderSt *header = (struct uffs_MiniHeaderSt *)buf->header; 1050 MSG(" header.status = %d\n", header->status); 1051 if (header->status != 0xFF) { 1052 for (i = 0; i < 64; i += line) { 1053 MSG(" "); 1054 for (j = 0; j < line; j++) 1055 MSG("%02X ", buf->header[i+j]); 1056 MSG("\n"); 1057 } 1058 MSG("\n"); 1059 } 1060 } 1061 1062 static void do_dump_tag(uffs_Device *dev, uffs_Tags *tag) 1063 { 1064 MSG(" tag sealed: %s\n", TAG_IS_SEALED(tag) ? "yes" : "no"); 1065 if (TAG_IS_GOOD(tag)) { 1066 if (TAG_IS_DIRTY(tag)) { 1067 MSG(" block_ts = %d\n", tag->s.block_ts); 1068 MSG(" type = %d\n", tag->s.type); 1069 MSG(" dirty = %d\n", tag->s.dirty); 1070 MSG(" page_id = %d\n", tag->s.page_id); 1071 MSG(" serial = %d\n", tag->s.serial); 1072 MSG(" parent = %d\n", tag->s.parent); 1073 MSG(" data_len = %d\n", tag->s.data_len); 1074 } 1075 else { 1076 MSG(" tag is GOOD but NOT DIRTY !!!???\n"); 1077 } 1078 } 1079 else if (TAG_IS_SEALED(tag)) { 1080 MSG(" tag is INVALID\n"); 1081 } 1082 } 1083 1084 static void do_dump_device(uffs_Device *dev) 1085 { 1086 URET ret; 1087 int block, page; 1088 uffs_Tags tag; 1089 uffs_Buf *buf; 1090 1091 buf = uffs_BufClone(dev, NULL); 1092 if (buf == NULL) { 1093 MSGLN("Can't clone buf"); 1094 return; 1095 } 1096 1097 for (block = dev->par.start; block <= dev->par.end; block++) { 1098 MSG("---- block %d ----\n", block); 1099 for (page = 0; page < dev->attr->pages_per_block; page++) { 1100 MSG(" == page %d ==\n", page); 1101 ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE); 1102 if (UFFS_FLASH_HAVE_ERR(ret)) { 1103 MSG(" !!! Read page failed, ret = %d !!!\n", ret); 1104 } 1105 else { 1106 do_dump_page(dev, buf); 1107 if (buf->header[0] != 0xFF) { 1108 ret = uffs_FlashReadPageTag(dev, block, page, &tag); 1109 if (UFFS_FLASH_HAVE_ERR(ret)) { 1110 MSG(" !!! Read TAG failed, ret = %d !!!\n", ret); 1111 } 1112 else { 1113 do_dump_tag(dev, &tag); 1114 } 1115 } 1116 } 1117 } 1118 } 1119 uffs_BufFreeClone(dev, buf); 1120 } 1121 1122 static int cmd_dump(int argc, char *argv[]) 1123 { 1124 const char *mount = "/"; 1125 uffs_Device *dev; 1126 1127 if (argc > 1) { 1128 mount = argv[1]; 1129 } 1130 1131 MSGLN("Dumping %s ... ", mount); 1132 1133 dev = uffs_GetDeviceFromMountPoint(mount); 1134 if (dev == NULL) { 1135 MSGLN("Can't get device from mount point."); 1136 } 1137 else { 1138 do_dump_device(dev); 1139 uffs_PutDevice(dev); 1140 } 1141 1142 return 0; 1143 } 1144 1145 static int cmd_apisrv(int argc, char *argv[]) 1146 { 1147 return api_server_start(); 1148 } 1149 1150 static const struct cli_command test_cmds[] = 1151 { 1152 { cmd_t1, "t1", "<name>", "test 1" }, 1153 { cmd_t2, "t2", NULL, "test 2" }, 1154 { cmd_t3, "t3", "<name> [<noecc>]", "test 3" }, 1155 { cmd_t4, "t4", NULL, "test 4" }, 1156 { cmd_t5, "t5", "<name>", "test 5" }, 1157 { cmd_TestPageReadWrite, "t_pgrw", NULL, "test page read/write" }, 1158 { cmd_TestFormat, "t_format", NULL, "test format file system" }, 1159 { cmd_TestPopulateFiles, "t_pfs", "[<start> [<n>]]", "test populate <n> files under <start>" }, 1160 { cmd_VerifyFile, "t_vf", "<file> [<noecc>]", "verify file" }, 1161 1162 { cmd_topen, "t_open", "<oflg> <file>", "open file, fd save to $1", }, 1163 { cmd_tread, "t_read", "<fd> <txt>", "read <fd> and check against <txt>", }, 1164 { cmd_tcheck_seq, "t_check_seq", "<fd> <size>", "read seq file <fd> and check", }, 1165 { cmd_twrite, "t_write", "<fd> <txt> [...]", "write <fd>", }, 1166 { cmd_twrite_seq, "t_write_seq", "<fd> <size>", "write seq file <fd>", }, 1167 { cmd_tseek, "t_seek", "<fd> <offset> [<origin>]", "seek <fd> file pointer to <offset> from <origin>", }, 1168 { cmd_tclose, "t_close", "<fd>", "close <fd>", }, 1169 { cmd_dump, "dump", "<mount>", "dump <mount>", }, 1170 1171 { cmd_apisrv, "apisrv", NULL, "start API test server", }, 1172 1173 { NULL, NULL, NULL, NULL } 1174 }; 1175 1176 static struct cli_commandset test_cmdset = { 1177 test_cmds, 1178 }; 1179 1180 struct cli_commandset * get_test_cmds() 1181 { 1182 return &test_cmdset; 1183 }; 1184 1185 1186 1187