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