Subversion Repositories DevTools

Rev

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