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