xref: /openbsd-src/gnu/usr.bin/cvs/src/filesubr.c (revision 780d15dfff9934c79e6717020f46114c9b7d7d04)
1 /* filesubr.c --- subroutines for dealing with files
2    Jim Blandy <jimb@cyclic.com>
3 
4    This file is part of GNU CVS.
5 
6    GNU CVS is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.  */
15 
16 /* These functions were moved out of subr.c because they need different
17    definitions under operating systems (like, say, Windows NT) with different
18    file system semantics.  */
19 
20 #include "cvs.h"
21 
22 /*
23  * I don't know of a convenient way to test this at configure time, or else
24  * I'd certainly do it there.
25  */
26 #if defined(NeXT)
27 #define LOSING_TMPNAM_FUNCTION
28 #endif
29 
30 static int deep_remove_dir PROTO((const char *path));
31 
32 /*
33  * Copies "from" to "to".
34  */
35 void
36 copy_file (from, to)
37     const char *from;
38     const char *to;
39 {
40     struct stat sb;
41     struct utimbuf t;
42     int fdin, fdout;
43 
44     if (trace)
45 #ifdef SERVER_SUPPORT
46 	(void) fprintf (stderr, "%c-> copy(%s,%s)\n",
47 			(server_active) ? 'S' : ' ', from, to);
48 #else
49 	(void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
50 #endif
51     if (noexec)
52 	return;
53 
54     if ((fdin = open (from, O_RDONLY)) < 0)
55 	error (1, errno, "cannot open %s for copying", from);
56     if (fstat (fdin, &sb) < 0)
57 	error (1, errno, "cannot fstat %s", from);
58     if ((fdout = creat (to, (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
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
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
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
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
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
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 *
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
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, 0777) < 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
264 make_directories (name)
265     const char *name;
266 {
267     char *cp;
268 
269     if (noexec)
270 	return;
271 
272     if (mkdir (name, 0777) == 0 || errno == EEXIST)
273 	return;
274     if (! existence_error (errno))
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, 0777);
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
293 mkdir_if_needed (name)
294     char *name;
295 {
296     if (mkdir (name, 0777) < 0)
297     {
298 	if (errno != EEXIST)
299 	    error (1, errno, "cannot make directory %s", name);
300 	return 1;
301     }
302     return 0;
303 }
304 
305 /*
306  * Change the mode of a file, either adding write permissions, or removing
307  * all write permissions.  Either change honors the current umask setting.
308  */
309 void
310 xchmod (fname, writable)
311     char *fname;
312     int writable;
313 {
314     struct stat sb;
315     mode_t mode, oumask;
316 
317     if (stat (fname, &sb) < 0)
318     {
319 	if (!noexec)
320 	    error (0, errno, "cannot stat %s", fname);
321 	return;
322     }
323     oumask = umask (0);
324     (void) umask (oumask);
325     if (writable)
326     {
327 	mode = sb.st_mode | (~oumask
328 			     & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
329 				| ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
330 				| ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
331     }
332     else
333     {
334 	mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
335     }
336 
337     if (trace)
338 #ifdef SERVER_SUPPORT
339 	(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
340 			(server_active) ? 'S' : ' ', fname,
341 			(unsigned int) mode);
342 #else
343 	(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
344 			(unsigned int) mode);
345 #endif
346     if (noexec)
347 	return;
348 
349     if (chmod (fname, mode) < 0)
350 	error (0, errno, "cannot change mode of file %s", fname);
351 }
352 
353 /*
354  * Rename a file and die if it fails
355  */
356 void
357 rename_file (from, to)
358     const char *from;
359     const char *to;
360 {
361     if (trace)
362 #ifdef SERVER_SUPPORT
363 	(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
364 			(server_active) ? 'S' : ' ', from, to);
365 #else
366 	(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
367 #endif
368     if (noexec)
369 	return;
370 
371     if (rename (from, to) < 0)
372 	error (1, errno, "cannot rename file %s to %s", from, to);
373 }
374 
375 /*
376  * link a file, if possible.  Warning: the Windows NT version of this
377  * function just copies the file, so only use this function in ways
378  * that can deal with either a link or a copy.
379  */
380 int
381 link_file (from, to)
382     const char *from;
383     const char *to;
384 {
385     if (trace)
386 #ifdef SERVER_SUPPORT
387 	(void) fprintf (stderr, "%c-> link(%s,%s)\n",
388 			(server_active) ? 'S' : ' ', from, to);
389 #else
390 	(void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
391 #endif
392     if (noexec)
393 	return (0);
394 
395     return (link (from, to));
396 }
397 
398 /*
399  * unlink a file, if possible.
400  */
401 int
402 unlink_file (f)
403     const char *f;
404 {
405     if (trace)
406 #ifdef SERVER_SUPPORT
407 	(void) fprintf (stderr, "%c-> unlink(%s)\n",
408 			(server_active) ? 'S' : ' ', f);
409 #else
410 	(void) fprintf (stderr, "-> unlink(%s)\n", f);
411 #endif
412     if (noexec)
413 	return (0);
414 
415     return (unlink (f));
416 }
417 
418 /*
419  * Unlink a file or dir, if possible.  If it is a directory do a deep
420  * removal of all of the files in the directory.  Return -1 on error
421  * (in which case errno is set).
422  */
423 int
424 unlink_file_dir (f)
425     const char *f;
426 {
427     if (trace)
428 #ifdef SERVER_SUPPORT
429 	(void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
430 			(server_active) ? 'S' : ' ', f);
431 #else
432 	(void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
433 #endif
434     if (noexec)
435 	return (0);
436 
437     /* For at least some unices, if root tries to unlink() a directory,
438        instead of doing something rational like returning EISDIR,
439        the system will gleefully go ahead and corrupt the filesystem.
440        So we first call isdir() to see if it is OK to call unlink().  This
441        doesn't quite work--if someone creates a directory between the
442        call to isdir() and the call to unlink(), we'll still corrupt
443        the filesystem.  Where is the Unix Haters Handbook when you need
444        it?  */
445     if (isdir(f))
446 	return deep_remove_dir(f);
447     else
448     {
449 	if (unlink (f) != 0)
450 	    return -1;
451     }
452     /* We were able to remove the file from the disk */
453     return 0;
454 }
455 
456 /* Remove a directory and everything it contains.  Returns 0 for
457  * success, -1 for failure (in which case errno is set).
458  */
459 
460 static int
461 deep_remove_dir (path)
462     const char *path;
463 {
464     DIR		  *dirp;
465     struct dirent *dp;
466 
467     if (rmdir (path) != 0)
468     {
469 	if (errno == ENOTEMPTY
470 	    || errno == EEXIST
471 	    /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug
472 	       (it defines ENOTEMPTY and EEXIST to 17 but actually
473 	       returns 87).  */
474 	    || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
475 	{
476 	    if ((dirp = opendir (path)) == NULL)
477 		/* If unable to open the directory return
478 		 * an error
479 		 */
480 		return -1;
481 
482 	    while ((dp = readdir (dirp)) != NULL)
483 	    {
484 		char *buf;
485 
486 		if (strcmp (dp->d_name, ".") == 0 ||
487 			    strcmp (dp->d_name, "..") == 0)
488 		    continue;
489 
490 		buf = xmalloc (strlen (path) + strlen (dp->d_name) + 5);
491 		sprintf (buf, "%s/%s", path, dp->d_name);
492 
493 		/* See comment in unlink_file_dir explanation of why we use
494 		   isdir instead of just calling unlink and checking the
495 		   status.  */
496 		if (isdir(buf))
497 		{
498 		    if (deep_remove_dir(buf))
499 		    {
500 			closedir(dirp);
501 			free (buf);
502 			return -1;
503 		    }
504 		}
505 		else
506 		{
507 		    if (unlink (buf) != 0)
508 		    {
509 			closedir(dirp);
510 			free (buf);
511 			return -1;
512 		    }
513 		}
514 		free (buf);
515 	    }
516 	    closedir (dirp);
517 	    return rmdir (path);
518 	}
519 	else
520 	    return -1;
521     }
522 
523     /* Was able to remove the directory return 0 */
524     return 0;
525 }
526 
527 /* Read NCHARS bytes from descriptor FD into BUF.
528    Return the number of characters successfully read.
529    The number returned is always NCHARS unless end-of-file or error.  */
530 static size_t
531 block_read (fd, buf, nchars)
532     int fd;
533     char *buf;
534     size_t nchars;
535 {
536     char *bp = buf;
537     size_t nread;
538 
539     do
540     {
541 	nread = read (fd, bp, nchars);
542 	if (nread == (size_t)-1)
543 	{
544 #ifdef EINTR
545 	    if (errno == EINTR)
546 		continue;
547 #endif
548 	    return (size_t)-1;
549 	}
550 
551 	if (nread == 0)
552 	    break;
553 
554 	bp += nread;
555 	nchars -= nread;
556     } while (nchars != 0);
557 
558     return bp - buf;
559 }
560 
561 
562 /*
563  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
564  */
565 int
566 xcmp (file1, file2)
567     const char *file1;
568     const char *file2;
569 {
570     char *buf1, *buf2;
571     struct stat sb1, sb2;
572     int fd1, fd2;
573     int ret;
574 
575     if ((fd1 = open (file1, O_RDONLY)) < 0)
576 	error (1, errno, "cannot open file %s for comparing", file1);
577     if ((fd2 = open (file2, O_RDONLY)) < 0)
578 	error (1, errno, "cannot open file %s for comparing", file2);
579     if (fstat (fd1, &sb1) < 0)
580 	error (1, errno, "cannot fstat %s", file1);
581     if (fstat (fd2, &sb2) < 0)
582 	error (1, errno, "cannot fstat %s", file2);
583 
584     /* A generic file compare routine might compare st_dev & st_ino here
585        to see if the two files being compared are actually the same file.
586        But that won't happen in CVS, so we won't bother. */
587 
588     if (sb1.st_size != sb2.st_size)
589 	ret = 1;
590     else if (sb1.st_size == 0)
591 	ret = 0;
592     else
593     {
594 	/* FIXME: compute the optimal buffer size by computing the least
595 	   common multiple of the files st_blocks field */
596 	size_t buf_size = 8 * 1024;
597 	size_t read1;
598 	size_t read2;
599 
600 	buf1 = xmalloc (buf_size);
601 	buf2 = xmalloc (buf_size);
602 
603 	do
604 	{
605 	    read1 = block_read (fd1, buf1, buf_size);
606 	    if (read1 == (size_t)-1)
607 		error (1, errno, "cannot read file %s for comparing", file1);
608 
609 	    read2 = block_read (fd2, buf2, buf_size);
610 	    if (read2 == (size_t)-1)
611 		error (1, errno, "cannot read file %s for comparing", file2);
612 
613 	    /* assert (read1 == read2); */
614 
615 	    ret = memcmp(buf1, buf2, read1);
616 	} while (ret == 0 && read1 == buf_size);
617 
618 	free (buf1);
619 	free (buf2);
620     }
621 
622     (void) close (fd1);
623     (void) close (fd2);
624     return (ret);
625 }
626 
627 /* Just in case this implementation does not define this.  */
628 #ifndef L_tmpnam
629 #define	L_tmpnam 50
630 #endif
631 
632 #ifdef LOSING_TMPNAM_FUNCTION
633 char *
634 cvs_temp_name ()
635 {
636     char value[L_tmpnam + 1];
637 
638     /* FIXME: Should be using TMPDIR.  */
639     strcpy (value, "/tmp/cvsXXXXXX");
640     mktemp (value);
641     return xstrdup (value);
642 }
643 #else
644 /* Generate a unique temporary filename.  Returns a pointer to a newly
645    malloc'd string containing the name.  Returns successfully or not at
646    all.  */
647 char *
648 cvs_temp_name ()
649 {
650     char value[L_tmpnam + 1];
651     char *retval;
652 
653     /* FIXME: should be using TMPDIR, perhaps by using tempnam on systems
654        which have it.  */
655     retval = tmpnam (value);
656     if (retval == NULL)
657 	error (1, errno, "cannot generate temporary filename");
658     return xstrdup (retval);
659 }
660 #endif
661 
662 /* Return non-zero iff FILENAME is absolute.
663    Trivial under Unix, but more complicated under other systems.  */
664 int
665 isabsolute (filename)
666     const char *filename;
667 {
668     return filename[0] == '/';
669 }
670 
671 
672 /* Return a pointer into PATH's last component.  */
673 char *
674 last_component (path)
675     char *path;
676 {
677     char *last = strrchr (path, '/');
678 
679     if (last)
680         return last + 1;
681     else
682         return path;
683 }
684 
685 /* Return the home directory.  Returns a pointer to storage
686    managed by this function or its callees (currently getenv).
687    This function will return the same thing every time it is
688    called.  */
689 char *
690 get_homedir ()
691 {
692     static char *home = NULL;
693     char *env = getenv ("HOME");
694     struct passwd *pw;
695 
696     if (home != NULL)
697 	return home;
698 
699     if (env)
700 	home = env;
701     else if ((pw = (struct passwd *) getpwuid (getuid ()))
702 	     && pw->pw_dir)
703 	home = xstrdup (pw->pw_dir);
704     else
705 	return 0;
706 
707     return home;
708 }
709 
710 /* See cvs.h for description.  On unix this does nothing, because the
711    shell expands the wildcards.  */
712 void
713 expand_wild (argc, argv, pargc, pargv)
714     int argc;
715     char **argv;
716     int *pargc;
717     char ***pargv;
718 {
719     int i;
720     *pargc = argc;
721     *pargv = (char **) xmalloc (argc * sizeof (char *));
722     for (i = 0; i < argc; ++i)
723 	(*pargv)[i] = xstrdup (argv[i]);
724 }
725