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