root/modules/file_shelter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _run
  2. _module_can_unload
  3. _module_exit_alt
  4. crc32_for_byte
  5. crc32
  6. read_file_f
  7. read_file_o
  8. compute_file_crc_f
  9. compute_file_crc_o
  10. write_file_f
  11. write_file_o
  12. read_file
  13. write_file
  14. compute_file_crc
  15. strcasecmp
  16. mkdir_if_not_exist
  17. is_parent
  18. is_current
  19. fs_readdir
  20. process_dir
  21. wordpad
  22. is_valid_stptr
  23. iswhitelisted
  24. get_next_object
  25. get_object_name
  26. get_object_data
  27. fproc_totalsize
  28. dproc_count
  29. dproc_store
  30. fproc_store
  31. alloc_storage
  32. restore
  33. can_boot_from_fat32
  34. gui_fileshelter_kbd_process
  35. basic_module_init
  36. gui_fileshelter_menu_kbd_process
  37. gui_fileshelter_draw

   1 #include "camera_info.h"
   2 #include "gui.h"
   3 #include "gui_draw.h"
   4 #include "meminfo.h"
   5 #include "module_load.h"
   6 #include "simple_module.h"
   7 #include "clock.h"
   8 #include "console.h"
   9 #include "conf.h"
  10 #include "sd_card.h"
  11 #include "cachebit.h"
  12 #include "exmem.h"
  13 #include "time.h"
  14 #include "dirent.h"
  15 #include "ctype.h"
  16 
  17 #define FSCRC_CALC 1 // 1 = file crc check immediately after writing, 0 = no check
  18 
  19 #define MAX_PATH_LEN    100
  20 
  21 // =========  MODULE INIT =================
  22 
  23 static int running = 0;
  24 static char osdbuf[128];
  25 
  26 extern int basic_module_init();
  27 
  28 /***************** BEGIN OF AUXILARY PART *********************
  29   ATTENTION: DO NOT REMOVE OR CHANGE SIGNATURES IN THIS SECTION
  30  **************************************************************/
  31 
  32 int _run()
  33 {
  34     basic_module_init();
  35 
  36     return 0;
  37 }
  38 
  39 int _module_can_unload()
  40 {
  41     return (running==0);
  42 }
  43 
  44 int _module_exit_alt()
  45 {
  46     //running = 0;
  47     return 0;
  48 }
  49 
  50 /******************** Module Information structure ******************/
  51 
  52 libsimple_sym _librun =
  53 {
  54     {
  55          0, 0, _module_can_unload, _module_exit_alt, _run
  56     }
  57 };
  58 
  59 ModuleInfo _module_info =
  60 {
  61     MODULEINFO_V1_MAGICNUM,
  62     sizeof(ModuleInfo),
  63     {1,0},      // Module version
  64 
  65     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,           // Requirements of CHDK version
  66     ANY_PLATFORM_ALLOWED,       // Specify platform dependency
  67 
  68     (int32_t)"CHDK backup & restore",
  69     MTYPE_TOOL,                 // Temporary file shelter for CHDK files
  70 
  71     &_librun.base,
  72 
  73     CONF_VERSION,               // CONF version
  74     CAM_SCREEN_VERSION,         // CAM SCREEN version
  75     ANY_VERSION,                // CAM SENSOR version
  76     ANY_VERSION,                // CAM INFO version
  77 
  78     0,
  79 };
  80 
  81 /*************** END OF AUXILARY PART *******************/
  82 //-------------------------------------------------------------------
  83 // From public domain crc32 code
  84 //-------------------------------------------------------------------
  85 
  86 unsigned long crc32_for_byte(unsigned long r) {
  87     unsigned long j;
  88     for (j = 0; j < 8; j++) {
  89         r = (r & 1? 0: (unsigned long)0xEDB88320) ^ r >> 1;
  90     }
  91     return r ^ (unsigned long)0xFF000000;
  92 }
  93 
  94 void crc32(const void *data, unsigned long n_bytes, unsigned long* crc) {
  95     static unsigned long ct[0x100] = {0};
  96     unsigned long i;
  97     if (!ct[0]) {
  98         for (i = 0; i < 0x100; i++) {
  99             ct[i] = crc32_for_byte(i);
 100         }
 101     }
 102     for (i = 0; i < n_bytes; i++) {
 103         *crc = ct[(unsigned char)*crc ^ ((unsigned char*)data)[i]] ^ *crc >> 8;
 104     }
 105 }
 106 
 107 //-------------------------------------------------------------------
 108 // file operation wrappers, allows switching between open/fopen
 109 // if required on a camera
 110 //-------------------------------------------------------------------
 111 static int use_open_rather_than_fopen = 1;
 112 
 113 int read_file_f(char *fn, void *buf, int size)
 114 {
 115     int ret = -1;
 116     FILE *fd = fopen(fn, "r+b");
 117     if (fd) {
 118         ret = fread(buf, 1, size, fd);
 119         fclose(fd);
 120         if (ret == size) {
 121             ret = 0;
 122         }
 123         else {
 124             ret = 1;
 125         }
 126     }
 127     return ret;
 128 }
 129 
 130 int read_file_o(char *fn, void *buf, int size)
 131 {
 132     int ret = -1;
 133     int fd = open(fn, O_RDONLY, 0777);
 134     if (fd >= 0) {
 135         ret = read(fd, buf, size);
 136         close(fd);
 137         if (ret == size) {
 138             ret = 0;
 139         }
 140         else {
 141             ret = 1;
 142         }
 143     }
 144     return ret;
 145 }
 146 
 147 int compute_file_crc_f(char *fn, void *buf, int size, int bufsize, unsigned long *crc)
 148 {
 149     int ret = 0;
 150     if (!fn || !buf || !crc || !bufsize) {
 151         return -1;
 152     }
 153     FILE *fd = fopen(fn, "r+b");
 154     if (fd) {
 155         long chunk = bufsize<size?bufsize:size;
 156         while (1) {
 157             long r = fread(buf, 1, chunk, fd);
 158             if (r != chunk) {
 159                 if (r != size) {
 160                     ret = 1;
 161                     break;
 162                 }
 163             }
 164             crc32(buf, r, crc);
 165             size -= r;
 166             if (size <= 0) {
 167                 break;
 168             }
 169         }
 170         fclose(fd);
 171     }
 172     return ret;
 173 }
 174 
 175 int compute_file_crc_o(char *fn, void *buf, int size, int bufsize, unsigned long *crc)
 176 {
 177     int ret = 0;
 178     if (!fn || !buf || !crc || !bufsize) {
 179         return -1;
 180     }
 181     int fd = open(fn, O_RDONLY, 0777);
 182     if (fd >= 0) {
 183         long chunk = bufsize<size?bufsize:size;
 184         while (1) {
 185             long r = read(fd, buf, chunk);
 186             if (r != chunk) {
 187                 if (r != size) {
 188                     ret = 1;
 189                     break;
 190                 }
 191             }
 192             crc32(buf, r, crc);
 193             size -= r;
 194             if (size <= 0) {
 195                 break;
 196             }
 197         }
 198         close(fd);
 199     }
 200     return ret;
 201 }
 202 
 203 int write_file_f(char *fn, void *buf, int size)
 204 {
 205     int ret = -1;
 206     FILE *fd = fopen(fn, "w+b");
 207     if (fd) {
 208         ret = fwrite(buf, 1, size, fd);
 209         fclose(fd);
 210         if (ret == size) {
 211             ret = 0;
 212         }
 213         else {
 214             ret = 1;
 215         }
 216     }
 217     return ret;
 218 }
 219 
 220 int write_file_o(char *fn, void *buf, int size)
 221 {
 222     int ret = -1;
 223     int fd = open(fn, O_WRONLY|O_CREAT|O_TRUNC, 0777);
 224     if (fd >= 0) {
 225         ret = write(fd, buf, size);
 226         close(fd);
 227         if (ret == size) {
 228             ret = 0;
 229         }
 230         else {
 231             ret = 1;
 232         }
 233     }
 234     return ret;
 235 }
 236 
 237 // reads size amount of bytes from file to buf
 238 // returns nonzero in case of error
 239 int read_file(char *fn, void *buf, int size)
 240 {
 241     if (use_open_rather_than_fopen) {
 242         return read_file_o(fn, buf, size);
 243     }
 244     return read_file_f(fn, buf, size);
 245 }
 246 
 247 // writes size amount of bytes from buf to file
 248 // returns nonzero in case of error
 249 int write_file(char *fn, void *buf, int size)
 250 {
 251     if (use_open_rather_than_fopen) {
 252         return write_file_o(fn, buf, size);
 253     }
 254     return write_file_f(fn, buf, size);
 255 }
 256 
 257 // computes crc of file
 258 // returns nonzero in case of error
 259 int compute_file_crc(char *fn, void *buf, int size, int bufsize, unsigned long *crc)
 260 {
 261     if (use_open_rather_than_fopen) {
 262         return compute_file_crc_o(fn, buf, size, bufsize, crc);
 263     }
 264     return compute_file_crc_f(fn, buf, size, bufsize, crc);
 265 }
 266 
 267 //-------------------------------------------------------------------
 268 // From glibc
 269 //-------------------------------------------------------------------
 270 
 271 int strcasecmp(const char *s1, const char *s2)
 272 {
 273   const unsigned char *p1 = (const unsigned char *) s1;
 274   const unsigned char *p2 = (const unsigned char *) s2;
 275   int result;
 276   if (p1 == p2)
 277     return 0;
 278   while ((result = tolower(*p1) - tolower(*p2++)) == 0)
 279     if (*p1++ == '\0')
 280       break;
 281   return result;
 282 }
 283 
 284 //-------------------------------------------------------------------
 285 // Following is to avoid another export from CHDK core
 286 //-------------------------------------------------------------------
 287 
 288 long mkdir_if_not_exist(const char *dirname)
 289 {
 290     // Check if directory exists and create it if it does not.
 291     if (stat(dirname,0) != 0) return mkdir(dirname);
 292     return 0;   // Success
 293 }
 294 
 295 //-------------------------------------------------------------------
 296 // Modified routines from gui_fselect.c
 297 //-------------------------------------------------------------------
 298 // Structure to hold info about a file or directory
 299 typedef struct
 300 {
 301     struct dirent   *de;
 302     unsigned long   size;
 303     unsigned long   mtime;
 304     unsigned char   deleted;        // deleted entry?
 305     unsigned char   isdir;          // directory?
 306     unsigned char   isparent;       // parent directory (..)?
 307     unsigned char   iscurrent;      // current directory (.)?
 308     unsigned char   isvalid;        // stat() call succeeded
 309     unsigned char   ishidden;       // hidden attribute?
 310 } fs_dirent;
 311 
 312 static int is_parent(const char *name)  { return (strcmp(name, "..") == 0); }
 313 static int is_current(const char *name)  { return (strcmp(name, ".") == 0); }
 314 
 315 // Custom readdir - populates extra info about the file or directory
 316 // Uses stat() after calling readdir() - we don't currently get this
 317 // extra data from the firmware function.
 318 static int fs_readdir(DIR *d, fs_dirent *de, const char* path)
 319 {
 320     char pbuf[MAX_PATH_LEN];
 321 
 322     de->de = readdir(d);
 323     de->size = 0;
 324     de->mtime = 0;
 325     de->deleted  = 0;
 326     de->isparent = 0;
 327     de->iscurrent = 0;
 328     de->isdir = 0;
 329     de->isvalid = 0;
 330     de->ishidden = 0;
 331 
 332     if (de->de)
 333     {
 334         if (de->de->d_name[0] == 0xE5)
 335         {
 336             de->deleted = 1;
 337         }
 338         else
 339         {
 340             de->isparent  = is_parent(de->de->d_name);
 341             de->iscurrent = is_current(de->de->d_name);
 342 
 343             sprintf(pbuf, "%s%s%s", path, path[strlen(path)-1]=='/'?"":"/", de->de->d_name);
 344             struct stat st;
 345             if (de->isparent || de->iscurrent)
 346             {
 347                 de->isdir = 1;
 348                 de->isvalid = 1;
 349             }
 350             else if (stat(pbuf, &st) == 0)
 351             {
 352                 de->size  = st.st_size;
 353                 de->mtime = st.st_mtime;
 354                 de->isvalid = 1;
 355                 de->isdir = ((st.st_attrib & DOS_ATTR_DIRECTORY) != 0);
 356                 de->ishidden = ((st.st_attrib & DOS_ATTR_HIDDEN) != 0);
 357             }
 358         }
 359 
 360         return 1;
 361     }
 362 
 363     return 0;
 364 }
 365 
 366 // Process contents of named directory
 367 //  - for sub directories, process recursively if required (up to 'nested' levels deep)
 368 //  - for files, call 'file_process' function
 369 // Once file & directory processing done, call 'dir_process' function on input path
 370 static void process_dir(const char *parent, const char *name, int nested, void (*file_process)(const char *path, const char *file, fs_dirent *de), void (*dir_process)(const char *path, fs_dirent *de))
 371 {
 372     DIR         *d;
 373     fs_dirent   de;
 374 
 375     // Get full name
 376     char *path;
 377     if (name)
 378     {
 379         path = malloc(strlen(parent) + strlen(name) + 2);
 380         sprintf(path, "%s%s%s", parent, parent[strlen(parent)-1]=='/'?"":"/", name);
 381     }
 382     else
 383     {
 384         path = (char*)parent;
 385     }
 386 
 387     // Open directory
 388     d = opendir_chdk(path,OPENDIR_FL_CHDK_LFN);
 389 
 390     if (d)
 391     {
 392         // let caller get the dir name first
 393         if (dir_process)
 394             dir_process(path, &de);
 395 
 396         // Process contents
 397         while (fs_readdir(d, &de, path))
 398         {
 399             if (!de.deleted)
 400             {
 401                 // Sub directory? Process recursively (but only 'nested' level deep)
 402                 if (de.isdir)
 403                 {
 404                     if (!de.isparent && !de.iscurrent && nested)
 405                         process_dir(path, de.de->d_name, nested-1, file_process, dir_process);
 406                 }
 407                 else if (file_process)
 408                 {
 409                     file_process(path, de.de->d_name, &de);
 410                 }
 411             }
 412         }
 413         closedir(d);
 414 
 415     }
 416 
 417     if (name)
 418         free(path);
 419 }
 420 
 421 
 422 //-------------------------------------------------------------------
 423 /*
 424  * File storage in memory
 425  * fs_fheader struct
 426  * file name (padded up to word boundary)
 427  * file content (padded up to word boundary)
 428  *
 429  * above repeated for each directory and its files, invalid magic means end of chain
 430  * directory is stored first to ease restoration
 431  */
 432 
 433 #define FMAGIC 0x004c4946 // FIL
 434 #define DMAGIC 0x00524944 // DIR
 435 
 436 enum rstatus {
 437     RS_OK = 0,
 438     RS_NAMELONG,
 439     RS_CRC,
 440     RS_FERR,
 441 };
 442 
 443 // restore status
 444 const char *rsshumanL[] = {
 445     "OK",
 446     "Files not backed up",
 447     "Stored files corrupted",
 448     "Stored files corrupted",
 449     "Storage area corrupted",
 450     "A/CHDK exists, aborting",
 451 };
 452 
 453 // following struct needs to be an integer number of words
 454 typedef struct
 455 {
 456     unsigned long   magic;      // "FIL" for file, "DIR" for directory
 457     unsigned long   size;       // file size
 458     unsigned long   mtime;      // modification timestamp
 459     unsigned long   nlen;       // name length
 460     unsigned long   crc;        // crc32 of file data
 461     unsigned long   status;     // result code when restoring
 462 } fs_fheader;
 463 
 464 //-------------------------------------------------------------------
 465 
 466 const char *wl1[] = {"DISKBOOT.BIN", "PS.FIR", "PS.FI2", 0};
 467 static void *whitelist = 0;
 468 static unsigned storageneed = 0;
 469 static unsigned filecount = 0;
 470 static unsigned failcount = 0;
 471 static unsigned dircount = 0;
 472 static unsigned tfilecount = 0;
 473 static unsigned tdircount = 0;
 474 static unsigned fileprocd = 0;
 475 static unsigned dirprocd = 0;
 476 static void *starea = 0; // start of allocated exmem area
 477 static unsigned stmax = 0; // size of allocated exmem area
 478 static void *tmpbuf = 0; // temporary buffer (for crc check of files written)
 479 const unsigned tmpsiz = 32768; // temporary buffer size
 480 static void *storptr = 0;
 481 static unsigned long stcrc = 0; // crc of whole storage area
 482 
 483 unsigned wordpad(unsigned u)
 484 {
 485     return (u + 3) & 0xfffffffc;
 486 }
 487 
 488 // returns nonzero if pointer is inside the storage area
 489 int is_valid_stptr(void *p)
 490 {
 491     if (p>starea+stmax-sizeof(fs_fheader) || p<starea) {
 492         return 0;
 493     }
 494     return 1;
 495 }
 496 
 497 // checks whether name is allowed
 498 // returns nonzero if it is on whitelist
 499 // also returns nonzero if whitelist is NULL
 500 int iswhitelisted(const char *name)
 501 {
 502     if (whitelist == 0) {
 503         return 1;
 504     }
 505     char **wl = whitelist;
 506     char *s = *wl;
 507     while (s) {
 508         if (strcasecmp(name, s) == 0) {
 509             return 1;
 510         }
 511         s = *(++wl);
 512     }
 513     return 0;
 514 }
 515 
 516 // moves *currptr from current, valid stored file/dir to the next (existing or not)
 517 // returns nonzero in case of success
 518 // if magic is nonzero, the next object with requested magic is searched
 519 int get_next_object(unsigned long magic, void **currptr)
 520 {
 521     char *p = *currptr;
 522     if (!is_valid_stptr(p)) {
 523         return 0;
 524     }
 525     fs_fheader *fh = (void*)p;
 526     while (fh->magic==FMAGIC || fh->magic==DMAGIC) {
 527         p += sizeof(fs_fheader) + wordpad(fh->nlen) + wordpad(fh->size);
 528         if (!is_valid_stptr(p)) {
 529             break;
 530         }
 531         fh = (void*)p;
 532         if (!magic || fh->magic == magic) {
 533             *currptr = (void*)p;
 534             return 1;
 535         }
 536     }
 537     return 0;
 538 }
 539 
 540 // returns pointer to current object's name or NULL when invalid
 541 char *get_object_name(void *p)
 542 {
 543     if (!is_valid_stptr(p)) {
 544         return 0;
 545     }
 546     fs_fheader *fh = p;
 547     p += sizeof(fs_fheader);
 548     if (!is_valid_stptr(p) || !is_valid_stptr(p+fh->nlen)) {
 549         return 0;
 550     }
 551     return (char*)p;
 552 }
 553 
 554 // returns pointer to current object's data or NULL when invalid
 555 char *get_object_data(void *p)
 556 {
 557     if (!is_valid_stptr(p)) {
 558         return 0;
 559     }
 560     fs_fheader *fh = p;
 561     p += sizeof(fs_fheader) + wordpad(fh->nlen);
 562     if (!is_valid_stptr(p) || !is_valid_stptr(p+fh->size)) {
 563         return 0;
 564     }
 565     return (char*)p;
 566 }
 567 
 568 // callback function for process_dir, counts files and their sizes
 569 void fproc_totalsize(const char *path, const char *file, fs_dirent *de)
 570 {
 571     if (whitelist && !iswhitelisted(file)) return;
 572     storageneed += wordpad(de->size);
 573     storageneed += wordpad(strlen(path) + 1 + strlen(file) + 1);
 574     storageneed += sizeof(fs_fheader);
 575     filecount += 1;
 576 }
 577 
 578 // callback function for process_dir, counts directories
 579 void dproc_count(const char *path, __attribute__ ((unused))fs_dirent *de)
 580 {
 581     if (whitelist && !iswhitelisted(path)) return;
 582     storageneed += wordpad(strlen(path) + 1);
 583     storageneed += sizeof(fs_fheader);
 584     dircount += 1;
 585 }
 586 
 587 // callback function for process_dir, stores directories
 588 void dproc_store(const char *path, fs_dirent *de)
 589 {
 590     if (whitelist && !iswhitelisted(path)) return;
 591     fs_fheader *fh = storptr;
 592     fh->magic = DMAGIC;
 593     fh->size = 0;
 594     fh->mtime = de->mtime;
 595     fh->nlen = strlen(path) + 1;
 596     fh->crc = 0;
 597     storptr += sizeof(fs_fheader);
 598     strcpy(storptr, path);
 599     storptr += wordpad(fh->nlen);
 600     dirprocd++;
 601 }
 602 
 603 // callback function for process_dir, stores files
 604 void fproc_store(const char *path, const char *file, fs_dirent *de)
 605 {
 606     if (whitelist && !iswhitelisted(file)) return;
 607     fs_fheader *fh = storptr;
 608     fh->magic = FMAGIC;
 609     fh->size = de->size;
 610     fh->mtime = de->mtime;
 611     fh->nlen = strlen(path) + 1 + strlen(file) + 1;
 612     fh->crc = 0;
 613     storptr += sizeof(fs_fheader);
 614     sprintf(storptr, "%s%s%s", path, path[strlen(path)-1]=='/'?"":"/", file);
 615     char *name = storptr;
 616     storptr += wordpad(fh->nlen);
 617     
 618     if ( read_file(name, storptr, fh->size) ) {
 619         failcount++;
 620         storptr -= sizeof(fs_fheader);
 621         storptr -= wordpad(fh->nlen);
 622         console_add_line(file);
 623     }
 624     else {
 625         crc32(storptr, fh->size, &fh->crc); // fh->crc is set to zero prior to this
 626         storptr += wordpad(fh->size);
 627         fileprocd++;
 628     }
 629 }
 630 
 631 // attempts to allocate an exmem area that is large enough to backup files
 632 // uses exmem types that are unlikely to be used and are widely available
 633 // uses globals
 634 void alloc_storage()
 635 {
 636     const char *exmemtypes[] = {"EXMEM_FIRMUP", "EXMEM_FAMODE", 0};
 637     const unsigned cushion = 128; // extra data to allocate (for eventual cached use)
 638     unsigned n, i;
 639     exmem_alloc_info ai;
 640     storageneed += sizeof(fs_fheader); // for the last entry
 641     storageneed += tmpsiz; // for temp buffer
 642     starea = 0;
 643     i = 0;
 644     while (exmemtypes[i]) {
 645         for (n=0; n<exmem_type_count; n++) {
 646             if (strncmp(exmemtypes[i],get_exmem_type_name(n),strlen(exmemtypes[i]))==0) {
 647                 get_exmem_type_status(n, &ai);
 648                 if (!ai.len) {
 649                     starea = exmem_alloc_uncached(n, storageneed+cushion, 0);
 650                     get_exmem_type_status(n, &ai);
 651                     if (ai.len-cushion < storageneed) {
 652                         starea = 0;
 653                         exmem_free_uncached(n);
 654                         char buf[64];
 655                         sprintf(buf,"%s need %x got %x",exmemtypes[i],storageneed,ai.len);
 656                         console_add_line(buf);
 657                     }
 658 #if 1
 659                     else {
 660                         char buf[64];
 661                         sprintf(buf,"%s adr %x",exmemtypes[i],starea);
 662                         console_add_line(buf);
 663                     }
 664 #endif
 665                 }
 666                 break;
 667             }
 668         }
 669         if (starea) {
 670             starea += cushion/2; // leave a safety border on both start and end of allocation
 671             stmax = storageneed - tmpsiz;
 672             tmpbuf = starea + stmax;
 673             storptr = starea;
 674             break;
 675         }
 676         i++;
 677     }
 678 }
 679 
 680 // restores stored files to directory 'dest'
 681 // test: 0 - write to card, 1 - check only
 682 // returns 0 for OK
 683 int restore(const char *dest, int test)
 684 {
 685     char buf[256];
 686     int ret = 0;
 687     if (!starea) {
 688         return 1;
 689     }
 690     if (!test && strlen(dest)>2) mkdir_if_not_exist(dest);
 691     storptr = starea;
 692     if (!is_valid_stptr(storptr)) {
 693         return 2;
 694     }
 695     fs_fheader *fh = storptr;
 696     while (1) {
 697         if (fh->magic==DMAGIC) {
 698             char *lastdir = get_object_name(storptr);
 699             lastdir += 2; // chop off A/
 700             if (strlen(dest)+1+strlen(lastdir) > 255) {
 701                 fh->status = RS_NAMELONG;
 702                 ret |= 0x40000000;
 703                 if (!get_next_object(0, &storptr)) {
 704                     break;
 705                 }
 706                 continue;
 707             }
 708             sprintf(buf,"%s/%s",dest,lastdir);
 709             if (!test) {
 710                 ret |= mkdir_if_not_exist(buf)?0x20000000:0;
 711                 if (stat(buf,0) == 0) {
 712                     tdircount--;
 713                 }
 714             }
 715             else {
 716                 msleep(10);
 717                 tdircount--;
 718             }
 719         }
 720         else if (fh->magic==FMAGIC) {
 721             if (strlen(dest)+1+fh->nlen-2 > 255) {
 722                 fh->status = RS_NAMELONG;
 723                 ret |= 0x40000000;
 724                 if (!get_next_object(0, &storptr)) {
 725                     break;
 726                 }
 727                 continue;
 728             }
 729             unsigned long crc = 0;
 730             char *fn = get_object_name(storptr);
 731             if (fn) {
 732                 fn +=2; // chop off A/
 733             }
 734             else {
 735                 return ret + 3;
 736             }
 737             char *fd = get_object_data(storptr);
 738             if (fd) {
 739                 crc32(fd, fh->size, &crc); // crc is set to zero prior to this
 740                 if (crc != fh->crc) {
 741                     fh->status = RS_CRC;
 742                     ret |= 0x10000000;
 743                     if (!get_next_object(0, &storptr)) {
 744                         break;
 745                     }
 746                     continue;
 747                 }
 748             }
 749             sprintf(buf,"%s/%s",dest,fn);
 750             if (!test) {
 751                 
 752                 if ( write_file(buf, fd, fh->size) ) {
 753                     console_add_line(fn);
 754                     fh->status = RS_FERR;
 755                     ret |= 0x08000000;
 756                 }
 757                 else {
 758 #if (FSCRC_CALC == 1)
 759                     crc = 0;
 760                     if ( compute_file_crc(buf, tmpbuf, fh->size, tmpsiz, &crc) ) {
 761                         console_add_line(fn);
 762                         fh->status = RS_FERR;
 763                         ret |= 0x04000000;
 764                     }
 765                     else {
 766                         if ( fh->crc != crc) {
 767                             console_add_line(fn);
 768                             fh->status = RS_FERR;
 769                             ret |= 0x02000000;
 770                         }
 771                         else {
 772                             struct utimbuf t;
 773                             t.actime = t.modtime = fh->mtime;
 774                             utime(buf, &t);
 775                             tfilecount--;
 776                         }
 777                     }
 778 #else // (FSCRC_CALC != 1)
 779                     struct utimbuf t;
 780                     t.actime = t.modtime = fh->mtime;
 781                     utime(buf, &t);
 782                     tfilecount--;
 783 #endif
 784                 }
 785                 
 786             }
 787             else {
 788                 msleep(10);
 789                 tfilecount--;
 790             }
 791         }
 792         else {
 793             break;
 794         }
 795         
 796         // advance pointer, error out if impossible
 797         if (!get_next_object(0, &storptr)) {
 798             ret += 4;
 799             break;
 800         }
 801         fh = storptr;
 802     }
 803     return ret;
 804 }
 805 
 806 //-------------------------------------------------------------------
 807 
 808 int can_boot_from_fat32()
 809 {
 810     if (conf.platformid > 0x3222) { // r47+
 811         return 1;
 812     }
 813     return 0;
 814 }
 815 
 816 //-------------------------------------------------------------------
 817 
 818 char *help1[] = {
 819     "Utility for temporarily storing CHDK",
 820     "system files in RAM, allowing to format",
 821     "card via Canon menu.",
 822     "Usage:",
 823     "1. Start this utility, press SET to backup",
 824     "2. Leave the utility, format card in Canon",
 825     "   menu. Do NOT switch off the camera.",
 826     "3. Start this utility again, press SET",
 827     "4. Make card bootable via CHDK menu",
 828     "5. Restart camera before starting to shoot",
 829     "IMPORTANT",
 830     "Do not format card if you get errors.",
 831     "Only the following files are stored:",
 832     "- Everything in CHDK directory.",
 833     "- DISKBOOT.BIN, PS.FIR, PS.FI2",
 834     "WARNING",
 835 //    "Do NOT use this on partitioned cards!",
 836 //    "Cards larger than 32GB will lose autoboot!",
 837 //    "Cards larger than 2GB will lose autoboot",
 838 //    "on cameras released prior to 2011 !",
 839     "Excessive amount of data in CHDK direcory",
 840     "may cause a crash while making backup!",
 841     "Do not use this on mission critical files!",
 842 };
 843 
 844 char *help_partwarn = "Do NOT format, card will lose partitions!";
 845 char *help_bootwarn = "Card will lose autoboot if formatted!";
 846 
 847 //-------------------------------------------------------------------
 848 
 849 
 850 /*************** GUI MODULE *******************/
 851 
 852 #include "gui_mbox.h"
 853 #include "keyboard.h"
 854 
 855 void gui_fileshelter_menu_kbd_process();
 856 int gui_fileshelter_kbd_process();
 857 void gui_fileshelter_draw();
 858 
 859 gui_handler GUI_MODE_FILESHELTER = 
 860 /*GUI_MODE_FILESHELTER*/   { GUI_MODE_MODULE, gui_fileshelter_draw, gui_fileshelter_kbd_process, gui_fileshelter_menu_kbd_process, 0, 0 };
 861 
 862 static unsigned int cardsize;
 863 static int canfat32boot;
 864 static int partcount;
 865 static int noformatyet;
 866 
 867 static int fileshelter_mode = 0;
 868 static unsigned disph = 0, dispw = 0, helph = 0;
 869 static unsigned restore_status;
 870 static unsigned scrolly;
 871 static int fileshelter_redraw;
 872 gui_handler *fileshelter_old_guimode;
 873 
 874 int gui_fileshelter_kbd_process()
 875 {
 876     switch (kbd_get_autoclicked_key())
 877     {
 878     case KEY_SET:
 879         if (starea) {
 880             if (stat("A/CHDK",0) != 0) {
 881                 // CHDK dir not found, assuming formatted card
 882                 unsigned long crc = 0;
 883                 tfilecount = filecount;
 884                 tdircount = dircount;
 885                 fileshelter_redraw = 8;
 886                 msleep(100); // give the display a chance to update
 887                 crc32(starea, stmax, &crc);
 888                 if (crc == stcrc) {
 889                     fileshelter_redraw = 5;
 890                     restore_status = restore("A",0);
 891                     fileshelter_redraw = 3;
 892                 }
 893                 else {
 894                     restore_status = 4;
 895                     fileshelter_redraw = 3;
 896                 }
 897             }
 898             else {
 899                 // CHDK dir present, doing a test run only
 900                 unsigned long crc = 0;
 901                 tfilecount = filecount;
 902                 tdircount = dircount;
 903                 fileshelter_redraw = 8;
 904                 msleep(100); // give the display a chance to update
 905                 crc32(starea, stmax, &crc);
 906                 if (crc == stcrc) {
 907                     fileshelter_redraw = 11;
 908                     restore_status = restore("A",1);
 909                     fileshelter_redraw = 10;
 910                 }
 911                 else {
 912                     restore_status = 4;
 913                     fileshelter_redraw = 10;
 914                 }
 915             }
 916         }
 917         else {
 918             fileshelter_redraw = 6;
 919             storageneed = 0;
 920             filecount = 0;
 921             dircount = 0;
 922             whitelist = wl1;
 923             process_dir("A/", 0, 0, fproc_totalsize, dproc_count);
 924             whitelist = 0;
 925             process_dir("A/CHDK", 0, 999, fproc_totalsize, dproc_count);
 926             alloc_storage();
 927             if (starea) {
 928                 fileshelter_redraw = 7;
 929                 failcount = 0;
 930                 fileprocd = 0;
 931                 dirprocd = 0;
 932                 whitelist = wl1;
 933                 process_dir("A/", 0, 0, fproc_store, dproc_store);
 934                 whitelist = 0;
 935                 process_dir("A/CHDK", 0, 999, fproc_store, dproc_store);
 936                 fs_fheader *fh = storptr;
 937                 fh->magic = 0;
 938                 stcrc = 0;
 939                 crc32(starea, stmax, &stcrc);
 940             }
 941             fileshelter_redraw = 1;
 942         }
 943         break;
 944     case KEY_DOWN:
 945         if (scrolly < sizeof(help1)/sizeof(char*)-1) {
 946             scrolly++;
 947         }
 948         else {
 949             scrolly = 0;
 950         }
 951         fileshelter_redraw = 4;
 952         break;
 953     case KEY_UP:
 954         if (scrolly > 0) {
 955             scrolly--;
 956         }
 957         else {
 958             scrolly = sizeof(help1)/sizeof(char*)-1;
 959         }
 960         fileshelter_redraw = 4;
 961         break;
 962     case KEY_SHOOT_HALF:
 963         fileshelter_mode = fileshelter_mode==0?1:0;
 964 #if 0
 965         if (fileshelter_mode) {
 966             use_open_rather_than_fopen = 0;
 967         }
 968         else {
 969             use_open_rather_than_fopen = 1;
 970         }
 971 #endif
 972         fileshelter_redraw = 2;
 973         break;
 974     }
 975     return 0;
 976 }
 977 
 978 //-------------------------------------------------------------------
 979 
 980 int basic_module_init()
 981 {
 982     if (!running) {
 983         running = 1;
 984         disph = camera_screen.height / FONT_HEIGHT;
 985         dispw = camera_screen.width / FONT_WIDTH;
 986         helph = camera_screen.height / FONT_HEIGHT - 5;
 987         noformatyet = 1;
 988     }
 989     else {
 990         noformatyet = stat("A/CHDK",0)?0:1;
 991     }
 992     scrolly = 0;
 993 
 994     cardsize = GetTotalCardSpaceKb();
 995     partcount = get_part_count();
 996     canfat32boot = can_boot_from_fat32();
 997 
 998     fileshelter_redraw = 2;
 999     fileshelter_old_guimode = gui_set_mode(&GUI_MODE_FILESHELTER);
1000     return 1;
1001 }
1002 
1003 void gui_fileshelter_menu_kbd_process()
1004 {
1005     if (!starea) {
1006         running = 0;
1007     }
1008 
1009     gui_set_mode(fileshelter_old_guimode);
1010 }
1011 
1012 void gui_fileshelter_draw()
1013 {
1014     static int selfupdate = 0;
1015     static int warnshown = 0;
1016     
1017     int fredraw = fileshelter_redraw;
1018     fileshelter_redraw = 0;
1019 
1020     if (fredraw || selfupdate) {
1021 
1022         if (fredraw == 2)
1023         {
1024             draw_rectangle(camera_screen.disp_left, 0, camera_screen.disp_right, camera_screen.height-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1025             draw_string(camera_screen.disp_left, 0, "CHDK backup & restore utility", MAKE_COLOR(COLOR_WHITE, COLOR_BLACK));
1026             draw_string(camera_screen.disp_left, FONT_HEIGHT, !starea?"SET-backup  MENU-exit \x18\x19-help":noformatyet?"SET-check   MENU-exit \x18\x19-help":"SET-restore MENU-exit \x18\x19-help", MAKE_COLOR(COLOR_BLACK, COLOR_WHITE));
1027 
1028 #if 0
1029             if (fileshelter_mode) { // meant to be temporary
1030                 draw_char(camera_screen.disp_left+FONT_WIDTH*30, 0, '*', MAKE_COLOR(COLOR_BLACK, COLOR_BLUE));
1031             }
1032             else {
1033                 draw_char(camera_screen.disp_left+FONT_WIDTH*30, 0, ' ', MAKE_COLOR(COLOR_BLACK, COLOR_BLUE));
1034             }
1035 #endif
1036 
1037             fredraw = 4;
1038             selfupdate = 0;
1039         }
1040         if (fredraw == 3)
1041         {
1042             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1043             if (tfilecount || tdircount) {
1044                 sprintf(osdbuf, "Not restored: %u files, %u dirs", tfilecount, tdircount);
1045                 if (sizeof(osdbuf)>dispw) osdbuf[dispw] = 0;
1046                 draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, COLOR_YELLOW));
1047             }
1048             unsigned rssl = restore_status & 0xff;
1049             char *hrsm = "???";
1050             if (rssl < sizeof(rsshumanL)/sizeof(char*)) {
1051                 hrsm = (char*)rsshumanL[rssl];
1052             }
1053             sprintf(osdbuf, restore_status?"Restore status: %08x":"Restore status:", restore_status);
1054             draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, restore_status?COLOR_RED:COLOR_GREEN));
1055             sprintf(osdbuf, "%s", hrsm);
1056             draw_string(camera_screen.disp_left, 4*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, restore_status?COLOR_RED:COLOR_GREEN));
1057             selfupdate = 0;
1058         }
1059         if (fredraw == 10)
1060         {
1061             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1062             if (tfilecount || tdircount) {
1063                 sprintf(osdbuf, "Failed: %u files, %u dirs", tfilecount, tdircount);
1064                 if (sizeof(osdbuf)>dispw) osdbuf[dispw] = 0;
1065                 draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, COLOR_YELLOW));
1066             }
1067             unsigned rssl = restore_status & 0xff;
1068             char *hrsm = "???";
1069             if (rssl < sizeof(rsshumanL)/sizeof(char*)) {
1070                 hrsm = (char*)rsshumanL[rssl];
1071             }
1072             sprintf(osdbuf, restore_status?"Test status: %08x":"Test status:", restore_status);
1073             draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, restore_status?COLOR_RED:COLOR_GREEN));
1074             sprintf(osdbuf, "%s", hrsm);
1075             draw_string(camera_screen.disp_left, 4*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, restore_status?COLOR_RED:COLOR_GREEN));
1076             selfupdate = 0;
1077         }
1078         if (fredraw == 1)
1079         {
1080             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1081             sprintf(osdbuf, "%u files, %u dirs, total %u bytes", filecount, dircount, storageneed);
1082             draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, COLOR_WHITE));
1083             if (starea && !failcount) {
1084                 draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, "Backup successful", MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1085             }
1086             else if (failcount) {
1087                 sprintf(osdbuf, "Backup failed to store %u file(s)", failcount);
1088                 draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, COLOR_YELLOW));
1089                 draw_string(camera_screen.disp_left, 4*FONT_HEIGHT, "See CHDK console for filename(s)", MAKE_COLOR(COLOR_BLACK, COLOR_YELLOW));
1090             }
1091             else if (!starea) {
1092                 draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, "Backup failed - insufficient memory", MAKE_COLOR(COLOR_BLACK, COLOR_RED));
1093             }
1094             else {
1095                 draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, "Backup failed", MAKE_COLOR(COLOR_BLACK, COLOR_RED));
1096             }
1097             selfupdate = 0;
1098         }
1099         if (fredraw == 4)
1100         {
1101             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*5, camera_screen.disp_right, camera_screen.height-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1102             unsigned y;
1103             for (y=0; y<helph; y++) {
1104                 if (scrolly+y < sizeof(help1)/sizeof(char*)) {
1105                     draw_string(camera_screen.disp_left, (5+y)*FONT_HEIGHT, help1[scrolly+y], MAKE_COLOR(COLOR_BLACK, COLOR_GREY));
1106                 }
1107             }
1108             if (!warnshown) {
1109                 warnshown = 1;
1110                 fredraw = 9;
1111             }
1112             selfupdate = 0;
1113         }
1114         if (fredraw == 5)
1115         {
1116             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1117             draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, "Restoring ...", MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1118             selfupdate = 5;
1119         }
1120         if (fredraw == 11)
1121         {
1122             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1123             draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, "Testing ...", MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1124             selfupdate = 5;
1125         }
1126         if (fredraw == 6)
1127         {
1128             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1129             draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, "Counting ...", MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1130             selfupdate = 6;
1131         }
1132         if (fredraw == 7)
1133         {
1134             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1135             draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, "Backing up ...", MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1136             selfupdate = 7;
1137         }
1138         if (fredraw == 8)
1139         {
1140             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1141             draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, "Verifying integrity ...", MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1142             selfupdate = 6;
1143         }
1144         if (fredraw == 9)
1145         {
1146             draw_rectangle(camera_screen.disp_left, FONT_HEIGHT*2, camera_screen.disp_right, FONT_HEIGHT*5-1, MAKE_COLOR(COLOR_BLACK, COLOR_BLACK), RECT_BORDER0|DRAW_FILLED);
1147 
1148             // draw card related warnings if any
1149             if (canfat32boot && cardsize>32*1024*1024) {
1150                 draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, help_bootwarn, MAKE_COLOR(COLOR_BLACK, COLOR_RED));
1151             }
1152             else if (!canfat32boot && cardsize>2*1024*1024) {
1153                 draw_string(camera_screen.disp_left, 2*FONT_HEIGHT, help_bootwarn, MAKE_COLOR(COLOR_BLACK, COLOR_RED));
1154             }
1155             if (partcount > 1) {
1156                 draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, help_partwarn, MAKE_COLOR(COLOR_BLACK, COLOR_RED));
1157             }
1158 
1159         }
1160 
1161         if (selfupdate == 5) {
1162             static unsigned fc=0,dc=0;
1163             if ((tfilecount!=fc) || (tdircount!=dc)) {
1164                 sprintf(osdbuf, "Remaining: %u files, %u dirs       ", tfilecount, tdircount);
1165                 if (sizeof(osdbuf)>dispw) osdbuf[dispw] = 0;
1166                 draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1167             }
1168             fc = tfilecount;
1169             dc = tdircount;
1170         }
1171         else if (selfupdate == 6) {
1172             static int phase = 0;
1173             const char *pc = "/-\\|";
1174             draw_char(camera_screen.disp_left, 3*FONT_HEIGHT, pc[phase&3], MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1175             phase++;
1176         }
1177         else if (selfupdate == 7) {
1178             static unsigned fc=0,dc=0;
1179             if ((fileprocd!=fc) || (dirprocd!=dc)) {
1180                 sprintf(osdbuf, "Remaining: %u files, %u dirs       ", filecount-fileprocd, dircount-dirprocd);
1181                 if (sizeof(osdbuf)>dispw) osdbuf[dispw] = 0;
1182                 draw_string(camera_screen.disp_left, 3*FONT_HEIGHT, osdbuf, MAKE_COLOR(COLOR_BLACK, COLOR_GREEN));
1183             }
1184             fc = fileprocd;
1185             dc = dirprocd;
1186         }
1187 
1188     }
1189 
1190 }
1191 

/* [<][>][^][v][top][bottom][index][help] */