1/* filesubr.c --- subroutines for dealing with files 2 Jim Blandy <jimb@cyclic.com> 3 4 This file is part of GNU CVS. 5 6 GNU CVS is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by the 8 Free Software Foundation; either version 2, or (at your option) any 9 later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. */ 15 16/* These functions were moved out of subr.c because they need different 17 definitions under operating systems (like, say, Windows NT) with different 18 file system semantics. */ 19 20#include <io.h> 21#include <windows.h> 22 23#include "cvs.h" 24 25static int deep_remove_dir PROTO((const char *path)); 26 27/* Copies "from" to "to". Note that the functionality here is similar 28 to the win32 function CopyFile, but (1) we copy LastAccessTime and 29 CopyFile doesn't, (2) we set file attributes to the default set by 30 the C library and CopyFile copies them. Neither #1 nor #2 was intentional 31 as far as I know, but changing them could be confusing, unless there 32 is some reason they should be changed (this would need more 33 investigation). */ 34void 35copy_file (from, to) 36 const char *from; 37 const char *to; 38{ 39 struct stat sb; 40 struct utimbuf t; 41 int fdin, fdout; 42 43 if (trace) 44#ifdef SERVER_SUPPORT 45 (void) fprintf (stderr, "%c-> copy(%s,%s)\n", 46 (server_active) ? 'S' : ' ', from, to); 47#else 48 (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to); 49#endif 50 if (noexec) 51 return; 52 53 if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0) 54 error (1, errno, "cannot open %s for copying", from); 55 if (fstat (fdin, &sb) < 0) 56 error (1, errno, "cannot fstat %s", from); 57 if ((fdout = open (to, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 58 (int) sb.st_mode & 07777)) < 0) 59 error (1, errno, "cannot create %s for copying", to); 60 if (sb.st_size > 0) 61 { 62 char buf[BUFSIZ]; 63 int n; 64 65 for (;;) 66 { 67 n = read (fdin, buf, sizeof(buf)); 68 if (n == -1) 69 { 70#ifdef EINTR 71 if (errno == EINTR) 72 continue; 73#endif 74 error (1, errno, "cannot read file %s for copying", from); 75 } 76 else if (n == 0) 77 break; 78 79 if (write(fdout, buf, n) != n) { 80 error (1, errno, "cannot write file %s for copying", to); 81 } 82 } 83 84#ifdef HAVE_FSYNC 85 if (fsync (fdout)) 86 error (1, errno, "cannot fsync file %s after copying", to); 87#endif 88 } 89 90 if (close (fdin) < 0) 91 error (0, errno, "cannot close %s", from); 92 if (close (fdout) < 0) 93 error (1, errno, "cannot close %s", to); 94 95 /* now, set the times for the copied file to match those of the original */ 96 memset ((char *) &t, 0, sizeof (t)); 97 t.actime = sb.st_atime; 98 t.modtime = sb.st_mtime; 99 (void) utime (to, &t); 100} 101 102/* FIXME-krp: these functions would benefit from caching the char * & 103 stat buf. */ 104 105/* 106 * Returns non-zero if the argument file is a directory, or is a symbolic 107 * link which points to a directory. 108 */ 109int 110isdir (file) 111 const char *file; 112{ 113 struct stat sb; 114 115 if (stat (file, &sb) < 0) 116 return (0); 117 return (S_ISDIR (sb.st_mode)); 118} 119 120/* 121 * Returns non-zero if the argument file is a symbolic link. 122 */ 123int 124islink (file) 125 const char *file; 126{ 127#ifdef S_ISLNK 128 struct stat sb; 129 130 if (lstat (file, &sb) < 0) 131 return (0); 132 return (S_ISLNK (sb.st_mode)); 133#else 134 return (0); 135#endif 136} 137 138/* 139 * Returns non-zero if the argument file exists. 140 */ 141int 142isfile (file) 143 const char *file; 144{ 145 return isaccessible(file, F_OK); 146} 147 148/* 149 * Returns non-zero if the argument file is readable. 150 */ 151int 152isreadable (file) 153 const char *file; 154{ 155 return isaccessible(file, R_OK); 156} 157 158/* 159 * Returns non-zero if the argument file is writable. 160 */ 161int 162iswritable (file) 163 const char *file; 164{ 165 return isaccessible(file, W_OK); 166} 167 168/* 169 * Returns non-zero if the argument file is accessable according to 170 * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid 171 * bits set. 172 */ 173int 174isaccessible (file, mode) 175 const char *file; 176 const int mode; 177{ 178#ifdef SETXID_SUPPORT 179 struct stat sb; 180 int umask = 0; 181 int gmask = 0; 182 int omask = 0; 183 int uid; 184 185 if (stat(file, &sb) == -1) 186 return 0; 187 if (mode == F_OK) 188 return 1; 189 190 uid = geteuid(); 191 if (uid == 0) /* superuser */ 192 { 193 if (mode & X_OK) 194 return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH); 195 else 196 return 1; 197 } 198 199 if (mode & R_OK) 200 { 201 umask |= S_IRUSR; 202 gmask |= S_IRGRP; 203 omask |= S_IROTH; 204 } 205 if (mode & W_OK) 206 { 207 umask |= S_IWUSR; 208 gmask |= S_IWGRP; 209 omask |= S_IWOTH; 210 } 211 if (mode & X_OK) 212 { 213 umask |= S_IXUSR; 214 gmask |= S_IXGRP; 215 omask |= S_IXOTH; 216 } 217 218 if (sb.st_uid == uid) 219 return (sb.st_mode & umask) == umask; 220 else if (sb.st_gid == getegid()) 221 return (sb.st_mode & gmask) == gmask; 222 else 223 return (sb.st_mode & omask) == omask; 224#else 225 return access(file, mode) == 0; 226#endif 227} 228 229/* 230 * Open a file and die if it fails 231 */ 232FILE * 233open_file (name, mode) 234 const char *name; 235 const char *mode; 236{ 237 FILE *fp; 238 239 if ((fp = fopen (name, mode)) == NULL) 240 error (1, errno, "cannot open %s", name); 241 return (fp); 242} 243 244/* 245 * Make a directory and die if it fails 246 */ 247void 248make_directory (name) 249 const char *name; 250{ 251 struct stat sb; 252 253 if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode))) 254 error (0, 0, "%s already exists but is not a directory", name); 255 if (!noexec && mkdir (name) < 0) 256 error (1, errno, "cannot make directory %s", name); 257} 258 259/* 260 * Make a path to the argument directory, printing a message if something 261 * goes wrong. 262 */ 263void 264make_directories (name) 265 const char *name; 266{ 267 char *cp; 268 269 if (noexec) 270 return; 271 272 if (mkdir (name) == 0 || errno == EEXIST) 273 return; 274 if (errno != ENOENT) 275 { 276 error (0, errno, "cannot make path to %s", name); 277 return; 278 } 279 if ((cp = strrchr (name, '/')) == NULL) 280 return; 281 *cp = '\0'; 282 make_directories (name); 283 *cp++ = '/'; 284 if (*cp == '\0') 285 return; 286 (void) mkdir (name); 287} 288 289/* Create directory NAME if it does not already exist; fatal error for 290 other errors. Returns 0 if directory was created; 1 if it already 291 existed. */ 292int 293mkdir_if_needed (name) 294 char *name; 295{ 296 if (mkdir (name) < 0) 297 { 298 if (errno != EEXIST 299#ifdef EACCESS 300 /* This was copied over from the OS/2 code; I would guess it 301 isn't needed here but that has not been verified. */ 302 && errno != EACCESS 303#endif 304#ifdef EACCES 305 /* This is said to be needed by NT on Alpha or PowerPC 306 (not sure what version) --August, 1996. */ 307 && errno != EACCES 308#endif 309 ) 310 error (1, errno, "cannot make directory %s", name); 311 return 1; 312 } 313 return 0; 314} 315 316/* 317 * Change the mode of a file, either adding write permissions, or removing 318 * all write permissions. Adding write permissions honors the current umask 319 * setting. 320 */ 321void 322xchmod (fname, writable) 323 char *fname; 324 int writable; 325{ 326 struct stat sb; 327 mode_t mode, oumask; 328 329 if (stat (fname, &sb) < 0) 330 { 331 if (!noexec) 332 error (0, errno, "cannot stat %s", fname); 333 return; 334 } 335 if (writable) 336 { 337 oumask = umask (0); 338 (void) umask (oumask); 339 mode = sb.st_mode | ~oumask & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) | 340 ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) | 341 ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)); 342 } 343 else 344 { 345 mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH); 346 } 347 348 if (trace) 349#ifdef SERVER_SUPPORT 350 (void) fprintf (stderr, "%c-> chmod(%s,%o)\n", 351 (server_active) ? 'S' : ' ', fname, mode); 352#else 353 (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode); 354#endif 355 if (noexec) 356 return; 357 358 if (chmod (fname, mode) < 0) 359 error (0, errno, "cannot change mode of file %s", fname); 360} 361 362 363/* Read the value of a symbolic link. 364 Under Windows NT, this function always returns EINVAL. */ 365int 366readlink (char *path, char *buf, int buf_size) 367{ 368 errno = EINVAL; 369 return -1; 370} 371 372/* Rename for NT which works for read only files. Apparently if we are 373 accessing FROM and TO via a Novell network, this is an issue. */ 374int 375wnt_rename (from, to) 376 const char *from; 377 const char *to; 378{ 379 int result, save_errno; 380 int readonly = !iswritable (from); 381 382 if (readonly) 383 { 384 if (chmod (from, S_IWRITE) < 0) 385 return -1; 386 } 387 result = rename (from, to); 388 save_errno = errno; 389 if (readonly) 390 { 391 if (result == 0) 392 { 393 if (chmod (to, S_IREAD) < 0) 394 return -1; 395 } 396 else 397 { 398 /* We have a choice of which error to report, if there is 399 one here too; report the one from rename (). */ 400 chmod (from, S_IREAD); 401 } 402 errno = save_errno; 403 } 404 return result; 405} 406 407/* 408 * Rename a file and die if it fails 409 */ 410void 411rename_file (from, to) 412 const char *from; 413 const char *to; 414{ 415 if (trace) 416#ifdef SERVER_SUPPORT 417 (void) fprintf (stderr, "%c-> rename(%s,%s)\n", 418 (server_active) ? 'S' : ' ', from, to); 419#else 420 (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to); 421#endif 422 if (noexec) 423 return; 424 425 /* Win32 unlink is stupid --- it fails if the file is read-only */ 426 chmod(to, S_IWRITE); 427 unlink(to); 428 if (CVS_RENAME (from, to) < 0) 429 error (1, errno, "cannot rename file %s to %s", from, to); 430} 431 432/* 433 * unlink a file, if possible. 434 */ 435int 436unlink_file (f) 437 const char *f; 438{ 439 if (trace) 440#ifdef SERVER_SUPPORT 441 (void) fprintf (stderr, "%c-> unlink(%s)\n", 442 (server_active) ? 'S' : ' ', f); 443#else 444 (void) fprintf (stderr, "-> unlink(%s)\n", f); 445#endif 446 if (noexec) 447 return (0); 448 449 /* Win32 unlink is stupid - it fails if the file is read-only */ 450 chmod (f, _S_IWRITE); 451 return (unlink (f)); 452} 453 454/* 455 * Unlink a file or dir, if possible. If it is a directory do a deep 456 * removal of all of the files in the directory. Return -1 on error 457 * (in which case errno is set). 458 */ 459int 460unlink_file_dir (f) 461 const char *f; 462{ 463 if (trace) 464#ifdef SERVER_SUPPORT 465 (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n", 466 (server_active) ? 'S' : ' ', f); 467#else 468 (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f); 469#endif 470 if (noexec) 471 return (0); 472 473 /* Win32 unlink is stupid - it fails if the file is read-only */ 474 chmod (f, _S_IWRITE); 475 if (unlink (f) != 0) 476 { 477 /* under Windows NT, unlink returns EACCES if the path 478 is a directory. Under Windows 95, ENOENT. */ 479 if (errno == EISDIR || errno == EACCES || errno == ENOENT) 480 return deep_remove_dir (f); 481 else 482 /* The file wasn't a directory and some other 483 * error occured 484 */ 485 return -1; 486 } 487 /* We were able to remove the file from the disk */ 488 return 0; 489} 490 491/* Remove a directory and everything it contains. Returns 0 for 492 * success, -1 for failure (in which case errno is set). 493 */ 494 495static int 496deep_remove_dir (path) 497 const char *path; 498{ 499 DIR *dirp; 500 struct dirent *dp; 501 char buf[PATH_MAX]; 502 503 /* ENOTEMPTY for NT (obvious) but EACCES for Win95 (not obvious) */ 504 if (rmdir (path) != 0 505 && (errno == ENOTEMPTY || errno == EACCES)) 506 { 507 if ((dirp = opendir (path)) == NULL) 508 /* If unable to open the directory return 509 * an error 510 */ 511 return -1; 512 513 while ((dp = readdir (dirp)) != NULL) 514 { 515 if (strcmp (dp->d_name, ".") == 0 || 516 strcmp (dp->d_name, "..") == 0) 517 continue; 518 519 sprintf (buf, "%s/%s", path, dp->d_name); 520 521 /* Win32 unlink is stupid - it fails if the file is read-only */ 522 chmod (buf, _S_IWRITE); 523 if (unlink (buf) != 0 ) 524 { 525 /* Under Windows NT, unlink returns EACCES if the path 526 is a directory. Under Windows 95, ENOENT. It 527 isn't really clear to me whether checking errno is 528 better or worse than using _stat to check for a directory. 529 We aren't really trying to prevent race conditions here 530 (e.g. what if something changes between readdir and 531 unlink?) */ 532 if (errno == EISDIR || errno == EACCES || errno == ENOENT) 533 { 534 if (deep_remove_dir (buf)) 535 { 536 closedir (dirp); 537 return -1; 538 } 539 } 540 else 541 { 542 /* buf isn't a directory, or there are 543 * some sort of permision problems 544 */ 545 closedir (dirp); 546 return -1; 547 } 548 } 549 } 550 closedir (dirp); 551 return rmdir (path); 552 } 553 /* Was able to remove the directory return 0 */ 554 return 0; 555} 556 557/* Read NCHARS bytes from descriptor FD into BUF. 558 Return the number of characters successfully read. 559 The number returned is always NCHARS unless end-of-file or error. */ 560static size_t 561block_read (fd, buf, nchars) 562 int fd; 563 char *buf; 564 size_t nchars; 565{ 566 char *bp = buf; 567 size_t nread; 568 569 do 570 { 571 nread = read (fd, bp, nchars); 572 if (nread == (size_t)-1) 573 { 574#ifdef EINTR 575 if (errno == EINTR) 576 continue; 577#endif 578 return (size_t)-1; 579 } 580 581 if (nread == 0) 582 break; 583 584 bp += nread; 585 nchars -= nread; 586 } while (nchars != 0); 587 588 return bp - buf; 589} 590 591 592/* 593 * Compare "file1" to "file2". Return non-zero if they don't compare exactly. 594 */ 595int 596xcmp (file1, file2) 597 const char *file1; 598 const char *file2; 599{ 600 char *buf1, *buf2; 601 struct stat sb1, sb2; 602 int fd1, fd2; 603 int ret; 604 605 if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0) 606 error (1, errno, "cannot open file %s for comparing", file1); 607 if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0) 608 error (1, errno, "cannot open file %s for comparing", file2); 609 if (fstat (fd1, &sb1) < 0) 610 error (1, errno, "cannot fstat %s", file1); 611 if (fstat (fd2, &sb2) < 0) 612 error (1, errno, "cannot fstat %s", file2); 613 614 /* A generic file compare routine might compare st_dev & st_ino here 615 to see if the two files being compared are actually the same file. 616 But that won't happen in CVS, so we won't bother. */ 617 618 if (sb1.st_size != sb2.st_size) 619 ret = 1; 620 else if (sb1.st_size == 0) 621 ret = 0; 622 else 623 { 624 /* FIXME: compute the optimal buffer size by computing the least 625 common multiple of the files st_blocks field */ 626 size_t buf_size = 8 * 1024; 627 size_t read1; 628 size_t read2; 629 630 buf1 = xmalloc (buf_size); 631 buf2 = xmalloc (buf_size); 632 633 do 634 { 635 read1 = block_read (fd1, buf1, buf_size); 636 if (read1 == (size_t)-1) 637 error (1, errno, "cannot read file %s for comparing", file1); 638 639 read2 = block_read (fd2, buf2, buf_size); 640 if (read2 == (size_t)-1) 641 error (1, errno, "cannot read file %s for comparing", file2); 642 643 /* assert (read1 == read2); */ 644 645 ret = memcmp(buf1, buf2, read1); 646 } while (ret == 0 && read1 == buf_size); 647 648 free (buf1); 649 free (buf2); 650 } 651 652 (void) close (fd1); 653 (void) close (fd2); 654 return (ret); 655} 656 657/* Generate a unique temporary filename. Returns a pointer to a newly 658 * malloc'd string containing the name. Returns successfully or not at 659 * all. 660 * 661 * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!! 662 * 663 * and yes, I know about the way the rcs commands use temp files. I think 664 * they should be converted too but I don't have time to look into it right 665 * now. 666 */ 667char * 668cvs_temp_name () 669{ 670 char *fn; 671 FILE *fp; 672 673 fp = cvs_temp_file (&fn); 674 if (fp == NULL) 675 error (1, errno, "Failed to create temporary file"); 676 if (fclose (fp) == EOF) 677 error (0, errno, "Failed to close temporary file %s", fn); 678 return fn; 679} 680 681/* Generate a unique temporary filename and return an open file stream 682 * to the truncated file by that name 683 * 684 * INPUTS 685 * filename where to place the pointer to the newly allocated file 686 * name string 687 * 688 * OUTPUTS 689 * filename dereferenced, will point to the newly allocated file 690 * name string. This value is undefined if the function 691 * returns an error. 692 * 693 * RETURNS 694 * An open file pointer to a read/write mode empty temporary file with the 695 * unique file name or NULL on failure. 696 * 697 * ERRORS 698 * on error, errno will be set to some value either by CVS_FOPEN or 699 * whatever system function is called to generate the temporary file name 700 */ 701FILE *cvs_temp_file (filename) 702 char **filename; 703{ 704 char *fn; 705 FILE *fp; 706 707 /* FIXME - I'd like to be returning NULL here in noexec mode, but I think 708 * some of the rcs & diff functions which rely on a temp file run in 709 * noexec mode too. 710 */ 711 712 /* assert (filename != NULL); */ 713 714 fn = _tempnam (Tmpdir, "cvs"); 715 if (fn == NULL) fp = NULL; 716 else if ((fp = CVS_FOPEN (fn, "w+")) == NULL) free (fn); 717 718 /* tempnam returns a pointer to a newly malloc'd string, so there's 719 * no need for a xstrdup 720 */ 721 722 *filename = fn; 723 return fp; 724} 725 726/* Return non-zero iff FILENAME is absolute. 727 Trivial under Unix, but more complicated under other systems. */ 728int 729isabsolute (filename) 730 const char *filename; 731{ 732 /* FIXME: This routine seems to interact poorly with 733 strip_trailing_slashes. For example, specify ":local:r:\" as 734 CVSROOT. The CVS/Root file will contain ":local:r:" and then 735 isabsolute will complain about the root not being an absolute 736 pathname. My guess is that strip_trailing_slashes is the right 737 place to fix this. */ 738 return (ISDIRSEP (filename[0]) 739 || (filename[0] != '\0' 740 && filename[1] == ':' 741 && ISDIRSEP (filename[2]))); 742} 743 744/* Return a pointer into PATH's last component. */ 745char * 746last_component (char *path) 747{ 748 char *scan; 749 char *last = 0; 750 751 for (scan = path; *scan; scan++) 752 if (ISDIRSEP (*scan)) 753 last = scan; 754 755 if (last && (last != path)) 756 return last + 1; 757 else 758 return path; 759} 760 761 762/* NT has two evironment variables, HOMEPATH and HOMEDRIVE, which, 763 when combined as ${HOMEDRIVE}${HOMEPATH}, give the unix equivalent 764 of HOME. Some NT users are just too unixy, though, and set the 765 HOME variable themselves. Therefore, we check for HOME first, and 766 then try to combine the other two if that fails. 767 768 Looking for HOME strikes me as bogus, particularly if the only reason 769 is to cater to "unixy users". On the other hand, if the reasoning is 770 there should be a single variable, rather than requiring people to 771 set both HOMEDRIVE and HOMEPATH, then it starts to make a little more 772 sense. 773 774 Win95: The system doesn't set HOME, HOMEDRIVE, or HOMEPATH (at 775 least if you set it up as the "all users under one user ID" or 776 whatever the name of that option is). Based on thing overheard on 777 the net, it seems that users of the pserver client have gotten in 778 the habit of setting HOME (if you don't use pserver, you can 779 probably get away without having a reasonable return from 780 get_homedir. Of course you lose .cvsrc and .cvsignore, but many 781 users won't notice). So it would seem that we should be somewhat 782 careful if we try to change the current behavior. 783 784 NT 3.51 or NT 4.0: I haven't checked this myself, but I am told 785 that HOME gets set, but not to the user's home directory. It is 786 said to be set to c:\users\default by default. */ 787 788char * 789get_homedir () 790{ 791 static char *pathbuf; 792 char *hd, *hp; 793 794 if (pathbuf != NULL) 795 return pathbuf; 796 else if ((hd = getenv ("HOME"))) 797 return hd; 798 else if ((hd = getenv ("HOMEDRIVE")) && (hp = getenv ("HOMEPATH"))) 799 { 800 pathbuf = xmalloc (strlen (hd) + strlen (hp) + 5); 801 strcpy (pathbuf, hd); 802 strcat (pathbuf, hp); 803 804 return pathbuf; 805 } 806 else 807 return NULL; 808} 809 810/* See cvs.h for description. */ 811void 812expand_wild (argc, argv, pargc, pargv) 813 int argc; 814 char **argv; 815 int *pargc; 816 char ***pargv; 817{ 818 int i; 819 int new_argc; 820 char **new_argv; 821 /* Allocated size of new_argv. We arrange it so there is always room for 822 one more element. */ 823 int max_new_argc; 824 825 new_argc = 0; 826 /* Add one so this is never zero. */ 827 max_new_argc = argc + 1; 828 new_argv = (char **) xmalloc (max_new_argc * sizeof (char *)); 829 for (i = 0; i < argc; ++i) 830 { 831 HANDLE h; 832 WIN32_FIND_DATA fdata; 833 834 /* These variables help us extract the directory name from the 835 given pathname. */ 836 837 char *last_forw_slash, *last_back_slash, *end_of_dirname; 838 int dirname_length = 0; 839 840 /* FIXME: If argv[i] is ".", this code will expand it to the 841 name of the current directory in its parent directory which 842 will cause start_recursion to do all manner of strange things 843 with it (culminating in an error). This breaks "cvs co .". 844 As nearly as I can guess, this bug has existed since 845 expand_wild was first created. At least, it is in CVS 1.9 (I 846 just tried it). */ 847 848 /* FindFirstFile doesn't return pathnames, so we have to do 849 this ourselves. Luckily, it's no big deal, since globbing 850 characters under Win32s can only occur in the last segment 851 of the path. For example, 852 /a/path/q*.h valid 853 /w32/q*.dir/cant/do/this/q*.h invalid */ 854 855 /* Win32 can handle both forward and backward slashes as 856 filenames -- check for both. */ 857 858 last_forw_slash = strrchr (argv[i], '/'); 859 last_back_slash = strrchr (argv[i], '\\'); 860 861#define cvs_max(x,y) ((x >= y) ? (x) : (y)) 862 863 /* FIXME: this comparing a NULL pointer to a non-NULL one is 864 extremely ugly, and I strongly suspect *NOT* sanctioned by 865 ANSI C. The code should just use last_component instead. */ 866 end_of_dirname = cvs_max (last_forw_slash, last_back_slash); 867 868 if (end_of_dirname == NULL) 869 dirname_length = 0; /* no directory name */ 870 else 871 dirname_length = end_of_dirname - argv[i] + 1; /* include slash */ 872 873 h = FindFirstFile (argv[i], &fdata); 874 if (h == INVALID_HANDLE_VALUE) 875 { 876 if (GetLastError () == ENOENT) 877 { 878 /* No match. The file specified didn't contain a wildcard (in which case 879 we clearly should return it unchanged), or it contained a wildcard which 880 didn't match (in which case it might be better for it to be an error, 881 but we don't try to do that). */ 882 new_argv [new_argc++] = xstrdup (argv[i]); 883 if (new_argc == max_new_argc) 884 { 885 max_new_argc *= 2; 886 new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *)); 887 } 888 } 889 else 890 { 891 error (1, errno, "cannot find %s", argv[i]); 892 } 893 } 894 else 895 { 896 while (1) 897 { 898 new_argv[new_argc] = 899 (char *) xmalloc (strlen (fdata.cFileName) + 1 900 + dirname_length); 901 902 /* Copy the directory name, if there is one. */ 903 904 if (dirname_length) 905 { 906 strncpy (new_argv[new_argc], argv[i], dirname_length); 907 new_argv[new_argc][dirname_length] = '\0'; 908 } 909 else 910 new_argv[new_argc][0] = '\0'; 911 912 /* Copy the file name. */ 913 914 if (fncmp (argv[i] + dirname_length, fdata.cFileName) == 0) 915 /* We didn't expand a wildcard; we just matched a filename. 916 Use the file name as specified rather than the filename 917 which exists in the directory (they may differ in case). 918 This is needed to make cvs add on a directory consistently 919 use the name specified on the command line, but it is 920 probably a good idea in other contexts too. */ 921 strcpy (new_argv[new_argc], argv[i]); 922 else 923 strcat (new_argv[new_argc], fdata.cFileName); 924 925 new_argc++; 926 927 if (new_argc == max_new_argc) 928 { 929 max_new_argc *= 2; 930 new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *)); 931 } 932 if (!FindNextFile (h, &fdata)) 933 { 934 if (GetLastError () == ERROR_NO_MORE_FILES) 935 break; 936 else 937 error (1, errno, "cannot find %s", argv[i]); 938 } 939 } 940 if (!FindClose (h)) 941 error (1, GetLastError (), "cannot close %s", argv[i]); 942 } 943 } 944 *pargc = new_argc; 945 *pargv = new_argv; 946} 947 948static void check_statbuf (const char *file, struct stat *sb) 949{ 950 struct tm *newtime; 951 time_t long_time; 952 953 /* Win32 processes file times in a 64 bit format 954 (see Win32 functions SetFileTime and GetFileTime). 955 If the file time on a file doesn't fit into the 956 32 bit time_t format, then stat will set that time 957 to -1. This would be OK, except that functions 958 like ctime() don't check for validity. So what we 959 do here is to give a error on -1. A cleaner solution 960 might be to change CVS's interfaces to return a time 961 in RCS format (for example), and then implement it 962 on Win32 via GetFileTime, but that would be a lot of 963 hair and I'm not sure there is much payoff. */ 964 if (sb->st_mtime == (time_t) -1) 965 error (1, 0, "invalid modification time for %s", file); 966 if (sb->st_ctime == (time_t) -1) 967 /* I'm not sure what this means on windows. It 968 might be a creation time (unlike unix).... */ 969 error (1, 0, "invalid ctime for %s", file); 970 if (sb->st_atime == (time_t) -1) 971 error (1, 0, "invalid access time for %s", file); 972 973 time( &long_time ); /* Get time as long integer. */ 974 newtime = localtime( &long_time ); /* Convert to local time. */ 975 976 /* we know for a fact that the stat function under Windoze NT 4.0 and, 977 * by all reports, many other Windoze systems, will return file times 978 * 3600 seconds too big when daylight savings time is in effect. This is 979 * a bug since it is defined as returning the time in UTC. 980 * 981 * So correct for it for now. 982 */ 983 if (newtime->tm_isdst == 1) 984 { 985 sb->st_ctime -= 3600; 986 sb->st_mtime -= 3600; 987 sb->st_atime -= 3600; 988 } 989} 990 991int 992wnt_stat (const char *file, struct stat *sb) 993{ 994 int retval; 995 996 retval = stat (file, sb); 997 if (retval < 0) 998 return retval; 999 check_statbuf (file, sb); 1000 return retval; 1001} 1002 1003int 1004wnt_lstat (const char *file, struct stat *sb) 1005{ 1006 int retval; 1007 1008 retval = lstat (file, sb); 1009 if (retval < 0) 1010 return retval; 1011 check_statbuf (file, sb); 1012 return retval; 1013} 1014