Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

573 lines
16 KiB

  1. /*
  2. * UPD: update
  3. *
  4. * HISTORY:
  5. *
  6. * 4/13/86 danl Fix /d bug. Print warning on eq time ne length
  7. * 4/11/86 danl Remove test for length just before copyfile
  8. * 4/09/86 danl Converted to ztools\lib
  9. * 5/07/86 danl Add msg if no such source found
  10. * 5/29/86 danl Add /s flag
  11. * 6/02/86 danl Add /g flag
  12. * 6/04/86 danl Allow %n with /g flag
  13. * 6/10/86 danl Allow blank lines in /g file, # are not echo'd
  14. * 6/12/86 danl Output \n and ends of lines
  15. * 6/26/86 danl Convert from fatal to usage
  16. * 7/01/86 danl Add /a flag
  17. * 12/04/86 danl Add /p flag
  18. * 12/24/86 danl Use malloc for pPat
  19. * 2/24/87 brianwi Use findclose()
  20. * 2/25/87 brianwi Add 'echo' and 'rem' to /g files
  21. * 07-Apr-87 danl Add fAnyUpd
  22. * 13-Apr-87 brianwi Issue error message if source dir invalid
  23. * 07-May-87 danl Add /e switch
  24. * 22-May-87 brianwi Fix descent from root directory bug
  25. * 20-Aug-87 brianwi Fix Null Pointer with /o ( free(pPat) in walk() )
  26. */
  27. #include <malloc.h>
  28. #include <math.h>
  29. #include <ctype.h>
  30. #include <fcntl.h>
  31. #include <sys\types.h>
  32. #include <sys\stat.h>
  33. #include <io.h>
  34. #include <string.h>
  35. #include <stdio.h>
  36. #include <process.h>
  37. #include <ctype.h>
  38. #include <math.h>
  39. #include <stdlib.h>
  40. #include <windows.h>
  41. #include <tools.h>
  42. // Forward Function Declarations...
  43. int savespec( char * );
  44. int copyfile( char *, struct findType *, char * );
  45. void walk( char *, struct findType *, void *);
  46. void RecWalk( char *, struct findType *, void * );
  47. void saveext( char * );
  48. void __cdecl usage( char *, ... );
  49. void getfile( int, char ** );
  50. char const rgstrUsage[] = {
  51. "Usage: UPD [/nxdfvosape] {src directories}+ dest directory [{wildcard specs}*]\n"
  52. " UPD /g file\n"
  53. " Options:\n"
  54. " -n No saving of replaced files to deleted directory\n"
  55. " -x eXclude files, see tools.ini\n"
  56. " -d Descend into subdirectories\n"
  57. " -f Files differ, then update\n"
  58. " -v Verbose\n"
  59. " -o Only files already existing in dest are updated\n"
  60. " -s Subdirectory DEBUG has priority\n"
  61. " -a Archive bit on source should NOT be reset\n"
  62. " -p Print actions, but do nothing\n"
  63. " -e Exit codes 1-error or no src else 0\n"
  64. " Default is 1-update done 0-no updates done\n"
  65. " -g Get params from file\n"
  66. };
  67. #define BUFLEN MAX_PATH
  68. #define MAXSPEC 32
  69. #define MAXFIL 256
  70. #define MAXARGV 20
  71. char *exclude[MAXFIL], dir[BUFLEN];
  72. unsigned _stack = 4096;
  73. flagType fInGetfile = FALSE;
  74. flagType _fExpand = FALSE;
  75. flagType fDescend = FALSE;
  76. flagType fAll = FALSE;
  77. flagType fExclude = FALSE;
  78. flagType fDel = TRUE;
  79. flagType fVerbose = FALSE;
  80. flagType fOnly = FALSE;
  81. flagType fSubDebug = FALSE; /* TRUE => priority to subdir DEBUG */
  82. flagType fArchiveReset = TRUE;
  83. flagType fPrintOnly = FALSE;
  84. flagType fErrorExit = FALSE; /* TRUE => exit (1) errors or no src else 0 */
  85. flagType fNoSrc = FALSE; /* TRUE => "No src msg emitted" */
  86. int numexcl = 0;
  87. int cCopied = 0;
  88. int fAnyUpd = 0;
  89. int nWildSpecs = 0;
  90. char *wildSpecs[MAXSPEC];
  91. struct findType buf;
  92. char source[BUFLEN], dest[BUFLEN], srcDebug[BUFLEN];
  93. /* for use by getfile */
  94. char *argv[MAXARGV];
  95. char bufIn[BUFLEN];
  96. char strLine[BUFLEN];
  97. char ekoLine[BUFLEN]; /* undestroyed copy of line for echo */
  98. savespec (p)
  99. char *p;
  100. {
  101. char namebuf[ 16 ];
  102. int i;
  103. buf.fbuf.dwFileAttributes = 0;
  104. namebuf[ 0 ] = 0;
  105. if (strchr(p, '\\') || strchr(p, ':' ) )
  106. return FALSE;
  107. ffirst( p, FILE_ATTRIBUTE_DIRECTORY, &buf );
  108. findclose( &buf );
  109. if ( /* !HASATTR( buf.attr, FILE_ATTRIBUTE_DIRECTORY ) && */
  110. filename( p, namebuf )
  111. ) {
  112. fileext( p, namebuf);
  113. upper( namebuf );
  114. for (i=0; i<nWildSpecs; i++)
  115. if (!strcmp( namebuf, wildSpecs[ i ]))
  116. return TRUE;
  117. if (nWildSpecs < MAXSPEC) {
  118. wildSpecs[ nWildSpecs++ ] = _strdup (namebuf);
  119. return TRUE;
  120. }
  121. else
  122. usage( "Too many wild card specifications - ", namebuf, 0 );
  123. }
  124. return FALSE;
  125. }
  126. copyfile( src, srctype, dst )
  127. char *src, *dst;
  128. struct findType *srctype;
  129. {
  130. int i;
  131. char *result, temp[ 20 ]; /* temp for storing file names */
  132. flagType fNewfile = FALSE;
  133. if ( fExclude ) {
  134. fileext( src, temp );
  135. for (i = 0; i< numexcl; i++) {
  136. if( !_strcmpi( exclude[i], temp ) ) {
  137. return( FALSE );
  138. }
  139. }
  140. }
  141. fflush( stdout );
  142. /* if the file already exists, fdelete will return 0; then don't */
  143. /* notify the user that a file transfer has taken place. Otherwise */
  144. /* a new file has been created so tell the user about it. */
  145. printf( " %s => %s", src, dst );
  146. fAnyUpd = 1;
  147. if ( !fPrintOnly ) {
  148. if (fDel) fNewfile = (flagType)((fdelete(dst)) ? TRUE : FALSE );
  149. if (!(result = fcopy( src, dst ))) {
  150. if (fArchiveReset)
  151. SetFileAttributes( src, srctype->fbuf.dwFileAttributes & ~FILE_ATTRIBUTE_ARCHIVE );
  152. if (fVerbose || fNewfile) printf( " [OK]" );
  153. }
  154. else
  155. printf( " %s - %s", result, error() );
  156. }
  157. else
  158. printf ( " [no upd]" );
  159. printf( "\n" );
  160. fflush( stdout );
  161. return TRUE;
  162. }
  163. void
  164. walk (
  165. char *p,
  166. struct findType *b,
  167. void *dummy
  168. )
  169. {
  170. int fNotFound;
  171. char *pPat;
  172. char *pT = p;
  173. struct findType *bT = b;
  174. struct findType bufT;
  175. if( strcmp( bT->fbuf.cFileName, "." ) &&
  176. strcmp( bT->fbuf.cFileName, ".." )
  177. ) {
  178. if (HASATTR (bT->fbuf.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
  179. /* do nothing if you find a dir */
  180. } else if( !HASATTR( bT->fbuf.dwFileAttributes, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM ) ) {
  181. //
  182. // Note: windows does not support FILE_ATTRIBUTE_VOLUME_LABEL, so
  183. // it was removed from above
  184. //
  185. pPat = malloc ( BUFLEN );
  186. if (pPat) {
  187. strcpy( pPat, dest );
  188. if (*(strend( pPat ) - 1) != '\\') {
  189. strcat( pPat, "\\" );
  190. }
  191. fileext( pT, strend ( pPat ) );
  192. /* ffirst == 0 => file found */
  193. if (fOnly && ffirst( pPat, -1, &buf ) ) {
  194. free ( pPat );
  195. return;
  196. }
  197. if (fOnly) {
  198. findclose( &buf );
  199. }
  200. /* so far we know src\file and dest\file exist */
  201. if (fSubDebug) {
  202. /* now check to see if src\DEBUG\file exists */
  203. drive(pT, srcDebug);
  204. path(pT, srcDebug + strlen(srcDebug));
  205. strcat(srcDebug + strlen(srcDebug), "debug\\");
  206. fileext(pT, srcDebug + strlen(srcDebug));
  207. if( !ffirst( srcDebug, -1, &bufT ) ) {
  208. findclose( &bufT );
  209. /* it exists so use it for the compares below */
  210. pT = srcDebug;
  211. bT = &bufT;
  212. }
  213. }
  214. cCopied++;
  215. if( ( fNotFound = ffirst( pPat, -1, &buf ) ) ||
  216. ( CompareFileTime( &buf.fbuf.ftLastWriteTime, &bT->fbuf.ftLastWriteTime ) < 0 ) ||
  217. ( fAll &&
  218. CompareFileTime( &buf.fbuf.ftLastWriteTime, &bT->fbuf.ftLastWriteTime ) > 0
  219. )
  220. ) {
  221. copyfile( pT, bT, pPat );
  222. } else if( !fNotFound &&
  223. CompareFileTime( &buf.fbuf.ftLastWriteTime, &bT->fbuf.ftLastWriteTime ) == 0 &&
  224. buf.fbuf.nFileSizeLow != bT->fbuf.nFileSizeLow
  225. ) {
  226. printf("\n\007UPD: warning - %s not copied\n", pT);
  227. printf("\007UPD: warning - same time, different length in src & dest\n", pT);
  228. }
  229. findclose( &buf );
  230. free ( pPat );
  231. }
  232. }
  233. }
  234. dummy;
  235. }
  236. /* a first walking routine, just copies the files on given directory */
  237. /* doesn't deal with nested subdirectories. Ie split the process up into */
  238. /* two parts, first deal with files on current directory, then deal with */
  239. /* subdirectories as necessary. */
  240. /* only called when fDescend is true */
  241. void
  242. RecWalk (
  243. char *p,
  244. struct findType *b,
  245. void *dummy
  246. )
  247. {
  248. char *pPat;
  249. char *pDestEnd;
  250. int i;
  251. if (strcmp (b->fbuf.cFileName, ".") && strcmp (b->fbuf.cFileName, ".."))
  252. if (HASATTR (b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) &&
  253. !HASATTR (b->fbuf.dwFileAttributes, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
  254. {
  255. /* ignore Hidden and System directories */
  256. pPat = malloc ( BUFLEN );
  257. if (pPat) {
  258. if ( (pDestEnd = strend(dest))[-1] != '\\' )
  259. strcat(pDestEnd, "\\");
  260. fileext(p, strend(pDestEnd));
  261. sprintf( pPat, "%s\\*.*", p);
  262. forfile( pPat, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, RecWalk, NULL );
  263. for (i=0; i<nWildSpecs; i++) {
  264. sprintf( pPat, "%s\\%s", p, wildSpecs[ i ] );
  265. forfile( pPat, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, walk, NULL );
  266. }
  267. *pDestEnd = '\0';
  268. free ( pPat );
  269. }
  270. }
  271. dummy;
  272. }
  273. void
  274. saveext (p)
  275. char *p;
  276. {
  277. upper (p) ;
  278. if (numexcl < MAXFIL)
  279. exclude [numexcl++] = _strdup (p);
  280. }
  281. void __cdecl usage( char *p, ... )
  282. {
  283. char **rgstr;
  284. rgstr = &p;
  285. if (*rgstr) {
  286. fprintf (stderr, "UPD: ");
  287. while (*rgstr)
  288. fprintf (stderr, "%s", *rgstr++);
  289. fprintf (stderr, "\n");
  290. }
  291. fputs(rgstrUsage, stderr);
  292. exit ((fErrorExit ? 1 : 0));
  293. }
  294. __cdecl
  295. main (c, v)
  296. int c;
  297. char *v[];
  298. {
  299. int i, j, k;
  300. FILE *fh;
  301. char *p, *p1, namebuf[ BUFLEN ];
  302. _fExpand = FALSE;
  303. fDescend = FALSE;
  304. fAll = FALSE;
  305. fExclude = FALSE;
  306. fDel = TRUE;
  307. fOnly = FALSE;
  308. fSubDebug = FALSE;
  309. fArchiveReset = TRUE;
  310. fPrintOnly = FALSE;
  311. numexcl = 0;
  312. cCopied = 0;
  313. nWildSpecs = 0;
  314. if (!fInGetfile)
  315. SHIFT(c, v); /* Flush the command name */
  316. /*
  317. * 13-SEPT-90 w-barry
  318. * Added test for arguments remaining before test for switch char.
  319. */
  320. while( c && fSwitChr ( *v[ 0 ] ) ) {
  321. p = v[ 0 ];
  322. SHIFT(c, v);
  323. while (*++p)
  324. switch (tolower(*p)) {
  325. case 'a':
  326. fArchiveReset = FALSE;
  327. break;
  328. case 'g':
  329. if (fInGetfile)
  330. usage( "/g allowed only on command line", 0);
  331. getfile(c, v);
  332. break;
  333. case 'e':
  334. fErrorExit = TRUE;
  335. case 'x':
  336. fExclude = TRUE;
  337. break;
  338. case 'v':
  339. fVerbose = TRUE;
  340. break;
  341. case 'd':
  342. fDescend = TRUE;
  343. break;
  344. case 'f':
  345. fAll = TRUE;
  346. break;
  347. case 'n':
  348. fDel = FALSE;
  349. break;
  350. case 'o':
  351. fOnly = TRUE;
  352. break;
  353. case 'p':
  354. fPrintOnly = TRUE;
  355. break;
  356. case 's':
  357. fSubDebug = TRUE;
  358. break;
  359. default:
  360. usage( "Invalid switch - ", p, 0);
  361. }
  362. }
  363. if (fSubDebug && fDescend) {
  364. printf("UPD: /s and /d both specified, /d ignored\n");
  365. fDescend = FALSE;
  366. }
  367. if (fExclude)
  368. if ((fh = swopen ("$USER:\\tools.ini", "upd")) ) {
  369. while (swread (p1 = dir, BUFLEN, fh)) {
  370. while (*(p = strbskip (p1, " "))) {
  371. if (*(p1 = strbscan (p, " ")))
  372. *p1++ = 0;
  373. saveext (p) ;
  374. }
  375. }
  376. swclose (fh) ;
  377. }
  378. /* Must be at least one source dir and the dest dir. */
  379. if (c < 2)
  380. usage( 0 );
  381. /* Save away any wildcard specs at end of argument list */
  382. for (i=c-1; i>=2; i--)
  383. if (!savespec( v[ i ] ))
  384. break;
  385. else
  386. c--;
  387. /* Still must be at least one source dir and the dest dir. */
  388. if (c < 2)
  389. usage( 0 );
  390. /* Make sure destination is a valid directory */
  391. rootpath( v[ c-1 ], dest );
  392. if (ffirst( dest, FILE_ATTRIBUTE_DIRECTORY, &buf ) == -1)
  393. usage( "Destination directory does not exist - ", v[ c-1 ], 0 );
  394. else {
  395. findclose( &buf );
  396. c--;
  397. }
  398. if (!nWildSpecs)
  399. savespec( "*.*" );
  400. if (fVerbose) {
  401. printf( "Copying all files matching:" );
  402. for (i=0; i<nWildSpecs; i++)
  403. printf( " %s", wildSpecs[ i ] );
  404. printf( "\n" );
  405. printf( "To destination directory: %s\n", dest );
  406. printf( "From the following source directories:\n" );
  407. }
  408. for (i=0; i<c; i++) {
  409. if (rootpath( v[ i ], namebuf )) {
  410. printf( "\aSource directory does not exist - %s\n", v[ i ]);
  411. continue;
  412. }
  413. if (fVerbose) printf( " %s\n", namebuf );
  414. if (namebuf[k = strlen( namebuf ) - 1] == '\\')
  415. namebuf[k] = '\0';
  416. for (j=0; j<nWildSpecs; j++) {
  417. sprintf( source, "%s\\%s", namebuf, wildSpecs[ j ] );
  418. cCopied = 0;
  419. forfile( source, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, walk, NULL );
  420. if (!cCopied) {
  421. printf( "UPD: no src file matching %s\\%s\n", namebuf, wildSpecs[ j ] );
  422. fNoSrc = 1;
  423. }
  424. }
  425. if (fDescend) {
  426. sprintf( source, "%s\\*.*", namebuf );
  427. forfile( source, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, RecWalk, NULL );
  428. }
  429. /* if (fVerbose) printf( "\n" ); */
  430. }
  431. if (!fInGetfile)
  432. return( (int)fErrorExit ? (int)fNoSrc : fAnyUpd );
  433. return 0;
  434. }
  435. /* call if UPD /g getfile, reads lines from getfile and for each line
  436. calls main */
  437. void getfile(c, v)
  438. int c;
  439. char *v[];
  440. {
  441. FILE *fp;
  442. int cargv = 0;
  443. int i, j;
  444. char *p;
  445. ConvertAppToOem( c, v );
  446. if( c == 0 ) {
  447. usage("no getfile specified", 0);
  448. }
  449. fInGetfile = TRUE;
  450. if( ( fp = fopen( *v, "r" ) ) == (FILE *)NULL ) {
  451. usage("error opening ", *v, 0);
  452. }
  453. SHIFT(c, v);
  454. /*
  455. * 13-SEPT-90 w-barry
  456. * Changed open to fopen and switched to fgets instead of assembly
  457. * routines 'getl' and 'getlinit'.
  458. *
  459. * getlinit((char far *)bufIn, BUFLEN, fh);
  460. * while (getl(strLine, BUFLEN) != NULL) {
  461. */
  462. while( fgets( strLine, BUFLEN, fp ) != NULL ) {
  463. if( *strLine == '#' )
  464. continue;
  465. if( *strLine == ';') {
  466. printf( "%s\n", strLine );
  467. continue;
  468. }
  469. /* fgets doesn't strip the trailing \n */
  470. *strbscan(strLine, "\n") = '\0';
  471. cargv = 0;
  472. /* convert strLine into argv */
  473. p = strbskip(strLine, " ");
  474. strcpy (ekoLine, p + 5);
  475. while (*p) {
  476. argv[cargv++] = p;
  477. p = strbscan(p, " ");
  478. if (*p)
  479. *p++ = '\0';
  480. p = strbskip(p, " ");
  481. }
  482. if (!_stricmp (argv[0], "rem")) continue;
  483. if (!_stricmp (argv[0], "echo"))
  484. {
  485. if (!_stricmp (argv[1], "on" ))
  486. {
  487. fVerbose = TRUE;
  488. printf ("Verbose On\n");
  489. }
  490. else if (!_stricmp (argv[1], "off"))
  491. {
  492. fVerbose = FALSE;
  493. printf ("Verbose Off\n");
  494. }
  495. else printf ("%s\n", ekoLine);
  496. continue;
  497. }
  498. for (i = 0; i < cargv; i++) {
  499. if (*(p = argv[i]) == '%') {
  500. if ((j = atoi(++p)) < c)
  501. argv[i] = v[j];
  502. else
  503. usage("bad arg ", argv[i], 0);
  504. }
  505. }
  506. if (cargv)
  507. main(cargv, argv);
  508. }
  509. fclose( fp );
  510. exit( (int)fErrorExit ? (int)fNoSrc : fAnyUpd );
  511. }