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 #include <sys/cdefs.h> 16 __RCSID("$NetBSD: filesubr.c,v 1.5 2016/05/17 14:00:09 christos Exp $"); 17 18 /* These functions were moved out of subr.c because they need different 19 definitions under operating systems (like, say, Windows NT) with different 20 file system semantics. */ 21 22 #include "cvs.h" 23 #include "lstat.h" 24 #include "save-cwd.h" 25 #include "xsize.h" 26 27 static int deep_remove_dir (const char *path); 28 29 /* 30 * Copies "from" to "to". 31 */ 32 void 33 copy_file (const char *from, const char *to) 34 { 35 struct stat sb; 36 struct utimbuf t; 37 int fdin, fdout; 38 ssize_t rsize; 39 40 TRACE (TRACE_FUNCTION, "copy(%s,%s)", from, to); 41 42 if (noexec) 43 return; 44 45 /* If the file to be copied is a link or a device, then just create 46 the new link or device appropriately. */ 47 if ((rsize = islink (from)) > 0) 48 { 49 char *source = Xreadlink (from, rsize); 50 if (symlink (source, to) == -1) 51 error (1, errno, "cannot symlink %s to %s", source, to); 52 free (source); 53 return; 54 } 55 56 if (isdevice (from)) 57 { 58 #if defined(HAVE_MKNOD) && defined(HAVE_STRUCT_STAT_ST_RDEV) 59 if (stat (from, &sb) < 0) 60 error (1, errno, "cannot stat %s", from); 61 mknod (to, sb.st_mode, sb.st_rdev); 62 #else 63 error (1, 0, "cannot copy device files on this system (%s)", from); 64 #endif 65 } 66 else 67 { 68 /* Not a link or a device... probably a regular file. */ 69 if ((fdin = open (from, O_RDONLY)) < 0) 70 error (1, errno, "cannot open %s for copying", from); 71 if (fstat (fdin, &sb) < 0) 72 error (1, errno, "cannot fstat %s", from); 73 if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0) 74 error (1, errno, "cannot create %s for copying", to); 75 if (sb.st_size > 0) 76 { 77 char buf[BUFSIZ]; 78 int n; 79 80 for (;;) 81 { 82 n = read (fdin, buf, sizeof(buf)); 83 if (n == -1) 84 { 85 #ifdef EINTR 86 if (errno == EINTR) 87 continue; 88 #endif 89 error (1, errno, "cannot read file %s for copying", from); 90 } 91 else if (n == 0) 92 break; 93 94 if (write(fdout, buf, n) != n) { 95 error (1, errno, "cannot write file %s for copying", to); 96 } 97 } 98 } 99 100 if (close (fdin) < 0) 101 error (0, errno, "cannot close %s", from); 102 if (close (fdout) < 0) 103 error (1, errno, "cannot close %s", to); 104 } 105 106 /* preserve last access & modification times */ 107 memset ((char *) &t, 0, sizeof (t)); 108 t.actime = sb.st_atime; 109 t.modtime = sb.st_mtime; 110 (void) utime (to, &t); 111 } 112 113 114 115 /* FIXME-krp: these functions would benefit from caching the char * & 116 stat buf. */ 117 118 /* 119 * Returns true if the argument file is a directory, or is a symbolic 120 * link which points to a directory. 121 */ 122 bool 123 isdir (const char *file) 124 { 125 struct stat sb; 126 127 if (stat (file, &sb) < 0) 128 return false; 129 return S_ISDIR (sb.st_mode); 130 } 131 132 133 134 /* 135 * Returns 0 if the argument file is not a symbolic link. 136 * Returns size of the link if it is a symbolic link. 137 */ 138 ssize_t 139 islink (const char *file) 140 { 141 ssize_t retsize = 0; 142 #ifdef S_ISLNK 143 struct stat sb; 144 145 if ((lstat (file, &sb) >= 0) && S_ISLNK (sb.st_mode)) 146 retsize = sb.st_size; 147 #endif 148 return retsize; 149 } 150 151 152 153 /* 154 * Returns true if the argument file is a block or 155 * character special device. 156 */ 157 bool 158 isdevice (const char *file) 159 { 160 struct stat sb; 161 162 if (lstat (file, &sb) < 0) 163 return false; 164 #ifdef S_ISBLK 165 if (S_ISBLK (sb.st_mode)) 166 return true; 167 #endif 168 #ifdef S_ISCHR 169 if (S_ISCHR (sb.st_mode)) 170 return true; 171 #endif 172 return false; 173 } 174 175 176 177 /* 178 * Returns true if the argument file exists. 179 */ 180 bool 181 isfile (const char *file) 182 { 183 return isaccessible (file, F_OK); 184 } 185 186 #ifdef SETXID_SUPPORT 187 int 188 ingroup(gid_t gid) 189 { 190 gid_t *gidp; 191 int i, ngroups; 192 193 if (gid == getegid()) 194 return 1; 195 196 ngroups = getgroups(0, NULL); 197 if (ngroups == -1) 198 return 0; 199 200 if ((gidp = malloc(sizeof(gid_t) * ngroups)) == NULL) 201 return 0; 202 203 if (getgroups(ngroups, gidp) == -1) { 204 free(gidp); 205 return 0; 206 } 207 208 for (i = 0; i < ngroups; i++) 209 if (gid == gidp[i]) 210 break; 211 212 free(gidp); 213 return i != ngroups; 214 } 215 #endif 216 217 /* 218 * Returns non-zero if the argument file is readable. 219 */ 220 bool 221 isreadable (const char *file) 222 { 223 return isaccessible (file, R_OK); 224 } 225 226 227 228 /* 229 * Returns non-zero if the argument file is writable. 230 */ 231 bool 232 iswritable (const char *file) 233 { 234 return isaccessible (file, W_OK); 235 } 236 237 238 239 /* 240 * Returns true if the argument file is accessable according to 241 * mode. If compiled with SETXID_SUPPORT also works if cvs has setxid 242 * bits set. 243 */ 244 bool 245 isaccessible (const char *file, const int mode) 246 { 247 #ifdef SETXID_SUPPORT 248 struct stat sb; 249 int umask = 0; 250 int gmask = 0; 251 int omask = 0; 252 int uid, mask; 253 254 if (stat (file, &sb)== -1) 255 return false; 256 if (mode == F_OK) 257 return true; 258 259 uid = geteuid(); 260 if (uid == 0) /* superuser */ 261 { 262 if (!(mode & X_OK) || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) 263 return true; 264 265 errno = EACCES; 266 return false; 267 } 268 269 if (mode & R_OK) 270 { 271 umask |= S_IRUSR; 272 gmask |= S_IRGRP; 273 omask |= S_IROTH; 274 } 275 if (mode & W_OK) 276 { 277 umask |= S_IWUSR; 278 gmask |= S_IWGRP; 279 omask |= S_IWOTH; 280 } 281 if (mode & X_OK) 282 { 283 umask |= S_IXUSR; 284 gmask |= S_IXGRP; 285 omask |= S_IXOTH; 286 } 287 288 mask = sb.st_uid == uid ? umask : ingroup(sb.st_gid) ? gmask : omask; 289 if ((sb.st_mode & mask) == mask) 290 return true; 291 errno = EACCES; 292 return false; 293 #else /* !SETXID_SUPPORT */ 294 return access (file, mode) == 0; 295 #endif /* SETXID_SUPPORT */ 296 } 297 298 299 300 /* 301 * Make a directory and die if it fails 302 */ 303 void 304 make_directory (const char *name) 305 { 306 struct stat sb; 307 308 if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode))) 309 error (0, 0, "%s already exists but is not a directory", name); 310 if (!noexec && mkdir (name, 0777) < 0) 311 error (1, errno, "cannot make directory %s", name); 312 } 313 314 /* 315 * Make a path to the argument directory, printing a message if something 316 * goes wrong. 317 */ 318 void 319 make_directories (const char *name) 320 { 321 char *cp; 322 323 if (noexec) 324 return; 325 326 if (mkdir (name, 0777) == 0 || errno == EEXIST) 327 return; 328 if (! existence_error (errno)) 329 { 330 error (0, errno, "cannot make path to %s", name); 331 return; 332 } 333 if ((cp = strrchr (name, '/')) == NULL) 334 return; 335 *cp = '\0'; 336 make_directories (name); 337 *cp++ = '/'; 338 if (*cp == '\0') 339 return; 340 (void) mkdir (name, 0777); 341 } 342 343 /* Create directory NAME if it does not already exist; fatal error for 344 other errors. Returns 0 if directory was created; 1 if it already 345 existed. */ 346 int 347 mkdir_if_needed (const char *name) 348 { 349 if (mkdir (name, 0777) < 0) 350 { 351 int save_errno = errno; 352 if (save_errno != EEXIST && !isdir (name)) 353 error (1, save_errno, "cannot make directory %s", name); 354 return 1; 355 } 356 return 0; 357 } 358 359 /* 360 * Change the mode of a file, either adding write permissions, or removing 361 * all write permissions. Either change honors the current umask setting. 362 * 363 * Don't do anything if PreservePermissions is set to `yes'. This may 364 * have unexpected consequences for some uses of xchmod. 365 */ 366 void 367 xchmod (const char *fname, int writable) 368 { 369 struct stat sb; 370 mode_t mode, oumask; 371 372 #ifdef PRESERVE_PERMISSIONS_SUPPORT 373 if (config->preserve_perms) 374 return; 375 #endif /* PRESERVE_PERMISSIONS_SUPPORT */ 376 377 if (stat (fname, &sb) < 0) 378 { 379 if (!noexec) 380 error (0, errno, "cannot stat %s", fname); 381 return; 382 } 383 oumask = umask (0); 384 (void) umask (oumask); 385 if (writable) 386 { 387 mode = sb.st_mode | (~oumask 388 & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) 389 | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) 390 | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0))); 391 } 392 else 393 { 394 mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask; 395 } 396 397 TRACE (TRACE_FUNCTION, "chmod(%s,%o)", fname, (unsigned int) mode); 398 399 if (noexec) 400 return; 401 402 if (chmod (fname, mode) < 0) 403 error (0, errno, "cannot change mode of file %s", fname); 404 } 405 406 /* 407 * Rename a file and die if it fails 408 */ 409 void 410 rename_file (const char *from, const char *to) 411 { 412 TRACE (TRACE_FUNCTION, "rename(%s,%s)", from, to); 413 414 if (noexec) 415 return; 416 417 if (rename (from, to) < 0) 418 error (1, errno, "cannot rename file %s to %s", from, to); 419 } 420 421 /* 422 * unlink a file, if possible. 423 */ 424 int 425 unlink_file (const char *f) 426 { 427 TRACE (TRACE_FUNCTION, "unlink_file(%s)", f); 428 429 if (noexec) 430 return (0); 431 432 return (CVS_UNLINK (f)); 433 } 434 435 436 437 /* 438 * Unlink a file or dir, if possible. If it is a directory do a deep 439 * removal of all of the files in the directory. Return -1 on error 440 * (in which case errno is set). 441 */ 442 int 443 unlink_file_dir (const char *f) 444 { 445 struct stat sb; 446 447 /* This is called by the server parent process in contexts where 448 it is not OK to send output (e.g. after we sent "ok" to the 449 client). */ 450 if (!server_active) 451 TRACE (TRACE_FUNCTION, "unlink_file_dir(%s)", f); 452 453 if (noexec) 454 return 0; 455 456 /* For at least some unices, if root tries to unlink() a directory, 457 instead of doing something rational like returning EISDIR, 458 the system will gleefully go ahead and corrupt the filesystem. 459 So we first call stat() to see if it is OK to call unlink(). This 460 doesn't quite work--if someone creates a directory between the 461 call to stat() and the call to unlink(), we'll still corrupt 462 the filesystem. Where is the Unix Haters Handbook when you need 463 it? */ 464 if (stat (f, &sb) < 0) 465 { 466 if (existence_error (errno)) 467 { 468 /* The file or directory doesn't exist anyhow. */ 469 return -1; 470 } 471 } 472 else if (S_ISDIR (sb.st_mode)) 473 return deep_remove_dir (f); 474 475 return CVS_UNLINK (f); 476 } 477 478 479 480 /* Remove a directory and everything it contains. Returns 0 for 481 * success, -1 for failure (in which case errno is set). 482 */ 483 484 static int 485 deep_remove_dir (const char *path) 486 { 487 DIR *dirp; 488 struct dirent *dp; 489 490 if (rmdir (path) != 0) 491 { 492 if (errno == ENOTEMPTY 493 || errno == EEXIST 494 /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug 495 (it defines ENOTEMPTY and EEXIST to 17 but actually 496 returns 87). */ 497 || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87)) 498 { 499 if ((dirp = CVS_OPENDIR (path)) == NULL) 500 /* If unable to open the directory return 501 * an error 502 */ 503 return -1; 504 505 errno = 0; 506 while ((dp = CVS_READDIR (dirp)) != NULL) 507 { 508 char *buf; 509 510 if (strcmp (dp->d_name, ".") == 0 || 511 strcmp (dp->d_name, "..") == 0) 512 continue; 513 514 buf = Xasprintf ("%s/%s", path, dp->d_name); 515 516 /* See comment in unlink_file_dir explanation of why we use 517 isdir instead of just calling unlink and checking the 518 status. */ 519 if (isdir (buf)) 520 { 521 if (deep_remove_dir (buf)) 522 { 523 CVS_CLOSEDIR (dirp); 524 free (buf); 525 return -1; 526 } 527 } 528 else 529 { 530 if (CVS_UNLINK (buf) != 0) 531 { 532 CVS_CLOSEDIR (dirp); 533 free (buf); 534 return -1; 535 } 536 } 537 free (buf); 538 539 errno = 0; 540 } 541 if (errno != 0) 542 { 543 int save_errno = errno; 544 CVS_CLOSEDIR (dirp); 545 errno = save_errno; 546 return -1; 547 } 548 CVS_CLOSEDIR (dirp); 549 return rmdir (path); 550 } 551 else 552 return -1; 553 } 554 555 /* Was able to remove the directory return 0 */ 556 return 0; 557 } 558 559 560 561 /* Read NCHARS bytes from descriptor FD into BUF. 562 Return the number of characters successfully read. 563 The number returned is always NCHARS unless end-of-file or error. */ 564 static size_t 565 block_read (int fd, char *buf, size_t nchars) 566 { 567 char *bp = buf; 568 size_t nread; 569 570 do 571 { 572 nread = read (fd, bp, nchars); 573 if (nread == (size_t)-1) 574 { 575 #ifdef EINTR 576 if (errno == EINTR) 577 continue; 578 #endif 579 return (size_t)-1; 580 } 581 582 if (nread == 0) 583 break; 584 585 bp += nread; 586 nchars -= nread; 587 } while (nchars != 0); 588 589 return bp - buf; 590 } 591 592 593 /* 594 * Compare "file1" to "file2". Return non-zero if they don't compare exactly. 595 * If FILE1 and FILE2 are special files, compare their salient characteristics 596 * (i.e. major/minor device numbers, links, etc. 597 */ 598 int 599 xcmp (const char *file1, const char *file2) 600 { 601 char *buf1, *buf2; 602 struct stat sb1, sb2; 603 int fd1, fd2; 604 int ret; 605 606 if (lstat (file1, &sb1) < 0) 607 error (1, errno, "cannot lstat %s", file1); 608 if (lstat (file2, &sb2) < 0) 609 error (1, errno, "cannot lstat %s", file2); 610 611 /* If FILE1 and FILE2 are not the same file type, they are unequal. */ 612 if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT)) 613 return 1; 614 615 /* If FILE1 and FILE2 are symlinks, they are equal if they point to 616 the same thing. */ 617 #ifdef S_ISLNK 618 if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode)) 619 { 620 int result; 621 buf1 = Xreadlink (file1, sb1.st_size); 622 buf2 = Xreadlink (file2, sb2.st_size); 623 result = (strcmp (buf1, buf2) == 0); 624 free (buf1); 625 free (buf2); 626 return result; 627 } 628 #endif 629 630 /* If FILE1 and FILE2 are devices, they are equal if their device 631 numbers match. */ 632 if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode)) 633 { 634 #ifdef HAVE_STRUCT_STAT_ST_RDEV 635 if (sb1.st_rdev == sb2.st_rdev) 636 return 0; 637 else 638 return 1; 639 #else 640 error (1, 0, "cannot compare device files on this system (%s and %s)", 641 file1, file2); 642 #endif 643 } 644 645 if ((fd1 = open (file1, O_RDONLY)) < 0) 646 error (1, errno, "cannot open file %s for comparing", file1); 647 if ((fd2 = open (file2, O_RDONLY)) < 0) 648 error (1, errno, "cannot open file %s for comparing", file2); 649 650 /* A generic file compare routine might compare st_dev & st_ino here 651 to see if the two files being compared are actually the same file. 652 But that won't happen in CVS, so we won't bother. */ 653 654 if (sb1.st_size != sb2.st_size) 655 ret = 1; 656 else if (sb1.st_size == 0) 657 ret = 0; 658 else 659 { 660 /* FIXME: compute the optimal buffer size by computing the least 661 common multiple of the files st_blocks field */ 662 size_t buf_size = 8 * 1024; 663 size_t read1; 664 size_t read2; 665 666 buf1 = xmalloc (buf_size); 667 buf2 = xmalloc (buf_size); 668 669 do 670 { 671 read1 = block_read (fd1, buf1, buf_size); 672 if (read1 == (size_t)-1) 673 error (1, errno, "cannot read file %s for comparing", file1); 674 675 read2 = block_read (fd2, buf2, buf_size); 676 if (read2 == (size_t)-1) 677 error (1, errno, "cannot read file %s for comparing", file2); 678 679 /* assert (read1 == read2); */ 680 681 ret = memcmp(buf1, buf2, read1); 682 } while (ret == 0 && read1 == buf_size); 683 684 free (buf1); 685 free (buf2); 686 } 687 688 (void) close (fd1); 689 (void) close (fd2); 690 return (ret); 691 } 692 693 /* Generate a unique temporary filename. Returns a pointer to a newly 694 * malloc'd string containing the name. Returns successfully or not at 695 * all. 696 * 697 * THIS FUNCTION IS DEPRECATED!!! USE cvs_temp_file INSTEAD!!! 698 * 699 * and yes, I know about the way the rcs commands use temp files. I think 700 * they should be converted too but I don't have time to look into it right 701 * now. 702 */ 703 char * 704 cvs_temp_name (void) 705 { 706 char *fn; 707 FILE *fp; 708 709 fp = cvs_temp_file (&fn); 710 if (fp == NULL) 711 error (1, errno, "Failed to create temporary file"); 712 if (fclose (fp) == EOF) 713 error (0, errno, "Failed to close temporary file %s", fn); 714 return fn; 715 } 716 717 /* Generate a unique temporary filename and return an open file stream 718 * to the truncated file by that name 719 * 720 * INPUTS 721 * filename where to place the pointer to the newly allocated file 722 * name string 723 * 724 * OUTPUTS 725 * filename dereferenced, will point to the newly allocated file 726 * name string. This value is undefined if the function 727 * returns an error. 728 * 729 * RETURNS 730 * An open file pointer to a read/write mode empty temporary file with the 731 * unique file name or NULL on failure. 732 * 733 * ERRORS 734 * On error, errno will be set to some value either by CVS_FOPEN or 735 * whatever system function is called to generate the temporary file name. 736 * The value of filename is undefined on error. 737 */ 738 FILE * 739 cvs_temp_file (char **filename) 740 { 741 char *fn; 742 FILE *fp; 743 int fd; 744 745 /* FIXME - I'd like to be returning NULL here in noexec mode, but I think 746 * some of the rcs & diff functions which rely on a temp file run in 747 * noexec mode too. 748 */ 749 750 assert (filename != NULL); 751 752 fn = Xasprintf ("%s/%s", get_cvs_tmp_dir (), "cvsXXXXXX"); 753 fd = mkstemp (fn); 754 755 /* a NULL return will be interpreted by callers as an error and 756 * errno should still be set 757 */ 758 if (fd == -1) 759 fp = NULL; 760 else if ((fp = CVS_FDOPEN (fd, "w+")) == NULL) 761 { 762 /* Attempt to close and unlink the file since mkstemp returned 763 * sucessfully and we believe it's been created and opened. 764 */ 765 int save_errno = errno; 766 if (close (fd)) 767 error (0, errno, "Failed to close temporary file %s", fn); 768 if (CVS_UNLINK (fn)) 769 error (0, errno, "Failed to unlink temporary file %s", fn); 770 errno = save_errno; 771 } 772 773 if (fp == NULL) 774 free (fn); 775 776 /* mkstemp is defined to open mode 0600 using glibc 2.0.7+. There used 777 * to be a complicated #ifdef checking the library versions here and then 778 * a chmod 0600 on the temp file for versions of glibc less than 2.1. This 779 * is rather a special case, leaves a race condition open regardless, and 780 * one could hope that sysadmins have read the relevant security 781 * announcements and upgraded by now to a version with a fix committed in 782 * January of 1999. 783 * 784 * If it is decided at some point that old, buggy versions of glibc should 785 * still be catered to, a umask of 0600 should be set before file creation 786 * instead then reset after file creation since this would avoid the race 787 * condition that the chmod left open to exploitation. 788 */ 789 790 *filename = fn; 791 return fp; 792 } 793 794 795 796 /* Return a pointer into PATH's last component. */ 797 const char * 798 last_component (const char *path) 799 { 800 const char *last = strrchr (path, '/'); 801 802 if (last && (last != path)) 803 return last + 1; 804 else 805 return path; 806 } 807 808 809 810 /* Return the home directory. Returns a pointer to storage 811 managed by this function or its callees (currently getenv). 812 This function will return the same thing every time it is 813 called. Returns NULL if there is no home directory. 814 815 Note that for a pserver server, this may return root's home 816 directory. What typically happens is that upon being started from 817 inetd, before switching users, the code in cvsrc.c calls 818 get_homedir which remembers root's home directory in the static 819 variable. Then the switch happens and get_homedir might return a 820 directory that we don't even have read or execute permissions for 821 (which is bad, when various parts of CVS try to read there). One 822 fix would be to make the value returned by get_homedir only good 823 until the next call (which would free the old value). Another fix 824 would be to just always malloc our answer, and let the caller free 825 it (that is best, because some day we may need to be reentrant). 826 827 The workaround is to put -f in inetd.conf which means that 828 get_homedir won't get called until after the switch in user ID. 829 830 The whole concept of a "home directory" on the server is pretty 831 iffy, although I suppose some people probably are relying on it for 832 .cvsrc and such, in the cases where it works. */ 833 char * 834 get_homedir (void) 835 { 836 static char *home = NULL; 837 char *env; 838 struct passwd *pw; 839 840 if (home != NULL) 841 return home; 842 843 if (!server_active && (env = getenv ("HOME")) != NULL) 844 home = env; 845 else if ((pw = (struct passwd *) getpwuid (getuid ())) 846 && pw->pw_dir) 847 home = xstrdup (pw->pw_dir); 848 else 849 return 0; 850 851 return home; 852 } 853 854 /* Compose a path to a file in the home directory. This is necessary because 855 * of different behavior on UNIX and VMS. See the notes in vms/filesubr.c. 856 * 857 * A more clean solution would be something more along the lines of a 858 * "join a directory to a filename" kind of thing which was not specific to 859 * the homedir. This should aid portability between UNIX, Mac, Windows, VMS, 860 * and possibly others. This is already handled by Perl - it might be 861 * interesting to see how much of the code was written in C since Perl is under 862 * the GPL and the Artistic license - we might be able to use it. 863 */ 864 char * 865 strcat_filename_onto_homedir (const char *dir, const char *file) 866 { 867 char *path = Xasprintf ("%s/%s", dir, file); 868 return path; 869 } 870 871 /* See cvs.h for description. On unix this does nothing, because the 872 shell expands the wildcards. */ 873 void 874 expand_wild (int argc, char **argv, int *pargc, char ***pargv) 875 { 876 int i; 877 if (size_overflow_p (xtimes (argc, sizeof (char *)))) { 878 *pargc = 0; 879 *pargv = NULL; 880 error (0, 0, "expand_wild: too many arguments"); 881 return; 882 } 883 *pargc = argc; 884 *pargv = xnmalloc (argc, sizeof (char *)); 885 for (i = 0; i < argc; ++i) 886 (*pargv)[i] = xstrdup (argv[i]); 887 } 888 889 890 891 static char *tmpdir_env; 892 893 /* Return path to temp directory. 894 */ 895 const char * 896 get_system_temp_dir (void) 897 { 898 if (!tmpdir_env) tmpdir_env = getenv (TMPDIR_ENV); 899 return tmpdir_env; 900 } 901 902 903 904 void 905 push_env_temp_dir (void) 906 { 907 const char *tmpdir = get_cvs_tmp_dir (); 908 if (tmpdir_env && strcmp (tmpdir_env, tmpdir)) 909 setenv (TMPDIR_ENV, tmpdir, 1); 910 } 911