Rev 2072 | Rev 2075 | 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 : CopyFile.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**** 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**** 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 );/*** Global*/_TCHAR currentDir[MAX_FILE + 1]; /* Current working directory */char verbose = 1; /* Debugging aid */char copyMode = 0; /* Mode *//*----------------------------------------------------------------------------** 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;_TCHAR src [MAX_FILE + 1];_TCHAR dst [MAX_FILE + 1];/*** Examine the first argument** Must be a character string of** [0] - Mode : c or d** [1] - Verbose : 0 .. 9*/if ( argc > 1 ){if ( argv[1][0] == 'c' ) {copyMode = 1;} else if ( argv[1][0] == 'd' ) {copyMode = 2;} else {ErrorExit("CopyFile: 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 ){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 )fprintf(stderr, "CWD: %ls\n", currentDir );/*** 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("Error: 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("Error: Attempt to allow write access: ", argv[3]);}}if (! DeleteFile( dst ) ){ErrorExit("Error: 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, "CopyFileLast Error: %ld\n", rv);ErrorExit("Error: 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("Error: 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("Error: 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("Error: Cound 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] != ':' ){_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] == '\\' ){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 )fprintf(stderr, "AbsPath: %ls\n", dst);}/*----------------------------------------------------------------------------** 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, "%s%ls\n", lpszMessage,lpszMessage2);fflush(stderr) ;ExitProcess(-1);}