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

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