Subversion Repositories DevTools

Rev

Rev 4814 | 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
**
2311 dpurdie 9
**  Description     :   Jats Build System File utility
10
**                      Used by the generated makefiles to perform specific operations
2072 dpurdie 11
**
2311 dpurdie 12
**                      The program exists to solve problems:
13
**                          Windows: Shell is very very slow to start up
14
**                          Windows: Some commands have ~260 character path length issue
15
**                          Windows/Solaris/Linux: Compatibility issues with the 'rm' command
16
**                          All: Consistent use of '/' as a path separator
2072 dpurdie 17
**
2311 dpurdie 18
**                      Note: There are two flavors of this program that MUST be
19
**                            kept in sync.
2310 dpurdie 20
**
2311 dpurdie 21
**                      The program will perform the following operations:
22
**                          (c) CopyFile
23
**                          (d) DeleteFile
24
**                          (r) Remove Files (wildcard)
25
**                          (D) DeleteDir after deleting specified files (wildcard)
2313 dpurdie 26
**                          (T) Delete Directory Trees
2354 dpurdie 27
**                          (R) Remove Files and Empty Directories
2764 dpurdie 28
**                          (P) Print Arguments
2311 dpurdie 29
**
30
**                      Example Usage
31
**
32
**                          JatsFileUtil c9 'copyFile'    aaa/bbb/ccc/dddd/file build_test.pl +w
33
**                          JatsFileUtil d9 'unCopyFile'  aaa/bbb/ccc/dddd/file
34
**                          JatsFileUtil r9 'deleteFile'  a1 b2 c3
35
**                          JatsFileUtil D9 'DeleteFiles' src/WIN32P.OBJ *.err *.pch '*'
36
**                          JatsFileUtil T9 'DeleteTree'  interface
2354 dpurdie 37
**                          JatsFileUtil R9 'RmItem'       build
2311 dpurdie 38
**
2310 dpurdie 39
**                      First two arguments are common to all
40
**                          argv[1]     - Mode specifier, Debug specifier
41
**                          argv[2]     - Display Text
42
**
2072 dpurdie 43
**  Information     :
2311 dpurdie 44
**   Compiler       : ANSI C
45
**   Target         : Windows 2000+, Linux, Solaris8+
2072 dpurdie 46
**
47
***==========================================================================*/
48
 
4814 dpurdie 49
#define _CRT_SECURE_NO_WARNINGS
50
 
2073 dpurdie 51
#include <tchar.h>
2072 dpurdie 52
#include <stdio.h>
53
#include <windows.h>
54
 
55
#define INVALID_FILE_ATTIBUTES ((DWORD) -1)
56
 
2073 dpurdie 57
VOID ErrorExit (char *lpszMessage, LPTSTR lpszMessage2);
58
void createPaths ( _TCHAR *path );
2085 dpurdie 59
void DeleteDir( int argc, _TCHAR* argv[] );
2310 dpurdie 60
_TCHAR * makePath( _TCHAR *base, _TCHAR *path);
61
void DeleteOneDirectoryTree( _TCHAR* baseDir );
62
void copyOneFile( int argc, _TCHAR* argv[] );
2354 dpurdie 63
void RmItem( int argc, _TCHAR* argv[] );
64
int DeleteOneFile (_TCHAR * dst );
65
void DeleteOneDirectory (_TCHAR *path );
66
void stdCheck( char *name, int argBad, _TCHAR *txt );
2764 dpurdie 67
void url_decode(_TCHAR *str);
2072 dpurdie 68
 
2073 dpurdie 69
/*
70
**  Global
71
*/
72
char  verbose = 1;                          /* Debugging aid */
2354 dpurdie 73
char  *helpText =
74
         "Usage: JatsFileUtil Mode Text Arguments\n"
75
         "\n"
76
         "  Where 'Mode' is two characters:\n"
77
         "      1 - Operation Specifier\n"
78
         "      2 - Debug Mode. 0..9\n"
79
         "  Where 'Text' is a, possibly empty, display string\n"
80
         "\n"
81
         "  By Example:\n"
5882 dpurdie 82
         "      c9 copyFile     dstPath srcPath modes(wxl)\n"
2354 dpurdie 83
         "      d9 unCopyFile   dstPath\n"
84
         "      r9 RmFile       file+\n"
85
         "      D9 DeleteFiles  dstDir file+ - supports (?*)\n"
86
         "      T9 DeleteTree   dstDir+\n"
2764 dpurdie 87
         "      R9 RmItem       (dir|file)+\n"
88
         "      P9 PrintArgs    ...\n";
2073 dpurdie 89
 
2072 dpurdie 90
/*----------------------------------------------------------------------------
91
** FUNCTION           : main
92
**
93
** DESCRIPTION        : Main entry points
94
**
95
**
2311 dpurdie 96
** INPUTS             : argc            - Argument Count
97
**                      argv            - Argument Vector
2072 dpurdie 98
**
99
** RETURNS            : 0 - All is good
100
**
101
----------------------------------------------------------------------------*/
2073 dpurdie 102
 
103
int _tmain(int argc, _TCHAR* argv[])
2072 dpurdie 104
{
2354 dpurdie 105
    _TCHAR * dst;
106
    int ii;
107
 
2072 dpurdie 108
    /*
2313 dpurdie 109
    **  User must provide some thing
110
    */
111
    if ( argc < 2 )
112
    {
2354 dpurdie 113
       fprintf(stderr, helpText );
114
       return 1;
2313 dpurdie 115
    }
116
 
117
    /*
2073 dpurdie 118
    **  Examine the first argument
119
    **  Must be a character string of
2311 dpurdie 120
    **      [0] - Mode : One character
2073 dpurdie 121
    **      [1] - Verbose : 0 .. 9
2072 dpurdie 122
    */
2310 dpurdie 123
    if ( argc > 1 && ( argv[1][1] >= '0' && argv[1][1] <= '9' ) )
2072 dpurdie 124
    {
2311 dpurdie 125
        verbose = argv[1][1] - '0';
2764 dpurdie 126
    }
2073 dpurdie 127
 
2764 dpurdie 128
    /*
129
    **  URL Decode most arguments
130
    **  To get past the stupidities of shells and make the arguments
131
    **  will have been URL(modified) encoded
132
    **
133
    **  Decode all args in place
134
    */
135
    for ( ii = 2; ii < argc ; ii++ )
136
    {
137
        url_decode(argv[ii]);
2311 dpurdie 138
        /*
139
        **  If Verbose, then display arguments
140
        */
141
        if ( verbose > 2 )
2764 dpurdie 142
            fprintf(stderr, "Arg%d: %ls:\n", ii, argv[ii] );
2072 dpurdie 143
    }
2764 dpurdie 144
     fflush(stderr) ;
2311 dpurdie 145
 
2072 dpurdie 146
    /*
2310 dpurdie 147
    **  Switch to required operation
2073 dpurdie 148
    */
2311 dpurdie 149
    switch( argv[1][0] )
2075 dpurdie 150
    {
2311 dpurdie 151
        /*
152
        **  CopyFile
153
        **      argv[2] - Text
154
        **      argv[3] - target path
155
        **      argv[4] - Source path
156
        **      argv[5] - File attributes
157
        */
2310 dpurdie 158
        case 'c':
2354 dpurdie 159
            stdCheck( "CopyFile", argc != 6, NULL );
160
            fprintf(stderr, "---- %ls %ls\n", argv[2], argv[3]);
161
            fflush(stderr) ;
2310 dpurdie 162
            copyOneFile(argc, argv);
163
            break;
2075 dpurdie 164
 
2311 dpurdie 165
        /*
166
        **  UnCopy a file
167
        **      argv[2] - Text
168
        **      argv[3] - target path
169
        */
2310 dpurdie 170
        case 'd':
2354 dpurdie 171
            stdCheck( "UnCopy", argc != 4, NULL );
172
            fprintf(stderr, "---- %ls %ls\n", argv[2], argv[3]);
173
            fflush(stderr) ;
2085 dpurdie 174
 
2354 dpurdie 175
            dst = makePath(argv[3], NULL);
176
            DeleteOneFile(dst);
177
            free (dst);
2310 dpurdie 178
            break;
2073 dpurdie 179
 
2311 dpurdie 180
        /*
181
        **  Remove named files
182
        **      argv[2]     - Text
183
        **      argv[3]+    - target path
184
        */
2310 dpurdie 185
        case 'r':
2354 dpurdie 186
            stdCheck( "RmFile", argc <= 3, argv[2] );
187
            for ( ii = 3; ii < argc ; ii++ )
188
            {
189
                _TCHAR * dst = makePath(argv[ii], NULL);
190
                DeleteOneFile(dst);
191
                free (dst);
192
            }
2310 dpurdie 193
            break;
2072 dpurdie 194
 
2311 dpurdie 195
        /*
196
        **  Delete files in directory - with wildcards
197
        **      argv[2]     - Text
198
        **      argv[3]     - Base directory
199
        **      argv[4]+    - Files in dir to delete.
200
        */
2310 dpurdie 201
        case 'D':
2354 dpurdie 202
            stdCheck( "DeleteDir", argc < 4, argv[2] );
203
            DeleteDir(argc, argv );
2310 dpurdie 204
            break;
2072 dpurdie 205
 
2311 dpurdie 206
        /*
207
        **  Delete files recursively
208
        **      argv[2] - Text
209
        **      argv[3]+  Base directory
210
        */
2310 dpurdie 211
        case 'T':
2354 dpurdie 212
            stdCheck( "DeleteDirTree", argc < 3, argv[2] );
213
            for ( ii = 3; ii < argc ; ii++)
214
            {
215
                DeleteOneDirectoryTree( argv[ii] );
216
            }
2310 dpurdie 217
            break;
2313 dpurdie 218
 
219
        /*
220
        **  Delete Empty Directories
221
        **      argv[2] - Text
222
        **      argv[3]+  Base directory
223
        */
224
        case 'R':
2354 dpurdie 225
            stdCheck( "RmItem", argc < 3, argv[2] );
226
            RmItem(argc, argv );
2313 dpurdie 227
            break;
2764 dpurdie 228
 
229
        /*
230
        **  Print arguments with a space betweenn them
231
        **  All on the same line
232
        **      argv[2]+ - Text
233
        */
234
        case 'P':
235
            for ( ii = 2; ii < argc ; ii++ )
236
            {
237
                if ( ii > 2 )
238
                    fprintf(stderr, " ");
239
                fprintf(stderr, "%ls", argv[ii] );
240
            }
241
            fprintf(stderr, "\n");
242
            break;
2073 dpurdie 243
 
2310 dpurdie 244
        default :
245
            ErrorExit("Unknown mode: ",argv[1]);
246
            break;
2072 dpurdie 247
    }
248
    return 0;
249
}
250
 
251
/*----------------------------------------------------------------------------
2354 dpurdie 252
** FUNCTION           : stdCheck
253
**
254
** DESCRIPTION        : Check arg count
255
**                      Print standard header
256
**
257
**
258
** INPUTS             : name        - Name of the operation
259
**                      argBad      - Arg count Not Ok
260
**                      text        - Text to print
261
**
262
** RETURNS            : Will not return on error
263
**
264
----------------------------------------------------------------------------*/
265
 
266
void stdCheck( char *name, int argBad, _TCHAR *txt )
267
{
268
    if ( argBad  )
269
    {
270
       fprintf(stderr, "JatsFileUtil:Incorrect argument count for %s\n", name);
271
       ErrorExit(NULL, NULL);
272
    }
273
 
274
    /*
275
    **  Display user text
276
    **      Suppress display if the message is empty
277
    */
278
    if ( txt && *txt )
279
    {
280
        fprintf(stderr, "%ls\n",txt);
281
        fflush(stderr) ;
282
    }
283
}
284
 
285
/*----------------------------------------------------------------------------
2072 dpurdie 286
** FUNCTION           : createPaths
287
**
288
** DESCRIPTION        : Create the path to the target
289
**
290
**
291
** INPUTS             : path
2073 dpurdie 292
**                      Assumed to be a \\?\X:\ style
2072 dpurdie 293
**
294
** RETURNS            : Will not return in error
295
**
296
----------------------------------------------------------------------------*/
297
 
2073 dpurdie 298
void createPaths ( _TCHAR *path )
2072 dpurdie 299
{
300
    DWORD rv;
2073 dpurdie 301
    _TCHAR *ptr = path + 7;
2072 dpurdie 302
    while ( *ptr )
303
    {
2073 dpurdie 304
        if ( *ptr == '/' || *ptr == '\\')
2072 dpurdie 305
        {
306
            *ptr = 0;
2073 dpurdie 307
//fprintf(stderr, "createPaths: %ls\n", path);
308
            if ( ! CreateDirectoryW ( path, NULL ))
2072 dpurdie 309
            {
310
                rv = GetLastError();
311
                if ( rv != ERROR_ALREADY_EXISTS )
2075 dpurdie 312
                    ErrorExit("Could not create directories:", path);
2072 dpurdie 313
            }
314
            *ptr = '\\';
315
        }
316
        ptr++;
317
    }
318
}
319
 
320
/*----------------------------------------------------------------------------
2310 dpurdie 321
** FUNCTION           : copyOneFile
2073 dpurdie 322
**
2310 dpurdie 323
** DESCRIPTION        : Copy one file to a target
324
**                      Used to package and install files
2073 dpurdie 325
**
326
**
2310 dpurdie 327
** INPUTS             : argc            - Argc count
328
**                      argv            - Argument list
329
**                          argv[2]     - Display text Prefix
330
**                          argv[3]     - Target path
331
**                          argv[4]     - Source Path
332
**                          argv[5]     - File attributes
2073 dpurdie 333
**
2310 dpurdie 334
** RETURNS            :
2073 dpurdie 335
**
336
----------------------------------------------------------------------------*/
337
 
2310 dpurdie 338
void copyOneFile( int argc, _TCHAR* argv[] )
2073 dpurdie 339
{
5882 dpurdie 340
    DWORD rv;
2310 dpurdie 341
    _TCHAR * src;
342
    _TCHAR * dst;
343
 
344
    dst = makePath(argv[3], NULL);
345
    src = makePath(argv[4], NULL);
346
 
347
    /*
348
    **   Check that the source is a file
349
    */
2354 dpurdie 350
    if ( verbose > 2)
2310 dpurdie 351
        fprintf(stderr, "Validate Source File: %ls\n", src);
352
 
353
    rv = GetFileAttributesW( src );
354
    if ( rv == INVALID_FILE_ATTIBUTES )
2073 dpurdie 355
    {
2310 dpurdie 356
/* Need to be a better message */
357
        fprintf(stderr, "Source: %ls\n", src);
358
        ErrorExit("Source File not found: ", argv[4]);
2073 dpurdie 359
    }
2310 dpurdie 360
 
361
    /*
2354 dpurdie 362
    **  Delete the destination file before the copy
363
    **  Will force it to be writable
2310 dpurdie 364
    */
365
    DeleteOneFile(dst);
366
 
367
    /*
368
    **  Create directories
369
    **  Use the path to the target - not the provided directory
370
    **  as the createPaths function will not create the last element
371
    */
372
    createPaths( dst );
373
 
374
    /*
375
    **   Copy the file
376
    */
377
    if ( ! CopyFile( src, dst, FALSE ) )
2073 dpurdie 378
    {
2310 dpurdie 379
        rv = GetLastError();
380
        fprintf(stderr, "CopyFile Last Error: %ld\n", rv);
381
        ErrorExit("Copy Error: ", argv[4]);
2073 dpurdie 382
    }
383
 
384
    /*
2310 dpurdie 385
    **  Test for files existence
2073 dpurdie 386
    */
2354 dpurdie 387
    if ( verbose > 1 )
2310 dpurdie 388
        fprintf(stderr, "Test target was copied: %ls\n", dst);
389
 
390
    rv = GetFileAttributesW( dst );
391
    if ( rv == INVALID_FILE_ATTIBUTES )
2073 dpurdie 392
    {
2310 dpurdie 393
/* Need to be a better message */
394
        ErrorExit("File not found after copy: ", argv[3]);
2073 dpurdie 395
    }
396
 
2310 dpurdie 397
    /*
398
    **  Set the files attributes
399
    **      Assume read-only
400
    */
401
    if ( _tcsstr( argv[5], L"-w" ) )
2075 dpurdie 402
    {
2310 dpurdie 403
        if ( verbose )
404
            fprintf(stderr, "Set target read-only: %ls\n", dst);
405
 
406
        rv |= FILE_ATTRIBUTE_READONLY;
407
        rv &= ~FILE_ATTRIBUTE_NORMAL;
408
        rv = SetFileAttributesW( dst, rv );
409
        if ( rv == 0 )
2075 dpurdie 410
        {
2310 dpurdie 411
            ErrorExit("Setting ReadOnly: ", argv[3]);
2075 dpurdie 412
        }
413
    }
414
}
415
 
2073 dpurdie 416
/*----------------------------------------------------------------------------
2085 dpurdie 417
** FUNCTION           : DeleteDir
418
**
419
** DESCRIPTION        : Delete a list of files in a specified directory
420
**                      Ensure files are writable
421
**                      Wilcarding is supported
422
**
423
**                      Then delete the directory - if its empty
424
**
425
**
426
** INPUTS             : argc    - count of args
427
**                      argv    - list of files to delete
2354 dpurdie 428
**                                [3]:  Base directory
429
**                                [4]+  Files in dir to delete
2085 dpurdie 430
**
2310 dpurdie 431
** RETURNS            : Will not return on error
2085 dpurdie 432
**
433
----------------------------------------------------------------------------*/
434
 
435
void DeleteDir( int argc, _TCHAR* argv[] )
436
{
5882 dpurdie 437
    DWORD rv;
2085 dpurdie 438
    _TCHAR* baseDir;
439
    WIN32_FIND_DATA FindFileData;
440
    HANDLE hFind;
2310 dpurdie 441
    _TCHAR *target;
442
    _TCHAR *dirPath;
2354 dpurdie 443
    int ii;
2085 dpurdie 444
 
445
    /*
446
    **  Extract the base directory from the argument list
447
    **  This must be a directory
448
    */
2354 dpurdie 449
    baseDir = argv[3];
2085 dpurdie 450
 
451
    /*
452
    **  Ensure that the base directory exists
453
    */
2310 dpurdie 454
    dirPath = makePath(baseDir, NULL);
455
    rv = GetFileAttributesW( dirPath );
2085 dpurdie 456
    if ( rv == INVALID_FILE_ATTIBUTES )
457
    {
458
        /*
459
        **  Directory does not exists
2311 dpurdie 460
        **  Assume its already deleted
2085 dpurdie 461
        */
462
        if ( verbose > 1 )
463
            fprintf(stderr, "Base dir does not exist: %ls\n", baseDir);
2310 dpurdie 464
        free(dirPath);
2085 dpurdie 465
        return;
466
    }
467
 
468
    if ( !(rv & FILE_ATTRIBUTE_DIRECTORY) )
469
    {
470
        /*
471
        **  Target is not a directory
472
        **  Don't do anything
473
        */
474
        if ( verbose > 1 )
475
            fprintf(stderr, "Base dir is not a directory: %ls\n", baseDir);
2310 dpurdie 476
        free(dirPath);
2085 dpurdie 477
        return;
478
    }
479
 
480
    /*
481
    **  Process all the suffixes
482
    **  They may contain a wild card
483
    */
2354 dpurdie 484
    for ( ii = 4; ii < argc ; ii++)
2085 dpurdie 485
    {
2354 dpurdie 486
        _TCHAR * thisDir = makePath( baseDir, argv[ii]);
2310 dpurdie 487
        hFind = FindFirstFile(thisDir, &FindFileData);
488
        free(thisDir);
489
 
2085 dpurdie 490
        if (hFind == INVALID_HANDLE_VALUE)
491
        {
492
            /*
493
            **  No match
494
            */
495
            if ( verbose > 1 )
2354 dpurdie 496
                fprintf(stderr, "No Match: %ls, %ls\n", baseDir, argv[ii]);
2085 dpurdie 497
            continue;
498
        }
499
 
500
        /*
501
        **  Iterate over all the files
502
        */
503
        do {
504
            if ( _tcscmp( TEXT("."), FindFileData.cFileName ) == 0 )
505
                continue;
506
 
507
            if ( _tcscmp( TEXT(".."), FindFileData.cFileName ) == 0 )
508
                continue;
509
 
2354 dpurdie 510
            if ( verbose > 1)
2085 dpurdie 511
                fprintf(stderr, "Match: %ls\n", FindFileData.cFileName);
512
 
513
            /*
2310 dpurdie 514
            **  Matching file found
2085 dpurdie 515
            */
2310 dpurdie 516
            target = makePath( baseDir, FindFileData.cFileName);
517
            DeleteOneFile(target);
518
            free (target);
2085 dpurdie 519
 
520
        } while  (FindNextFile(hFind, &FindFileData) != 0);
521
        FindClose(hFind);
522
    }
523
 
524
    /*
2311 dpurdie 525
    **  Finally delete the directory
2085 dpurdie 526
    **      Unless its '.'
527
    */
528
    if ( _tcscmp( TEXT("."),baseDir) != 0 )
529
    {
2354 dpurdie 530
        DeleteOneDirectory(baseDir);
2085 dpurdie 531
    }
2310 dpurdie 532
    free(dirPath);
2085 dpurdie 533
}
534
 
2310 dpurdie 535
/*----------------------------------------------------------------------------
536
** FUNCTION           : DeleteOneDirectoryTree
537
**
538
** DESCRIPTION        : Delete an entire directory tree(s)
2354 dpurdie 539
**                      Force it writable and searchable before deletion
540
**                      Don't follow symbolic links - just delete them
2310 dpurdie 541
**
542
** INPUTS             : path    - Dir to delete
543
**
544
** RETURNS            : Will not return on error
545
**
546
----------------------------------------------------------------------------*/
547
 
548
void DeleteOneDirectoryTree( _TCHAR* baseDir )
549
{
5882 dpurdie 550
    DWORD rv;
2310 dpurdie 551
    WIN32_FIND_DATA FindFileData;
552
    HANDLE hFind;
553
    _TCHAR *target;
554
    _TCHAR *dirPath;
555
    _TCHAR *thisDir;
556
 
557
    /*
558
    **  A bit of a sanity test
559
    */
560
    if ( _tcscmp( L".", baseDir) == 0 || _tcscmp( L"..", baseDir) == 0 )
561
    {
562
        fprintf(stderr, "DeleteOneDirectoryTree will not delete '.' or '..'\n");
563
        return;
564
    }
565
 
566
    /*
567
    **  Ensure that the base directory exists
568
    */
569
    dirPath = makePath(baseDir, NULL);
570
    rv = GetFileAttributesW( dirPath );
571
    if ( rv == INVALID_FILE_ATTIBUTES )
572
    {
573
        /*
574
        **  Directory does not exists
2311 dpurdie 575
        **  Assume its already deleted
2310 dpurdie 576
        */
577
        if ( verbose > 1 )
578
            fprintf(stderr, "Base dir does not exist: %ls\n", baseDir);
579
        free(dirPath);
580
        return;
581
    }
582
 
583
    if ( !(rv & FILE_ATTRIBUTE_DIRECTORY) )
584
    {
585
        /*
586
        **  Target is not a directory
587
        **  Don't do anything
588
        */
589
        if ( verbose > 1 )
590
            fprintf(stderr, "Base dir is not a directory: %ls\n", baseDir);
591
        free(dirPath);
592
        return;
593
    }
594
 
595
    /*
596
    **  Read next directory entry
597
    */
598
    thisDir = makePath( baseDir, TEXT("*"));
599
    hFind = FindFirstFile(thisDir, &FindFileData);
600
    free(thisDir);
601
 
602
    if (hFind != INVALID_HANDLE_VALUE)
603
    {
604
 
605
        /*
606
        **  Iterate over all the files
607
        */
608
        do {
609
            if ( _tcscmp( TEXT("."), FindFileData.cFileName ) == 0 )
610
                continue;
611
 
612
            if ( _tcscmp( TEXT(".."), FindFileData.cFileName ) == 0 )
613
                continue;
614
 
2313 dpurdie 615
            if ( verbose > 2 )
616
                fprintf(stderr, "Directory Entry:%ls,%ls\n", baseDir, FindFileData.cFileName );
617
 
2310 dpurdie 618
            /*
619
            **  Create a full path to the file
620
            */
621
            target = makePath( baseDir, FindFileData.cFileName);
622
            if ( FindFileData.dwFileAttributes  & FILE_ATTRIBUTE_DIRECTORY)
623
            {
624
                DeleteOneDirectoryTree( target );
625
            }
626
            else
627
            {
628
                DeleteOneFile (target);
629
            }
630
            free (target);
631
 
632
        } while  (FindNextFile(hFind, &FindFileData) != 0);
633
        FindClose(hFind);
634
    }
635
 
636
    /*
2311 dpurdie 637
    **  Finally delete the directory
2354 dpurdie 638
    **  It should now be empty
2310 dpurdie 639
    */
2354 dpurdie 640
    DeleteOneDirectory(baseDir);
2310 dpurdie 641
 
2354 dpurdie 642
    free(dirPath);
643
}
644
 
645
/*----------------------------------------------------------------------------
646
** FUNCTION           : RmItem
647
**
648
** DESCRIPTION        : Remove Empty directories and files
649
**
650
** INPUTS             : argc    - count of args
651
**                      argv    - list of files to delete
652
**                                [3]+  Base directory
653
**
654
** RETURNS            : Will not return on error
655
**
656
----------------------------------------------------------------------------*/
657
 
658
 
659
void RmItem( int argc, _TCHAR* argv[] )
660
{
661
    int ii;
662
    _TCHAR *target;
663
    DWORD rv;
664
 
665
    for ( ii = 3; ii < argc ; ii++)
2310 dpurdie 666
    {
2354 dpurdie 667
 
668
        if ( verbose > 2)
2450 dpurdie 669
            fprintf(stderr, "RmItem: %ls\n", argv[ii]);
2354 dpurdie 670
 
671
        target = makePath( argv[ii],NULL);
672
        rv = GetFileAttributesW( target );
673
        if ( rv != INVALID_FILE_ATTIBUTES )
674
        {
675
            if ( rv  & FILE_ATTRIBUTE_DIRECTORY)
676
            {
677
                DeleteOneDirectory( target );
678
            }
679
            else
680
            {
681
                DeleteOneFile (target);
682
            }
683
        }
684
        free(target);
2310 dpurdie 685
    }
686
}
687
 
688
/*----------------------------------------------------------------------------
689
** FUNCTION           : DeleteOneFile
690
**
691
** DESCRIPTION        : Delete a file
2354 dpurdie 692
**                      Low level deletion operation to be used by other functions
2310 dpurdie 693
**                      Force it writable before deletion
2354 dpurdie 694
**                      Don't follow symbolic links - just delete them
2310 dpurdie 695
**
696
** INPUTS             : path        - path to the file
697
**
698
** RETURNS            : 0           - OK (file deleted or not present)
699
**
700
----------------------------------------------------------------------------*/
701
 
702
int DeleteOneFile (_TCHAR * dst )
703
{
5882 dpurdie 704
    DWORD rv;
2310 dpurdie 705
    int result = 0;
706
 
707
    if ( verbose > 1)
708
        fprintf(stderr, "Delete File: %ls\n", dst);
709
 
710
    rv = GetFileAttributesW( dst );
711
    if ( rv != INVALID_FILE_ATTIBUTES )
712
    {
713
        if ( verbose )
714
            fprintf(stderr, "Delete file: %ls : Attr: 0x%lx\n", dst, rv);
715
        if ( rv & FILE_ATTRIBUTE_READONLY )
716
        {
717
            rv &= ~FILE_ATTRIBUTE_READONLY;
718
            rv = SetFileAttributesW( dst, rv );
719
            if ( rv == 0 )
720
            {
721
                fprintf(stderr, "Warning: Attempt to allow write access: %ls\n", dst);
722
            }
723
        }
724
 
725
        if (! DeleteFile( dst ) )
726
        {
727
            fprintf(stderr, "Warning: Did not remove file: %ls\n", dst);
728
            result = 1;
729
        }
730
    }
731
 
732
    return result;
733
}
734
 
735
/*----------------------------------------------------------------------------
2354 dpurdie 736
** FUNCTION           : DeleteOneDirectory
2313 dpurdie 737
**
2354 dpurdie 738
** DESCRIPTION        : Low level function to delete a directory
739
**                      Assumes that checks have been performed
740
**                          It is a directory
741
**                          It does exist
2313 dpurdie 742
**
743
**
2354 dpurdie 744
** INPUTS             : path            - Target Path
2313 dpurdie 745
**
2354 dpurdie 746
** RETURNS            : Nothing
747
**
2313 dpurdie 748
----------------------------------------------------------------------------*/
749
 
2354 dpurdie 750
void DeleteOneDirectory (_TCHAR *path )
2313 dpurdie 751
{
2354 dpurdie 752
    if ( verbose )
753
        fprintf(stderr, "Delete Directory: %ls\n", path);
2313 dpurdie 754
 
2354 dpurdie 755
    if ( ! RemoveDirectory(path))
2313 dpurdie 756
    {
2354 dpurdie 757
        if ( verbose )
758
            fprintf(stderr, "Directory not deleted: %ls\n", path);
2313 dpurdie 759
    }
760
}
761
 
762
/*----------------------------------------------------------------------------
2310 dpurdie 763
** FUNCTION           : makePath
764
**
765
** DESCRIPTION        : Creates a full file path for user
766
**                      Join 2 components together
767
**                      Convert relative path to ABS path with \\?\ from
768
**                      Convert / into \ for windows
769
**
770
**                      Handle path elements
771
**                          ./                  - Remove
772
**                          /bbb/../            - Remove
773
**                          /aaa/bbb/../../     - Remove
774
**
775
**
776
** INPUTS             : base        - Part 1
777
**                                    May already contain \\?\
778
**                      file        - Part 2 or NULL
779
**
780
** RETURNS            : fullPath - User must free memory
781
**
782
----------------------------------------------------------------------------*/
783
 
784
_TCHAR * makePath ( _TCHAR * base, _TCHAR *file )
785
{
4814 dpurdie 786
    size_t lenp = 0;
787
    size_t lencwd = 0;
788
    size_t len1 = _tcslen(base);
789
    size_t len2 = 0;
790
    size_t dlen = _tcslen(TEXT("\\\\?\\"));
2310 dpurdie 791
    _TCHAR *data;
792
    _TCHAR *cdata;
793
    _TCHAR *udst;
794
 
795
    /*
796
    **  If the base contains a \\?\ then we don't need to add it
797
    */
798
    if ( !( len1 > 3 && base[2] == '?' ) )
799
    {
2450 dpurdie 800
        lenp = dlen;
2310 dpurdie 801
    }
802
 
803
    /*
804
    **  Unless an absolute path we need to insert CWD too
805
    **  Just determine the length of the entry for now
806
    */
807
    if ( lenp && ( ( base[0] && (base[1] != ':') ) || base[0] == 0 ) )
808
    {
809
        lencwd = GetCurrentDirectory(0,0) - 1; // determine size needed
810
    }
811
 
812
    /*
813
    **  2nd file argument may be a NULL
814
    */
815
    if ( file )
816
    {
817
        len2 = _tcslen(file);
818
    }
819
 
820
    data = (_TCHAR *)malloc((lenp + lencwd+ len1 + len2 + 10) * sizeof(_TCHAR));
821
    cdata = data;
822
    if ( data == NULL )
823
    {
824
        ErrorExit ("Malloc error:makePath",L"");
825
    }
826
 
827
    /*
828
    **  Join all the strings together
829
    */
830
    if ( lenp )
831
    {
832
        _tcscpy( cdata,TEXT("\\\\?\\"));
833
        cdata += lenp;
834
    }
835
 
836
    if ( lencwd )
837
    {
4814 dpurdie 838
        GetCurrentDirectory((DWORD)(lencwd+1), cdata);
2310 dpurdie 839
        cdata += lencwd;
840
        _tcscpy( cdata, TEXT("\\"));
841
        cdata += 1;
842
    }
843
 
844
    _tcscpy( cdata, base);
845
    cdata += len1;
846
 
847
    if ( len2 )
848
    {
849
        _tcscpy( cdata, TEXT("\\"));
850
        _tcscpy( cdata+1, file);
851
        cdata += len2 + 1;
852
    }
853
 
854
    /*
855
    **  Convert / into \
856
    */
857
    for ( udst = data; *udst ; udst++)
858
    {
859
        if ( *udst == '/' )
860
            *udst = '\\';
861
    }
862
 
863
    /*
864
    **  Now remove silly relative path bits
2450 dpurdie 865
    **  Also duplicate '\\'
2310 dpurdie 866
    */
2450 dpurdie 867
    udst = data + dlen;
2310 dpurdie 868
    while ( *udst )
869
    {
2450 dpurdie 870
        if ( udst[0] == '\\' && udst[1] == '\\' )
871
        {
872
            TCHAR* ptr1 = udst;
873
            TCHAR* ptr2 = udst + 1;
874
            while ( *ptr1++ = *ptr2++ ) {}
875
            continue;
876
        }
877
 
2310 dpurdie 878
        if ( udst[0] == '\\' && udst[1] == '.' && (udst[2] == '\\' || udst[2] == 0) )
879
        {
880
            TCHAR* ptr1 = udst;
881
            TCHAR* ptr2 = udst + 2;
882
            while ( *ptr1++ = *ptr2++ ) {}
883
        }
884
        else if ( udst[0] == '\\' && udst[1] == '.' && udst[2] == '.' && udst[3] == '\\'  )
885
        {
886
            TCHAR* ptr = udst - 1;
887
            TCHAR* ptr2 = udst + 3;
888
 
889
            while ( *ptr-- != '\\' )
890
            {
891
                if ( ptr - data < 6)
892
                {
893
                    *ptr = 0;
894
                    fprintf(stderr, "Path: %ls\n", data);
895
                    ErrorExit("Bad relative path: ", data);
896
                }
897
            }
898
            ptr++;
899
            udst = ptr;
900
            while ( *ptr++ = *ptr2++ ) {}
901
        }
902
        else
903
        {
904
            *udst++;
905
        }
906
    }
907
 
2354 dpurdie 908
    if ( verbose > 5)
2310 dpurdie 909
        fprintf(stderr, "makePath: %ls\n", data);
910
 
911
    return data;
912
}
913
 
914
/*----------------------------------------------------------------------------
2764 dpurdie 915
** FUNCTION           : from_hex
916
**
917
** DESCRIPTION        : Converts a hex character to its integer value
918
**                      Expects well formed HEX
919
**
920
**
921
** INPUTS             : Character to convert
922
**
923
** RETURNS            : Character
924
**
925
----------------------------------------------------------------------------*/
926
_TCHAR from_hex(_TCHAR ch)
927
{
928
    if ( ch >= '0' && ch <= '9' )
929
    {
930
        return ch - '0';
931
    }
932
 
933
    if ( ch >= 'A' && ch <= 'F' )
934
    {
935
        return ch - 'A' + 10;
936
    }
937
 
938
    if ( ch >= 'a' && ch <= 'f' )
939
    {
940
        return ch - 'f' + 10;
941
    }
942
 
943
    return 0;
944
}
945
 
946
/*----------------------------------------------------------------------------
947
** FUNCTION           : url_decode
948
**
949
** DESCRIPTION        : Perform (modified) URL decoding of a string
950
**                      Only support %nn stuff
951
**                      Its done inplace
952
**
953
**
954
** INPUTS             : str             - String to process
955
**
956
** RETURNS            : Nothing
957
**
958
----------------------------------------------------------------------------*/
959
 
960
void url_decode(_TCHAR *str)
961
{
962
  _TCHAR *pstr = str;
963
  _TCHAR *pbuf = str;
964
 
965
    while (*pstr)
966
    {
967
        if (*pstr == '%')
968
        {
969
            if (pstr[1] && pstr[2])
970
            {
971
                *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
972
                pstr += 2;
973
            }
974
/*        } */
975
/*      } else if (*pstr == '+') {  */
976
/*              *pbuf++ = ' '; */
977
    }
978
    else
979
    {
980
        *pbuf++ = *pstr;
981
    }
982
        pstr++;
983
    }
984
    *pbuf = '\0';
985
}
986
 
987
/*----------------------------------------------------------------------------
2072 dpurdie 988
** FUNCTION           : ErrorExit
989
**
990
** DESCRIPTION        : Error processing
991
**                      Report an error and terminate process
992
**
993
**
994
** INPUTS             : lpszMessage     - Message to display
995
**
996
** RETURNS            : Does't return
997
**                      Will exit with bad code
998
**
999
----------------------------------------------------------------------------*/
1000
 
2073 dpurdie 1001
VOID ErrorExit (char *lpszMessage, LPTSTR lpszMessage2)
2354 dpurdie 1002
{
1003
    if ( lpszMessage  )
1004
    {
1005
        fprintf(stderr, "JatsFileUtil:Error:%s%ls\n", lpszMessage,lpszMessage2);
1006
    }
2072 dpurdie 1007
   fflush(stderr) ;
1008
   ExitProcess(-1);
1009
} 
1010