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