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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>

#define MAX_FILE 2000

void ErrorExit (char * lpszMessage, char * lpszMessage2);
void createPaths ( char *path );
int CopyFile ( char *src, char *dst, mode_t st_mode );
void deleteFileList( int argc, char* argv[] );
void DeleteDir( int argc, char* argv[] );
int wildcmp(char *string, char *wild );

/*
**  Global
*/
char  verbose = 1;                          /* Debugging aid */
char  copyMode = 0;                         /* Mode */
char  dst [MAX_FILE + 1];                   /* Scratch string workspace */

/*----------------------------------------------------------------------------
** 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 main(int argc, char* argv[])
{

        int rv;
    struct stat fstat;
    char *dst;
    char *src;
    mode_t src_mode;

    /*
    **  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: %s:\n", ii, argv[ii] );
        }
        fprintf(stderr, "Mode   : %d:\n", copyMode );
        fprintf(stderr, "Verbose: %d:\n", verbose );
        fflush(stderr) ;
    }

    /*
    **  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 ) {
        src = argv[4];
        dst = argv[3];

    } else if ( copyMode == 2 && argc == 4) {
        dst = argv[3];

    } else {
        fprintf(stderr, "Mode: %d, Args: %d\n", copyMode, argc);
        ErrorExit("Incorrect argument count for mode","");
    }

    /*
    **  Display user text
    */
    fprintf(stderr, "---- %s %s\n", argv[2], argv[3]);
    fflush(stderr) ;

    /*
    **   Check that the source is a file
    */
    if ( copyMode == 1 )
    {
        if ( verbose )
            fprintf(stderr, "Validate Source File: %s\n", src);
        
        rv = stat( src, &fstat );
        if ( rv != 0 )
        {
    /* Need to be a better message */
            fprintf(stderr, "Source: %s\n", src);
            ErrorExit("Source File not found: ", argv[4]);
        }
        src_mode = fstat.st_mode;
    }

    /*
    **  Remove the ReadOnly attribute on the dest file
    */
    if ( verbose )
        fprintf(stderr, "Remove target file: %s\n", dst);
    rv = stat( dst, &fstat );
    if ( rv == 0 )
    {
        if ( verbose )
            fprintf(stderr, "FileExists with attr: 0%o\n", fstat.st_mode);
        if ( !(fstat.st_mode & S_IWRITE) )
        {
            fstat.st_mode |= S_IWRITE;
            rv = chmod( dst, fstat.st_mode );
            if ( rv != 0 )
            {
                ErrorExit("Attempt to allow write access: ", argv[3]);
            }
        }

        if ( unlink( 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, src_mode ) )
        {
            ErrorExit("Copy Error: ", argv[4]);
        }

        /*
        **  Test for files existence
        */
        if ( verbose )
            fprintf(stderr, "Test target was copied: %s\n", dst);
        rv = stat( dst, &fstat );
        if ( rv != 0 )
        {
    /* Need to be a better message */
            ErrorExit("File not found after copy: ", argv[3]);
        }

        /*
        **  Set the files attributes
        **      Assume read-only
        */
        if ( strstr( argv[5], "-w" ) )
        {
            if ( verbose > 1 )
                fprintf(stderr, "Set target read-only: %s\n", dst);
            fstat.st_mode &= ~(S_IWRITE | S_IWOTH | S_IWGRP );
        }

        if ( strstr( argv[5], "+w" ) )
        {
            if ( verbose > 1 )
                fprintf(stderr, "Set target writable: %s\n", dst);
            fstat.st_mode |= (S_IWRITE | S_IWOTH | S_IWGRP );
        }

        if ( strstr( argv[5], "+x" ) )
        {
            if ( verbose > 1 )
                fprintf(stderr, "Set target executable: %s\n", dst);
            fstat.st_mode |= ( S_IXUSR | S_IXOTH | S_IXGRP );
        }

        if ( strstr( argv[5], "-x" ) )
        {
            if ( verbose > 1)
                fprintf(stderr, "Set target executable: %s\n", dst);
            fstat.st_mode &= ~( S_IXUSR | S_IXOTH | S_IXGRP );
        }
        
        if ( verbose )
            fprintf(stderr, "Set target perms: %s, 0%o\n", dst, fstat.st_mode);
        rv = chmod( dst, fstat.st_mode );
        if ( rv != 0 )
        {
            ErrorExit("Setting ReadOnly: ", argv[3]);
            }
        }

    return 0;
}

/*----------------------------------------------------------------------------
** FUNCTION           : createPaths
**
** DESCRIPTION        : Create the path to the target
**
**
** INPUTS             : path
**
** RETURNS            : Will not return in error
**
----------------------------------------------------------------------------*/

void createPaths ( char *path )
{
    struct stat fstat;
    int  rv;
    char *ptr = path;

    while ( *ptr )
    {
        if ( *ptr == '/' )
        {
            *ptr = 0;

            rv = stat( path, &fstat );
            if ( rv )
            {
                if ( verbose > 1 )
                {
                    fprintf(stderr, "createPaths: %s\n", path);
                    fflush(stderr) ;
                }
                rv = mkdir( path, 0777 );
                if ( rv )
                {
                    ErrorExit("Could not create directories:", path);
                }
            }
            *ptr = '/';
        }
        ptr++;
    }
}

/*----------------------------------------------------------------------------
** FUNCTION           : CopyFile
**
** DESCRIPTION        : Just copy a file
**
**
** INPUTS             : src - source path - already exists
**                      dst - path. Dirs already exist
**                      st_mode - Creation  mode. Copied from source file
**
** RETURNS            : false - Error
**
----------------------------------------------------------------------------*/

#define COPYSIZE  1024
int CopyFile ( char *src, char *dst, mode_t st_mode )
{

     ssize_t rlen = 0 ;
     ssize_t wlen = 0 ;
     int in;
     int out;
     int ferror = 0;
    char buffer[COPYSIZE] = { '\0' } ;

    if ( verbose )
    {
        fprintf(stderr, "CopyFile: Output Mode: 0%o\n", st_mode);
        fflush(stderr) ;
    }

    in = open( src, O_RDONLY ) ;
    if ( in < 0 )
        ErrorExit("Could not open source:", src);

    out = open( dst, O_WRONLY | O_CREAT, st_mode | S_IWRITE );
    if ( out < 0 )
        ErrorExit("Could not open dst:", dst);

    while( (rlen = read( in, buffer, COPYSIZE )) > 0 )
    {
        wlen = write( out, buffer, rlen ) ;
        if ( wlen != rlen )
        {
            ferror = 1;
            break;
        }
    }

    close(in) ;
    close(out) ;

    /*
    **  File error
    **  Delete target
    */
    if ( ferror || rlen < 0 )
    {
        unlink(dst) ;
        return 0;
    }
    return 1;
}

/*----------------------------------------------------------------------------
** 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, char* argv[] )
{
        int rv;
    struct stat fstat;

    for ( ; argc ; argc--, argv++ )
    {
        /*
        **  Remove the ReadOnly attribute on the dest file
        */
        if ( verbose > 1 )
            fprintf(stderr, "Remove target file: %s\n", *argv);


        rv = stat( *argv, &fstat );
        if ( rv == 0 )
        {
            if ( verbose )
                fprintf(stderr, "Delete file: %s : Attr: 0%o\n", *argv, fstat.st_mode);
            if ( !(fstat.st_mode & S_IWRITE) )
            {
                fstat.st_mode |= S_IWRITE;
                rv = chmod( *argv, fstat.st_mode );
                if ( rv != 0 )
                {
                    fprintf(stderr, "Warning: Attempt to allow write access: %s\n", *argv);
                }
            }

            if ( unlink( *argv ) )
            {
                fprintf(stderr, "Warning: Did not remove file: %s\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
**                                [0]:  Text to display
**                                [1]:  Base directory
**                                [2]+  File in dir to delete
**
** RETURNS            : Wil not return on error
**
----------------------------------------------------------------------------*/

void DeleteDir( int argc, char* argv[] )
{
        int rv;
    struct stat fstat;
    char* baseDir;
    DIR *dir;
    struct dirent *dirent;

    if ( argc < 3 )
        ErrorExit("Insuffiecient arguments for DeleteDir","");
        
    /*
    **  Display the user message
    **      Supress display if the message is empty
    */
    if ( argv[0][0] )
    {
        fprintf(stderr, "%s\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
    */
    rv = stat( baseDir, &fstat );
    if ( rv != 0 )
    {
        /*
        **  Directory does not exists
        **  Assume its aleady deleted
        */
        if ( verbose > 1 )
            fprintf(stderr, "Base dir does not exist: %s\n", baseDir);
        return;
    }

    if ( !(fstat.st_mode & S_IFDIR))
    {
        /*
        **  Target is not a directory
        **  Don't do anything
        */
        if ( verbose > 1 )
            fprintf(stderr, "Base dir is not a directory: %s\n", baseDir);
        return;
    }

    /*
    **  Process all the suffixes
    **  They may contain a wild card
    */
    dir = opendir( baseDir );
    if ( dir == NULL )
    {
        /*
        **  Target is not a directory
        **  Don't do anything
        */
        if ( verbose > 1 )
            fprintf(stderr, "Base dir is not a directory: %s\n", baseDir);
        return;
    }

    /*
    **  Read next directory entry
    */
    while ( (dirent = readdir(dir)) != NULL )
    {
        int ii;
        if ( verbose > 2 )
            fprintf(stderr, "Directory Entry:%s,%s\n", baseDir, dirent->d_name );
        
        if ( strcmp( ".", dirent->d_name ) == 0 )
            continue;

        if ( strcmp( "..", dirent->d_name ) == 0 )
            continue;

        /*
        **  Compare against each item in the user list
        */
        for ( ii = 0; ii < argc ; ii++)
        {

            if ( wildcmp(dirent->d_name, argv[ii] )  )
            {
                if ( verbose > 1 )
                    fprintf(stderr, "Matching: %s, %s --- Found\n", dirent->d_name, argv[ii] );
                /*
                **  Matching file found
                */
                strcpy( dst, baseDir);
                strcat( dst, "/");
                strcat( dst, dirent->d_name);

                rv = stat( dst, &fstat );
                if ( rv == 0 )
                {
                    if ( verbose )
                        fprintf(stderr, "Delete file: %s : Attr: 0%o\n", dst, fstat.st_mode);
                    if ( !(fstat.st_mode & S_IWRITE) )
                    {
                        fstat.st_mode |= S_IWRITE;
                        rv = chmod( dst, fstat.st_mode );
                        if ( rv != 0 )
                        {
                            fprintf(stderr, "Warning: Attempt to allow write access: %s\n", dst);
                        }
                    }

                    if ( unlink(dst) )
                    {
                        fprintf(stderr, "Warning: Did not remove file: %s\n", dst);
                    }
                }
            }
        }
    }
    closedir(dir);

    /*
    **  Finally delete the diretory
    **      Unless its '.'
    */
    if ( strcmp( ".", baseDir) != 0 )
    {
        if ( verbose > 1 )
            fprintf(stderr, "Delete Directory: %s\n", baseDir);
        if ( rmdir (baseDir ) )
        {
            if ( verbose )
                fprintf(stderr, "Directory not deleted: %s\n", baseDir);
        }
    }
}

/*----------------------------------------------------------------------------
** FUNCTION           : wildcmp
**
** DESCRIPTION        : Wildcard comparision
**
**
** INPUTS             : string          - String
**                      wild            - Wildcard template
**
** RETURNS            : TRUE - Match
**
----------------------------------------------------------------------------*/

int wildcmp(char *string, char *wild )
{
    char *cp, *mp;
    while ((*string) && (*wild != '*'))
    {
        if ((*wild != *string) && (*wild != '?'))
        {
            return 0;
        }
         wild++;
         string++;
    }

    while (*string)
    {
        if (*wild == '*')
        {
            if (!*++wild)
            {
                return 1;
            }
            mp = wild;
            cp = string+1;
        }
        else if ((*wild == *string) || (*wild == '?'))
        {
            wild++;
            string++;
        }
        else
        {
            wild = mp;
            string = cp++;
        }
    }

    while (*wild == '*')
    {
        wild++;
    }

    return !*wild;
}




/*----------------------------------------------------------------------------
** 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, char * lpszMessage2)
{ 
   fprintf(stderr, "JatsFileUtil:Error: %s%s\n", lpszMessage,lpszMessage2);
   fflush(stderr) ;
   exit(-1);
}