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 <assert.h>
21 #include <io.h>
22 #include <sys/socket.h>  /* This does: #include <windows.h> */
23 
24 #include "cvs.h"
25 #include "setenv.h"
26 
27 #include "JmgStat.h"
28 
29 #undef mkdir
30 
31 static int deep_remove_dir( const char *path );
32 
33 /* Copies "from" to "to".  Note that the functionality here is similar
34    to the win32 function CopyFile, but (1) we copy LastAccessTime and
35    CopyFile doesn't, (2) we set file attributes to the default set by
36    the C library and CopyFile copies them.  Neither #1 nor #2 was intentional
37    as far as I know, but changing them could be confusing, unless there
38    is some reason they should be changed (this would need more
39    investigation).  */
40 void
copy_file(from,to)41 copy_file (from, to)
42     const char *from;
43     const char *to;
44 {
45     struct stat sb;
46     struct utimbuf t;
47     int fdin, fdout;
48 
49     if (trace)
50 #ifdef SERVER_SUPPORT
51 	(void) fprintf (stderr, "%c-> copy(%s,%s)\n",
52 			(server_active) ? 'S' : ' ', from, to);
53 #else
54 	(void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
55 #endif
56     if (noexec)
57 	return;
58 
59     if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
60 	error (1, errno, "cannot open %s for copying", from);
61     if (fstat (fdin, &sb) < 0)
62 	error (1, errno, "cannot fstat %s", from);
63     if ((fdout = open (to, O_CREAT | O_TRUNC | O_RDWR | O_BINARY,
64 		       (int) sb.st_mode & 07777)) < 0)
65 	error (1, errno, "cannot create %s for copying", to);
66     if (sb.st_size > 0)
67     {
68 	char buf[BUFSIZ];
69 	int n;
70 
71 	for (;;)
72 	{
73 	    n = read (fdin, buf, sizeof(buf));
74 	    if (n == -1)
75 	    {
76 #ifdef EINTR
77 		if (errno == EINTR)
78 		    continue;
79 #endif
80 		error (1, errno, "cannot read file %s for copying", from);
81 	    }
82             else if (n == 0)
83 		break;
84 
85 	    if (write(fdout, buf, n) != n) {
86 		error (1, errno, "cannot write file %s for copying", to);
87 	    }
88 	}
89 
90 #ifdef HAVE_FSYNC
91 	if (fsync (fdout))
92 	    error (1, errno, "cannot fsync file %s after copying", to);
93 #endif
94     }
95 
96     if (close (fdin) < 0)
97 	error (0, errno, "cannot close %s", from);
98     if (close (fdout) < 0)
99 	error (1, errno, "cannot close %s", to);
100 
101     /* now, set the times for the copied file to match those of the original */
102     memset ((char *) &t, 0, sizeof (t));
103     t.actime = sb.st_atime;
104     t.modtime = sb.st_mtime;
105     (void) utime (to, &t);
106 }
107 
108 
109 static char *tmpdir_env;
110 /*
111  * Return seperator (\) terminated path to system temporary directory.
112  */
113 const char *
get_system_temp_dir(void)114 get_system_temp_dir (void)
115 {
116 	if (! tmpdir_env)
117 	{
118 		DWORD dwBufferSize, dwReturn;
119 
120 		dwReturn = 0;
121 		dwBufferSize = 64;
122 		do {
123 			if (dwReturn >= dwBufferSize)
124 			{
125 				dwBufferSize = dwReturn + 4;
126 			}
127 
128 			tmpdir_env = xrealloc (tmpdir_env, dwBufferSize);
129 			if (tmpdir_env)
130 			{
131 				dwReturn = GetTempPath (dwBufferSize, tmpdir_env);
132 				if (dwReturn <= 0)
133 				{
134 					free (tmpdir_env);
135 					tmpdir_env = NULL;
136 				}
137 			}
138 		} while (tmpdir_env && dwReturn >= dwBufferSize);
139 	}
140 
141 	return tmpdir_env;
142 }
143 
144 
145 void
push_env_temp_dir(void)146 push_env_temp_dir (void)
147 {
148 	const char *tmpdir = get_cvs_tmp_dir ();
149 
150 	if (tmpdir_env && strcmp (tmpdir_env, tmpdir))
151 		setenv ("TMP", tmpdir, 1);
152 }
153 
154 
155 /* FIXME-krp: these functions would benefit from caching the char * &
156    stat buf.  */
157 
158 /*
159  * Returns non-zero if the argument file is a directory, or is a symbolic
160  * link which points to a directory.
161  */
162 int
isdir(file)163 isdir (file)
164     const char *file;
165 {
166     struct stat sb;
167 
168     if (stat (file, &sb) < 0)
169 	return (0);
170     return (S_ISDIR (sb.st_mode));
171 }
172 
173 /*
174  * Returns non-zero if the argument file is a symbolic link.
175  */
176 int
islink(file)177 islink (file)
178     const char *file;
179 {
180 #ifdef S_ISLNK
181     struct stat sb;
182 
183     if (lstat (file, &sb) < 0)
184 	return (0);
185     return (S_ISLNK (sb.st_mode));
186 #else
187     return (0);
188 #endif
189 }
190 
191 /*
192  * Returns non-zero if the argument file exists.
193  */
194 int
isfile(file)195 isfile (file)
196     const char *file;
197 {
198     return isaccessible(file, F_OK);
199 }
200 
201 /*
202  * Returns non-zero if the argument file is readable.
203  */
204 int
isreadable(file)205 isreadable (file)
206     const char *file;
207 {
208     return isaccessible(file, R_OK);
209 }
210 
211 /*
212  * Returns non-zero if the argument file is writable.
213  */
214 int
iswritable(file)215 iswritable (file)
216     const char *file;
217 {
218     return isaccessible(file, W_OK);
219 }
220 
221 /*
222  * Returns non-zero if the argument file is accessable according to
223  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
224  * bits set.
225  */
226 int
isaccessible(file,mode)227 isaccessible (file, mode)
228     const char *file;
229     const int mode;
230 {
231 #ifdef SETXID_SUPPORT
232     struct stat sb;
233     int umask = 0;
234     int gmask = 0;
235     int omask = 0;
236     int uid;
237 
238     if (stat(file, &sb) == -1)
239 	return 0;
240     if (mode == F_OK)
241 	return 1;
242 
243     uid = geteuid();
244     if (uid == 0)		/* superuser */
245     {
246 	if (mode & X_OK)
247 	    return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
248 	else
249 	    return 1;
250     }
251 
252     if (mode & R_OK)
253     {
254 	umask |= S_IRUSR;
255 	gmask |= S_IRGRP;
256 	omask |= S_IROTH;
257     }
258     if (mode & W_OK)
259     {
260 	umask |= S_IWUSR;
261 	gmask |= S_IWGRP;
262 	omask |= S_IWOTH;
263     }
264     if (mode & X_OK)
265     {
266 	umask |= S_IXUSR;
267 	gmask |= S_IXGRP;
268 	omask |= S_IXOTH;
269     }
270 
271     if (sb.st_uid == uid)
272 	return (sb.st_mode & umask) == umask;
273     else if (sb.st_gid == getegid())
274 	return (sb.st_mode & gmask) == gmask;
275     else
276 	return (sb.st_mode & omask) == omask;
277 #else
278     return access(file, mode) == 0;
279 #endif
280 }
281 
282 
283 
284 /*
285  * Make a directory and die if it fails
286  */
287 void
make_directory(name)288 make_directory (name)
289     const char *name;
290 {
291     struct stat sb;
292 
293     if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
294 	    error (0, 0, "%s already exists but is not a directory", name);
295     if (!noexec && mkdir (name) < 0)
296 	error (1, errno, "cannot make directory %s", name);
297 }
298 
299 /*
300  * Make a path to the argument directory, printing a message if something
301  * goes wrong.
302  */
303 void
make_directories(name)304 make_directories (name)
305     const char *name;
306 {
307     char *cp;
308 
309     if (noexec)
310 	return;
311 
312     if (mkdir (name) == 0 || errno == EEXIST)
313 	return;
314     if (errno != ENOENT)
315     {
316 	error (0, errno, "cannot make path to %s", name);
317 	return;
318     }
319     if ((cp = strrchr (name, '/')) == NULL)
320 	return;
321     *cp = '\0';
322     make_directories (name);
323     *cp++ = '/';
324     if (*cp == '\0')
325 	return;
326     (void) mkdir (name);
327 }
328 
329 /* Create directory NAME if it does not already exist; fatal error for
330    other errors.  Returns 0 if directory was created; 1 if it already
331    existed.  */
332 int
mkdir_if_needed(name)333 mkdir_if_needed (name)
334     const char *name;
335 {
336     if (mkdir (name) < 0)
337     {
338 	if (errno != EEXIST
339 #ifdef EACCESS
340 	    /* This was copied over from the OS/2 code; I would guess it
341 	       isn't needed here but that has not been verified.  */
342 	    && errno != EACCESS
343 #endif
344 #ifdef EACCES
345 	    /* This is said to be needed by NT on Alpha or PowerPC
346 	       (not sure what version) --August, 1996.  */
347 	    && errno != EACCES
348 #endif
349 	    )
350 	    error (1, 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.  Adding write permissions honors the current umask
359  * setting.
360  */
361 void
xchmod(fname,writable)362 xchmod (fname, writable)
363     const char *fname;
364     int writable;
365 {
366     struct stat sb;
367     mode_t mode, oumask;
368 
369     if (stat (fname, &sb) < 0)
370     {
371 	if (!noexec)
372 	    error (0, errno, "cannot stat %s", fname);
373 	return;
374     }
375     if (writable)
376     {
377 	oumask = umask (0);
378 	(void) umask (oumask);
379 	mode = sb.st_mode | ~oumask & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0) |
380 				       ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0) |
381 				       ((sb.st_mode & S_IROTH) ? S_IWOTH : 0));
382     }
383     else
384     {
385 	mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH);
386     }
387 
388     if (trace)
389 #ifdef SERVER_SUPPORT
390 	(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
391 			(server_active) ? 'S' : ' ', fname, mode);
392 #else
393 	(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, mode);
394 #endif
395     if (noexec)
396 	return;
397 
398     if (chmod (fname, mode) < 0)
399 	error (0, errno, "cannot change mode of file %s", fname);
400 }
401 
402 
403 /* Rename for NT which works for read only files.  Apparently if we are
404    accessing FROM and TO via a Novell network, this is an issue.  */
405 int
wnt_rename(from,to)406 wnt_rename (from, to)
407     const char *from;
408     const char *to;
409 {
410     int result, save_errno;
411     int readonly = !iswritable (from);
412 
413     if (readonly)
414     {
415 	if (chmod (from, S_IWRITE) < 0)
416 	    return -1;
417     }
418     result = rename (from, to);
419     save_errno = errno;
420     if (readonly)
421     {
422 	if (result == 0)
423 	{
424 	    if (chmod (to, S_IREAD) < 0)
425 		return -1;
426 	}
427 	else
428 	{
429 	    /* We have a choice of which error to report, if there is
430 	       one here too; report the one from rename ().  */
431 	    chmod (from, S_IREAD);
432 	}
433 	errno = save_errno;
434     }
435     return result;
436 }
437 
438 /*
439  * Rename a file and die if it fails
440  */
441 void
rename_file(from,to)442 rename_file (from, to)
443     const char *from;
444     const char *to;
445 {
446     if (trace)
447 #ifdef SERVER_SUPPORT
448 	(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
449 			(server_active) ? 'S' : ' ', from, to);
450 #else
451 	(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
452 #endif
453     if (noexec)
454 	return;
455 
456     /* Win32 unlink is stupid --- it fails if the file is read-only  */
457     chmod(to, S_IWRITE);
458     unlink(to);
459     if (CVS_RENAME (from, to) < 0)
460 	error (1, errno, "cannot rename file %s to %s", from, to);
461 }
462 
463 /*
464  * unlink a file, if possible.
465  */
466 int
unlink_file(f)467 unlink_file (f)
468     const char *f;
469 {
470     if (trace)
471 #ifdef SERVER_SUPPORT
472 	(void) fprintf (stderr, "%c-> unlink(%s)\n",
473 			(server_active) ? 'S' : ' ', f);
474 #else
475 	(void) fprintf (stderr, "-> unlink(%s)\n", f);
476 #endif
477     if (noexec)
478 	return (0);
479 
480     /* Win32 unlink is stupid - it fails if the file is read-only */
481     chmod (f, _S_IWRITE);
482     return (unlink (f));
483 }
484 
485 /*
486  * Unlink a file or dir, if possible.  If it is a directory do a deep
487  * removal of all of the files in the directory.  Return -1 on error
488  * (in which case errno is set).
489  */
490 int
unlink_file_dir(f)491 unlink_file_dir (f)
492     const char *f;
493 {
494     if (trace)
495 #ifdef SERVER_SUPPORT
496 	(void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
497 			(server_active) ? 'S' : ' ', f);
498 #else
499 	(void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
500 #endif
501     if (noexec)
502 	return (0);
503 
504     /* Win32 unlink is stupid - it fails if the file is read-only */
505     chmod (f, _S_IWRITE);
506     if (unlink (f) != 0)
507     {
508 	/* Under Windows NT, unlink returns EACCES if the path
509            is a directory.  Under Windows 95, it returns ENOENT.
510            Under Windows XP, it can return ENOTEMPTY. */
511         if (errno == EISDIR || errno == EACCES || errno == ENOENT
512             || errno == ENOTEMPTY)
513                 return deep_remove_dir (f);
514         else
515 		/* The file wasn't a directory and some other
516 		 * error occured
517 		 */
518                 return -1;
519     }
520     /* We were able to remove the file from the disk */
521     return 0;
522 }
523 
524 /* Remove a directory and everything it contains.  Returns 0 for
525  * success, -1 for failure (in which case errno is set).
526  */
527 
528 static int
deep_remove_dir(path)529 deep_remove_dir (path)
530     const char *path;
531 {
532     DIR		  *dirp;
533     struct dirent *dp;
534     char	   buf[PATH_MAX];
535 
536     /* ENOTEMPTY for NT (obvious) but EACCES for Win95 (not obvious) */
537     if (rmdir (path) != 0)
538     {
539 	if (errno == ENOTEMPTY || errno == EACCES)
540 	{
541 	    if ((dirp = CVS_OPENDIR (path)) == NULL)
542 		/* If unable to open the directory return
543 		 * an error
544 		 */
545 		return -1;
546 
547 	    while ((dp = CVS_READDIR (dirp)) != NULL)
548 	    {
549 		if (strcmp (dp->d_name, ".") == 0 ||
550 			    strcmp (dp->d_name, "..") == 0)
551 		    continue;
552 
553 		sprintf (buf, "%s/%s", path, dp->d_name);
554 
555 		/* Win32 unlink is stupid - it fails if the file is read-only */
556 		chmod (buf, _S_IWRITE);
557 		if (unlink (buf) != 0 )
558 		{
559 		    /* Under Windows NT, unlink returns EACCES if the path
560 		     * is a directory.  Under Windows 95, it returns ENOENT.
561                      * Under Windows XP, it can return ENOTEMPTY.  It
562 		     * isn't really clear to me whether checking errno is
563 		     * better or worse than using _stat to check for a
564                      * directory.
565 		     * We aren't really trying to prevent race conditions here
566 		     * (e.g. what if something changes between readdir and
567 		     * unlink?)
568                      */
569 		    if (errno == EISDIR || errno == EACCES || errno == ENOENT
570                         || errno == ENOTEMPTY)
571 		    {
572 			if (deep_remove_dir (buf))
573 			{
574 			    closedir (dirp);
575 			    return -1;
576 			}
577 		    }
578 		    else
579 		    {
580 			/* buf isn't a directory, or there are
581 			 * some sort of permision problems
582 			 */
583 			CVS_CLOSEDIR (dirp);
584 			return -1;
585 		    }
586 		}
587 	    }
588 	    CVS_CLOSEDIR (dirp);
589 	    return rmdir (path);
590 	}
591 	else
592 	    return -1;
593     }
594     /* Was able to remove the directory return 0 */
595     return 0;
596 }
597 
598 /* Read NCHARS bytes from descriptor FD into BUF.
599    Return the number of characters successfully read.
600    The number returned is always NCHARS unless end-of-file or error.  */
601 static size_t
block_read(fd,buf,nchars)602 block_read (fd, buf, nchars)
603     int fd;
604     char *buf;
605     size_t nchars;
606 {
607     char *bp = buf;
608     size_t nread;
609 
610     do
611     {
612 	nread = read (fd, bp, nchars);
613 	if (nread == (size_t)-1)
614 	{
615 #ifdef EINTR
616 	    if (errno == EINTR)
617 		continue;
618 #endif
619 	    return (size_t)-1;
620 	}
621 
622 	if (nread == 0)
623 	    break;
624 
625 	bp += nread;
626 	nchars -= nread;
627     } while (nchars != 0);
628 
629     return bp - buf;
630 }
631 
632 
633 /*
634  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
635  */
636 int
xcmp(file1,file2)637 xcmp (file1, file2)
638     const char *file1;
639     const char *file2;
640 {
641     char *buf1, *buf2;
642     struct stat sb1, sb2;
643     int fd1, fd2;
644     int ret;
645 
646     if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
647 	error (1, errno, "cannot open file %s for comparing", file1);
648     if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
649 	error (1, errno, "cannot open file %s for comparing", file2);
650     if (fstat (fd1, &sb1) < 0)
651 	error (1, errno, "cannot fstat %s", file1);
652     if (fstat (fd2, &sb2) < 0)
653 	error (1, errno, "cannot fstat %s", file2);
654 
655     /* A generic file compare routine might compare st_dev & st_ino here
656        to see if the two files being compared are actually the same file.
657        But that won't happen in CVS, so we won't bother. */
658 
659     if (sb1.st_size != sb2.st_size)
660 	ret = 1;
661     else if (sb1.st_size == 0)
662 	ret = 0;
663     else
664     {
665 	/* FIXME: compute the optimal buffer size by computing the least
666 	   common multiple of the files st_blocks field */
667 	size_t buf_size = 8 * 1024;
668 	size_t read1;
669 	size_t read2;
670 
671 	buf1 = xmalloc (buf_size);
672 	buf2 = xmalloc (buf_size);
673 
674 	do
675 	{
676 	    read1 = block_read (fd1, buf1, buf_size);
677 	    if (read1 == (size_t)-1)
678 		error (1, errno, "cannot read file %s for comparing", file1);
679 
680 	    read2 = block_read (fd2, buf2, buf_size);
681 	    if (read2 == (size_t)-1)
682 		error (1, errno, "cannot read file %s for comparing", file2);
683 
684 	    /* assert (read1 == read2); */
685 
686 	    ret = memcmp(buf1, buf2, read1);
687 	} while (ret == 0 && read1 == buf_size);
688 
689 	free (buf1);
690 	free (buf2);
691     }
692 
693     (void) close (fd1);
694     (void) close (fd2);
695     return (ret);
696 }
697 
698 /* Generate a unique temporary filename.  Returns a pointer to a newly
699  * malloc'd string containing the name.  Returns successfully or not at
700  * all.
701  *
702  *     THIS FUNCTION IS DEPRECATED!!!  USE cvs_temp_file INSTEAD!!!
703  *
704  * and yes, I know about the way the rcs commands use temp files.  I think
705  * they should be converted too but I don't have time to look into it right
706  * now.
707  */
708 char *
cvs_temp_name()709 cvs_temp_name ()
710 {
711     char *fn;
712     FILE *fp;
713 
714     fp = cvs_temp_file (&fn);
715     if (fp == NULL)
716 	error (1, errno, "Failed to create temporary file");
717     if (fclose (fp) == EOF)
718 	error (0, errno, "Failed to close temporary file %s", fn);
719     return fn;
720 }
721 
722 /* Generate a unique temporary filename and return an open file stream
723  * to the truncated file by that name
724  *
725  *  INPUTS
726  *	filename	where to place the pointer to the newly allocated file
727  *   			name string
728  *
729  *  OUTPUTS
730  *	filename	dereferenced, will point to the newly allocated file
731  *			name string.  This value is undefined if the function
732  *			returns an error.
733  *
734  *  RETURNS
735  *	An open file pointer to a read/write mode empty temporary file with the
736  *	unique file name or NULL on failure.
737  *
738  *  ERRORS
739  *	on error, errno will be set to some value either by CVS_FOPEN or
740  *	whatever system function is called to generate the temporary file name
741  */
742 /* FIXME: This should use the mkstemp() function from the lib/mkstemp.c file
743  * from the GNULIB project.
744  */
cvs_temp_file(char ** filename)745 FILE *cvs_temp_file (char ** filename)
746 {
747     char *fn;
748     FILE *fp;
749 
750     /* FIXME - I'd like to be returning NULL here in noexec mode, but I think
751      * some of the rcs & diff functions which rely on a temp file run in
752      * noexec mode too.
753      */
754 
755     /* assert (filename != NULL); */
756 
757     fn = _tempnam (getenv("TEMP"), "cvs");
758     if (fn == NULL) fp = NULL;
759     else
760     if ((fp = CVS_FOPEN (fn, "w+")) == NULL)
761     {
762         free (fn);
763         fn = NULL;
764     }
765 
766     /* tempnam returns a pointer to a newly malloc'd string, so there's
767      * no need for a xstrdup
768      */
769 
770     *filename = fn;
771     return fp;
772 }
773 
774 
775 
776 /* Return a pointer into PATH's last component.  */
777 const char *
last_component(const char * path)778 last_component (const char *path)
779 {
780     const char *scan;
781     const char *last = 0;
782 
783     for (scan = path; *scan; scan++)
784         if (ISSLASH (*scan))
785 	    last = scan;
786 
787     if (last && (last != path))
788         return last + 1;
789     else
790         return path;
791 }
792 
793 
794 /* NT has two evironment variables, HOMEPATH and HOMEDRIVE, which,
795    when combined as ${HOMEDRIVE}${HOMEPATH}, give the unix equivalent
796    of HOME.  Some NT users are just too unixy, though, and set the
797    HOME variable themselves.  Therefore, we check for HOME first, and
798    then try to combine the other two if that fails.
799 
800    Looking for HOME strikes me as bogus, particularly if the only reason
801    is to cater to "unixy users".  On the other hand, if the reasoning is
802    there should be a single variable, rather than requiring people to
803    set both HOMEDRIVE and HOMEPATH, then it starts to make a little more
804    sense.
805 
806    Win95: The system doesn't set HOME, HOMEDRIVE, or HOMEPATH (at
807    least if you set it up as the "all users under one user ID" or
808    whatever the name of that option is).  Based on thing overheard on
809    the net, it seems that users of the pserver client have gotten in
810    the habit of setting HOME (if you don't use pserver, you can
811    probably get away without having a reasonable return from
812    get_homedir.  Of course you lose .cvsrc and .cvsignore, but many
813    users won't notice).  So it would seem that we should be somewhat
814    careful if we try to change the current behavior.
815 
816    NT 3.51 or NT 4.0: I haven't checked this myself, but I am told
817    that HOME gets set, but not to the user's home directory.  It is
818    said to be set to c:\users\default by default.  */
819 
820 char *
get_homedir(void)821 get_homedir (void)
822 {
823     char *homedir;
824 
825     homedir = getenv ("HOME");
826 
827     if (homedir == NULL)
828 	homedir = woe32_home_dir ();
829 
830     return homedir;
831 }
832 
833 /* Compose a path to a file in the home directory.  This is necessary because
834  * of different behavior on UNIX, Windows, and VMS.  See more notes in
835  * vms/filesubr.c.
836  *
837  * A more clean solution would be something more along the lines of a
838  * "join a directory to a filename" kind of thing which was not specific to
839  * the homedir.  This should aid portability between UNIX, Mac, Windows, VMS,
840  * and possibly others.  This is already handled by Perl - it might be
841  * interesting to see how much of the code was written in C since Perl is under
842  * the GPL and the Artistic license - we might be able to use it.
843  */
844 char *
strcat_filename_onto_homedir(dir,file)845 strcat_filename_onto_homedir (dir, file)
846     const char *dir;
847     const char *file;
848 {
849     char *path = xmalloc (strlen (dir) + 1 + strlen(file) + 1);
850     sprintf (path, "%s\\%s", dir, file);
851     return path;
852 }
853 
854 /* See cvs.h for description.  */
855 void
expand_wild(argc,argv,pargc,pargv)856 expand_wild (argc, argv, pargc, pargv)
857     int argc;
858     char **argv;
859     int *pargc;
860     char ***pargv;
861 {
862     int i;
863     int new_argc;
864     char **new_argv;
865     /* Allocated size of new_argv.  We arrange it so there is always room for
866 	   one more element.  */
867     int max_new_argc;
868 
869     new_argc = 0;
870     /* Add one so this is never zero.  */
871     max_new_argc = argc + 1;
872     new_argv = (char **) xmalloc (max_new_argc * sizeof (char *));
873     for (i = 0; i < argc; ++i)
874     {
875 	HANDLE h;
876 	WIN32_FIND_DATA fdata;
877 
878 	/* These variables help us extract the directory name from the
879            given pathname. */
880 
881 	char *last_forw_slash, *last_back_slash, *end_of_dirname;
882 	int dirname_length = 0;
883 
884 	if ( strcmp( argv[i], "." ) == 0 )
885 	{
886 	    new_argv[new_argc] = (char *) xmalloc ( 2 );
887 	    strcpy( new_argv[ new_argc++ ], "." );
888 	    continue;
889 	}
890 
891 	/* FindFirstFile doesn't return pathnames, so we have to do
892 	   this ourselves.  Luckily, it's no big deal, since globbing
893 	   characters under Win32s can only occur in the last segment
894 	   of the path.  For example,
895                 /a/path/q*.h                      valid
896 	        /w32/q*.dir/cant/do/this/q*.h     invalid */
897 
898 	/* Win32 can handle both forward and backward slashes as
899            filenames -- check for both. */
900 
901 	last_forw_slash = strrchr (argv[i], '/');
902 	last_back_slash = strrchr (argv[i], '\\');
903 
904 #define cvs_max(x,y) ((x >= y) ? (x) : (y))
905 
906 	/* FIXME: this comparing a NULL pointer to a non-NULL one is
907 	   extremely ugly, and I strongly suspect *NOT* sanctioned by
908 	   ANSI C.  The code should just use last_component instead.  */
909 	end_of_dirname = cvs_max (last_forw_slash, last_back_slash);
910 
911 	if (end_of_dirname == NULL)
912 	  dirname_length = 0;	/* no directory name */
913 	else
914 	  dirname_length = end_of_dirname - argv[i] + 1; /* include slash */
915 
916 	h = FindFirstFile (argv[i], &fdata);
917 	if (h == INVALID_HANDLE_VALUE)
918 	{
919 	    if (GetLastError () == ENOENT)
920 	    {
921 		/* No match.  The file specified didn't contain a wildcard (in which case
922 		   we clearly should return it unchanged), or it contained a wildcard which
923 		   didn't match (in which case it might be better for it to be an error,
924 		   but we don't try to do that).  */
925 		new_argv [new_argc++] = xstrdup (argv[i]);
926 		if (new_argc == max_new_argc)
927 		{
928 		    max_new_argc *= 2;
929 		    new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
930 		}
931 	    }
932 	    else
933 	    {
934 		error (1, errno, "cannot find %s", argv[i]);
935 	    }
936 	}
937 	else
938 	{
939 	    while (1)
940 	    {
941 		new_argv[new_argc] =
942 		    (char *) xmalloc (strlen (fdata.cFileName) + 1
943 				      + dirname_length);
944 
945 		/* Copy the directory name, if there is one. */
946 
947 		if (dirname_length)
948 		{
949 		    strncpy (new_argv[new_argc], argv[i], dirname_length);
950 		    new_argv[new_argc][dirname_length] = '\0';
951 		}
952 		else
953 		    new_argv[new_argc][0] = '\0';
954 
955 		/* Copy the file name. */
956 
957 		if (fncmp (argv[i] + dirname_length, fdata.cFileName) == 0)
958 		    /* We didn't expand a wildcard; we just matched a filename.
959 		       Use the file name as specified rather than the filename
960 		       which exists in the directory (they may differ in case).
961 		       This is needed to make cvs add on a directory consistently
962 		       use the name specified on the command line, but it is
963 		       probably a good idea in other contexts too.  */
964 		    strcpy (new_argv[new_argc], argv[i]);
965 		else
966 		    strcat (new_argv[new_argc], fdata.cFileName);
967 
968 		new_argc++;
969 
970 		if (new_argc == max_new_argc)
971 		{
972 		    max_new_argc *= 2;
973 		    new_argv = xrealloc (new_argv, max_new_argc * sizeof (char *));
974 		}
975 		if (!FindNextFile (h, &fdata))
976 		{
977 		    if (GetLastError () == ERROR_NO_MORE_FILES)
978 			break;
979 		    else
980 			error (1, errno, "cannot find %s", argv[i]);
981 		}
982 	    }
983 	    if (!FindClose (h))
984 		error (1, GetLastError (), "cannot close %s", argv[i]);
985 	}
986     }
987     *pargc = new_argc;
988     *pargv = new_argv;
989 }
990 
991 /* undo config.h stat macro */
992 #undef stat
993 extern int stat (const char *file, struct wnt_stat *sb);
994 
995 /* see config.h stat macro */
996 int
wnt_stat(const char * file,struct wnt_stat * sb)997 wnt_stat (const char *file, struct wnt_stat *sb)
998 {
999     int retval;
1000 
1001     retval = stat (file, sb);
1002     if (retval < 0)
1003 		return retval;
1004 
1005 	/* Win32 processes file times in a 64 bit format
1006        (see Win32 functions SetFileTime and GetFileTime).
1007        If the file time on a file doesn't fit into the
1008        32 bit time_t format, then stat will set that time
1009        to -1.  This would be OK, except that functions
1010        like ctime() don't check for validity.  So what we
1011        do here is to give a error on -1.  A cleaner solution
1012        might be to change CVS's interfaces to return a time
1013        in RCS format (for example), and then implement it
1014        on Win32 via GetFileTime, but that would be a lot of
1015        hair and I'm not sure there is much payoff.  */
1016     if (sb->st_mtime == (time_t) -1)
1017 		error (1, 0, "invalid modification time for %s", file);
1018     if (sb->st_ctime == (time_t) -1)
1019 	/* I'm not sure what this means on windows.  It
1020 	   might be a creation time (unlike unix)....  */
1021 		error (1, 0, "invalid ctime for %s", file);
1022     if (sb->st_atime == (time_t) -1)
1023 		error (1, 0, "invalid access time for %s", file);
1024 
1025     if (!GetUTCFileModTime (file, &sb->st_mtime))
1026 		error (1, 0, "Failed to retrieve modification time for %s", file);
1027 
1028     return retval;
1029 }
1030