1 /* filesubr.c --- subroutines for dealing with files under OS/2 2 Jim Blandy <jimb@cyclic.com> and Karl Fogel <kfogel@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 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 19 20 /* These functions were moved out of subr.c because they need different 21 definitions under operating systems (like, say, Windows NT) with different 22 file system semantics. */ 23 24 #include <io.h> 25 26 #include "cvs.h" 27 28 #ifndef lint 29 static const char rcsid[] = "$CVSid:$"; 30 USE(rcsid); 31 #endif 32 33 /* 34 * I don't know of a convenient way to test this at configure time, or else 35 * I'd certainly do it there. -JimB 36 */ 37 #if defined(NeXT) 38 #define LOSING_TMPNAM_FUNCTION 39 #endif 40 41 static int deep_remove_dir PROTO((const char *path)); 42 43 /* 44 * Copies "from" to "to". 45 */ 46 void 47 copy_file (from, to) 48 const char *from; 49 const char *to; 50 { 51 struct stat sb; 52 struct utimbuf t; 53 int fdin, fdout; 54 55 if (trace) 56 #ifdef SERVER_SUPPORT 57 (void) fprintf (stderr, "%c-> copy(%s,%s)\n", 58 (server_active) ? 'S' : ' ', from, to); 59 #else 60 (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to); 61 #endif 62 if (noexec) 63 return; 64 65 if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0) 66 error (1, errno, "cannot open %s for copying", from); 67 if (fstat (fdin, &sb) < 0) 68 error (1, errno, "cannot fstat %s", from); 69 if ((fdout = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 70 (int) sb.st_mode & 07777)) < 0) 71 error (1, errno, "cannot create %s for copying", to); 72 if (sb.st_size > 0) 73 { 74 char buf[BUFSIZ]; 75 int n; 76 77 for (;;) 78 { 79 n = read (fdin, buf, sizeof(buf)); 80 if (n == -1) 81 { 82 #ifdef EINTR 83 if (errno == EINTR) 84 continue; 85 #endif 86 error (1, errno, "cannot read file %s for copying", from); 87 } 88 else if (n == 0) 89 break; 90 91 if (write(fdout, buf, n) != n) { 92 error (1, errno, "cannot write file %s for copying", to); 93 } 94 } 95 96 #ifdef HAVE_FSYNC 97 if (fsync (fdout)) 98 error (1, errno, "cannot fsync file %s after copying", to); 99 #endif 100 } 101 102 if (close (fdin) < 0) 103 error (0, errno, "cannot close %s", from); 104 if (close (fdout) < 0) 105 error (1, errno, "cannot close %s", to); 106 107 /* now, set the times for the copied file to match those of the original */ 108 memset ((char *) &t, 0, sizeof (t)); 109 t.actime = sb.st_atime; 110 t.modtime = sb.st_mtime; 111 (void) utime (to, &t); 112 } 113 114 /* 115 * link a file, if possible. Warning: the Windows NT version of this 116 * function just copies the file, so only use this function in ways 117 * that can deal with either a link or a copy. 118 */ 119 int 120 link_file (from, to) 121 const char *from; 122 const char *to; 123 { 124 copy_file (from, to); 125 return 0; 126 } 127 128 /* FIXME-krp: these functions would benefit from caching the char * & 129 stat buf. */ 130 131 /* 132 * Returns non-zero if the argument file is a directory, or is a symbolic 133 * link which points to a directory. 134 */ 135 int 136 isdir (file) 137 const char *file; 138 { 139 struct stat sb; 140 141 if (stat (file, &sb) < 0) 142 return (0); 143 return (S_ISDIR (sb.st_mode)); 144 } 145 146 /* 147 * Returns non-zero if the argument file is a symbolic link. 148 */ 149 int 150 islink (file) 151 const char *file; 152 { 153 #ifdef S_ISLNK 154 struct stat sb; 155 156 if (lstat (file, &sb) < 0) 157 return (0); 158 return (S_ISLNK (sb.st_mode)); 159 #else 160 return (0); 161 #endif 162 } 163 164 /* 165 * Returns non-zero if the argument file exists. 166 */ 167 int 168 isfile (file) 169 const char *file; 170 { 171 struct stat sb; 172 173 if (stat (file, &sb) < 0) 174 return (0); 175 return (1); 176 } 177 178 /* 179 * Returns non-zero if the argument file is readable. 180 * XXX - must be careful if "cvs" is ever made setuid! 181 */ 182 int 183 isreadable (file) 184 const char *file; 185 { 186 return (access (file, R_OK) != -1); 187 } 188 189 /* 190 * Returns non-zero if the argument file is writable 191 * XXX - muct be careful if "cvs" is ever made setuid! 192 */ 193 int 194 iswritable (file) 195 const char *file; 196 { 197 return (access (file, W_OK) != -1); 198 } 199 200 /* 201 * Returns non-zero if the argument file is accessable according to 202 * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid 203 * bits set. 204 */ 205 int 206 isaccessible (file, mode) 207 const char *file; 208 const int mode; 209 { 210 return access(file, mode) == 0; 211 } 212 213 214 /* 215 * Open a file and die if it fails 216 */ 217 FILE * 218 open_file (name, mode) 219 const char *name; 220 const char *mode; 221 { 222 FILE *fp; 223 224 if ((fp = fopen (name, mode)) == NULL) 225 error (1, errno, "cannot open %s", name); 226 return (fp); 227 } 228 229 /* 230 * Make a directory and die if it fails 231 */ 232 void 233 make_directory (name) 234 const char *name; 235 { 236 struct stat buf; 237 238 if (stat (name, &buf) == 0 && (!S_ISDIR (buf.st_mode))) 239 error (0, 0, "%s already exists but is not a directory", name); 240 if (!noexec && mkdir (name) < 0) 241 error (1, errno, "cannot make directory %s", name); 242 } 243 244 /* 245 * Make a path to the argument directory, printing a message if something 246 * goes wrong. 247 */ 248 void 249 make_directories (name) 250 const char *name; 251 { 252 char *cp; 253 254 if (noexec) 255 return; 256 257 if (mkdir (name) == 0 || errno == EACCESS) 258 return; 259 if (! existence_error (errno)) 260 { 261 error (0, errno, "cannot make path to %s", name); 262 return; 263 } 264 if ((cp = strrchr (name, '/')) == NULL) 265 return; 266 *cp = '\0'; 267 make_directories (name); 268 *cp++ = '/'; 269 if (*cp == '\0') 270 return; 271 (void) mkdir (name); 272 } 273 274 /* 275 * Change the mode of a file, either adding write permissions, or removing 276 * all write permissions. Adding write permissions honors the current umask 277 * setting. 278 */ 279 void 280 xchmod (fname, writable) 281 char *fname; 282 int writable; 283 { 284 char *attrib_cmd; 285 char *attrib_option; 286 char *whole_cmd; 287 char *p; 288 char *q; 289 290 if (!isfile (fname)) 291 return ENOENT; 292 293 attrib_cmd = "attrib "; /* No, really? */ 294 295 if (writable) 296 attrib_option = "-r "; /* make writeable */ 297 else 298 attrib_option = "+r "; /* make read-only */ 299 300 whole_cmd = xmalloc (strlen (attrib_cmd) 301 + strlen (attrib_option) 302 + strlen (fname) 303 + 1); 304 305 strcpy (whole_cmd, attrib_cmd); 306 strcat (whole_cmd, attrib_option); 307 308 /* Copy fname to the end of whole_cmd, translating / to \. 309 Attrib doesn't take / but many parts of CVS rely 310 on being able to use it. */ 311 p = whole_cmd + strlen (whole_cmd); 312 q = fname; 313 while (*q) 314 { 315 if (*q == '/') 316 *p++ = '\\'; 317 else 318 *p++ = *q; 319 ++q; 320 } 321 *p = '\0'; 322 323 system (whole_cmd); 324 free (whole_cmd); 325 } 326 327 328 /* Read the value of a symbolic link. 329 Under OS/2, this function always returns EINVAL. */ 330 int 331 readlink (char *path, char *buf, int buf_size) 332 { 333 errno = EINVAL; 334 return -1; 335 } 336 337 /* 338 * unlink a file, if possible. 339 */ 340 int 341 unlink_file (f) 342 const char *f; 343 { 344 if (trace) 345 #ifdef SERVER_SUPPORT 346 (void) fprintf (stderr, "%c-> unlink(%s)\n", 347 (server_active) ? 'S' : ' ', f); 348 #else 349 (void) fprintf (stderr, "-> unlink(%s)\n", f); 350 #endif 351 if (noexec) 352 return (0); 353 354 /* Win32 unlink is stupid - it fails if the file is read-only. 355 * OS/2 is similarly stupid. It does have a remove() function, 356 * but the documentation does not make clear why remove() is or 357 * isn't preferable to unlink(). I'll use unlink() because the 358 * name is closer to our interface, what the heck. Also, we know 359 * unlink()'s error code when trying to remove a directory. 360 */ 361 xchmod (f, 1); 362 return (unlink (f)); 363 } 364 365 /* 366 * Unlink a file or dir, if possible. If it is a directory do a deep 367 * removal of all of the files in the directory. Return -1 on error 368 * (in which case errno is set). 369 */ 370 int 371 unlink_file_dir (f) 372 const char *f; 373 { 374 if (trace) 375 #ifdef SERVER_SUPPORT 376 (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n", 377 (server_active) ? 'S' : ' ', f); 378 #else 379 (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f); 380 #endif 381 if (noexec) 382 return (0); 383 384 if (unlink_file (f) != 0) 385 { 386 /* under OS/2, unlink returns EACCESS if the path 387 is a directory. */ 388 if (errno == EACCESS) 389 return deep_remove_dir (f); 390 else 391 /* The file wasn't a directory and some other 392 * error occured 393 */ 394 return -1; 395 } 396 /* We were able to remove the file from the disk */ 397 return 0; 398 } 399 400 /* Remove a directory and everything it contains. Returns 0 for 401 * success, -1 for failure (in which case errno is set). 402 */ 403 404 static int 405 deep_remove_dir (path) 406 const char *path; 407 { 408 DIR *dirp; 409 struct dirent *dp; 410 char buf[PATH_MAX]; 411 412 if ( rmdir (path) != 0 && errno == EACCESS ) 413 { 414 if ((dirp = opendir (path)) == NULL) 415 /* If unable to open the directory return 416 * an error 417 */ 418 return -1; 419 420 while ((dp = readdir (dirp)) != NULL) 421 { 422 if (strcmp (dp->d_name, ".") == 0 || 423 strcmp (dp->d_name, "..") == 0) 424 continue; 425 426 sprintf (buf, "%s/%s", path, dp->d_name); 427 428 if (unlink_file (buf) != 0 ) 429 { 430 if (errno == EACCES) 431 { 432 if (deep_remove_dir (buf)) 433 { 434 closedir (dirp); 435 return -1; 436 } 437 } 438 else 439 { 440 /* buf isn't a directory, or there are 441 * some sort of permision problems 442 */ 443 closedir (dirp); 444 return -1; 445 } 446 } 447 } 448 closedir (dirp); 449 return rmdir (path); 450 } 451 /* Was able to remove the directory return 0 */ 452 return 0; 453 } 454 455 456 /* 457 * Rename a file and die if it fails 458 */ 459 void 460 rename_file (from, to) 461 const char *from; 462 const char *to; 463 { 464 if (trace) 465 #ifdef SERVER_SUPPORT 466 (void) fprintf (stderr, "%c-> rename(%s,%s)\n", 467 (server_active) ? 'S' : ' ', from, to); 468 #else 469 (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to); 470 #endif 471 if (noexec) 472 return; 473 474 unlink_file (to); 475 if (rename (from, to) != 0) 476 error (1, errno, "cannot rename file %s to %s", from, to); 477 } 478 479 480 /* Read NCHARS bytes from descriptor FD into BUF. 481 Return the number of characters successfully read. 482 The number returned is always NCHARS unless end-of-file or error. */ 483 static size_t 484 block_read (fd, buf, nchars) 485 int fd; 486 char *buf; 487 size_t nchars; 488 { 489 char *bp = buf; 490 size_t nread; 491 492 do 493 { 494 nread = read (fd, bp, nchars); 495 if (nread == (size_t)-1) 496 { 497 #ifdef EINTR 498 if (errno == EINTR) 499 continue; 500 #endif 501 return (size_t)-1; 502 } 503 504 if (nread == 0) 505 break; 506 507 bp += nread; 508 nchars -= nread; 509 } while (nchars != 0); 510 511 return bp - buf; 512 } 513 514 515 /* 516 * Compare "file1" to "file2". Return non-zero if they don't compare exactly. 517 */ 518 int 519 xcmp (file1, file2) 520 const char *file1; 521 const char *file2; 522 { 523 char *buf1, *buf2; 524 struct stat sb1, sb2; 525 int fd1, fd2; 526 int ret; 527 528 if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0) 529 error (1, errno, "cannot open file %s for comparing", file1); 530 if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0) 531 error (1, errno, "cannot open file %s for comparing", file2); 532 if (fstat (fd1, &sb1) < 0) 533 error (1, errno, "cannot fstat %s", file1); 534 if (fstat (fd2, &sb2) < 0) 535 error (1, errno, "cannot fstat %s", file2); 536 537 /* A generic file compare routine might compare st_dev & st_ino here 538 to see if the two files being compared are actually the same file. 539 But that won't happen in CVS, so we won't bother. */ 540 541 if (sb1.st_size != sb2.st_size) 542 ret = 1; 543 else if (sb1.st_size == 0) 544 ret = 0; 545 else 546 { 547 /* FIXME: compute the optimal buffer size by computing the least 548 common multiple of the files st_blocks field */ 549 size_t buf_size = 8 * 1024; 550 size_t read1; 551 size_t read2; 552 553 buf1 = xmalloc (buf_size); 554 buf2 = xmalloc (buf_size); 555 556 do 557 { 558 read1 = block_read (fd1, buf1, buf_size); 559 if (read1 == (size_t)-1) 560 error (1, errno, "cannot read file %s for comparing", file1); 561 562 read2 = block_read (fd2, buf2, buf_size); 563 if (read2 == (size_t)-1) 564 error (1, errno, "cannot read file %s for comparing", file2); 565 566 /* assert (read1 == read2); */ 567 568 ret = memcmp(buf1, buf2, read1); 569 } while (ret == 0 && read1 == buf_size); 570 571 free (buf1); 572 free (buf2); 573 } 574 575 (void) close (fd1); 576 (void) close (fd2); 577 return (ret); 578 } 579 580 581 /* The equivalence class mapping for filenames. 582 OS/2 filenames are case-insensitive, but case-preserving. Both / 583 and \ are path element separators. 584 Thus, this table maps both upper and lower case to lower case, and 585 both / and \ to /. 586 587 Much thanks to Jim Blandy, who already invented this wheel in the 588 Windows NT port. */ 589 590 #if 0 591 main () 592 { 593 int c; 594 595 for (c = 0; c < 256; c++) 596 { 597 int t; 598 599 if (c == '\\') 600 t = '/'; 601 else 602 t = tolower (c); 603 604 if ((c & 0x7) == 0x0) 605 printf (" "); 606 printf ("0x%02x,", t); 607 if ((c & 0x7) == 0x7) 608 putchar ('\n'); 609 else if ((c & 0x7) == 0x3) 610 putchar (' '); 611 } 612 } 613 #endif 614 615 616 unsigned char 617 OS2_filename_classes[] = 618 { 619 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 620 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, 621 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 622 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f, 623 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27, 624 0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f, 625 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37, 626 0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f, 627 0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, 628 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f, 629 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, 630 0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f, 631 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, 632 0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f, 633 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, 634 0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f, 635 0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87, 636 0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f, 637 0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97, 638 0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f, 639 0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7, 640 0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf, 641 0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7, 642 0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf, 643 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7, 644 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf, 645 0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7, 646 0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf, 647 0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7, 648 0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef, 649 0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7, 650 0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff, 651 }; 652 653 /* Like strcmp, but with the appropriate tweaks for file names. 654 Under OS/2, filenames are case-insensitive but case-preserving, and 655 both \ and / are path element separators. */ 656 int 657 fncmp (const char *n1, const char *n2) 658 { 659 while (*n1 && *n2 660 && (OS2_filename_classes[(unsigned char) *n1] 661 == OS2_filename_classes[(unsigned char) *n2])) 662 n1++, n2++; 663 return (OS2_filename_classes[(unsigned char) *n1] 664 - OS2_filename_classes[(unsigned char) *n1]); 665 } 666 667 /* Fold characters in FILENAME to their canonical forms. 668 If FOLD_FN_CHAR is not #defined, the system provides a default 669 definition for this. */ 670 void 671 fnfold (char *filename) 672 { 673 while (*filename) 674 { 675 *filename = FOLD_FN_CHAR (*filename); 676 filename++; 677 } 678 } 679 680 681 /* Return non-zero iff FILENAME is absolute. 682 Trivial under Unix, but more complicated under other systems. */ 683 int 684 isabsolute (filename) 685 const char *filename; 686 { 687 return (ISDIRSEP (filename[0]) 688 || (filename[0] != '\0' 689 && filename[1] == ':' 690 && ISDIRSEP (filename[2]))); 691 } 692 693 /* Return a pointer into PATH's last component. */ 694 char * 695 last_component (char *path) 696 { 697 char *scan; 698 char *last = 0; 699 700 for (scan = path; *scan; scan++) 701 if (ISDIRSEP (*scan)) 702 last = scan; 703 704 if (last) 705 return last + 1; 706 else 707 return path; 708 } 709 710 711 /* Read data from INFILE, and copy it to OUTFILE. 712 Open INFILE using INFLAGS, and OUTFILE using OUTFLAGS. 713 This is useful for converting between CRLF and LF line formats. */ 714 void 715 convert_file (char *infile, int inflags, 716 char *outfile, int outflags) 717 { 718 int infd, outfd; 719 char buf[8192]; 720 int len; 721 722 if ((infd = open (infile, inflags, S_IREAD | S_IWRITE)) < 0) 723 error (1, errno, "couldn't read %s", infile); 724 if ((outfd = open (outfile, outflags, S_IREAD | S_IWRITE)) < 0) 725 error (1, errno, "couldn't write %s", outfile); 726 727 while ((len = read (infd, buf, sizeof (buf))) > 0) 728 if (write (outfd, buf, len) < 0) 729 error (1, errno, "error writing %s", outfile); 730 if (len < 0) 731 error (1, errno, "error reading %s", infile); 732 733 if (close (outfd) < 0) 734 error (0, errno, "warning: couldn't close %s", outfile); 735 if (close (infd) < 0) 736 error (0, errno, "warning: couldn't close %s", infile); 737 } 738