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