Subversion Repositories DevTools

Rev

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);
}