|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /****************************** Module Header ******************************* ! 13: * Module Name: SCANDIR.C ! 14: * ! 15: * Scan a directory tree and build a sorted list of filenames within that ! 16: * tree. ! 17: * ! 18: * Functions: ! 19: * ! 20: * dir_buildlist() ! 21: * dir_delete() ! 22: * dir_isfile() ! 23: * dir_firstitem() ! 24: * dir_nextitem() ! 25: * dir_findnextfile() ! 26: * dir_getrelname() ! 27: * dir_getfullname() ! 28: * dir_getroot_list() ! 29: * dir_getroot_item() ! 30: * dir_freerelname() ! 31: * dir_freefullname() ! 32: * dir_freeroot_list() ! 33: * dir_freerootitem() ! 34: * dir_getopenname() ! 35: * dir_freeopenname() ! 36: * dir_openfile() ! 37: * dir_closefile() ! 38: * dir_filesize() ! 39: * dir_startcopy() ! 40: * dir_endcopy() ! 41: * dir_copy() ! 42: * dir_finalelem() ! 43: * dir_cleardirect() ! 44: * dir_adddirect() ! 45: * dir_addfile() ! 46: * dir_scan() ! 47: * dir_isvaliddir() ! 48: * dir_isvalidfile() ! 49: * dir_fileinit() ! 50: * dir_dirinit() ! 51: * dir_getpathsize() ! 52: * dir_findnextfile() ! 53: * ! 54: * Comments: ! 55: * ! 56: * The call dir_buildlist takes a pathname and returns a handle. Subsequent ! 57: * calls to dir_firstitem and dir_nextitem return handles to ! 58: * items within the list, from which you can get the name of the ! 59: * file (relative to the original pathname, or complete), and filesize. ! 60: * ! 61: * The list can be either built entirely during the build call, or ! 62: * built one directory at a time as required by dir_nextitem calls. This ! 63: * option affects only relative performance, and is taken as a ! 64: * recommendation only (ie some of the time we will ignore the flag). ! 65: * ! 66: * The list is ordered alphabetically (case-insensitive using lstrcmpi). ! 67: * within any one directory, we list filenames before going on ! 68: * to subdirectory contents. ! 69: * ! 70: * All memory is allocated from a gmem_* heap hHeap declared ! 71: * and initialised elsewhere. ! 72: * ! 73: * The caller gets handles to two things: a DIRLIST, representing the ! 74: * entire list of filenames, and a DIRITEM: one item within the list. ! 75: * ! 76: * From the DIRITEM he can get the filename (including or excluding the ! 77: * tree root passed to dir_build*) - and also he can get to the next ! 78: * DIRITEM. ! 79: * ! 80: * We permit lazy building of the tree (usually so the caller can keep ! 81: * the user-interface up-to-date as we go along). In this case, ! 82: * we need to store information about how far we have scanned and ! 83: * what is next to do. We need to scan an entire directory at a time and then ! 84: * sort it so we can return files in the correct order. ! 85: * ! 86: * We scan an entire directory and store it in a DIRECT struct. This contains ! 87: * a list of DIRITEMs for the files in the current directory, and a list of ! 88: * DIRECTs for the subdirectories (possible un-scanned). ! 89: * ! 90: * dir_nextitem will use the list functions to get the next DIRITEM on the list. ! 91: * When the end of the list is reached, it will use the backpointer back to the ! 92: * DIRECT struct to find the next directory to scan. ! 93: * ! 94: ****************************************************************************/ ! 95: ! 96: #include <windows.h> ! 97: #include <stdlib.h> ! 98: #include <string.h> ! 99: #include <dos.h> ! 100: #include <direct.h> ! 101: ! 102: #include "gutils.h" ! 103: #include "list.h" ! 104: #include "scandir.h" ! 105: #include "windiff.h" ! 106: #include "wdiffrc.h" ! 107: ! 108: /* ! 109: * Hold name and information about a given file (one ITEM in a DIRectory) ! 110: * caller's DIRITEM handle is a pointer to one of these structures ! 111: */ ! 112: struct diritem { ! 113: LPSTR name; /* ptr to filename (final element only) */ ! 114: long size; /* filesize */ ! 115: struct direct FAR * direct; /* containing directory */ ! 116: LPSTR localname; /* name of temp copy of file */ ! 117: BOOL bLocalIsTemp; /* true if localname is tempfile. ! 118: */ ! 119: }; ! 120: ! 121: ! 122: /* DIRECT: Hold state about directory and current position in list of filenames. ! 123: */ ! 124: typedef struct direct { ! 125: LPSTR relname; /* name of dir relative to DIRLIST root */ ! 126: DIRLIST head; /* back ptr (to get fullname) */ ! 127: struct direct FAR * parent; /* parent directory (NULL if above tree root)*/ ! 128: ! 129: BOOL bScanned; /* TRUE if scanned */ ! 130: LIST diritems; /* list of DIRITEMs for files in cur. dir */ ! 131: LIST directs; /* list of DIRECTs for child dirs */ ! 132: ! 133: int pos; /* where are we begin, files, dirs */ ! 134: struct direct FAR * curdir; /* subdir being scanned (ptr to list element)*/ ! 135: } FAR * DIRECT; ! 136: ! 137: /* Values for direct.pos */ ! 138: #define DL_FILES 1 /* reading files from the diritems */ ! 139: #define DL_DIRS 2 /* in the dirs: List_Next on curdir */ ! 140: ! 141: ! 142: /* ! 143: * The DIRLIST handle returned from a build function is in fact ! 144: * a pointer to one of these ! 145: */ ! 146: struct dirlist { ! 147: ! 148: char rootname[256]; /* name of root of tree */ ! 149: BOOL bFile; /* TRUE if root of tree is file, not dir */ ! 150: DIRECT dot; /* dir for '.' - for tree root dir */ ! 151: }; ! 152: ! 153: extern BOOL bAbort; /* from windiff.c (read only here). */ ! 154: ! 155: ! 156: /* ------ memory allocation ---------------------------------------------*/ ! 157: ! 158: /* All memory is allocated from a heap created by the application */ ! 159: extern HANDLE hHeap; ! 160: ! 161: /*-- forward declaration of internal functions ---------------------------*/ ! 162: ! 163: LPSTR dir_finalelem(LPSTR path); ! 164: void dir_cleardirect(DIRECT dir); ! 165: void dir_adddirect(DIRECT dir, LPSTR path); ! 166: void dir_addfile(DIRECT dir, LPSTR path, DWORD size); ! 167: void dir_scan(DIRECT dir, BOOL bRecurse); ! 168: BOOL dir_isvaliddir(LPSTR path); ! 169: BOOL dir_isvalidfile(LPSTR path); ! 170: void dir_fileinit(DIRITEM pfile, DIRECT dir, LPSTR path, long size); ! 171: void dir_dirinit(DIRECT dir, DIRLIST head, DIRECT parent, LPSTR name); ! 172: long dir_getpathsize(LPSTR path); ! 173: DIRITEM dir_findnextfile(DIRLIST dl, DIRECT curdir); ! 174: ! 175: ! 176: ! 177: /*************************************************************************** ! 178: * Function: dir_buildlist ! 179: * ! 180: * Purpose: ! 181: * ! 182: * Build a list of filenames ! 183: * ! 184: * Optionally build the list on demand, in which case we scan the ! 185: * entire directory but don't recurse into subdirs until needed ! 186: * ! 187: */ ! 188: ! 189: DIRLIST ! 190: dir_buildlist(LPSTR path, BOOL bOnDemand) ! 191: { ! 192: DIRLIST dl; ! 193: BOOL bFile; ! 194: ! 195: /* first check if the path is valid */ ! 196: if (dir_isvaliddir(path)) { ! 197: bFile = FALSE; ! 198: } else if (dir_isvalidfile(path)) { ! 199: bFile = TRUE; ! 200: } else { ! 201: /* not valid */ ! 202: return(NULL); ! 203: } ! 204: ! 205: ! 206: /* alloc and init the DIRLIST head */ ! 207: ! 208: dl = (DIRLIST) gmem_get(hHeap, sizeof(struct dirlist)); ! 209: memset(dl, 0, sizeof(struct dirlist)); ! 210: ! 211: /* convert the pathname to an absolute path */ ! 212: ! 213: _fullpath(dl->rootname, path, sizeof(dl->rootname)); ! 214: ! 215: dl->bFile = bFile; ! 216: /* make a '.' directory for the current directory - ! 217: * all files and subdirs will be listed from here ! 218: */ ! 219: dl->dot = (DIRECT) gmem_get(hHeap, sizeof(struct direct)); ! 220: dir_dirinit(dl->dot, dl, NULL, "."); ! 221: ! 222: /* were we given a file or a directory ? */ ! 223: if (bFile) { ! 224: /* its a file. create a single file entry ! 225: * and set the state accordingly ! 226: */ ! 227: dl->dot->bScanned = TRUE; ! 228: ! 229: dir_addfile(dl->dot, dir_finalelem(path), ! 230: dir_getpathsize(path)); ! 231: ! 232: return(dl); ! 233: } ! 234: ! 235: /* scan the root directory and return. if we are asked ! 236: * to scan the whole thing, this will cause a recursive ! 237: * scan all the way down the tree ! 238: */ ! 239: dir_scan(dl->dot, (!bOnDemand) ); ! 240: ! 241: return(dl); ! 242: } /* dir_buildlist */ ! 243: ! 244: /*************************************************************************** ! 245: * Function: dir_delete ! 246: * ! 247: * Purpose: ! 248: * ! 249: * Free up the DIRLIST and all associated memory ! 250: */ ! 251: void ! 252: dir_delete(DIRLIST dl) ! 253: { ! 254: if (dl == NULL) { ! 255: return; ! 256: } ! 257: dir_cleardirect(dl->dot); ! 258: gmem_free(hHeap, (LPSTR) dl->dot, sizeof(struct direct)); ! 259: ! 260: ! 261: gmem_free(hHeap, (LPSTR) dl, sizeof(struct dirlist)); ! 262: } ! 263: ! 264: ! 265: ! 266: /*************************************************************************** ! 267: * Function: dir_isfile ! 268: * ! 269: * Purpose: ! 270: * ! 271: * Was the original build request a file or a directory ? ! 272: */ ! 273: BOOL ! 274: dir_isfile(DIRLIST dl) ! 275: { ! 276: if (dl == NULL) { ! 277: return(FALSE); ! 278: } ! 279: ! 280: return(dl->bFile); ! 281: } ! 282: ! 283: /*************************************************************************** ! 284: * Function: dir_firstitem ! 285: * ! 286: * Purpose: ! 287: * ! 288: * Return the first file in the list, or NULL if no files found. ! 289: * Returns a DIRITEM. This can be used to get filename, size and chcksum. ! 290: * If there are no files in the root, we recurse down until we find a file. ! 291: */ ! 292: DIRITEM ! 293: dir_firstitem(DIRLIST dl) ! 294: { ! 295: if (dl == NULL) { ! 296: return(NULL); ! 297: } ! 298: /* ! 299: * reset the state to indicate that no files have been read yet ! 300: */ ! 301: dl->dot->pos = DL_FILES; ! 302: dl->dot->curdir = NULL; ! 303: ! 304: /* now get the next filename */ ! 305: return(dir_findnextfile(dl, dl->dot)); ! 306: } /* dir_firstitem */ ! 307: ! 308: ! 309: /*************************************************************************** ! 310: * Function:dir_nextitem ! 311: * ! 312: * Purpose: ! 313: * ! 314: * Get the next filename after the one given. ! 315: * ! 316: * The List_Next function can give us the next element on the list of files. ! 317: * If this is null, we need to go back to the DIRECT and find the ! 318: * next list of files to traverse (in the next subdir). ! 319: * ! 320: * After scanning all the subdirs, return to the parent to scan further ! 321: * dirs that are peers of this, if there are any. If we have reached the end of ! 322: * the tree (no more dirs in dl->dot to scan), return NULL. ! 323: * ! 324: * Don't recurse to lower levels unless fDeep is TRUE ! 325: */ ! 326: DIRITEM ! 327: dir_nextitem(DIRLIST dl, DIRITEM cur, BOOL fDeep) ! 328: { ! 329: DIRITEM next; ! 330: ! 331: if ((dl == NULL) || (cur == NULL)) { ! 332: return(NULL); ! 333: } ! 334: if (bAbort) return NULL; /* user requested abort */ ! 335: ! 336: if ( (next = List_Next(cur)) != NULL) { ! 337: /* there was another file on this list */ ! 338: return(next); ! 339: } ! 340: if (!fDeep) return NULL; ! 341: ! 342: /* get the head of the next list of filenames from the directory */ ! 343: cur->direct->pos = DL_DIRS; ! 344: cur->direct->curdir = NULL; ! 345: return(dir_findnextfile(dl, cur->direct)); ! 346: } /* dir_nextitem */ ! 347: ! 348: /*************************************************************************** ! 349: * Function: dir_findnextfile ! 350: * ! 351: * Purpose: ! 352: * ! 353: * Gets the next file in the directory ! 354: */ ! 355: DIRITEM ! 356: dir_findnextfile(DIRLIST dl, DIRECT curdir) ! 357: { ! 358: DIRITEM curfile; ! 359: ! 360: if ((dl == NULL) || (curdir == NULL)) { ! 361: return(NULL); ! 362: } ! 363: ! 364: /* scan the subdir if necessary */ ! 365: if (!curdir->bScanned) { ! 366: dir_scan(curdir, FALSE); ! 367: } ! 368: ! 369: /* have we already read the files in this directory ? */ ! 370: if (curdir->pos == DL_FILES) { ! 371: /* no - return head of file list */ ! 372: curfile = (DIRITEM) List_First(curdir->diritems); ! 373: if (curfile != NULL) { ! 374: return(curfile); ! 375: } ! 376: ! 377: /* no more files - try the subdirs */ ! 378: curdir->pos = DL_DIRS; ! 379: } ! 380: ! 381: /* try the next subdir on the list, if any */ ! 382: /* is this the first or the next */ ! 383: if (curdir->curdir == NULL) { ! 384: curdir->curdir = (DIRECT) List_First(curdir->directs); ! 385: } else { ! 386: curdir->curdir = (DIRECT) List_Next(curdir->curdir); ! 387: } ! 388: /* did we find a subdir ? */ ! 389: if (curdir->curdir == NULL) { ! 390: ! 391: /* no more dirs - go back to parent if there is one */ ! 392: if (curdir->parent == NULL) { ! 393: /* no parent - we have exhausted the tree */ ! 394: return(NULL); ! 395: } ! 396: ! 397: /* reset parent state to indicate this is the current ! 398: * directory - so that next gets the next after this. ! 399: * this ensures that multiple callers of dir_nextitem() ! 400: * to the same tree work. ! 401: */ ! 402: curdir->parent->pos = DL_DIRS; ! 403: curdir->parent->curdir = curdir; ! 404: ! 405: return(dir_findnextfile(dl, curdir->parent)); ! 406: } ! 407: ! 408: /* there is a next directory - set it to the ! 409: * beginning and get the first file from it ! 410: */ ! 411: curdir->curdir->pos = DL_FILES; ! 412: curdir->curdir->curdir = NULL; ! 413: return(dir_findnextfile(dl, curdir->curdir)); ! 414: ! 415: } /* dir_findnextfile */ ! 416: ! 417: ! 418: /*-- pathnames ---- ! 419: * ! 420: * This module supports two types of pathnames, called relative and full. ! 421: * Relative names are relative to the root passed in the initial call ! 422: * to dir_build*, and full names include the tree root. ! 423: * ! 424: * Note that this is a different distinction to relative vs absolute ! 425: * pathnames, since the tree root may still be either relative or absolute. ! 426: * ! 427: * Examples: ! 428: * ! 429: * - if you called dir_buildlist("c:\") ! 430: * getrelname gives: ".\config.sys" ! 431: * getfullname gives: "c:\config.sys" ! 432: * ! 433: * - if you called dir_buildlist(".\geraintd") ! 434: * getrelname gives: ".\source\scandir.h" ! 435: * getfullname gives either ! 436: * ".\geraintd\source\scandir.h" ! 437: * or "c:\geraintd\source\scandir.h" ! 438: * (depending on the implementation). ! 439: * ! 440: * To support this, we maintain the tree root name in the DIRLIST head, and ! 441: * in each directory, the name of that directory relative to tree root. ! 442: * Files just have the filename, so we need to prepend the directory name, ! 443: * and (for getfullname) the tree root name as well ! 444: * ! 445: * We store the directory name with a trailing ! 446: * slash to make concatenation easier ! 447: * ! 448: * ----- ! 449: */ ! 450: ! 451: /*************************************************************************** ! 452: * Function: dir_getrelname ! 453: * ! 454: * Purpose: ! 455: * ! 456: * Return the name of the current file relative to tree root ! 457: */ ! 458: LPSTR ! 459: dir_getrelname(DIRITEM cur) ! 460: { ! 461: LPSTR name; ! 462: int size; ! 463: ! 464: /* check this is a valid item */ ! 465: if (cur == NULL) { ! 466: return(NULL); ! 467: } ! 468: /* remember to include the NULL when sizing */ ! 469: size = lstrlen(cur->direct->relname) + lstrlen(cur->name) + 1; ! 470: name = gmem_get(hHeap, size); ! 471: lstrcpy(name, cur->direct->relname); ! 472: lstrcat(name, cur->name); ! 473: ! 474: return(name); ! 475: } /* dir_getrelname */ ! 476: ! 477: /*************************************************************************** ! 478: * Function: dir_getfullname ! 479: * ! 480: * Purpose: ! 481: * ! 482: * Return the fullname of the file (including the tree root passed in) ! 483: */ ! 484: LPSTR ! 485: dir_getfullname(DIRITEM cur) ! 486: { ! 487: LPSTR name; ! 488: int size; ! 489: LPSTR head; ! 490: ! 491: /* check this is a valid item */ ! 492: if (cur == NULL) { ! 493: return(NULL); ! 494: } ! 495: ! 496: if (cur->direct->head->bFile) { ! 497: return(cur->direct->head->rootname); ! 498: } ! 499: ! 500: /* remember to include the NULL when sizing */ ! 501: size = lstrlen(cur->name) + 1; ! 502: ! 503: size += lstrlen(cur->direct->relname); ! 504: ! 505: /* add on root name */ ! 506: head = cur->direct->head->rootname; ! 507: size += lstrlen(head); ! 508: ! 509: /* root names may not end in a slash. we need to ! 510: * insert one in this case. Also, relnames always begin .\, so ! 511: * we skip the . always, and the .\ if we don't need to ! 512: * append a slash ! 513: * ! 514: */ ! 515: size--; /* omit the '.' */ ! 516: if (head[lstrlen(head) -1] == '\\') { ! 517: size--; /* omit the .\ */ ! 518: } ! 519: ! 520: name = gmem_get(hHeap, size); ! 521: ! 522: lstrcpy(name, cur->direct->head->rootname); ! 523: ! 524: /* add relname and then name, omiting the .\ */ ! 525: ! 526: /* skip . or .\ before relname */ ! 527: if (head[lstrlen(head) -1] == '\\') { ! 528: lstrcat(name, &cur->direct->relname[2]); ! 529: } else { ! 530: lstrcat(name, &cur->direct->relname[1]); ! 531: } ! 532: lstrcat(name, cur->name); ! 533: return(name); ! 534: } /* dir_getfullname */ ! 535: ! 536: ! 537: /*************************************************************************** ! 538: * Function: dir_getroot_list ! 539: * ! 540: * Purpose: ! 541: * ! 542: * Return the name of the tree root given a handle to the DIRLIST. ! 543: */ ! 544: LPSTR ! 545: dir_getroot_list(DIRLIST dl) ! 546: { ! 547: if (dl == NULL) ! 548: return(NULL); ! 549: return(dl->rootname); ! 550: } /* dir_getroot_list */ ! 551: ! 552: /*************************************************************************** ! 553: * Function: dir_getroot_item ! 554: * ! 555: * Purpose: ! 556: * ! 557: * Return the root name of this tree given a handle to a DIRITEM in the ! 558: * list. ! 559: */ ! 560: LPSTR dir_getroot_item(DIRITEM item) ! 561: { ! 562: if (item == NULL) ! 563: return(NULL); ! 564: ! 565: return(dir_getroot_list(item->direct->head)); ! 566: } ! 567: ! 568: ! 569: /*************************************************************************** ! 570: * Function: dir_freerelname ! 571: * ! 572: * Purpose: ! 573: * ! 574: * Free up a relname that we allocated. This interface allows us ! 575: * some flexibility in how we store relative and complete names ! 576: * ! 577: */ ! 578: void ! 579: dir_freerelname(DIRITEM cur, LPSTR name) ! 580: { ! 581: if((cur != NULL) && (name != NULL)) ! 582: gmem_free(hHeap, name, lstrlen(name) +1); ! 583: } /* dir_freerelname */ ! 584: ! 585: /*************************************************************************** ! 586: * Function: dir_freefullname ! 587: * ! 588: * Purpose: ! 589: * ! 590: */ ! 591: void ! 592: dir_freefullname(DIRITEM cur, LPSTR name) ! 593: { ! 594: if (cur->direct->head->bFile) ! 595: return; ! 596: ! 597: if (name != NULL) ! 598: gmem_free(hHeap, name, lstrlen(name) + 1); ! 599: } /* dir_freefullname */ ! 600: ! 601: /*************************************************************************** ! 602: * Function: dir_freeroot_list ! 603: * ! 604: * Purpose: ! 605: * ! 606: * Free up rootname allocated by dir_getroot_list. ! 607: * We just gave a pointer to the rootname, so do nothing. ! 608: */ ! 609: void ! 610: dir_freeroot_list(DIRLIST dl, LPSTR name) ! 611: { ! 612: if ((dl == NULL) || (name == NULL)) { ! 613: return; ! 614: } ! 615: return; ! 616: } /* dir_freeroot_list */ ! 617: ! 618: /*************************************************************************** ! 619: * Function: dir_freeroot_item ! 620: * ! 621: * Purpose: ! 622: * ! 623: * Free up memory alloc-ed by a call to dir_getroot_item. ! 624: */ ! 625: void ! 626: dir_freeroot_item(DIRITEM item, LPSTR name) ! 627: { ! 628: if ((item == NULL) || (name == NULL)) ! 629: return; ! 630: dir_freeroot_list(item->direct->head, name); ! 631: } ! 632: ! 633: /*************************************************************************** ! 634: * Function: dir_getopenname ! 635: * ! 636: * Purpose: ! 637: * ! 638: * Get an open-able name for the file. This will be the same as the fullname. ! 639: */ ! 640: LPSTR ! 641: dir_getopenname(DIRITEM item) ! 642: { ! 643: LPSTR fname; ! 644: ! 645: if (item == NULL) ! 646: return(NULL); ! 647: ! 648: fname = dir_getfullname(item); ! 649: ! 650: return(fname); ! 651: } /* dir_getopenname */ ! 652: ! 653: ! 654: /*************************************************************************** ! 655: * Function: dir_freeopenname ! 656: * ! 657: * Purpose: ! 658: * ! 659: * Free up memory created by a call to dir_getopenname(). This *may* ! 660: * cause the file to be deleted if it was a temporary copy. ! 661: */ ! 662: void ! 663: dir_freeopenname(DIRITEM item, LPSTR openname) ! 664: { ! 665: if ((item == NULL) || (openname == NULL)) ! 666: return; ! 667: ! 668: dir_freefullname(item, openname); ! 669: } /* dir_freeopenname */ ! 670: ! 671: /*************************************************************************** ! 672: * Function: dir_openfile ! 673: * ! 674: * Purpose: ! 675: * ! 676: * Return an open file handle to the file. ! 677: */ ! 678: int ! 679: dir_openfile(DIRITEM item) ! 680: { ! 681: LPSTR fname; ! 682: int fh; ! 683: OFSTRUCT os; ! 684: ! 685: fname = dir_getfullname(item); ! 686: fh = OpenFile(fname, &os, OF_READ|OF_SHARE_DENY_NONE); ! 687: dir_freefullname(item, fname); ! 688: return(fh); ! 689: } /* dir_openfile */ ! 690: ! 691: /*************************************************************************** ! 692: * Function: dir_closefile ! 693: * ! 694: * Purpose: ! 695: * ! 696: * Close a file opened with dir_openfile. ! 697: */ ! 698: void ! 699: dir_closefile(DIRITEM item, int fh) ! 700: { ! 701: _lclose(fh); ! 702: ! 703: } /* dir_closefile */ ! 704: ! 705: ! 706: /*************************************************************************** ! 707: * Function: dir_getfilesize ! 708: * ! 709: * Purpose: ! 710: * ! 711: * Return the file size (set during scanning) ! 712: */ ! 713: long ! 714: dir_getfilesize(DIRITEM cur) ! 715: { ! 716: /* check this is a valid item */ ! 717: if (cur == NULL) ! 718: return(0); ! 719: ! 720: return(cur->size); ! 721: } /* dir_getfilesize */ ! 722: ! 723: ! 724: ! 725: /* ss_endcopy returns a number indicating the number of files copied, ! 726: but we may have some local copies too. We need to count these ! 727: ourselves and add them in ! 728: */ ! 729: ! 730: int nLocalCopies; /* cleared in startcopy, ++d in copy ! 731: ** inspected in endcopy ! 732: */ ! 733: ! 734: /*************************************************************************** ! 735: * Function: dir_startcopy ! 736: * ! 737: * Purpose: ! 738: * ! 739: * Start a bulk copy ! 740: */ ! 741: BOOL dir_startcopy(DIRLIST dl) ! 742: { ! 743: nLocalCopies = 0; ! 744: return(TRUE); ! 745: ! 746: } /* dir_startcopy */ ! 747: /*************************************************************************** ! 748: * Function: dir_endcopy ! 749: * ! 750: */ ! 751: ! 752: int dir_endcopy(DIRLIST dl) ! 753: { ! 754: return(nLocalCopies); ! 755: ! 756: } /* dir_endcopy */ ! 757: ! 758: /*************************************************************************** ! 759: * Function: dir_copy ! 760: * ! 761: * Purpose: ! 762: * ! 763: * Create a copy of the file, in the new root directory. Creates sub-dirs as ! 764: * necessary. ! 765: * ! 766: * Returns TRUE for success and FALSE for failure. ! 767: */ ! 768: BOOL dir_copy(DIRITEM item, LPSTR newroot) ! 769: { ! 770: static char newpath[256]; ! 771: LPSTR relname, fullname; ! 772: LPSTR pstart, pdest, pel; ! 773: BOOL bOK; ! 774: ! 775: BY_HANDLE_FILE_INFORMATION bhfi; ! 776: HANDLE hfile; ! 777: ! 778: /* ! 779: * check that the newroot directory itself exists ! 780: */ ! 781: if ((item == NULL) || !dir_isvaliddir(newroot)) { ! 782: return(FALSE); ! 783: } ! 784: ! 785: /* ! 786: * name of file relative to the tree root ! 787: */ ! 788: relname = dir_getrelname(item); ! 789: ! 790: /* ! 791: * build the new pathname by concatenating the new root and ! 792: * the old relative name. add one path element at a time and ! 793: * ensure that the directory exists, creating it if necessary. ! 794: */ ! 795: lstrcpy(newpath, newroot); ! 796: ! 797: /* add separating slash if not already there */ ! 798: if (newpath[lstrlen(newpath) -1] != '\\') { ! 799: lstrcat(newpath, "\\"); ! 800: } ! 801: ! 802: pstart = relname; ! 803: while ( (pel = strchr(pstart, '\\')) != NULL) { ! 804: ! 805: /* found another element ending in slash. incr past the \\ */ ! 806: pel++; ! 807: ! 808: /* ! 809: * ignore . ! 810: */ ! 811: if (strncmp(pstart, ".\\", 2) != 0) { ! 812: ! 813: pdest = &newpath[lstrlen(newpath)]; ! 814: strncpy(pdest, pstart, pel - pstart); ! 815: pdest[pel - pstart] = '\0'; ! 816: ! 817: /* create subdir if necessary */ ! 818: if (!dir_isvaliddir(newpath)) { ! 819: if (_mkdir(newpath) != 0) { ! 820: return(FALSE); ! 821: } ! 822: } ! 823: } ! 824: ! 825: pstart = pel; ! 826: } ! 827: ! 828: /* ! 829: * there are no more slashes, so pstart points at the final ! 830: * element ! 831: */ ! 832: lstrcat(newpath, pstart); ! 833: ! 834: fullname = dir_getfullname(item); ! 835: ! 836: bOK = CopyFile(fullname, newpath, FALSE); ! 837: ! 838: /* having copied the file, now copy the times, attributes */ ! 839: hfile = CreateFile(fullname, GENERIC_READ, 0, NULL, ! 840: OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 841: bhfi.dwFileAttributes = GetFileAttributes(fullname); ! 842: GetFileTime(hfile, &bhfi.ftCreationTime, ! 843: &bhfi.ftLastAccessTime, &bhfi.ftLastWriteTime); ! 844: CloseHandle(hfile); ! 845: ! 846: hfile = CreateFile(newpath, GENERIC_WRITE, 0, NULL, ! 847: OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ! 848: SetFileTime(hfile, &bhfi.ftCreationTime, ! 849: &bhfi.ftLastAccessTime, ! 850: &bhfi.ftLastWriteTime); ! 851: CloseHandle(hfile); ! 852: SetFileAttributes(newpath, bhfi.dwFileAttributes); ! 853: ! 854: ! 855: if (bOK) ++nLocalCopies; ! 856: ! 857: dir_freerelname(item, relname); ! 858: dir_freefullname(item, fullname); ! 859: ! 860: return(bOK); ! 861: } /* dir_copy */ ! 862: ! 863: ! 864: /*************************************************************************** ! 865: * Function: dir_dirinit ! 866: * ! 867: * Purpose: ! 868: * ! 869: * Fill out a new DIRECT for a subdirectory (pre-allocated). ! 870: * Init files and dirs lists to empty (List_Create). Set the relname ! 871: * of the directory by pre-pending the parent relname if there ! 872: * is a parent, and appending a trailing slash (if there isn't one). ! 873: */ ! 874: void ! 875: dir_dirinit(DIRECT dir, DIRLIST head, DIRECT parent, LPSTR name) ! 876: { ! 877: int size; ! 878: ! 879: dir->head = head; ! 880: dir->parent = parent; ! 881: ! 882: /* add on one for the null and one for the trailing slash */ ! 883: size = lstrlen(name) + 2; ! 884: if (parent != NULL) { ! 885: size += lstrlen(parent->relname); ! 886: } ! 887: ! 888: /* build the relname from the parent and the current name ! 889: * with a terminating slash ! 890: */ ! 891: dir->relname = gmem_get(hHeap, size); ! 892: if (parent != NULL) { ! 893: lstrcpy(dir->relname, parent->relname); ! 894: } else{ ! 895: dir->relname[0] = '\0'; ! 896: } ! 897: ! 898: lstrcat(dir->relname, name); ! 899: ! 900: if (dir->relname[lstrlen(dir->relname) -1] != '\\') { ! 901: lstrcat(dir->relname, "\\"); ! 902: } ! 903: ! 904: /* force name to lowercase */ ! 905: AnsiLowerBuff(dir->relname, lstrlen(dir->relname)); ! 906: ! 907: dir->diritems = List_Create(); ! 908: dir->directs = List_Create(); ! 909: dir->bScanned = FALSE; ! 910: dir->pos = DL_FILES; ! 911: ! 912: } /* dir_dirinit */ ! 913: ! 914: ! 915: /*************************************************************************** ! 916: * Function: dir_fileinit ! 917: * ! 918: * Purpose: ! 919: * ! 920: * Initialise the contents of an (allocated) DIRITEM struct. ! 921: */ ! 922: void ! 923: dir_fileinit(DIRITEM pfile, DIRECT dir, LPSTR path, long size) ! 924: { ! 925: ! 926: pfile->name = gmem_get(hHeap, lstrlen(path) + 1); ! 927: lstrcpy(pfile->name, path); ! 928: ! 929: /* force name to lower case */ ! 930: AnsiLowerBuff(pfile->name, lstrlen(path)); ! 931: ! 932: pfile->direct = dir; ! 933: pfile->size = size; ! 934: ! 935: pfile->localname = NULL; ! 936: ! 937: } /* dir_fileinit */ ! 938: ! 939: /*************************************************************************** ! 940: * Function: dir_isfilevalid ! 941: * ! 942: * Purpose: ! 943: * ! 944: * Is this a valid file or not ! 945: */ ! 946: BOOL ! 947: dir_isvalidfile(LPSTR path) ! 948: { ! 949: DWORD dwAttrib; ! 950: ! 951: dwAttrib = GetFileAttributes(path); ! 952: if (dwAttrib == -1) { ! 953: return(FALSE); ! 954: } ! 955: if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) { ! 956: return(FALSE); ! 957: } ! 958: return(TRUE); ! 959: } /* dir_isvalidfile */ ! 960: ! 961: /*************************************************************************** ! 962: * Function: dir_isvaliddir ! 963: * ! 964: * Purpose: ! 965: * ! 966: * Is this a valid directory ? ! 967: */ ! 968: BOOL ! 969: dir_isvaliddir(LPSTR path) ! 970: { ! 971: DWORD dwAttrib; ! 972: ! 973: dwAttrib = GetFileAttributes(path); ! 974: if (dwAttrib == -1) { ! 975: return(FALSE); ! 976: } ! 977: if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) { ! 978: return(TRUE); ! 979: } ! 980: return(FALSE); ! 981: } /* dir_isvaliddir */ ! 982: ! 983: /*************************************************************************** ! 984: * Function: dir_scan ! 985: * ! 986: * Purpose: ! 987: * ! 988: * Scan the directory given. Add all files to the list ! 989: * in alphabetic order, and add all directories in alphabetic ! 990: * order to the list of child DIRITEMs. If bRecurse is true, go on to ! 991: * recursive call dir_scan for each of the child DIRITEMs ! 992: */ ! 993: void ! 994: dir_scan(DIRECT dir, BOOL bRecurse) ! 995: { ! 996: PSTR path; ! 997: int size; ! 998: DIRECT child; ! 999: BOOL bMore; ! 1000: long filesize; ! 1001: BOOL bIsDir; ! 1002: LPSTR name; ! 1003: ! 1004: HANDLE hFind; ! 1005: WIN32_FIND_DATA finddata; ! 1006: ! 1007: char debugmsg[200]; ! 1008: wsprintf(debugmsg, "scandir: %s %s\n", ! 1009: dir->relname, bRecurse?"recursive":"non-recursive" ! 1010: ); ! 1011: ! 1012: /* make the complete search string including *.* */ ! 1013: size = lstrlen(dir->head->rootname); ! 1014: size += lstrlen(dir->relname); ! 1015: ! 1016: /* add on one null and *.* */ ! 1017: size += 4; ! 1018: ! 1019: path = LocalLock(LocalAlloc(LHND, size)); ! 1020: ! 1021: lstrcpy(path, dir->head->rootname); ! 1022: ! 1023: /* omit the . at the beginning of the relname, and the ! 1024: * .\ if there is a trailing \ on the rootname ! 1025: */ ! 1026: if (path[strlen(path)-1] == '\\') { ! 1027: lstrcat(path, &dir->relname[2]); ! 1028: } else { ! 1029: lstrcat(path, &dir->relname[1]); ! 1030: } ! 1031: lstrcat(path, "*.*"); ! 1032: ! 1033: /* read all entries in the directory */ ! 1034: hFind = FindFirstFile(path, &finddata); ! 1035: bMore = (hFind != (HANDLE) -1); ! 1036: LocalUnlock(LocalHandle ( (PSTR) path)); ! 1037: LocalFree(LocalHandle ( (PSTR) path)); ! 1038: ! 1039: while (bMore) { ! 1040: ! 1041: bIsDir = (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); ! 1042: name = (LPSTR) &finddata.cFileName; ! 1043: filesize = finddata.nFileSizeLow; ! 1044: if (!bIsDir) { ! 1045: ! 1046: dir_addfile(dir, name, filesize); ! 1047: ! 1048: } else if ( (lstrcmp(name, ".") != 0) && ! 1049: ( lstrcmp(name, "..") != 0) ) { ! 1050: ! 1051: dir_adddirect(dir, name); ! 1052: } ! 1053: ! 1054: bMore = FindNextFile(hFind, &finddata); ! 1055: } ! 1056: ! 1057: FindClose(hFind); ! 1058: ! 1059: dir->bScanned = TRUE; ! 1060: dir->pos = DL_FILES; ! 1061: ! 1062: if (bRecurse) { ! 1063: List_TRAVERSE(dir->directs, child) { ! 1064: dir_scan(child, TRUE); ! 1065: } ! 1066: } ! 1067: ! 1068: } /* dir_scan */ ! 1069: ! 1070: ! 1071: /*************************************************************************** ! 1072: * Function: dir_addfile ! 1073: * ! 1074: * Purpose: ! 1075: * ! 1076: * Add the file 'path' to the list of files in dir, in order. ! 1077: */ ! 1078: void ! 1079: dir_addfile(DIRECT dir, LPSTR path, DWORD size) ! 1080: { ! 1081: DIRITEM pfile; ! 1082: ! 1083: AnsiLowerBuff(path, lstrlen(path)); // needless? ! 1084: ! 1085: List_TRAVERSE(dir->diritems, pfile) { ! 1086: /////if (lstrcmpi(pfile->name, path) > 0) { ! 1087: if (utils_CompPath(pfile->name, path) > 0) { ! 1088: ! 1089: /* goes before this one */ ! 1090: pfile = List_NewBefore(dir->diritems, pfile, sizeof(struct diritem)); ! 1091: dir_fileinit(pfile, dir, path, size); ! 1092: return; ! 1093: } ! 1094: } ! 1095: /* goes at end */ ! 1096: pfile = List_NewLast(dir->diritems, sizeof(struct diritem)); ! 1097: dir_fileinit(pfile, dir, path, size); ! 1098: } /* dir_addfile */ ! 1099: ! 1100: ! 1101: /*************************************************************************** ! 1102: * Function: dir_addirect ! 1103: * ! 1104: * Purpose: ! 1105: * ! 1106: * Add a new directory in alphabetic order on ! 1107: * the list dir->directs ! 1108: * ! 1109: */ ! 1110: void ! 1111: dir_adddirect(DIRECT dir, LPSTR path) ! 1112: { ! 1113: DIRECT child; ! 1114: LPSTR finalel; ! 1115: char achTempName[256]; ! 1116: ! 1117: AnsiLowerBuff(path, lstrlen(path)); ! 1118: List_TRAVERSE(dir->directs, child) { ! 1119: ! 1120: int cmpval; ! 1121: ! 1122: /* we need to compare the child name with the new name. ! 1123: * the child name is a relname with a trailing ! 1124: * slash - so compare only the name up to but ! 1125: * not including the final slash. ! 1126: */ ! 1127: finalel = dir_finalelem(child->relname); ! 1128: ! 1129: /* ! 1130: * we cannot use strnicmp since this uses a different ! 1131: * collating sequence to lstrcmpi. So copy the portion ! 1132: * we are interested in to a null-term. buffer. ! 1133: */ ! 1134: strncpy(achTempName, finalel, lstrlen(finalel)-1); ! 1135: achTempName[lstrlen(finalel)-1] = '\0'; ! 1136: ! 1137: cmpval = utils_CompPath(achTempName, path); ! 1138: ! 1139: if (cmpval > 0) { ! 1140: ! 1141: /* goes before this one */ ! 1142: child = List_NewBefore(dir->directs, child, sizeof(struct direct)); ! 1143: dir_dirinit(child, dir->head, dir, path); ! 1144: return; ! 1145: } ! 1146: } ! 1147: /* goes at end */ ! 1148: child = List_NewLast(dir->directs, sizeof(struct direct)); ! 1149: dir_dirinit(child, dir->head, dir, path); ! 1150: } /* dir_adddirect */ ! 1151: ! 1152: ! 1153: /*************************************************************************** ! 1154: * Function: dir_cleardirect ! 1155: * ! 1156: * Purpose: ! 1157: * ! 1158: * Free all memory associated with a DIRECT (including freeing ! 1159: * child lists). Don't de-alloc the direct itself (allocated on a list) ! 1160: */ ! 1161: void ! 1162: dir_cleardirect(DIRECT dir) ! 1163: { ! 1164: DIRITEM pfile; ! 1165: DIRECT child; ! 1166: ! 1167: /* clear contents of files list */ ! 1168: List_TRAVERSE(dir->diritems, pfile) { ! 1169: gmem_free(hHeap, pfile->name, lstrlen(pfile->name)); ! 1170: if ((pfile->localname) && (pfile->bLocalIsTemp)) { ! 1171: ! 1172: /* ! 1173: * the copy will have copied the attributes, ! 1174: * including read-only. We should unset this bit ! 1175: * so we can delete the temp file. ! 1176: */ ! 1177: SetFileAttributes(pfile->localname, ! 1178: GetFileAttributes(pfile->localname) ! 1179: & ~FILE_ATTRIBUTE_READONLY); ! 1180: DeleteFile(pfile->localname); ! 1181: gmem_free(hHeap, pfile->localname, 256); ! 1182: pfile->localname = NULL; ! 1183: } ! 1184: ! 1185: } ! 1186: List_Destroy(&dir->diritems); ! 1187: ! 1188: /* clear contents of dirs list (recursively) */ ! 1189: List_TRAVERSE(dir->directs, child) { ! 1190: dir_cleardirect(child); ! 1191: } ! 1192: List_Destroy(&dir->directs); ! 1193: ! 1194: gmem_free(hHeap, dir->relname, lstrlen(dir->relname) + 1); ! 1195: ! 1196: } /* dir_cleardirect */ ! 1197: ! 1198: /*************************************************************************** ! 1199: * Function: dir_finalelem ! 1200: * ! 1201: * Purpose: ! 1202: * ! 1203: * Return a pointer to the final element in a path. Note that ! 1204: * we may be passed relnames with a trailing final slash - ignore this ! 1205: * and return the element before that final slash. ! 1206: */ ! 1207: LPSTR ! 1208: dir_finalelem(LPSTR path) ! 1209: { ! 1210: LPSTR chp; ! 1211: int size; ! 1212: ! 1213: /* is the final character a slash ? */ ! 1214: size = lstrlen(path) - 1; ! 1215: if (path[size] == '\\') { ! 1216: /* find the slash before this */ ! 1217: for (size-- ; size > 0; size--) { ! 1218: if (path[size] == '\\') { ! 1219: /* skip the slash itself */ ! 1220: size++; ! 1221: break; ! 1222: } ! 1223: } ! 1224: return(&path[size]); ! 1225: } ! 1226: /* look for final slash */ ! 1227: chp = strrchr(path, '\\'); ! 1228: if (chp != NULL) { ! 1229: return(chp+1); ! 1230: } ! 1231: ! 1232: /* no slash - is there a drive letter ? */ ! 1233: chp = strrchr(path, ':'); ! 1234: if (chp != NULL) { ! 1235: return(chp+1); ! 1236: } ! 1237: ! 1238: /* this is a final-element anyway */ ! 1239: return(path); ! 1240: ! 1241: } /* dir_finalelem */ ! 1242: ! 1243: /*************************************************************************** ! 1244: * Function: dir_getpathsize ! 1245: * ! 1246: * Purpose: ! 1247: * ! 1248: * Find the size of a file given a pathname to it ! 1249: */ ! 1250: long ! 1251: dir_getpathsize(LPSTR path) ! 1252: { ! 1253: int fh; ! 1254: OFSTRUCT os; ! 1255: long size; ! 1256: fh = OpenFile(path, &os, OF_READ|OF_SHARE_DENY_NONE); ! 1257: if (fh == -1) { ! 1258: return(0); ! 1259: } ! 1260: ! 1261: size = GetFileSize( (HANDLE) fh, NULL); ! 1262: _lclose(fh); ! 1263: return(size); ! 1264: } /* dir_getpathsize */ ! 1265: ! 1266:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.