Subversion Repositories DevTools

Rev

Rev 2073 | Rev 2085 | 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
**
**                      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.
**
**                      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[] );

/*
**  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
    **      [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 {
            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;
    }

    /*
    **  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] != ':' )
    {
            _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 > 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           : 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);
}