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