Rev 2310 | Rev 2313 | 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 : Jats Build System File utility** Used by the generated makefiles to perform specific operations**** The program exists to solve problems:** Windows: Shell is very very slow to start up** Windows: Some commands have ~260 character path length issue** Windows/Solaris/Linux: Compatibility issues with the 'rm' command** All: Consistent use of '/' as a path separator**** Note: There are two flavors of this program that MUST be** kept in sync.**** The program will perform the following operations:** (c) CopyFile** (d) DeleteFile** (r) Remove Files (wildcard)** (D) DeleteDir after deleting specified files (wildcard)** (T) Delete Directory Tree**** Example Usage**** JatsFileUtil c9 'copyFile' aaa/bbb/ccc/dddd/file build_test.pl +w** JatsFileUtil d9 'unCopyFile' aaa/bbb/ccc/dddd/file** JatsFileUtil r9 'deleteFile' a1 b2 c3** JatsFileUtil D9 'DeleteFiles' src/WIN32P.OBJ *.err *.pch '*'** JatsFileUtil T9 'DeleteTree' interface**** First two arguments are common to all** argv[1] - Mode specifier, Debug specifier** argv[2] - Display Text**** Information :** Compiler : ANSI C** Target : Windows 2000+, Linux, Solaris8+*****==========================================================================*/#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>void ErrorExit (char * lpszMessage, char * lpszMessage2);void createPaths ( char *path );void DeleteDir( int argc, char* argv[] );void DeleteDirTree( int argc, char* argv[] );char * makePath( char *base, char *path);int DeleteOneFile (char * dst );void DeleteOneDirectoryTree( char* baseDir );void copyOneFile( int argc, char* argv[] );int CopyFile ( char *src, char *dst, mode_t st_mode );int wildcmp(char *string, char *wild );/*** Global*/char verbose = 1; /* Debugging aid *//*----------------------------------------------------------------------------** FUNCTION : main**** DESCRIPTION : Main entry points****** INPUTS : argc - Argument Count** argv - Argument Vector**** RETURNS : 0 - All is good**----------------------------------------------------------------------------*/int main(int argc, char* argv[]){/*** Examine the first argument** Must be a character string of** [0] - Mode : One character** [1] - Verbose : 0 .. 9*/if ( argc > 1 && ( argv[1][1] >= '0' && argv[1][1] <= '9' ) ){verbose = argv[1][1] - '0';/*** If Verbose, then display arguments*/if ( verbose > 2 ){int ii;for ( ii = 0; ii < argc ; ii++ ){fprintf(stderr, "Arg%d: %s:\n", ii, argv[ii] );}fflush(stderr) ;}}/*** Switch to required operation*/switch( argv[1][0] ){/*** CopyFile** argv[2] - Text** argv[3] - target path** argv[4] - Source path** argv[5] - File attributes*/case 'c':copyOneFile(argc, argv);break;/*** UnCopy a file** argv[2] - Text** argv[3] - target path*/case 'd':{if ( argc != 4 )ErrorExit("Incorrect argument count for mode","");/*** Display user text*/fprintf(stderr, "---- %s %s\n", argv[2], argv[3]);fflush(stderr) ;DeleteOneFile(argv[3]);}break;/*** Remove named files** argv[2] - Text** argv[3]+ - target path*/case 'r':{int ii;if ( argc < 4 )ErrorExit("Incorrect argument count for mode","");/*** Display user text*/if ( argv[2][0] ){fprintf(stderr, "%s\n", argv[2]);fflush(stderr) ;}for ( ii = 3; ii < argc ; ii++ ){DeleteOneFile(argv[ii]);}}break;/*** Delete files in directory - with wildcards** argv[2] - Text** argv[3] - Base directory** argv[4]+ - Files in dir to delete.*/case 'D':DeleteDir(argc - 2, argv + 2 );break;/*** Delete files recursively** argv[2] - Text** argv[3]+ Base directory*/case 'T':DeleteDirTree(argc - 2, argv + 2 );break;default :ErrorExit("Unknown mode: ",argv[1]);break;}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;/* fprintf(stderr, "createPaths: %s\n", path); */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 : copyOneFile**** DESCRIPTION : Copy one file to a target** Used to package and install files****** INPUTS : argc - Argc count** argv - Argument list** argv[2] - Display text Prefix** argv[3] - Target path** argv[4] - Source Path** argv[5] - File attributes**** RETURNS :**----------------------------------------------------------------------------*/void copyOneFile( int argc, char* argv[] ){int rv;char * src;char * dst;struct stat fstat;if ( argc != 6 )ErrorExit("Incorrect argument count for file copy","");/*** Display user text*/fprintf(stderr, "---- %s %s\n", argv[2], argv[3]);fflush(stderr) ;dst = argv[3];src = argv[4];/*** Check that the source is a file*/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]);}/*** Remove the ReadOnly attribute on the dest file*/DeleteOneFile(dst);/*** 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, fstat.st_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]);}}/*----------------------------------------------------------------------------** 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 1024int 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 : 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]+ Files in dir to delete**** RETURNS : Will not return on error**----------------------------------------------------------------------------*/void DeleteDir( int argc, char* argv[] ){int rv;struct stat fstat;char* baseDir;DIR *dir;struct dirent *dirent;char *target;if ( argc < 3 )ErrorExit("Insufficient 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*/target = makePath( baseDir, dirent->d_name);DeleteOneFile(target);free(target);}}}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 : DeleteDirTree**** DESCRIPTION : Delete an entire directory tree(s)**** INPUTS : argc - count of args** argv - list of files to delete** [0]: Text to display** [1]+ Base directory**** RETURNS : Will not return on error**----------------------------------------------------------------------------*/void DeleteDirTree( int argc, char* argv[] ){int ii;if ( argc < 2 )ErrorExit("Insufficient arguments for DeleteDirTree","");/*** Display the user message** Supress display if the message is empty*/if ( argv[0][0] ){fprintf(stderr, "%s\n", argv[0]);fflush(stderr) ;}for ( ii = 1; ii < argc ; ii++){DeleteOneDirectoryTree( argv[ii] );}}/*----------------------------------------------------------------------------** FUNCTION : DeleteOneDirectoryTree**** DESCRIPTION : Delete an entire directory tree(s)**** INPUTS : path - Dir to delete**** RETURNS : Will not return on error**----------------------------------------------------------------------------*/void DeleteOneDirectoryTree( char* baseDir ){struct stat fstat;DIR *dir;struct dirent *dirent;char *target;int rv;/*** A bit of a sanity test*/if ( strcmp( ".", baseDir) == 0 || strcmp( "..", baseDir) == 0 ){fprintf(stderr, "DeleteOneDirectoryTree will not delete '.' or '..'\n");return;}/*** Process all entries*/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 ){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;target = makePath( baseDir, dirent->d_name);rv = stat( target, &fstat );if ( rv == 0 ){if ( fstat.st_mode & S_IFDIR ){DeleteOneDirectoryTree( target );}else{DeleteOneFile (target);}}free(target);}closedir(dir);/*** Finally delete the directory*/if ( verbose )fprintf(stderr, "Delete Directory: %s\n", baseDir);if ( rmdir (baseDir ) ){if ( verbose )fprintf(stderr, "Directory not deleted: %s\n", baseDir);}}/*----------------------------------------------------------------------------** FUNCTION : DeleteOneFile**** DESCRIPTION : Delete a file** Force it writable before deletion**** INPUTS : path - path to the file**** RETURNS : 0 - OK (file deleted or not present)**----------------------------------------------------------------------------*/int DeleteOneFile (char * dst ){int rv;struct stat fstat;int result = 0;if ( verbose > 1)fprintf(stderr, "Delete File: %s\n", dst);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);result = 1;}}return result;}/*----------------------------------------------------------------------------** FUNCTION : makePath**** DESCRIPTION : Create a path from two elements** Allocate memory****** INPUTS : base - Part 1** file - Part 2**** RETURNS :**----------------------------------------------------------------------------*/char * makePath( char *base, char *path){int len1 = strlen(base);int len2 = strlen(path);char *data;data = (char *)malloc(len1 + len2 + 10);if ( data == NULL ){ErrorExit ("Malloc error:makePath","");}strcpy( data,base);strcpy( data + len1, "/");strcpy( data + len1 + 1, path);return data;}/*----------------------------------------------------------------------------** 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);}