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