Rev 2075 | Rev 2310 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*============================================================================** Copyright (C) 1998-2012 Vix Technology, All rights reserved**============================================================================**** Project/Product :** Filename : JatsFileUtil.c** Author(s) : DDP**** Description :** The program mimics - but a lot faster a Jats Makefile fragment** The program will:**** Operate in two modes** CopyFile** DeleteFile** Remove Files** DeleteDir after deleting specified files**** CopyFile (5 args)** 1) Display the ----- Text dest** 2) Error if the source is not found** 3) Create target path if not alraedy existing** 4) Copy the source to the target - overwritting the target** 5) Set File mode** 6) Test for file existence**** DeleteFile (3 args)** 1) Display the ----- Text dest** 2) Delete the target file**** RemoveFiles ( >1 arg)** 1) Silenty delete a list of files. The files may** be readonly so the attributes will need to be fixed.**** Assumes the current directory**** DeleteDir (> 2 args)** 1) Silenty delete a list of files. The files may** be readonly so the attributes will need to be fixed.** 2) Delete the directory if its empty**** Make paths use '/'****** Information :** Compiler : ANSI C++** Target :*****==========================================================================*/#include <tchar.h>#include <stdio.h>#include <windows.h>#define MAX_FILE 2000#define INVALID_FILE_ATTIBUTES ((DWORD) -1)void fullPath ( _TCHAR * src, _TCHAR *dst );VOID ErrorExit (char *lpszMessage, LPTSTR lpszMessage2);void createPaths ( _TCHAR *path );void deleteFileList( int argc, _TCHAR* argv[] );void DeleteDir( int argc, _TCHAR* argv[] );/*** Global*/_TCHAR currentDir[MAX_FILE + 1]; /* Current working directory */char verbose = 1; /* Debugging aid */char copyMode = 0; /* Mode */_TCHAR src [MAX_FILE + 1];_TCHAR dst [MAX_FILE + 1];/*----------------------------------------------------------------------------** FUNCTION : main**** DESCRIPTION : Main entry points****** INPUTS : Arguments are fixed** Mode - ModeDebug** Text - Text to output** dest - Target Path** file - Source path [Copy Only]** fmode - File mode [Copy Only]**** RETURNS : 0 - All is good**----------------------------------------------------------------------------*/int _tmain(int argc, _TCHAR* argv[]){DWORD rv;/*** Examine the first argument** Must be a character string of** [0] - Mode : c or d or r or l** [1] - Verbose : 0 .. 9*/if ( argc > 1 ){if ( argv[1][0] == 'c' ) {copyMode = 1;} else if ( argv[1][0] == 'd' ) {copyMode = 2;} else if ( argv[1][0] == 'r' ) {copyMode = 3;} else if ( argv[1][0] == 'D' ) {copyMode = 4;} else {ErrorExit("Unknown mode: ",argv[1]);}if ( argv[1][1] >= '0' && argv[1][1] <= '9' ) {verbose = argv[1][1] - '0';}}/*** If Verbose, then display arguments*/if ( verbose > 1 ){int ii;for ( ii = 0; ii < argc ; ii++ ){fprintf(stderr, "Arg%d: %ls:\n", ii, argv[ii] );}fprintf(stderr, "Mode : %d:\n", copyMode );fprintf(stderr, "Verbose: %d:\n", verbose );fflush(stderr) ;}/*** Determine cwd** Used for ab path conversion*/GetCurrentDirectory( MAX_FILE, currentDir );if ( verbose > 1 )fprintf(stderr, "CWD: %ls\n", currentDir );/*** Determine required operation*/if ( copyMode == 3 ){deleteFileList(argc - 2, argv + 2 );return 0;}if ( copyMode == 4 ){DeleteDir(argc - 2, argv + 2 );return 0;}/*** Determine mode of operation** Copy or Delete*/if ( copyMode == 1 && argc == 6 ) {fullPath( argv[4], src);fullPath( argv[3], dst);} else if ( copyMode == 2 && argc == 4) {fullPath( argv[3], dst);} else {fprintf(stderr, "Mode: %d, Args: %d\n", copyMode, argc);ErrorExit("Incorrect argument count for mode",L"");}/*** Display user text*/fprintf(stderr, "---- %ls %ls\n", argv[2], argv[3]);fflush(stderr) ;/*** Check that the source is a file*/if ( copyMode == 1 ){if ( verbose )fprintf(stderr, "Validate Source File: %ls\n", src);rv = GetFileAttributesW( src );if ( rv == INVALID_FILE_ATTIBUTES ){/* Need to be a better message */fprintf(stderr, "Source: %ls\n", src);ErrorExit("Source File not found: ", argv[4]);}}/*** Remove the ReadOnly attribute on the dest file*/if ( verbose )fprintf(stderr, "Remove target file: %ls\n", dst);rv = GetFileAttributesW( dst );if ( rv != INVALID_FILE_ATTIBUTES ){if ( verbose )fprintf(stderr, "FileExists with attr: %ld\n", rv);if ( rv & FILE_ATTRIBUTE_READONLY ){rv &= ~FILE_ATTRIBUTE_READONLY;rv = SetFileAttributesW( dst, rv );if ( rv == 0 ){ErrorExit("Attempt to allow write access: ", argv[3]);}}if (! DeleteFile( dst ) ){ErrorExit("Deleting file: ", argv[3]);}}if ( copyMode == 1 ){/*** Create directories** Use the path to the target - not the provided directory** as the createPaths function will not create the last element*/createPaths( dst );/*** Copy the file*/if ( ! CopyFile( src, dst, FALSE ) ){rv = GetLastError();fprintf(stderr, "CopyFile Last Error: %ld\n", rv);ErrorExit("Copy Error: ", argv[4]);}/*** Test for files existence*/if ( verbose )fprintf(stderr, "Test target was copied: %ls\n", dst);rv = GetFileAttributesW( dst );if ( rv == INVALID_FILE_ATTIBUTES ){/* Need to be a better message */ErrorExit("File not found after copy: ", argv[3]);}/*** Set the files attributes** Assume read-only*/if ( _tcsstr( argv[5], L"-w" ) ){if ( verbose )fprintf(stderr, "Set target read-only: %ls\n", dst);rv |= FILE_ATTRIBUTE_READONLY;rv &= ~FILE_ATTRIBUTE_NORMAL;rv = SetFileAttributesW( dst, rv );if ( rv == 0 ){ErrorExit("Setting ReadOnly: ", argv[3]);}}}return 0;}/*----------------------------------------------------------------------------** FUNCTION : createPaths**** DESCRIPTION : Create the path to the target****** INPUTS : path** Assumed to be a \\?\X:\ style**** RETURNS : Will not return in error**----------------------------------------------------------------------------*/void createPaths ( _TCHAR *path ){DWORD rv;_TCHAR *ptr = path + 7;while ( *ptr ){if ( *ptr == '/' || *ptr == '\\'){*ptr = 0;//fprintf(stderr, "createPaths: %ls\n", path);if ( ! CreateDirectoryW ( path, NULL )){rv = GetLastError();if ( rv != ERROR_ALREADY_EXISTS )ErrorExit("Could not create directories:", path);}*ptr = '\\';}ptr++;}}/*----------------------------------------------------------------------------** FUNCTION : fullPath**** DESCRIPTION : Creates a full file path for user** Convert relative path to ABS path with \\?\ from** Convert / into \ for windows**** Handle path elements** ./ - Remove** /bbb/../ - Remove** /aaa/bbb/../../ - Remove****** INPUTS : src - Partial file path** dst - Area to create full name** Assumed to address a MAX_FILE space**** RETURNS : Nothing**----------------------------------------------------------------------------*/void fullPath ( _TCHAR * src, _TCHAR *dst ){_TCHAR *udst = dst;_TCHAR *usrc = src;_tcscpy(dst, TEXT("\\\\?\\"));if ( ( src[0] && (src[1] != ':') ) || src[0] == 0 ){_tcscat(dst, currentDir );_tcscat(dst, TEXT("\\") );}udst += _tcslen(udst);while ( *usrc ){if ( *usrc == '/' ) {*udst++ = '\\';} else {*udst++ = *usrc;}usrc++;}*udst = 0;/*** Now remove silly relative path bits*/udst = dst;while ( *udst ){if ( udst[0] == '\\' && udst[1] == '.' && (udst[2] == '\\' || udst[2] == 0) ){TCHAR* ptr1 = udst;TCHAR* ptr2 = udst + 2;while ( *ptr1++ = *ptr2++ ) {}}else if ( udst[0] == '\\' && udst[1] == '.' && udst[2] == '.' && udst[3] == '\\' ){TCHAR* ptr = udst - 1;TCHAR* ptr2 = udst + 3;while ( *ptr-- != '\\' ){if ( ptr - dst < 6){*ptr = 0;fprintf(stderr, "Path: %ls\n", dst);ErrorExit("Bad relative path: ", src);}}ptr++;udst = ptr;while ( *ptr++ = *ptr2++ ) {}}else{*udst++;}}if ( verbose > 1)fprintf(stderr, "AbsPath: %ls\n", dst);}/*----------------------------------------------------------------------------** FUNCTION : deleteFileList**** DESCRIPTION : Delete a list of files** Ensure files are writable****** INPUTS : argc - count of args** argv - list of files to delete**** RETURNS : Wil not return on error**----------------------------------------------------------------------------*/void deleteFileList( int argc, _TCHAR* argv[] ){DWORD rv;for ( ; argc ; argc--, argv++ ){fullPath( *argv, dst);/*** Remove the ReadOnly attribute on the dest file*/if ( verbose > 1 )fprintf(stderr, "Remove target file: %ls\n", dst);rv = GetFileAttributesW( dst );if ( rv != INVALID_FILE_ATTIBUTES ){if ( verbose )fprintf(stderr, "Delete file: %ls : Attr: 0x%lx\n", *argv, rv);if ( rv & FILE_ATTRIBUTE_READONLY ){rv &= ~FILE_ATTRIBUTE_READONLY;rv = SetFileAttributesW( dst, rv );if ( rv == 0 ){fprintf(stderr, "Warning: Attempt to allow write access: %ls\n", *argv);}}if (! DeleteFile( dst ) ){fprintf(stderr, "Warning: Did not remove file: %ls\n", *argv);}}}}/*----------------------------------------------------------------------------** FUNCTION : DeleteDir**** DESCRIPTION : Delete a list of files in a specified directory** Ensure files are writable** Wilcarding is supported**** Then delete the directory - if its empty****** INPUTS : argc - count of args** argv - list of files to delete** First entry is a directory**** RETURNS : Wil not return on error**----------------------------------------------------------------------------*/void DeleteDir( int argc, _TCHAR* argv[] ){DWORD rv;_TCHAR* baseDir;WIN32_FIND_DATA FindFileData;HANDLE hFind;if ( argc < 3 )ErrorExit("Insuffiecient arguments for DeleteDir",L"");/*** Display the user message** Supress display if the message is empty*/if ( argv[0][0] ){fprintf(stderr, "%ls\n", argv[0]);fflush(stderr) ;}/*** Extract the base directory from the argument list** This must be a directory*/baseDir = argv[1];argc -= 2;argv+=2;/*** Ensure that the base directory exists*/fullPath( baseDir, dst);rv = GetFileAttributesW( dst );if ( rv == INVALID_FILE_ATTIBUTES ){/*** Directory does not exists** Assume its aleady deleted*/if ( verbose > 1 )fprintf(stderr, "Base dir does not exist: %ls\n", baseDir);return;}if ( !(rv & FILE_ATTRIBUTE_DIRECTORY) ){/*** Target is not a directory** Don't do anything*/if ( verbose > 1 )fprintf(stderr, "Base dir is not a directory: %ls\n", baseDir);return;}/*** Process all the suffixes** They may contain a wild card*/for ( ; argc ; argc--, argv++ ){_tcscpy(src, baseDir);_tcscat(src, TEXT("\\"));_tcscat(src, *argv);fullPath( src, dst);hFind = FindFirstFile(dst, &FindFileData);if (hFind == INVALID_HANDLE_VALUE){/*** No match*/if ( verbose > 1 )fprintf(stderr, "No Match: %ls\n", dst);continue;}/*** Iterate over all the files*/do {if ( _tcscmp( TEXT("."), FindFileData.cFileName ) == 0 )continue;if ( _tcscmp( TEXT(".."), FindFileData.cFileName ) == 0 )continue;/*** Create a full path to the file*/_tcscpy(src, baseDir);_tcscat(src, TEXT("\\"));_tcscat(src, FindFileData.cFileName);if ( verbose )fprintf(stderr, "Match: %ls\n", FindFileData.cFileName);/*** Force file to be writable*/if ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY){rv = SetFileAttributesW( src, FindFileData.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY );if ( rv == 0 ){fprintf(stderr, "Warning: Attempt to allow write access: %ls\n", FindFileData.cFileName);}}/*** Delete the file*/if (! DeleteFile( src ) ){fprintf(stderr, "Warning: Did not remove file: %ls\n", FindFileData.cFileName);}} while (FindNextFile(hFind, &FindFileData) != 0);FindClose(hFind);}/*** Finally delete the diretory** Unless its '.'*/if ( _tcscmp( TEXT("."),baseDir) != 0 ){fullPath( baseDir, dst);if ( verbose > 1 )fprintf(stderr, "Delete Directory: %ls\n", baseDir);if ( ! RemoveDirectory( dst ) ){if ( verbose )fprintf(stderr, "Directory not deleted: %ls\n", baseDir);}}}/*----------------------------------------------------------------------------** FUNCTION : ErrorExit**** DESCRIPTION : Error processing** Report an error and terminate process****** INPUTS : lpszMessage - Message to display**** RETURNS : Does't return** Will exit with bad code**----------------------------------------------------------------------------*/VOID ErrorExit (char *lpszMessage, LPTSTR lpszMessage2){fprintf(stderr, "JatsFileUtil:Error:%s%ls\n", lpszMessage,lpszMessage2);fflush(stderr) ;ExitProcess(-1);}