rtoss - Blame information for rev 267

Subversion Repositories:
Rev:
Rev Author Line No. Line
267 roytam 1 /* touch.c v1.22 - 2014-03-24
258 roytam 2 Update:
3   http://myc01.free.fr/touch
4  
5 License:
6   Public Domain Dedication (CC0 1.0)
7   http://creativecommons.org/publicdomain/zero/1.0/
8  
9 Usage:
10 touch.exe [-hxamcDsvq] [-r ref_file|-t time|-d date_time] -- <file_1> [file_N]
11  
12   -h : Show this help
13   -x : Modify creation time
14   -a : Modify access time
15   -m : Modify modification time
16   -c : Do not create file if not found
17   -r : Use a file or directory as a reference time source
18   -D : If target doesn't exist, create a directory
19   -s : Browse sub-directories
20   -v : Output the result of every file processed
21   -q : Silent mode, no error is displayed (disable '-v')
22   -t : Use time [[CC]YY]MMDDhhmm[.SS] instead of today
23   -d : Use date_time [[YYYY-]MM-DD][Thh:mm[:ss]] instead of today
24   -- : Finish options, followed by the file list
25 The options '-r', '-d' and '-t' can not be used simultaneously.
26 By default, all times will be modified (creation, access and modification).
27  
28 Examples:
29   touch.exe -sv -d 2011-04-23          -- ".\folder\*.txt"
30   touch.exe -cv -d           T10:55:00 -- *.dat
31   touch.exe -xv -d 2011-04-23T10:55    -- test2.txt test3.txt
32  
33 ********************************************************************************
34 Changelog:
267 roytam 35 1.22 - 2014-03-24
36   * fix '-c', '-D' switch, '-c' is always on and '-D' is ignored in 1.21
37   * make '--' optional
38  
258 roytam 39 1.21 - 2011-04-28
40   * fix decode date/time
41   * add touch folder with *.*
42   * Combination of the options '-s' '-v' : '-sv'
43  
44 1.2 - 2011-04-26
45   * argument from 'GetCommandLine' / 'CommandLineToArgv'
46   * change option '-d' to '-D'
47   * add option '-d date_time'
48  
49 1.1 - 2011-04-24
50   * add options '-v' verbose, '-s' scan-subfolder, '-q' silent mode
51  
52 1.0 - 2011-04-20
53   * initial version with options '-hxamcrdt -- file_n ...'
54 */
55  
56  
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <windows.h>
60  
265 roytam 61 #ifndef INVALID_FILE_ATTRIBUTES
62 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
63 #endif
64  
258 roytam 65 #define PRG_NAME  "Touch"
267 roytam 66 #define PRG_VERS  "1.22"
67 #define PRG_DATE  "2014-03-24"
258 roytam 68 #define PRG_LIC   "Public Domain Dedication (CC0 1.0)"
69  
70 /* Options in command line */
71 #define OPT_MODIFY_TIME_C     1  /* -x */
72 #define OPT_MODIFY_TIME_A     2  /* -a */
73 #define OPT_MODIFY_TIME_M     4  /* -m */
74 #define OPT_NO_CREATE         8  /* -c */
75 #define OPT_USE_REF_FILE     16  /* -r */
76 #define OPT_USER_TIME        32  /* -t */
77 #define OPT_USER_DATE        64  /* -d */
78 #define OPT_CREATE_DIR      128  /* -D */
79 #define OPT_VERBOSE         256  /* -v */
80 #define OPT_RECURSIVE       512  /* -s */
81 #define OPT_QUIET          1024  /* -q */
82  
83 #define CommandLineToArgv  _CommandLineToArgvA
84 #define LEN_PATH           1024     /* _MAX_PATH = 260 */
85  
86 LPFILETIME lpTimeC, lpTimeA, lpTimeM;
87 DWORD      dwOptions;
88 HANDLE     hStdOut;
89  
90 char **ARGV;
91 int    ARGC;
92  
93  
94 char **_CommandLineToArgvA (const char *CmdLine, int *pnArgc)
95 {
96     char           a;
97     char         **argv, *pcArgv;
98     unsigned long  len, i, j, argc = 0;
99     int            in_QM = FALSE, in_TEXT = FALSE, in_SPACE = TRUE;
100  
101     len = strlen (CmdLine);
102     i = ( (len + 2) / 2) * sizeof (void*) + sizeof (void*);
103  
104     argv   = (char**) calloc (i + (len + 2) * sizeof (char), 1);
105     pcArgv = (char*) ( ( (unsigned char*) argv) + i);
106  
107     argv[argc] = pcArgv;
108     i = j = 0;
109  
110     while ( (a = CmdLine[i]) )
111     {
112         if (in_QM)
113         {
114             if (a == '\"')
115                 in_QM = FALSE;
116             else
117                 pcArgv[j++] = a;
118         }
119         else
120         {
121             switch (a)
122             {
123             case '\"':
124                 in_QM = in_TEXT = TRUE;
125                 if (in_SPACE)
126                     argv[argc++] = pcArgv + j;
127                 in_SPACE = FALSE;
128                 break;
129             case ' ' :
130             case '\t':
131             case '\n':
132             case '\r':
133                 if (in_TEXT)
134                     pcArgv[j++] = '\0';
135                 in_TEXT  = FALSE;
136                 in_SPACE = TRUE;
137                 break;
138             default:
139                 in_TEXT = TRUE;
140                 if (in_SPACE)
141                     argv[argc++] = pcArgv + j;
142                 pcArgv[j++] = a;
143                 in_SPACE = FALSE;
144                 break;
145             }
146         }
147         i++;
148     }
149     pcArgv[j]  = '\0';
150     argv[argc] = NULL;
151  
152     (*pnArgc) = argc;
153     return argv;
154 }  /* _CommandLineToArgvA */
155  
156  
157 BOOL FolderExists (LPCTSTR lpPath)
158 {
159     DWORD Attr = GetFileAttributes (lpPath);
160     if (Attr != INVALID_FILE_ATTRIBUTES)
161         if (Attr & FILE_ATTRIBUTE_DIRECTORY)
162             return TRUE;
163  
164     return FALSE;
165 }  /* FolderExists */
166  
167  
168 BOOL Exists (LPCTSTR lpFileName)
169 {
170     if (GetFileAttributes (lpFileName) != INVALID_FILE_ATTRIBUTES)
171         return TRUE;
172     else if (GetLastError () == ERROR_SHARING_VIOLATION)
173         return TRUE;
174     return FALSE;
175 } /* Exists */
176  
177  
178 int printFileTime (LPFILETIME lpFileTime)
179 {
180     FILETIME   fTime;
181     SYSTEMTIME sTime;
182  
265 roytam 183     if (!lpFileTime) return 0;
184  
258 roytam 185     FileTimeToLocalFileTime (lpFileTime, &fTime);
186     FileTimeToSystemTime    (&fTime    , &sTime);
187     return printf ("%04hu"      "-%02hu"      "-%02hu"    "T%02hu"     ":%02hu"       ":%02hu",
188                    sTime.wYear, sTime.wMonth, sTime.wDay, sTime.wHour, sTime.wMinute, sTime.wSecond);
189 }  /* printFileTime */
190  
191  
192 int printfOem (LPCTSTR lpFmt, ...)
193 {
266 roytam 194     PCHAR lpBuf;
195     INT nLen;
258 roytam 196     if (dwOptions & OPT_QUIET) return 0;
197     if (! lpFmt) return 0;
198     if (!*lpFmt) return 0;
199  
265 roytam 200     lpBuf = calloc (LEN_PATH, 1);
201     nLen = _vsnprintf (lpBuf, LEN_PATH, lpFmt, (va_list)(&lpFmt + 1));
258 roytam 202     if (nLen < 0)
203         nLen = strlen (lpBuf);
204     CharToOemBuff (lpBuf, lpBuf, nLen);
205     WriteConsole (hStdOut, lpBuf, nLen, (PDWORD)&nLen, NULL);
206     free (lpBuf);
207     return nLen;
208 }  /* printfOem */
209  
210  
211 DWORD Touch (LPCTSTR lpFileName)
212 {
266 roytam 213     DWORD dwFileAttributes, dwResult;
214     HANDLE hFile;
215     BOOL bCreateDir;
258 roytam 216     SetLastError (ERROR_SUCCESS);
265 roytam 217     dwFileAttributes = GetFileAttributes (lpFileName);
218     dwResult = GetLastError ();
258 roytam 219     if ((dwFileAttributes == INVALID_FILE_ATTRIBUTES) && (dwResult != ERROR_FILE_NOT_FOUND))
220         return dwResult;
221  
265 roytam 222     bCreateDir = ((OPT_CREATE_DIR   & dwOptions)                && (dwFileAttributes == INVALID_FILE_ATTRIBUTES)) ||
258 roytam 223                       ((dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (dwFileAttributes != INVALID_FILE_ATTRIBUTES));
224  
225     /* If target doesn't exist, create a directory. */
226     if (bCreateDir && (dwFileAttributes == INVALID_FILE_ATTRIBUTES))
227     {
228         SetLastError (ERROR_SUCCESS);
229         if (!CreateDirectory (lpFileName, NULL))
230         {
231             if ((dwResult = GetLastError ()) != ERROR_ALREADY_EXISTS)
232                 return dwResult;
233         }
234         else
235             return ERROR_SUCCESS;  /* Done, the directory is created. */
236     }
237  
238     SetLastError (ERROR_SUCCESS);
265 roytam 239     hFile = CreateFile (lpFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
258 roytam 240                                ( (dwOptions & OPT_NO_CREATE) || bCreateDir) ? OPEN_EXISTING : OPEN_ALWAYS,
241                                FILE_ATTRIBUTE_NORMAL | (bCreateDir ? FILE_FLAG_BACKUP_SEMANTICS : 0), 0);
242     dwResult = GetLastError ();
243  
244     /* Check for CreateFile() special cases */
245     if (hFile == INVALID_HANDLE_VALUE)
246     {
247         if ( (dwOptions & OPT_NO_CREATE) && dwResult == ERROR_FILE_NOT_FOUND)
248             return ERROR_SUCCESS;  /* not an error */
249         else if (dwResult == ERROR_ALREADY_EXISTS)
250             dwResult = ERROR_SUCCESS;  /* not an error according to MSDN docs */
251         return dwResult;
252     }
253  
254     if (lpTimeC || lpTimeA || lpTimeM)
255     {
256         if (SetFileTime (hFile, lpTimeC, lpTimeA, lpTimeM))
257         {
258             if ( (dwOptions & OPT_VERBOSE) && !(dwOptions & OPT_QUIET) )
259                 printfOem     ("%s\n", lpFileName);  /*
260                 printf        ("%s\n", lpFileName);  */
261             dwResult = ERROR_SUCCESS;
262         }
263         else
264             dwResult = GetLastError ();
265     }
266     CloseHandle (hFile);
267  
268     return dwResult;
269 }  /* Touch */
270  
271  
272 BOOL PrintHelp (LPCTSTR lpMessage)
273 {
274     if (lpMessage)
275         printf ("%s\n\n", lpMessage);
276  
277     puts (PRG_NAME" v"PRG_VERS" ("PRG_DATE") - License: "PRG_LIC);  /*
278     puts ("********************************************************************************"); */
279     puts ("Usage:\n"
259 roytam 280           "touch.exe [-hxamcDsvq] [-r ref_file|-t time|-d date_time] [--] <file_1> [file_N]");
258 roytam 281     puts ("  -h : Show this help\n"
282           "  -x : Modify creation time\n"
283           "  -a : Modify access time\n"
284           "  -m : Modify modification time\n"
285           "  -c : Do not create file if not found\n"
286           "  -r : Use a file or directory as a reference time source\n"
287           "  -D : If target doesn't exist, create a directory\n"
288           "  -s : Browse sub-directories\n"
289           "  -v : Output the result of every file processed\n"
290           "  -q : Silent mode, no error is displayed (disable '-v')\n"
291           "  -t : Use time [[CC]YY]MMDDhhmm[.SS] instead of today\n"
292           "  -d : Use date_time [[YYYY-]MM-DD][Thh:mm[:ss]] instead of today\n"
293           "  -- : Finish options, followed by the file list\n"
259 roytam 294           "       Without this switch, only last entry will be processed\n"
258 roytam 295           "The options '-r', '-d' and '-t' can not be used simultaneously.\n"
296           "By default, all times will be modified (creation, access and modification).");
297     puts ("Examples:\n"
298           "  touch.exe -sv -d 2011-04-23          -- \".\\folder\\*.txt\"\n"
299           "  touch.exe -cv -d           T10:55:00 -- *.dat\n"
300           "  touch.exe -xv -d 2011-04-23T10:55    -- test2.txt test3.txt");
301  
302     return FALSE;
303 }  /* PrintHelp */
304  
305  
306 /* Prints a message translated from a Windows Error code, then prints the usage */
307 PCHAR PrintError (LPCTSTR lpInfo, DWORD dwError)
308 {
265 roytam 309     LPTSTR lpText = NULL;
258 roytam 310     if (dwOptions & OPT_QUIET) return NULL;
311  
312     FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
313                    NULL, dwError, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpText, 0, NULL);
314     printfOem ("\nError: %s = %s", lpInfo, lpText);
315     LocalFree (lpText);
316  
317     return NULL;
318 }  /* PrintError */
319  
320  
321 BOOL GetArgs (LPDWORD dwList, LPTSTR *lpRefFile, LPTSTR *lpDateTime, LPDWORD dwOptions)
322 {
266 roytam 323     int i, find_double_dash = 0;
258 roytam 324     if (ARGC < 2)
325         return PrintHelp (NULL);
326     else if (ARGC == 2)
327     {
266 roytam 328         if (ARGV[1][0] == '-' && ARGV[1][0] == 'h')
258 roytam 329             return PrintHelp (NULL);
330         else if (ARGV[1][0] == '-')
331             return PrintHelp ("Error 1: Not enough arguments.");
332         *dwList = 1;
333     }
334     else
335     {
266 roytam 336         for(i = 1; i < (find_double_dash ? *dwList : (DWORD)ARGC); i++) {
337             if(ARGV[i][0]=='-') {
338                 switch(ARGV[i][1]) {
339                     case 'x':
340                         *dwOptions |= OPT_MODIFY_TIME_C;
341                         break;
342                     case 'a':
343                         *dwOptions |= OPT_MODIFY_TIME_A;
344                         break;
345                     case 'm':
346                         *dwOptions |= OPT_MODIFY_TIME_M;
347                         break;
348                     case 'c':
349                         *dwOptions |= OPT_NO_CREATE;
350                         break;
351                     case 'D':
352                         *dwOptions |= OPT_CREATE_DIR;
353                         break;
354                     case 'v':
355                         *dwOptions |= OPT_VERBOSE;
356                         break;
357                     case 's':
358                         *dwOptions |= OPT_RECURSIVE;
359                         break;
360                     case 'q':
361                         *dwOptions |= OPT_QUIET;
362                         break;
363                     case 'h':
364                         return PrintHelp (NULL);
365                     case '-':
366                         find_double_dash = 1;
367                         *dwList = i;
368                         break;
369                     case 'r':
370                         if(i+1 < ARGC) {
371                             *lpRefFile = ARGV[++i];
372                             *dwOptions |= OPT_USE_REF_FILE;
373                         }
374                         break;
375                     case 'd':
376                         if(i+1 < ARGC) {
377                             *lpDateTime = ARGV[++i];
378                             *dwOptions |= OPT_USER_DATE;
379                         }
380                         break;
381                     case 't':
382                         if(i+1 < ARGC) {
383                             *lpDateTime = ARGV[++i];
384                             *dwOptions |= OPT_USER_TIME;
385                         }
386                         break;
387                 }
388             } else {
258 roytam 389                 break;
266 roytam 390             }
391         }
258 roytam 392  
266 roytam 393         if(!find_double_dash && i < ARGC) {
394             *dwList = i;
395         }
396  
397         if ((find_double_dash && ++(*dwList) >= (DWORD)ARGC) ||
398             (!find_double_dash && (*dwList) >= (DWORD)ARGC))
399             return PrintHelp ("Error 2: No file(s) specified!");
258 roytam 400     }
401  
402     if ( (*dwOptions & OPT_USE_REF_FILE) &&  (*dwOptions & OPT_USER_TIME) )
403         return PrintHelp ("Error 3: You may not specify both '-r' and '-t'.");
404  
405     if ( (*dwOptions & OPT_USE_REF_FILE) &&  (*dwOptions & OPT_USER_DATE) )
406         return PrintHelp ("Error 4: You may not specify both '-r' and '-d'.");
407  
408     if ( (*dwOptions & OPT_USER_TIME   ) &&  (*dwOptions & OPT_USER_DATE) )
409         return PrintHelp ("Error 5: You may not specify both '-t' and '-d'.");
410  
411     if ( (*dwOptions & OPT_USE_REF_FILE) && !(*lpRefFile                ) )
412         return PrintHelp ("Error 6: You must specify a 'ref_file' together with '-r'.");
413  
414     if ( (*dwOptions & OPT_USER_TIME   ) && !(*lpDateTime               ) )
415         return PrintHelp ("Error 7: You must specify a timestamp together with '-t'.");
416  
417     /* If -x, -a and -m wasn't specified, then all of them are implied */
418     if (! (*dwOptions &  (OPT_MODIFY_TIME_C | OPT_MODIFY_TIME_A | OPT_MODIFY_TIME_M) ) )
419            *dwOptions |= (OPT_MODIFY_TIME_C | OPT_MODIFY_TIME_A | OPT_MODIFY_TIME_M);
420  
421     return TRUE;
422 }  /* GetArgs */
423  
424  
425 /* Gets FILETIME from a file */
426 BOOL GetFileTimes (LPCTSTR lpFileName, LPFILETIME fTimeC, LPFILETIME fTimeA, LPFILETIME fTimeM)
427 {
428     BOOL bResult = TRUE;
429     HANDLE hFile = CreateFile (lpFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
430                                NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
431  
432     if (INVALID_HANDLE_VALUE == hFile)
433         return PrintHelp (PrintError (lpFileName, GetLastError ()));
434  
435     if (!GetFileTime (hFile, fTimeC, fTimeA, fTimeM))
436         bResult = PrintHelp (PrintError (lpFileName, GetLastError ()));
437  
438     CloseHandle (hFile);
439     return bResult;
440 }  /* GetFileTimes */
441  
442  
443 /* Format: ISO 8601:2004(E)
444     http://en.wikipedia.org/wiki/ISO_8601
445     http://dotat.at/tmp/ISO_8601-2004_E.pdf
446     Extended format: YYYY-MM-DDThh:mm:ss Example: 1985-04-12T10:15:30
447  
448     [[[YYYY-]MM-DD][Thh:mm[:ss]]]
449     123456789ABCDEF1234
450     YYYY-MM-DDThh:mm:ss
451     YYYY-MM-DD
452     MM-DD
453     Thh:mm:ss
454     Thh:mm
455 */
456 BOOL DecodeDateTime (LPTSTR lpDateTime, LPSYSTEMTIME st)
457 {
458     char *pTime;
459     int nLen = (lpDateTime) ? strlen (lpDateTime) : 0;
460  
461     if ((nLen < 5) || (nLen > 19))
462         return PrintHelp ("Error 8: Invalid time format.");
463  
464     if (nLen && (pTime = strchr (lpDateTime, 'T')))
465     {
466         st->wSecond = st->wMilliseconds = 0;
467         nLen = strlen (pTime);
468              if (nLen == 9)  /* Thh:mm:ss */
469             sscanf (pTime, "T%02hu:%02hu:%02hu", &st->wHour, &st->wMinute, &st->wSecond);
470         else if (nLen == 6)  /* Thh:mm    */
471             sscanf (pTime, "T%02hu:%02hu"      , &st->wHour, &st->wMinute              );
472         else if (nLen >  0)
473             return PrintHelp ("Error 9: Invalid time format.");
474         *pTime = '\0';
475         nLen = strlen (lpDateTime);
476     }
477  
478     if (nLen > 0)
479     {
480              if (nLen == 10)  /* YYYY-MM-DD */
481             sscanf (lpDateTime, "%4hu-%02hu-%02hu", &st->wYear, &st->wMonth, &st->wDay);
482         else if (nLen ==  5)  /*      MM-DD */
483             sscanf (lpDateTime,      "%02hu-%02hu",             &st->wMonth, &st->wDay);
484         else
485             return PrintHelp ("Error 10: Invalid date format.");
486     }
487     return TRUE;
488 }  /* DecodeDateTime */
489  
490  
491 /* Format:
492   [[CC]YY]MMDDhhmm[.SS]
493   123456789ABCDEF
494   CCYYMMDDhhmm.SS
495   CCYYMMDDhhmm
496   MMDDhhmm
497  */
498 BOOL DecodeTime (LPTSTR lpDateTime, LPSYSTEMTIME st)
499 {
500     PCHAR pSec;
501     INT   nLen = (lpDateTime) ? strlen (lpDateTime) : 0;
502     WORD  CC = st->wYear / 100;
503     WORD  YY = st->wYear % 100;
504     st->wSecond = st->wMilliseconds = 0;
505  
506     if ((nLen < 8) || (nLen > 15))
507         return PrintHelp ("Error 11: Invalid time format.");
508  
509     if ((pSec = strchr (lpDateTime, '.')))
510     {
511         sscanf (pSec, ".%02hu", &st->wSecond);
512         *pSec = '\0';
513         nLen = strlen (lpDateTime);
514     }
515  
516     if (nLen > 0)
517     {
518              if (nLen == 12)  /* CC  YY   MM   DD  hh  mm */
519             sscanf (lpDateTime, "%2hu%02hu%02hu%2hu%2hu%2hu", &CC, &YY, &st->wMonth, &st->wDay, &st->wHour, &st->wMinute);
520         else if (nLen == 10)  /*     YY   MM   DD  hh  mm */
521             sscanf (lpDateTime,     "%02hu%02hu%2hu%2hu%2hu",      &YY, &st->wMonth, &st->wDay, &st->wHour, &st->wMinute);
522         else if (nLen ==  8)  /*          MM   DD  hh  mm */
523             sscanf (lpDateTime,          "%02hu%2hu%2hu%2hu",           &st->wMonth, &st->wDay, &st->wHour, &st->wMinute);
524         else
525             return PrintHelp ("Error 12: Invalid date format.");
526         if (nLen == 10)
527             CC = (YY < 69) ? 20 : 19;
528         st->wYear = CC * 100 + YY;
529     }
530     return TRUE;
531 }  /* DecodeTime */
532  
533  
534 BOOL StrToFileTime (LPTSTR lpDateTime, LPFILETIME ts)
535 {
265 roytam 536     FILETIME ft;
537     SYSTEMTIME st;
258 roytam 538     INT nLen = (lpDateTime) ? strlen (lpDateTime) : 0;
539     GetLocalTime (&st);
540  
541     if (nLen)
542     {
543         if (strchr (lpDateTime, ':') || strchr (lpDateTime, '-'))
544         {
545             if (!DecodeDateTime (lpDateTime, &st))  /* [[[YYYY-]MM-DD][Thh:mm[:ss]]] */
546                 return FALSE;
547         }
548         else
549         {
550             if (!DecodeTime (lpDateTime, &st))  /* [[CC]YY]MMDDhhmm[.SS] */
551                 return FALSE;
552         }
553     }
554  
555     if (!SystemTimeToFileTime (&st, &ft))
556         return PrintHelp (PrintError ("13 SystemTimeToFileTime()"   , GetLastError ()));
557  
558     if (!LocalFileTimeToFileTime (&ft, ts))
559         return PrintHelp (PrintError ("14 LocalFileTimeToFileTime()", GetLastError ()));
560  
561     return TRUE;
562 }  /* StrToFileTime */
563  
564  
565 DWORD FindFileRecursive (LPCTSTR lpDir, LPCTSTR lpFindName)
566 {
567     DWORD           dwResult = ERROR_SUCCESS;
568     HANDLE          hFile;
569     CHAR            szPath[LEN_PATH];
570     WIN32_FIND_DATA fData;
571  
572     strcpy (szPath, lpDir);
573     strcat (szPath, "\\");
574     strcat (szPath, (*lpFindName) ? lpFindName : "*.*");
575  
576     if ((hFile = FindFirstFile (szPath, &fData)) == INVALID_HANDLE_VALUE)
577         return GetLastError ();
578  
579     do
580     {
581         if (!strcmp (fData.cFileName, ".") || !strcmp (fData.cFileName, ".."))
582             continue;
583  
584         strcpy (szPath, lpDir);
585         strcat (szPath, "\\");
586         strcat (szPath, fData.cFileName);
587  
588         if (fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
589         {
590             if (fData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
591                 continue;
592  
593             if ((dwResult = Touch (szPath)) != ERROR_SUCCESS)
594                 PrintError (szPath, dwResult);
595  
596             if (dwOptions & OPT_RECURSIVE)
597             {
598                 if ((dwResult = FindFileRecursive (szPath, lpFindName)) != ERROR_SUCCESS)
599                 {
600                     FindClose (hFile);
601                     return dwResult;
602                 }
603             }
604         }
605         else
606             if ((dwResult = Touch (szPath)) != ERROR_SUCCESS)
607                 PrintError (szPath, dwResult);
608     }
609     while (FindNextFile (hFile, &fData));
610  
611     FindClose (hFile);
612     return dwResult;
613 }  /* FindFileRecursive */
614  
615  
616 int ExitCode (int status)
617 {
618     free (ARGV);
619     exit (status);
620 }  /* ExitCode */
621  
622  
623 int main (void)  /* (int argc, char *argv[]) */
624 {
625     DWORD     dwFilesList, dwResult;
626     CHAR      szPath [LEN_PATH], szFullPath [LEN_PATH], szFindName[_MAX_FNAME];
627     CHAR      szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFileName[_MAX_FNAME], szExt[_MAX_EXT];
628     PCHAR     lpRefFile = NULL, lpDateTime = NULL;
629     FILETIME  fTimeC, fTimeA, fTimeM;
259 roytam 630     HANDLE    fh;
258 roytam 631  
632     ARGV = CommandLineToArgv (GetCommandLine (), &ARGC);
633     hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
634  
635     if (!GetArgs (&dwFilesList, &lpRefFile, &lpDateTime, &dwOptions))
636         ExitCode (-1);
637  
638     if (dwOptions & OPT_USE_REF_FILE)
639     {
640         if (!GetFileTimes (lpRefFile, &fTimeC, &fTimeA, &fTimeM))
641             ExitCode (-1);
642     }
643     else
644     {
645         if (!StrToFileTime (lpDateTime, &fTimeM))
646             ExitCode (-1);
647         fTimeC = fTimeA = fTimeM;
648     }
649  
650     lpTimeC = (dwOptions & OPT_MODIFY_TIME_C) ? &fTimeC : NULL;
651     lpTimeA = (dwOptions & OPT_MODIFY_TIME_A) ? &fTimeA : NULL;
652     lpTimeM = (dwOptions & OPT_MODIFY_TIME_M) ? &fTimeM : NULL;
653  
654     if ( (dwOptions & OPT_VERBOSE) && !(dwOptions & OPT_QUIET) )
655     {
656         printf (    "Create       = ");
657         printf ("%s\nAccess       = ", printFileTime (lpTimeC) ? "" : "unchanged");
658         printf ("%s\nModification = ", printFileTime (lpTimeA) ? "" : "unchanged");
659         printf ("%s\n\n"             , printFileTime (lpTimeM) ? "" : "unchanged");
660     }
661  
662     while (dwFilesList < (DWORD)ARGC)
663     {
664         /* puts */ (strcpy (szPath, ARGV[dwFilesList++]));
665  
666         if (szPath[strlen (szPath) - 1] == '\"')
667             szPath[strlen (szPath) - 1]  = '\\';
668  
261 roytam 669  
670         if (!(dwOptions & OPT_RECURSIVE) )  /* file or directory */
259 roytam 671         {
672             _fullpath (szFullPath, szPath, LEN_PATH);
258 roytam 673             if ((dwResult = Touch (szFullPath)) != ERROR_SUCCESS)
674                 PrintError (szPath, dwResult);
675         }
676         else if ( strchr (szPath, '*') || (dwOptions & OPT_RECURSIVE) )
677         {
678             if (FolderExists (szPath))
679                 strcat (szPath, "\\");
680  
681             _splitpath (szPath, szDrive, szDir, szFileName, szExt);
682             strcpy (szPath, szDrive);
683             strcat (szPath, szDir);
684             strcpy (szFindName, szFileName);
685             strcat (szFindName, szExt);
686             _fullpath (szFullPath, (szPath[0]) ? szPath : ".\\", LEN_PATH);
687             szFullPath[strlen (szFullPath) - 1] = '\0';  /* Delete the last '\' */
688  
689             FindFileRecursive (szFullPath, szFindName);
690         }
691     }
692  
693     return ExitCode (ERROR_SUCCESS);
694 }  /* main */