|
|
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.