Subversion Repositories DevTools

Rev

Rev 2075 | Rev 2310 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2073 dpurdie 1
/*============================================================================
2072 dpurdie 2
** Copyright (C) 1998-2012 Vix Technology, All rights reserved
3
**============================================================================
4
**
5
**  Project/Product : 
2075 dpurdie 6
**  Filename        : JatsFileUtil.c
2072 dpurdie 7
**  Author(s)       : DDP
8
**
9
**  Description     :
10
**                      The program mimics - but a lot faster a Jats Makefile fragment
11
**                      The program will:
12
**
13
**                      Operate in two modes
14
**                          CopyFile
15
**                          DeleteFile
2075 dpurdie 16
**                          Remove Files
2085 dpurdie 17
**                          DeleteDir after deleting specified files
2072 dpurdie 18
**
19
**                      CopyFile (5 args)
20
**                          1) Display the ----- Text dest
21
**                          2) Error if the source is not found
22
**                          3) Create target path if not alraedy existing
23
**                          4) Copy the source to the target - overwritting the target
24
**                          5) Set File mode
25
**                          6) Test for file existence
26
**
2073 dpurdie 27
**                      DeleteFile (3 args)
2072 dpurdie 28
**                          1) Display the ----- Text dest
29
**                          2) Delete the target file
30
**
2075 dpurdie 31
**                      RemoveFiles ( >1 arg)
32
**                          1) Silenty delete a list of files. The files may
33
**                             be readonly so the attributes will need to be fixed.
34
**
2085 dpurdie 35
**                             Assumes the current directory
36
**
37
**                       DeleteDir (> 2 args)
38
**                          1) Silenty delete a list of files. The files may
39
**                             be readonly so the attributes will need to be fixed.
40
**                          2) Delete the directory if its empty
41
**
2072 dpurdie 42
**                      Make paths use '/'
43
**
44
**
45
**  Information     :
46
**   Compiler       : ANSI C++
47
**   Target         : 
48
**
49
***==========================================================================*/
50
 
2073 dpurdie 51
#include <tchar.h>
2072 dpurdie 52
#include <stdio.h>
53
#include <windows.h>
54
 
2073 dpurdie 55
#define MAX_FILE 2000
2072 dpurdie 56
#define INVALID_FILE_ATTIBUTES ((DWORD) -1)
57
 
2073 dpurdie 58
void fullPath ( _TCHAR * src, _TCHAR *dst );
59
VOID ErrorExit (char *lpszMessage, LPTSTR lpszMessage2);
60
void createPaths ( _TCHAR *path );
2075 dpurdie 61
void deleteFileList( int argc, _TCHAR* argv[] );
2085 dpurdie 62
void DeleteDir( int argc, _TCHAR* argv[] );
2072 dpurdie 63
 
2073 dpurdie 64
/*
65
**  Global
66
*/
67
_TCHAR currentDir[MAX_FILE + 1];            /* Current working directory */
68
char  verbose = 1;                          /* Debugging aid */
69
char  copyMode = 0;                         /* Mode */
70
 
2075 dpurdie 71
_TCHAR src [MAX_FILE + 1];
72
_TCHAR dst [MAX_FILE + 1];
73
 
2072 dpurdie 74
/*----------------------------------------------------------------------------
75
** FUNCTION           : main
76
**
77
** DESCRIPTION        : Main entry points
78
**
79
**
80
** INPUTS             : Arguments are fixed
2073 dpurdie 81
**                          Mode    - ModeDebug
2072 dpurdie 82
**                          Text    - Text to output
83
**                          dest    - Target Path
2073 dpurdie 84
**                          file    - Source path   [Copy Only]
85
**                          fmode   - File mode     [Copy Only]
2072 dpurdie 86
**
87
** RETURNS            : 0 - All is good
88
**
89
----------------------------------------------------------------------------*/
2073 dpurdie 90
 
91
int _tmain(int argc, _TCHAR* argv[])
2072 dpurdie 92
{
2073 dpurdie 93
	DWORD rv;
94
 
2072 dpurdie 95
    /*
2073 dpurdie 96
    **  Examine the first argument
97
    **  Must be a character string of
2085 dpurdie 98
    **      [0] - Mode : c or d or r or l
2073 dpurdie 99
    **      [1] - Verbose : 0 .. 9
2072 dpurdie 100
    */
2073 dpurdie 101
    if ( argc > 1 )
2072 dpurdie 102
    {
2073 dpurdie 103
        if ( argv[1][0] == 'c' ) {
104
            copyMode = 1;
105
        } else if ( argv[1][0] == 'd' ) {
106
            copyMode = 2;
2075 dpurdie 107
        } else if ( argv[1][0] == 'r' ) {
108
            copyMode = 3;
2085 dpurdie 109
        } else if ( argv[1][0] == 'D' ) {
110
            copyMode = 4;
2073 dpurdie 111
        } else {
2075 dpurdie 112
            ErrorExit("Unknown mode: ",argv[1]);
2073 dpurdie 113
        }
114
 
115
        if ( argv[1][1] >= '0' && argv[1][1] <= '9' ) {
116
            verbose = argv[1][1] - '0';
117
        }
118
    }
119
 
120
    /*
121
    **  If Verbose, then display arguments
122
    */
2075 dpurdie 123
    if ( verbose > 1 )
2073 dpurdie 124
    {
2072 dpurdie 125
        int ii;
126
        for ( ii = 0; ii < argc ; ii++ )
127
        {
2073 dpurdie 128
            fprintf(stderr, "Arg%d: %ls:\n", ii, argv[ii] );
2072 dpurdie 129
        }
2073 dpurdie 130
        fprintf(stderr, "Mode   : %d:\n", copyMode );
131
        fprintf(stderr, "Verbose: %d:\n", verbose );
2072 dpurdie 132
        fflush(stderr) ;
133
    }
134
 
135
    /*
2073 dpurdie 136
    **  Determine cwd
137
    **  Used for ab path conversion
138
    */
139
    GetCurrentDirectory( MAX_FILE, currentDir );
2075 dpurdie 140
    if ( verbose > 1 )
2073 dpurdie 141
        fprintf(stderr, "CWD: %ls\n", currentDir );
2075 dpurdie 142
 
2073 dpurdie 143
    /*
2075 dpurdie 144
    **  Determine required operation
145
    */
146
    if ( copyMode == 3 )
147
    {
148
        deleteFileList(argc - 2, argv + 2 );
149
        return 0;
150
    }
151
 
2085 dpurdie 152
    if ( copyMode == 4 )
153
    {
154
        DeleteDir(argc - 2, argv + 2 );
155
        return 0;
156
    }
157
 
2075 dpurdie 158
    /*
2072 dpurdie 159
    **  Determine mode of operation
160
    **      Copy or Delete
161
    */
2073 dpurdie 162
    if ( copyMode == 1 && argc == 6 ) {
163
        fullPath( argv[4], src);
164
        fullPath( argv[3], dst);
165
 
166
    } else if ( copyMode == 2 && argc == 4) {
167
        fullPath( argv[3], dst);
168
 
2072 dpurdie 169
    } else {
2073 dpurdie 170
        fprintf(stderr, "Mode: %d, Args: %d\n", copyMode, argc);
171
        ErrorExit("Incorrect argument count for mode",L"");
2072 dpurdie 172
    }
173
 
174
    /*
175
    **  Display user text
176
    */
2073 dpurdie 177
    fprintf(stderr, "---- %ls %ls\n", argv[2], argv[3]);
2072 dpurdie 178
    fflush(stderr) ;
179
 
180
    /*
181
    **   Check that the source is a file
182
    */
2073 dpurdie 183
    if ( copyMode == 1 )
2072 dpurdie 184
    {
2073 dpurdie 185
        if ( verbose )
186
            fprintf(stderr, "Validate Source File: %ls\n", src);
187
 
188
        rv = GetFileAttributesW( src );
2072 dpurdie 189
        if ( rv == INVALID_FILE_ATTIBUTES )
190
        {
2073 dpurdie 191
    /* Need to be a better message */
192
            fprintf(stderr, "Source: %ls\n", src);
2075 dpurdie 193
            ErrorExit("Source File not found: ", argv[4]);
2072 dpurdie 194
        }
195
    }
196
 
197
    /*
198
    **  Remove the ReadOnly attribute on the dest file
199
    */
2073 dpurdie 200
    if ( verbose )
201
        fprintf(stderr, "Remove target file: %ls\n", dst);
202
    rv = GetFileAttributesW( dst );
2072 dpurdie 203
    if ( rv != INVALID_FILE_ATTIBUTES )
204
    {
205
        if ( verbose )
206
            fprintf(stderr, "FileExists with attr: %ld\n", rv);
207
        if ( rv & FILE_ATTRIBUTE_READONLY )
208
        {
209
            rv &= ~FILE_ATTRIBUTE_READONLY;
2073 dpurdie 210
            rv = SetFileAttributesW( dst, rv );
2072 dpurdie 211
            if ( rv == 0 )
212
            {
2075 dpurdie 213
                ErrorExit("Attempt to allow write access: ", argv[3]);
2072 dpurdie 214
            }
215
        }
216
 
2073 dpurdie 217
        if (! DeleteFile( dst ) )
2072 dpurdie 218
        {
2075 dpurdie 219
                ErrorExit("Deleting file: ", argv[3]);
2072 dpurdie 220
        }
221
    }
2073 dpurdie 222
 
223
    if ( copyMode == 1 )
2072 dpurdie 224
    {
225
        /*
226
        **  Create directories
227
        **  Use the path to the target - not the provided directory
228
        **  as the createPaths function will not create the last element
229
        */
2073 dpurdie 230
        createPaths( dst );
2072 dpurdie 231
 
232
        /*
233
        **   Copy the file
234
        */
2073 dpurdie 235
        if ( ! CopyFile( src, dst, FALSE ) )
2072 dpurdie 236
        {
237
            rv = GetLastError();
2075 dpurdie 238
            fprintf(stderr, "CopyFile Last Error: %ld\n", rv);
239
            ErrorExit("Copy Error: ", argv[4]);
2072 dpurdie 240
        }
241
 
242
        /*
243
        **  Test for files existence
244
        */
2073 dpurdie 245
        if ( verbose )
246
            fprintf(stderr, "Test target was copied: %ls\n", dst);
247
        rv = GetFileAttributesW( dst );
2072 dpurdie 248
        if ( rv == INVALID_FILE_ATTIBUTES )
249
        {
2073 dpurdie 250
    /* Need to be a better message */
2075 dpurdie 251
            ErrorExit("File not found after copy: ", argv[3]);
2072 dpurdie 252
        }
253
 
254
        /*
255
        **  Set the files attributes
256
        **      Assume read-only
257
        */
2073 dpurdie 258
        if ( _tcsstr( argv[5], L"-w" ) )
2072 dpurdie 259
        {
2073 dpurdie 260
            if ( verbose )
261
                fprintf(stderr, "Set target read-only: %ls\n", dst);
262
 
263
            rv |= FILE_ATTRIBUTE_READONLY;
264
            rv &= ~FILE_ATTRIBUTE_NORMAL;
265
            rv = SetFileAttributesW( dst, rv );
266
            if ( rv == 0 )
267
            {
2075 dpurdie 268
                ErrorExit("Setting ReadOnly: ", argv[3]);
2073 dpurdie 269
            }
2072 dpurdie 270
        }
271
    }
272
 
273
    return 0;
274
}
275
 
276
/*----------------------------------------------------------------------------
277
** FUNCTION           : createPaths
278
**
279
** DESCRIPTION        : Create the path to the target
280
**
281
**
282
** INPUTS             : path
2073 dpurdie 283
**                      Assumed to be a \\?\X:\ style
2072 dpurdie 284
**
285
** RETURNS            : Will not return in error
286
**
287
----------------------------------------------------------------------------*/
288
 
2073 dpurdie 289
void createPaths ( _TCHAR *path )
2072 dpurdie 290
{
291
    DWORD rv;
2073 dpurdie 292
    _TCHAR *ptr = path + 7;
2072 dpurdie 293
    while ( *ptr )
294
    {
2073 dpurdie 295
        if ( *ptr == '/' || *ptr == '\\')
2072 dpurdie 296
        {
297
            *ptr = 0;
2073 dpurdie 298
//fprintf(stderr, "createPaths: %ls\n", path);
299
            if ( ! CreateDirectoryW ( path, NULL ))
2072 dpurdie 300
            {
301
                rv = GetLastError();
302
                if ( rv != ERROR_ALREADY_EXISTS )
2075 dpurdie 303
                    ErrorExit("Could not create directories:", path);
2072 dpurdie 304
            }
305
            *ptr = '\\';
306
        }
307
        ptr++;
308
    }
309
}
310
 
2073 dpurdie 311
 
2072 dpurdie 312
/*----------------------------------------------------------------------------
2073 dpurdie 313
** FUNCTION           : fullPath
314
**
315
** DESCRIPTION        : Creates a full file path for user
316
**                      Convert relative path to ABS path with \\?\ from
317
**                      Convert / into \ for windows
318
**
319
**                      Handle path elements
320
**                          ./                  - Remove
321
**                          /bbb/../            - Remove
322
**                          /aaa/bbb/../../     - Remove
323
**
324
**
325
** INPUTS             : src         - Partial file path
326
**                      dst         - Area to create full name
327
**                                    Assumed to address a MAX_FILE space
328
**
329
** RETURNS            : Nothing
330
**
331
----------------------------------------------------------------------------*/
332
 
333
void fullPath ( _TCHAR * src, _TCHAR *dst )
334
{
335
    _TCHAR *udst = dst;
336
    _TCHAR *usrc = src;
337
	_tcscpy(dst, TEXT("\\\\?\\"));
2085 dpurdie 338
    if ( ( src[0] && (src[1] != ':') ) || src[0] == 0 )
2073 dpurdie 339
    {
340
	    _tcscat(dst, currentDir );
341
	    _tcscat(dst, TEXT("\\") );
342
    }
343
    udst += _tcslen(udst);
344
    while ( *usrc )
345
    {
346
        if ( *usrc == '/' ) {
347
            *udst++ = '\\';
348
        } else {
349
            *udst++ = *usrc;
350
        }
351
        usrc++;
352
    }
353
    *udst = 0;
354
 
355
    /*
356
    **  Now remove silly relative path bits
357
    */
358
    udst = dst;
359
    while ( *udst )
360
    {
2085 dpurdie 361
        if ( udst[0] == '\\' && udst[1] == '.' && (udst[2] == '\\' || udst[2] == 0) )
2073 dpurdie 362
        {
363
            TCHAR* ptr1 = udst;
364
            TCHAR* ptr2 = udst + 2;
365
            while ( *ptr1++ = *ptr2++ ) {}
366
        }
367
        else if ( udst[0] == '\\' && udst[1] == '.' && udst[2] == '.' && udst[3] == '\\'  )
368
        {
369
            TCHAR* ptr = udst - 1;
370
            TCHAR* ptr2 = udst + 3;
371
 
372
            while ( *ptr-- != '\\' )
373
            {
374
                if ( ptr - dst < 6)
375
                {
376
                    *ptr = 0;
377
                    fprintf(stderr, "Path: %ls\n", dst);
378
                    ErrorExit("Bad relative path: ", src);
379
                }
380
            }
381
            ptr++;
382
            udst = ptr;
383
            while ( *ptr++ = *ptr2++ ) {}
384
        }
385
        else
386
        {
387
            *udst++;
388
        }
389
    }
390
 
2075 dpurdie 391
if ( verbose > 1)
2073 dpurdie 392
    fprintf(stderr, "AbsPath: %ls\n", dst);
393
}
394
 
2075 dpurdie 395
/*----------------------------------------------------------------------------
396
** FUNCTION           : deleteFileList
397
**
398
** DESCRIPTION        : Delete a list of files
399
**                      Ensure files are writable
400
**
401
**
402
** INPUTS             : argc    - count of args
403
**                      argv    - list of files to delete
404
**
405
** RETURNS            : Wil not return on error
406
**
407
----------------------------------------------------------------------------*/
2073 dpurdie 408
 
2075 dpurdie 409
void deleteFileList( int argc, _TCHAR* argv[] )
410
{
411
	DWORD rv;
412
 
413
    for ( ; argc ; argc--, argv++ )
414
    {
415
        fullPath( *argv, dst);
416
 
417
        /*
418
        **  Remove the ReadOnly attribute on the dest file
419
        */
420
        if ( verbose > 1 )
421
            fprintf(stderr, "Remove target file: %ls\n", dst);
422
 
423
        rv = GetFileAttributesW( dst );
424
        if ( rv != INVALID_FILE_ATTIBUTES )
425
        {
426
            if ( verbose )
427
                fprintf(stderr, "Delete file: %ls : Attr: 0x%lx\n", *argv, rv);
428
            if ( rv & FILE_ATTRIBUTE_READONLY )
429
            {
430
                rv &= ~FILE_ATTRIBUTE_READONLY;
431
                rv = SetFileAttributesW( dst, rv );
432
                if ( rv == 0 )
433
                {
434
                    fprintf(stderr, "Warning: Attempt to allow write access: %ls\n", *argv);
435
                }
436
            }
437
 
438
            if (! DeleteFile( dst ) )
439
            {
440
                fprintf(stderr, "Warning: Did not remove file: %ls\n", *argv);
441
            }
442
        }
443
    }
444
}
445
 
2073 dpurdie 446
/*----------------------------------------------------------------------------
2085 dpurdie 447
** FUNCTION           : DeleteDir
448
**
449
** DESCRIPTION        : Delete a list of files in a specified directory
450
**                      Ensure files are writable
451
**                      Wilcarding is supported
452
**
453
**                      Then delete the directory - if its empty
454
**
455
**
456
** INPUTS             : argc    - count of args
457
**                      argv    - list of files to delete
458
**                                First entry is a directory
459
**
460
** RETURNS            : Wil not return on error
461
**
462
----------------------------------------------------------------------------*/
463
 
464
void DeleteDir( int argc, _TCHAR* argv[] )
465
{
466
	DWORD rv;
467
    _TCHAR* baseDir;
468
    WIN32_FIND_DATA FindFileData;
469
    HANDLE hFind;
470
 
471
    if ( argc < 3 )
472
        ErrorExit("Insuffiecient arguments for DeleteDir",L"");
473
 
474
    /*
475
    **  Display the user message
476
    **      Supress display if the message is empty
477
    */
478
    if ( argv[0][0] )
479
    {
480
        fprintf(stderr, "%ls\n", argv[0]);
481
        fflush(stderr) ;
482
    }
483
 
484
    /*
485
    **  Extract the base directory from the argument list
486
    **  This must be a directory
487
    */
488
    baseDir = argv[1];
489
    argc -= 2;
490
    argv+=2;
491
 
492
    /*
493
    **  Ensure that the base directory exists
494
    */
495
    fullPath( baseDir, dst);
496
    rv = GetFileAttributesW( dst );
497
    if ( rv == INVALID_FILE_ATTIBUTES )
498
    {
499
        /*
500
        **  Directory does not exists
501
        **  Assume its aleady deleted
502
        */
503
        if ( verbose > 1 )
504
            fprintf(stderr, "Base dir does not exist: %ls\n", baseDir);
505
        return;
506
    }
507
 
508
    if ( !(rv & FILE_ATTRIBUTE_DIRECTORY) )
509
    {
510
        /*
511
        **  Target is not a directory
512
        **  Don't do anything
513
        */
514
        if ( verbose > 1 )
515
            fprintf(stderr, "Base dir is not a directory: %ls\n", baseDir);
516
        return;
517
    }
518
 
519
    /*
520
    **  Process all the suffixes
521
    **  They may contain a wild card
522
    */
523
    for ( ; argc ; argc--, argv++ )
524
    {
525
    	_tcscpy(src, baseDir);
526
    	_tcscat(src, TEXT("\\"));
527
    	_tcscat(src, *argv);
528
        fullPath( src, dst);
529
 
530
        hFind = FindFirstFile(dst, &FindFileData);
531
        if (hFind == INVALID_HANDLE_VALUE)
532
        {
533
            /*
534
            **  No match
535
            */
536
            if ( verbose > 1 )
537
                fprintf(stderr, "No Match: %ls\n", dst);
538
            continue;
539
        }
540
 
541
        /*
542
        **  Iterate over all the files
543
        */
544
        do {
545
            if ( _tcscmp( TEXT("."), FindFileData.cFileName ) == 0 )
546
                continue;
547
 
548
            if ( _tcscmp( TEXT(".."), FindFileData.cFileName ) == 0 )
549
                continue;
550
 
551
            /*
552
            **  Create a full path to the file
553
            */
554
    	    _tcscpy(src, baseDir);
555
    	    _tcscat(src, TEXT("\\"));
556
    	    _tcscat(src, FindFileData.cFileName);
557
 
558
            if ( verbose )
559
                fprintf(stderr, "Match: %ls\n", FindFileData.cFileName);
560
 
561
            /*
562
            **  Force file to be writable
563
            */
564
            if ( FindFileData.dwFileAttributes  & FILE_ATTRIBUTE_READONLY)
565
            {
566
                rv = SetFileAttributesW( src, FindFileData.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY );
567
                if ( rv == 0 )
568
                {
569
                    fprintf(stderr, "Warning: Attempt to allow write access: %ls\n", FindFileData.cFileName);
570
                }
571
            }
572
 
573
            /*
574
            **  Delete the file
575
            */
576
            if (! DeleteFile( src ) )
577
            {
578
                fprintf(stderr, "Warning: Did not remove file: %ls\n", FindFileData.cFileName);
579
            }
580
 
581
        } while  (FindNextFile(hFind, &FindFileData) != 0);
582
        FindClose(hFind);
583
    }
584
 
585
    /*
586
    **  Finally delete the diretory
587
    **      Unless its '.'
588
    */
589
    if ( _tcscmp( TEXT("."),baseDir) != 0 )
590
    {
591
        fullPath( baseDir, dst);
592
        if ( verbose > 1 )
593
            fprintf(stderr, "Delete Directory: %ls\n", baseDir);
594
        if ( ! RemoveDirectory( dst ) )
595
        {
596
            if ( verbose )
597
                fprintf(stderr, "Directory not deleted: %ls\n", baseDir);
598
        }
599
    }
600
}
601
 
602
 
603
/*----------------------------------------------------------------------------
2072 dpurdie 604
** FUNCTION           : ErrorExit
605
**
606
** DESCRIPTION        : Error processing
607
**                      Report an error and terminate process
608
**
609
**
610
** INPUTS             : lpszMessage     - Message to display
611
**
612
** RETURNS            : Does't return
613
**                      Will exit with bad code
614
**
615
----------------------------------------------------------------------------*/
616
 
2073 dpurdie 617
VOID ErrorExit (char *lpszMessage, LPTSTR lpszMessage2)
2072 dpurdie 618
{ 
2075 dpurdie 619
   fprintf(stderr, "JatsFileUtil:Error:%s%ls\n", lpszMessage,lpszMessage2);
2072 dpurdie 620
   fflush(stderr) ;
621
   ExitProcess(-1);
622
} 
623