/************************************************************************ * Compdir: compare directories * ************************************************************************/ #ifdef COMPILE_FOR_DOS #include #include #define _CRTAPI1 #define IF_GET_ATTR_FAILS(FileName, Attributes) if (GET_ATTRIBUTES(FileName, Attributes) != 0) #define SET_ATTRIBUTES(FileName, Attributes) _dos_setfileattr(FileName, Attributes) #define FIND_FIRST(String, Buff) _dos_findfirst(String,_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR, &Buff) #define FIND_NEXT(handle, Buff) _dos_findnext(&Buff) #define FindClose(bogus) #define BOOLEAN BOOL #define MAX_PATH _MAX_PATH #else // COMPILE_FOR_NT #define IF_GET_ATTR_FAILS(FileName, Attributes) GET_ATTRIBUTES(FileName, Attributes); if (Attributes == GetFileAttributeError) #define SET_ATTRIBUTES(FileName, Attributes) !SetFileAttributes(FileName, Attributes) #define FIND_FIRST(String, Buff) FindFirstFile(String, &Buff) #define FIND_NEXT(handle, Buff) !FindNextFile(handle, &Buff) #endif #include "compdir.h" #define NONREADONLYSYSTEMHIDDEN (~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) char *MatchList[MAX_PATH]; // used in ParseArgs int MatchListLength = 0; // used in ParseArgs char *ExcludeList[MAX_PATH*20]; // used in ParseArgs int ExcludeListLength = 0; // used in ParseArgs DWORD Granularity = 0; // used in ParseArgs // // Flags passed to COMPDIR // BOOL fBreakLinks = FALSE; BOOL fCheckAttribs = FALSE; BOOL fCheckBits = FALSE; BOOL fChecking = FALSE; BOOL fCheckSize = FALSE; BOOL fCheckTime = FALSE; BOOL fCreateNew = FALSE; BOOL fCreateLink = FALSE; BOOL fDoNotDelete = FALSE; BOOL fDoNotRecurse = FALSE; BOOL fExclude = FALSE; BOOL fExecute = FALSE; BOOL fMatching = FALSE; BOOL fScript = FALSE; BOOL fVerbose = FALSE; void _CRTAPI1 main(int argc, char **argv) { ATTRIBUTE_TYPE Attributes1, Attributes2; char *Path1, *Path2; Attributes1 = GetFileAttributeError; Attributes2 = GetFileAttributeError; ParseArgs(argc, argv); // Check argument validity. // // Check existence of first path. // IF_GET_ATTR_FAILS(argv[argc - 2], Attributes1) { fprintf(stderr, "Could not find %s (error = %d)\n", argv[argc - 2], GetLastError()); exit(1); } IF_GET_ATTR_FAILS(argv[argc - 1], Attributes2) { if (!fCreateNew) { fprintf(stderr, "Could not find %s (error = %d)\n", argv[argc - 1], GetLastError()); exit(1); } else Attributes2 = Attributes1; } // // If second directory is a drive letter append path of first directory // to it // if ((strlen(argv[argc-1]) == 2) && (*(argv[argc-1] + 1) == ':') ) { if ((Path2 = _strlwr(_fullpath( NULL, argv[argc-2], 0))) == NULL) Path2 = argv[argc-1]; else { Path2[0] = *(argv[argc-1]); IF_GET_ATTR_FAILS(Path2, Attributes2) { if (!fCreateNew) { fprintf(stderr, "Could not find %s (error = %d)\n", Path2, GetLastError()); exit(1); } else Attributes2 = Attributes1; } } } else if ((Path2 = _strlwr(_fullpath( NULL, argv[argc-1], 0))) == NULL) Path2 = argv[argc-1]; if ((Path1 = _strlwr(_fullpath( NULL, argv[argc-2], 0))) == NULL) { Path1 = argv[argc-2]; } if (fVerbose) { fprintf( stdout, "Compare criterion: existence" ); if (fCheckSize) fprintf( stdout, ", size" ); if (fCheckTime) fprintf( stdout, ", date/time" ); if (fCheckBits) fprintf( stdout, ", contents" ); fprintf( stdout, "\n" ); fprintf( stdout, "Path1: %s\n", Path1); fprintf( stdout, "Path2: %s\n", Path2); } if (Attributes1 & FILE_ATTRIBUTE_DIRECTORY) CompDir(Path1, Path2, TRUE); else CompDir(Path1, Path2, FALSE); free(Path1); free(Path2); } // main #ifndef COMPILE_FOR_DOS BOOL BinaryCompare(char *file1, char *file2) { HANDLE hFile1, hFile2; HANDLE hMappedFile1, hMappedFile2; LPVOID MappedAddr1, MappedAddr2; if (( hFile1 = CreateFile(file1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == (HANDLE)-1 ) { fprintf( stderr, "Unable to open %s, error code %d\n", file1, GetLastError() ); if (hFile1 != INVALID_HANDLE_VALUE) CloseHandle( hFile1 ); return FALSE; } if (( hFile2 = CreateFile(file2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == (HANDLE)-1 ) { fprintf( stderr, "Unable to open %s, error code %d\n", file2, GetLastError() ); if (hFile2 != INVALID_HANDLE_VALUE) CloseHandle( hFile2 ); return FALSE; } hMappedFile1 = CreateFileMapping( hFile1, NULL, PAGE_READONLY, 0, 0, NULL ); if (hMappedFile1 == NULL) { fprintf( stderr, "Unable to map %s, error code %d\n", file1, GetLastError() ); CloseHandle(hFile1); return FALSE; } hMappedFile2 = CreateFileMapping( hFile2, NULL, PAGE_READONLY, 0, 0, NULL ); if (hMappedFile2 == NULL) { fprintf( stderr, "Unable to map %s, error code %d\n", file2, GetLastError() ); CloseHandle(hFile2); return FALSE; } MappedAddr1 = MapViewOfFile( hMappedFile1, FILE_MAP_READ, 0, 0, 0 ); if (MappedAddr1 == NULL) { fprintf( stderr, "Unable to get mapped view of %s, error code %d\n", file1, GetLastError() ); CloseHandle( hFile1 ); return FALSE; } MappedAddr2 = MapViewOfFile( hMappedFile2, FILE_MAP_READ, 0, 0, 0 ); if (MappedAddr2 == NULL) { fprintf( stderr, "Unable to get mapped view of %s, error code %d\n", file1, GetLastError() ); UnmapViewOfFile( MappedAddr1 ); CloseHandle( hFile1 ); return FALSE; } CloseHandle(hMappedFile1); CloseHandle(hMappedFile2); if (memcmp( MappedAddr1, MappedAddr2, GetFileSize(hFile1, NULL)) == 0) { UnmapViewOfFile( MappedAddr1 ); UnmapViewOfFile( MappedAddr2 ); CloseHandle( hFile1 ); CloseHandle( hFile2 ); return TRUE; } else { UnmapViewOfFile( MappedAddr1 ); UnmapViewOfFile( MappedAddr2 ); CloseHandle( hFile1 ); CloseHandle( hFile2 ); return FALSE; } } #endif // // CompDir turns Path1 and Path2 into: // // AddList - Files that exist in Path1 but not in Path2 // // DelList - Files that do not exist in Path1 but exist in Path2 // // DifList - Files that are different between Path1 and Path2 based // on criteria provided by flags passed to CompDir // // It then passes these lists to CompLists and processes the result. // void CompDir(char *Path1, char *Path2, BOOL Directories) { LinkedFileList AddList, DelList, DifList; BOOL SameNames, AppendPath; AddList = NULL; // DelList = NULL; // Start with empty lists DifList = NULL; // SameNames = TRUE; AppendPath = TRUE; // // If comparing two files and not two directories the files can have // different names and paths are complete (they don't need to append // the files names). // if (!Directories) { SameNames = FALSE; AppendPath = FALSE; } CreateFileList(&AddList, Path1); CreateFileList(&DelList, Path2); CompLists(&AddList, &DelList, &DifList, Path1, Path2, SameNames, AppendPath); ProcessLists(AddList, DelList, DifList, Path1, Path2, AppendPath); FreeList(&DifList); FreeList(&DelList); FreeList(&AddList); } // CompDir BOOL CompFiles(LinkedFileList File1, LinkedFileList File2, char *Path1, char *Path2) { #ifndef COMPILE_FOR_DOS DWORD High1, High2, Low1, Low2; // Used in comparing times #endif BOOL Differ = FALSE; // // Check if same name is a directory under Path1 // and a file under Path2 or vice-versa // if (((*File1).Attributes & FILE_ATTRIBUTE_DIRECTORY) || ((*File2).Attributes & FILE_ATTRIBUTE_DIRECTORY)) { if (((*File1).Attributes & FILE_ATTRIBUTE_DIRECTORY) && ((*File2).Attributes & FILE_ATTRIBUTE_DIRECTORY)) CompDir(Path1, Path2, TRUE); else { if(!((*File1).Attributes & FILE_ATTRIBUTE_DIRECTORY)) strcat((*File1).Flag, "@"); else strcat((*File2).Flag, "@"); Differ = TRUE; } } else { if (fCheckTime) { if (Granularity) { #ifdef COMPILE_FOR_DOS if ( (((*File1).Time > (*File2).Time) ? (unsigned)((*File1).Time - (*File2).Time) : (unsigned)((*File2).Time - (*File1).Time)) > (unsigned)(Granularity)) { #else // // Bit manipulation to deal with large integers. // High1 = (*File1).Time.dwHighDateTime>>23; High2 = (*File2).Time.dwHighDateTime>>23; if (High1 == High2) { Low1 = ((*File1).Time.dwHighDateTime<<9) | ((*File1).Time.dwLowDateTime>>23); Low2 = ((*File2).Time.dwHighDateTime<<9) | ((*File2).Time.dwLowDateTime>>23); if ( ((Low1 > Low2) ? (Low1 - Low2) : (Low2 - Low1)) > Granularity) { #endif strcat((*File1).Flag, "T"); Differ = TRUE; } #ifdef COMPILE_FOR_DOS } else if (((*File1).Time) != (*File2).Time) { #else } else Differ = TRUE; } else if (CompareFileTime(&((*File1).Time), &((*File2).Time)) != 0) { #endif strcat((*File1).Flag, "T"); Differ = TRUE; } } if (fCheckSize && (((*File1).SizeLow != (*File2).SizeLow) || ((*File1).SizeHigh != (*File2).SizeHigh))) { strcat((*File1).Flag, "S"); Differ = TRUE; } if (fCheckAttribs) { if ((*File1).Attributes != (*File2).Attributes) { strcat((*File1).Flag, "A"); Differ = TRUE; } } if (fCheckBits) { if (((*File1).SizeLow != (*File2).SizeLow) || ((*File1).SizeHigh != (*File2).SizeHigh) || (((*File1).SizeLow != 0 || (*File1).SizeHigh != 0) && (!BinaryCompare(Path1, Path2)))) { strcat((*File1).Flag, "B"); Differ = TRUE; } } } return Differ; } // CompFiles // // CompLists Does the dirty work for CompDir // void CompLists(LinkedFileList *AddList, LinkedFileList *DelList, LinkedFileList *DifList, char *Path1, char *Path2, BOOL SameNames, BOOL AppendPath) { LinkedFileList *TmpAdd, *TmpDel, TmpFront; char *PathWithSlash1, *FullPath1, *PathWithSlash2, *FullPath2; if ((DelList == NULL) || (*DelList == NULL) || (AddList == NULL) || (*AddList == NULL)) return; TmpAdd = AddList; // pointer to keep track of position in addlist (Path1[strlen(Path1) - 1] == '\\') ? (PathWithSlash1 = _strdup(Path1)) : (PathWithSlash1 = MyStrCat(Path1, "\\")); (Path2[strlen(Path2) - 1] == '\\') ? (PathWithSlash2 = _strdup(Path2)) : (PathWithSlash2 = MyStrCat(Path2, "\\")); do { if (SameNames) TmpDel = FindInList((**TmpAdd).Name, DelList); else TmpDel = DelList; if (TmpDel != NULL) { // // Create Full Path Strings // if (AppendPath) FullPath1 = MyStrCat(PathWithSlash1, (**TmpAdd).Name); else FullPath1 = _strdup(Path1); if (AppendPath) FullPath2 = MyStrCat(PathWithSlash2, (**TmpDel).Name); else FullPath2 = _strdup(Path2); if (CompFiles(*TmpAdd, *TmpDel, FullPath1, FullPath2)) { // // Combine Both Nodes together so they // can be printed out together // AddToList(*TmpDel, &(**TmpAdd).DiffNode); AddToList(*TmpAdd, DifList); RemoveFront(TmpAdd); RemoveFront(TmpDel); } else { TmpFront = RemoveFront(TmpDel); FreeList(&TmpFront); TmpFront = RemoveFront(TmpAdd); FreeList(&TmpFront); } free(FullPath1); free(FullPath2); } // if (*TmpDel != NULL) else TmpAdd = &(**TmpAdd).Next; } while (*TmpAdd != NULL); free(PathWithSlash1); free(PathWithSlash2); } // CompLists // // CopyNode walks the source node and its children (recursively) // and creats the appropriate parts on the destination node // void CopyNode (char *Destination, LinkedFileList Source, char *FullPathSrc) { BOOL pend, CanDetectFreeSpace = TRUE; int i; DWORD sizeround; DWORD BytesPerCluster; ATTRIBUTE_TYPE Attributes; #ifdef COMPILE_FOR_DOS DWORD freespac; struct diskfree_t diskfree; if( _dos_getdiskfree( (toupper(*Destination) - 'A' + 1), &diskfree ) != 0) { CanDetectFreeSpace = FALSE; } else freespac = ( (DWORD)diskfree.bytes_per_sector * (DWORD)diskfree.sectors_per_cluster * (DWORD)diskfree.avail_clusters ); BytesPerCluster = diskfree.sectors_per_cluster * diskfree.bytes_per_sector; #else int LastErrorGot; __int64 freespac; char root[5] = {*Destination,':','\\','\0'}; DWORD cSecsPerClus, cBytesPerSec, cFreeClus, cTotalClus; if( !GetDiskFreeSpace( root, &cSecsPerClus, &cBytesPerSec, &cFreeClus, &cTotalClus ) ) { CanDetectFreeSpace = FALSE; } else freespac = ( (__int64)cBytesPerSec * (__int64)cSecsPerClus * (__int64)cFreeClus ); BytesPerCluster = cSecsPerClus * cBytesPerSec; #endif if ((*Source).Attributes & FILE_ATTRIBUTE_DIRECTORY) { // // Skip the . and .. entries; they're useless // if (!strcmp ((*Source).Name, ".") || !strcmp ((*Source).Name, "..")) return; sizeround = 256; sizeround += BytesPerCluster - 1; sizeround /= BytesPerCluster; sizeround *= BytesPerCluster; if (CanDetectFreeSpace) { if (freespac < sizeround) { fprintf (stderr, "not enough space\n"); return; } } fprintf (stdout, "Making %s\t", Destination); i = _mkdir (Destination); fprintf (stdout, "%s\n", i != -1 ? "[OK]" : ""); if (i == -1) fprintf (stderr, "Unable to mkdir %s\n", Destination); CompDir(FullPathSrc, Destination, TRUE); } else { sizeround = (*Source).SizeLow; sizeround += BytesPerCluster - 1; sizeround /= BytesPerCluster; sizeround *= BytesPerCluster; if (CanDetectFreeSpace) { if (freespac < sizeround) { fprintf (stderr, "not enough space\n"); return; } } fprintf (stdout, "%s => %s\t", FullPathSrc, Destination); GET_ATTRIBUTES(Destination, Attributes); SET_ATTRIBUTES(Destination, Attributes & NONREADONLYSYSTEMHIDDEN ); #ifndef COMPILE_FOR_DOS if (!fCreateLink) if (!fBreakLinks) pend = CopyFile (FullPathSrc, Destination, FALSE); else if (NumberOfLinks(Destination) > 1) { _unlink(Destination); pend = CopyFile (FullPathSrc, Destination, FALSE); } else pend = CopyFile (FullPathSrc, Destination, FALSE); else pend = MakeLink (FullPathSrc, Destination); if (!pend) { LastErrorGot = GetLastError (); if ((fCreateLink) && (LastErrorGot == 1)) fprintf(stderr, "Can only make links on NTFS and OFS"); else if (fCreateLink) fprintf(stderr, "(error = %d)", LastErrorGot); else fprintf(stderr, "Copy Error (error = %d)", LastErrorGot); } #else pend = FCopy (FullPathSrc, Destination); #endif fprintf (stdout, "%s\n", pend == TRUE ? "[OK]" : ""); // // Copy attributes from Source to Destination // GET_ATTRIBUTES(FullPathSrc, Attributes); SET_ATTRIBUTES(Destination, Attributes); } } // CopyNode // // CreateFileList walks down list adding files as they are found // void CreateFileList(LinkedFileList *List, char *Path) { LinkedFileList Node; char *String; ATTRIBUTE_TYPE Attributes; #ifdef COMPILE_FOR_DOS int handle; struct find_t Buff; #else HANDLE handle; WIN32_FIND_DATA Buff; #endif IF_GET_ATTR_FAILS(Path, Attributes) return; if (Attributes & FILE_ATTRIBUTE_DIRECTORY) { (Path[strlen(Path) - 1] != '\\') ? (String = MyStrCat(Path,"\\*.*")) : (String = MyStrCat(Path,"*.*")); } else String = _strdup(Path); handle = FIND_FIRST(String, Buff); free(String); if (handle != INVALID_HANDLE_VALUE) { // // Need to find the '.' or '..' directories and get them out of the way // do { if ((strcmp(Buff.cFileName, ".") != 0) && (strcmp(Buff.cFileName, "..") != 0) ) { // // If extensions are defined we match them here // if (MatchElements(Buff.cFileName, Path)) { if ((!fDoNotRecurse) || (!(Buff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) ){ CreateNode(&Node, &Buff); AddToList(Node, List); } } } } while (FIND_NEXT(handle, Buff) == 0); } // (handle != INVALID_HANDLE_VALUE) FindClose(handle); } // CreateFileList void DelNode (char *Path) { char *String, *String1; ATTRIBUTE_TYPE Attributes; #ifdef COMPILE_FOR_DOS int handle; struct find_t Buff; #else HANDLE handle; WIN32_FIND_DATA Buff; #endif IF_GET_ATTR_FAILS(Path, Attributes) return; if (Attributes & FILE_ATTRIBUTE_DIRECTORY) { (Path[strlen(Path) - 1] != '\\') ? (String = MyStrCat(Path,"\\*.*")) : (String = MyStrCat(Path,"*.*")); handle = FIND_FIRST(String, Buff); if (handle == INVALID_HANDLE_VALUE) { fprintf(stderr, "%s is inaccesible\n", Path); return; } free(String); do { // // Need to find the '.' or '..' directories and get them out of the way // if ((strcmp(Buff.cFileName, ".") != 0) && (strcmp(Buff.cFileName, "..") != 0) ) { // // if directory is read-only, make it writable // if (Attributes & FILE_ATTRIBUTE_READONLY) if(SET_ATTRIBUTES(Path, Attributes & ~FILE_ATTRIBUTE_READONLY) != 0) { break; } String1 = MyStrCat(Path ,"\\"); String = MyStrCat(String1, Buff.cFileName); DelNode (String); free (String); free (String1); } } while (FIND_NEXT(handle, Buff) == 0); FindClose(handle); _rmdir (Path); } else { // // if file is read-only, make it writable // if (Attributes & FILE_ATTRIBUTE_READONLY) if(SET_ATTRIBUTES(Path, Attributes & ~FILE_ATTRIBUTE_READONLY) != 0) { return; } _unlink (Path); } } // DelNode BOOL IsFlag(char *argv) { char String[MAX_PATH]; char *String1, *String2; char *TmpArg; char *ExcludeFile; FILE *FileHandle; if ((*argv == '/') || (*argv == '-')) { fMatching = FALSE; // If there's a new flag then that's the fExclude = FALSE; // end of the match/exclude list if (strchr(argv, '?')) Usage(); TmpArg = _strlwr(argv); while (*++TmpArg != '\0') { switch (*TmpArg) { case 'a' : fCheckAttribs = TRUE; fChecking = TRUE; break; case 'b' : fCheckBits = TRUE; fChecking = TRUE; break; case 'c' : fScript = TRUE; break; case 'd' : fDoNotDelete = TRUE; break; case 'e' : fExecute = TRUE; break; case 'k' : fBreakLinks = TRUE; break; case 'l' : fCreateLink = TRUE; break; case 'm' : fMatching = TRUE; break; case 'n' : fCreateNew = TRUE; break; case 'r' : fDoNotRecurse = TRUE; break; case 's' : fCheckSize = TRUE; fChecking = TRUE; break; case 't' : // // Get Granularity parameter // if ((*(TmpArg + 1) == ':') && (*(TmpArg + 2) != '\0') ) { sscanf((TmpArg + 2), "%d", &Granularity); #ifndef COMPILE_FOR_DOS Granularity = Granularity*78125/65536; // Conversion to seconds ^^^^^^^ // 10^7/2^23 #endif while isdigit(*(++TmpArg + 1)) {} } fCheckTime = TRUE; break; case 'v' : fVerbose = TRUE; break; case 'x' : if ((*(TmpArg + 1) == ':') && (*(TmpArg + 2) != '\0') ) { (ExcludeFile = TmpArg + 2); while isgraph(*(++TmpArg + 1)) {} if ((FileHandle = fopen (ExcludeFile, "r")) == NULL) { fprintf (stderr, "cannot open %s\n", ExcludeFile); Usage(); } else { while (fgets (String1 = String, MAX_PATH, FileHandle) != NULL) { while ( *(String2 = &(String1[ strspn (String1, "\n\r") ]))) { if (*(String1 = &(String2[ strcspn (String2, "\n\r") ]))) *String1++ = 0; ExcludeListLength++; ExcludeList[ExcludeListLength - 1] = _strdup (String2); } } fclose (FileHandle) ; } } fExclude = TRUE; break; case '/' : break; default : fprintf(stderr, "Don't know flag(s) %s\n", argv); Usage(); } } } else return FALSE; return TRUE; } // IsFlag BOOL MatchElements(char *FileName, char *Path) { char *PathPlusName; PathPlusName = MyStrCat(Path, FileName); if ( ((ExcludeListLength == 0) && (MatchListLength == 0)) || ( ( (ExcludeListLength == 0) || ( (!AnyMatches(ExcludeList, FileName, ExcludeListLength)) && (!AnyMatches(ExcludeList, PathPlusName, ExcludeListLength)) ) ) && ( ( MatchListLength == 0) || (AnyMatches(MatchList, FileName, MatchListLength)) || (AnyMatches(MatchList, PathPlusName, MatchListLength)) ) ) ) { free(PathPlusName); return TRUE; } else { free(PathPlusName); return FALSE; } } void ParseArgs(int argc, char *argv[]) { int ArgCount, FlagCount; ArgCount = 1; FlagCount = 0; // // Check that number of arguments is two or more // if (argc < 2) { fprintf(stderr, "Too few arguments\n"); Usage(); } do { if (IsFlag( argv[ArgCount] )) { if ((fScript) && (fVerbose)) { fprintf(stderr, "Cannot do both script and verbose\n"); Usage(); } if ((fVerbose) && (fExecute)) { fprintf(stderr, "Cannot do both verbose and execute\n"); Usage(); } if ((fScript) && (fExecute)) { fprintf(stderr, "Cannot do both script and execute\n"); Usage(); } if ((fExclude) && (fMatching)) { fprintf(stderr, "Cannot do both match and exclude\n"); Usage(); } if ((fCreateLink) && (!fExecute)) { fprintf(stderr, "Cannot do link without execute flag\n"); Usage(); } if ((fBreakLinks) && (!fExecute)) { fprintf(stderr, "Cannot break links without execute flag\n"); Usage(); } FlagCount++; } // (IsFlag( argv[ArgCount] )) else { if (ArgCount + 2 < argc) { if (fMatching) { MatchListLength++; MatchList[MatchListLength - 1] = argv[ArgCount]; } if (fExclude) { ExcludeListLength++; ExcludeList[ExcludeListLength - 1] = argv[ArgCount]; } if ((!fMatching) && (!fExclude)) { fprintf(stderr, "Don't know option %s\n", argv[ArgCount]); Usage(); } } } } while (ArgCount++ < argc - 1); if ((argc - FlagCount) < 3) { fprintf(stderr, "Too few arguments\n"); Usage(); } } // ParseArgs void PrintFile(LinkedFileList File, char *Path, char *DiffPath) { #ifdef COMPILE_FOR_DOS struct tm *SysTime; #else SYSTEMTIME SysTime; FILETIME LocalTime; #endif if (File != NULL) { // Don't print Dirs if we have match list if ((MatchListLength == 0) || (!(*File).Attributes & FILE_ATTRIBUTE_DIRECTORY)) { if (fVerbose) { #ifdef COMPILE_FOR_DOS SysTime = localtime(&(*File).Time); fprintf (stdout, "% 9ld %.24s %s\n", (*File).SizeLow, asctime(SysTime), Path); #else FileTimeToLocalFileTime(&(*File).Time, &LocalTime); FileTimeToSystemTime(&LocalTime, &SysTime); fprintf (stdout, "%-4s % 9ld %2d-%02d-%d %2d:%02d.%02d.%03d%c %s\n", (*File).Flag, (*File).SizeLow, SysTime.wMonth, SysTime.wDay, SysTime.wYear, ( SysTime.wHour > 12 ? (SysTime.wHour)-12 : SysTime.wHour ), SysTime.wMinute, SysTime.wSecond, SysTime.wMilliseconds, ( SysTime.wHour >= 12 ? 'p' : 'a' ), Path); #endif } else fprintf(stdout, "%-4s %s\n", (*File).Flag, Path); } PrintFile((*File).DiffNode, DiffPath, NULL); } } // PrintFile void ProcessAdd(LinkedFileList List, char *String1, char *String2) { if (fScript) { (((*List).Attributes & FILE_ATTRIBUTE_DIRECTORY)) ? fprintf(stdout, "echo d | xcopy /cdehikr %s %s\n", String1, String2) : fprintf(stdout, "echo f | xcopy /cdehikr %s %s\n", String1, String2); } else if (fExecute) CopyNode (String2, List, String1); else PrintFile(List, String1, NULL); } // ProcessAdd void ProcessDel(LinkedFileList List, char *String) { if (fScript) { (((*List).Attributes & FILE_ATTRIBUTE_DIRECTORY)) ? fprintf(stdout, "echo y | rd /s %s\n", String) : fprintf(stdout, "del /f %s\n", String); } else if (fExecute) { fprintf(stdout, "Removing %s\n", String); DelNode(String); } else PrintFile(List, String, NULL); } // ProcessDel void ProcessDiff(LinkedFileList List, char *String1, char *String2) { if (strchr ((*List).Flag, '@')) { if (fScript) { if (((*List).Attributes & FILE_ATTRIBUTE_DIRECTORY)) { fprintf(stdout, "echo y | rd /s %s\n", String2); fprintf(stdout, "echo d | xcopy /cdehikr %s %s\n", String1, String2); } else { fprintf(stdout, "del /f %s\n", String2); fprintf(stdout, "echo f | xcopy /cdehikr %s %s\n", String1, String2); } } if (fExecute) { fprintf(stdout, "Removing %s\n", String2); DelNode (String2); CopyNode (String2, List, String1); } } if (fScript) { (((*List).Attributes & FILE_ATTRIBUTE_DIRECTORY)) ? fprintf(stdout, "echo d | xcopy /cdehikr %s %s\n", String1, String2) : fprintf(stdout, "echo f | xcopy /cdehikr %s %s\n", String1, String2); } else if (fExecute) CopyNode (String2, List, String1); else PrintFile(List, String1, String2); } // ProcessDiff void ProcessLists(LinkedFileList AddList, LinkedFileList DelList, LinkedFileList DifList, char *Path1, char *Path2, BOOL AppendPath ) { LinkedFileList TmpList; char *PathWithSlash1, *String1, *PathWithSlash2, *String2; int PathLength1, PathLength2; (Path1[strlen(Path1) - 1] == '\\') ? (PathWithSlash1 = _strdup(Path1)) : (PathWithSlash1 = MyStrCat(Path1, "\\")); (Path2[strlen(Path2) - 1] == '\\') ? (PathWithSlash2 = _strdup(Path2)) : (PathWithSlash2 = MyStrCat(Path2, "\\")); PathLength1 = strlen(PathWithSlash1); PathLength2 = strlen(PathWithSlash2); String1 = _strdup(PathWithSlash1); String2 = _strdup(PathWithSlash2); free(PathWithSlash1); free(PathWithSlash2); TmpList = AddList; while (TmpList != NULL) { String1 = realloc(String1, PathLength1 + strlen((*TmpList).Name) + 1); if (String1 == NULL) OutOfMem(); strcpy(&(String1[PathLength1]), (*TmpList).Name); String2 = realloc(String2, PathLength2 + strlen((*TmpList).Name) + 1); if (String2 == NULL) OutOfMem(); strcpy(&(String2[PathLength2]), (*TmpList).Name); if (AppendPath) ProcessAdd(TmpList, String1, String2); else ProcessAdd(TmpList, Path1, Path2); TmpList = (*TmpList).Next; } TmpList = DelList; while (TmpList != NULL) { String2 = realloc(String2, PathLength2 + strlen((*TmpList).Name) + 1); if (String2 == NULL) OutOfMem(); strcpy(&(String2[PathLength2]), (*TmpList).Name); if (!fDoNotDelete) ProcessDel(TmpList, String2); TmpList = (*TmpList).Next; } TmpList = DifList; while (TmpList != NULL) { String1 = realloc(String1, PathLength1 + strlen((*TmpList).Name) + 1); if (String1 == NULL) OutOfMem(); strcpy(&(String1[PathLength1]), (*TmpList).Name); String2 = realloc(String2, PathLength2 + strlen((*TmpList).Name) + 1); if (String2 == NULL) OutOfMem(); strcpy(&(String2[PathLength2]), (*TmpList).Name); if (AppendPath) ProcessDiff(TmpList, String1, String2); else ProcessDiff(TmpList, Path1, Path2); TmpList = (*TmpList).Next; } free (String1); free (String2); } // ProcessLists void Usage(void) { fprintf (stderr, "Usage: compdir [/abcdelnrstv] [/m {wildcard specs}] [/x {wildcard specs}] Path1 Path2 \n"); fprintf (stderr, " /a checks for attribute difference \n"); fprintf (stderr, " /b checks for sum difference \n"); fprintf (stderr, " /c prints out script to make \n"); fprintf (stderr, " directory2 look like directory1 \n"); fprintf (stderr, " /d do not perform or denote deletions \n"); fprintf (stderr, " /e execution of tree duplication \n"); fprintf (stderr, " /k break links if copying files (on NT only)\n"); fprintf (stderr, " /l use links instead of copies (on NT only)\n"); fprintf (stderr, " /m marks start of match list \n"); fprintf (stderr, " /n create second path if it doesn't exist\n"); fprintf (stderr, " /r do not recurse into subdirectories \n"); fprintf (stderr, " /s checks for size difference \n"); fprintf (stderr, " /t[:#] checks for time-date difference; \n"); fprintf (stderr, " takes margin-of-error parameter \n"); fprintf (stderr, " in number of seconds. \n"); fprintf (stderr, " /v prints verbose output \n"); fprintf (stderr, " /x[:f] marks start of exclude list. f is an \n"); fprintf (stderr, " exclude file \n"); fprintf (stderr, " /? prints this message \n"); exit(1); } // Usage