xref: /openbsd-src/gnu/usr.bin/cvs/src/filesubr.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
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    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19 
20 /* These functions were moved out of subr.c because they need different
21    definitions under operating systems (like, say, Windows NT) with different
22    file system semantics.  */
23 
24 #include "cvs.h"
25 
26 /*
27  * I don't know of a convenient way to test this at configure time, or else
28  * I'd certainly do it there.
29  */
30 #if defined(NeXT)
31 #define LOSING_TMPNAM_FUNCTION
32 #endif
33 
34 static int deep_remove_dir PROTO((const char *path));
35 
36 /*
37  * Copies "from" to "to".
38  */
39 void
40 copy_file (from, to)
41     const char *from;
42     const char *to;
43 {
44     struct stat sb;
45     struct utimbuf t;
46     int fdin, fdout;
47 
48     if (trace)
49 #ifdef SERVER_SUPPORT
50 	(void) fprintf (stderr, "%c-> copy(%s,%s)\n",
51 			(server_active) ? 'S' : ' ', from, to);
52 #else
53 	(void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
54 #endif
55     if (noexec)
56 	return;
57 
58     if ((fdin = open (from, O_RDONLY)) < 0)
59 	error (1, errno, "cannot open %s for copying", from);
60     if (fstat (fdin, &sb) < 0)
61 	error (1, errno, "cannot fstat %s", from);
62     if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
63 	error (1, errno, "cannot create %s for copying", to);
64     if (sb.st_size > 0)
65     {
66 	char buf[BUFSIZ];
67 	int n;
68 
69 	for (;;)
70 	{
71 	    n = read (fdin, buf, sizeof(buf));
72 	    if (n == -1)
73 	    {
74 #ifdef EINTR
75 		if (errno == EINTR)
76 		    continue;
77 #endif
78 		error (1, errno, "cannot read file %s for copying", from);
79 	    }
80             else if (n == 0)
81 		break;
82 
83 	    if (write(fdout, buf, n) != n) {
84 		error (1, errno, "cannot write file %s for copying", to);
85 	    }
86 	}
87 
88 #ifdef HAVE_FSYNC
89 	if (fsync (fdout))
90 	    error (1, errno, "cannot fsync file %s after copying", to);
91 #endif
92     }
93 
94     if (close (fdin) < 0)
95 	error (0, errno, "cannot close %s", from);
96     if (close (fdout) < 0)
97 	error (1, errno, "cannot close %s", to);
98 
99     /* now, set the times for the copied file to match those of the original */
100     memset ((char *) &t, 0, sizeof (t));
101     t.actime = sb.st_atime;
102     t.modtime = sb.st_mtime;
103     (void) utime (to, &t);
104 }
105 
106 /* FIXME-krp: these functions would benefit from caching the char * &
107    stat buf.  */
108 
109 /*
110  * Returns non-zero if the argument file is a directory, or is a symbolic
111  * link which points to a directory.
112  */
113 int
114 isdir (file)
115     const char *file;
116 {
117     struct stat sb;
118 
119     if (stat (file, &sb) < 0)
120 	return (0);
121     return (S_ISDIR (sb.st_mode));
122 }
123 
124 /*
125  * Returns non-zero if the argument file is a symbolic link.
126  */
127 int
128 islink (file)
129     const char *file;
130 {
131 #ifdef S_ISLNK
132     struct stat sb;
133 
134     if (lstat (file, &sb) < 0)
135 	return (0);
136     return (S_ISLNK (sb.st_mode));
137 #else
138     return (0);
139 #endif
140 }
141 
142 /*
143  * Returns non-zero if the argument file exists.
144  */
145 int
146 isfile (file)
147     const char *file;
148 {
149     return isaccessible(file, F_OK);
150 }
151 
152 /*
153  * Returns non-zero if the argument file is readable.
154  */
155 int
156 isreadable (file)
157     const char *file;
158 {
159     return isaccessible(file, R_OK);
160 }
161 
162 /*
163  * Returns non-zero if the argument file is writable.
164  */
165 int
166 iswritable (file)
167     const char *file;
168 {
169     return isaccessible(file, W_OK);
170 }
171 
172 /*
173  * Returns non-zero if the argument file is accessable according to
174  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
175  * bits set.
176  */
177 int
178 isaccessible (file, mode)
179     const char *file;
180     const int mode;
181 {
182 #ifdef SETXID_SUPPORT
183     struct stat sb;
184     int umask = 0;
185     int gmask = 0;
186     int omask = 0;
187     int uid;
188 
189     if (stat(file, &sb) == -1)
190 	return 0;
191     if (mode == F_OK)
192 	return 1;
193 
194     uid = geteuid();
195     if (uid == 0)		/* superuser */
196     {
197 	if (mode & X_OK)
198 	    return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
199 	else
200 	    return 1;
201     }
202 
203     if (mode & R_OK)
204     {
205 	umask |= S_IRUSR;
206 	gmask |= S_IRGRP;
207 	omask |= S_IROTH;
208     }
209     if (mode & W_OK)
210     {
211 	umask |= S_IWUSR;
212 	gmask |= S_IWGRP;
213 	omask |= S_IWOTH;
214     }
215     if (mode & X_OK)
216     {
217 	umask |= S_IXUSR;
218 	gmask |= S_IXGRP;
219 	omask |= S_IXOTH;
220     }
221 
222     if (sb.st_uid == uid)
223 	return (sb.st_mode & umask) == umask;
224     else if (sb.st_gid == getegid())
225 	return (sb.st_mode & gmask) == gmask;
226     else
227 	return (sb.st_mode & omask) == omask;
228 #else
229     return access(file, mode) == 0;
230 #endif
231 }
232 
233 /*
234  * Open a file and die if it fails
235  */
236 FILE *
237 open_file (name, mode)
238     const char *name;
239     const char *mode;
240 {
241     FILE *fp;
242 
243     if ((fp = fopen (name, mode)) == NULL)
244 	error (1, errno, "cannot open %s", name);
245     return (fp);
246 }
247 
248 /*
249  * Make a directory and die if it fails
250  */
251 void
252 make_directory (name)
253     const char *name;
254 {
255     struct stat sb;
256 
257     if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
258 	    error (0, 0, "%s already exists but is not a directory", name);
259     if (!noexec && mkdir (name, 0777) < 0)
260 	error (1, errno, "cannot make directory %s", name);
261 }
262 
263 /*
264  * Make a path to the argument directory, printing a message if something
265  * goes wrong.
266  */
267 void
268 make_directories (name)
269     const char *name;
270 {
271     char *cp;
272 
273     if (noexec)
274 	return;
275 
276     if (mkdir (name, 0777) == 0 || errno == EEXIST)
277 	return;
278     if (! existence_error (errno))
279     {
280 	error (0, errno, "cannot make path to %s", name);
281 	return;
282     }
283     if ((cp = strrchr (name, '/')) == NULL)
284 	return;
285     *cp = '\0';
286     make_directories (name);
287     *cp++ = '/';
288     if (*cp == '\0')
289 	return;
290     (void) mkdir (name, 0777);
291 }
292 
293 /* Create directory NAME if it does not already exist; fatal error for
294    other errors.  Returns 0 if directory was created; 1 if it already
295    existed.  */
296 int
297 mkdir_if_needed (name)
298     char *name;
299 {
300     if (mkdir (name, 0777) < 0)
301     {
302 	if (errno != EEXIST)
303 	    error (1, errno, "cannot make directory %s", name);
304 	return 1;
305     }
306     return 0;
307 }
308 
309 /*
310  * Change the mode of a file, either adding write permissions, or removing
311  * all write permissions.  Either change honors the current umask setting.
312  */
313 void
314 xchmod (fname, writable)
315     char *fname;
316     int writable;
317 {
318     struct stat sb;
319     mode_t mode, oumask;
320 
321     if (stat (fname, &sb) < 0)
322     {
323 	if (!noexec)
324 	    error (0, errno, "cannot stat %s", fname);
325 	return;
326     }
327     oumask = umask (0);
328     (void) umask (oumask);
329     if (writable)
330     {
331 	mode = sb.st_mode | (~oumask
332 			     & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
333 				| ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
334 				| ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
335     }
336     else
337     {
338 	mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
339     }
340 
341     if (trace)
342 #ifdef SERVER_SUPPORT
343 	(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
344 			(server_active) ? 'S' : ' ', fname,
345 			(unsigned int) mode);
346 #else
347 	(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
348 			(unsigned int) mode);
349 #endif
350     if (noexec)
351 	return;
352 
353     if (chmod (fname, mode) < 0)
354 	error (0, errno, "cannot change mode of file %s", fname);
355 }
356 
357 /*
358  * Rename a file and die if it fails
359  */
360 void
361 rename_file (from, to)
362     const char *from;
363     const char *to;
364 {
365     if (trace)
366 #ifdef SERVER_SUPPORT
367 	(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
368 			(server_active) ? 'S' : ' ', from, to);
369 #else
370 	(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
371 #endif
372     if (noexec)
373 	return;
374 
375     if (rename (from, to) < 0)
376 	error (1, errno, "cannot rename file %s to %s", from, to);
377 }
378 
379 /*
380  * link a file, if possible.  Warning: the Windows NT version of this
381  * function just copies the file, so only use this function in ways
382  * that can deal with either a link or a copy.
383  */
384 int
385 link_file (from, to)
386     const char *from;
387     const char *to;
388 {
389     if (trace)
390 #ifdef SERVER_SUPPORT
391 	(void) fprintf (stderr, "%c-> link(%s,%s)\n",
392 			(server_active) ? 'S' : ' ', from, to);
393 #else
394 	(void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
395 #endif
396     if (noexec)
397 	return (0);
398 
399     return (link (from, to));
400 }
401 
402 /*
403  * unlink a file, if possible.
404  */
405 int
406 unlink_file (f)
407     const char *f;
408 {
409     if (trace)
410 #ifdef SERVER_SUPPORT
411 	(void) fprintf (stderr, "%c-> unlink(%s)\n",
412 			(server_active) ? 'S' : ' ', f);
413 #else
414 	(void) fprintf (stderr, "-> unlink(%s)\n", f);
415 #endif
416     if (noexec)
417 	return (0);
418 
419     return (unlink (f));
420 }
421 
422 /*
423  * Unlink a file or dir, if possible.  If it is a directory do a deep
424  * removal of all of the files in the directory.  Return -1 on error
425  * (in which case errno is set).
426  */
427 int
428 unlink_file_dir (f)
429     const char *f;
430 {
431     if (trace)
432 #ifdef SERVER_SUPPORT
433 	(void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
434 			(server_active) ? 'S' : ' ', f);
435 #else
436 	(void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
437 #endif
438     if (noexec)
439 	return (0);
440 
441     /* For at least some unices, if root tries to unlink() a directory,
442        instead of doing something rational like returning EISDIR,
443        the system will gleefully go ahead and corrupt the filesystem.
444        So we first call isdir() to see if it is OK to call unlink().  This
445        doesn't quite work--if someone creates a directory between the
446        call to isdir() and the call to unlink(), we'll still corrupt
447        the filesystem.  Where is the Unix Haters Handbook when you need
448        it?  */
449     if (isdir(f))
450 	return deep_remove_dir(f);
451     else
452     {
453 	if (unlink (f) != 0)
454 	    return -1;
455     }
456     /* We were able to remove the file from the disk */
457     return 0;
458 }
459 
460 /* Remove a directory and everything it contains.  Returns 0 for
461  * success, -1 for failure (in which case errno is set).
462  */
463 
464 static int
465 deep_remove_dir (path)
466     const char *path;
467 {
468     DIR		  *dirp;
469     struct dirent *dp;
470     char	   buf[PATH_MAX];
471 
472     if (rmdir (path) != 0 && (errno == ENOTEMPTY || errno == EEXIST))
473     {
474 	if ((dirp = opendir (path)) == NULL)
475 	    /* If unable to open the directory return
476 	     * an error
477 	     */
478 	    return -1;
479 
480 	while ((dp = readdir (dirp)) != NULL)
481 	{
482 	    if (strcmp (dp->d_name, ".") == 0 ||
483 			strcmp (dp->d_name, "..") == 0)
484 		continue;
485 
486 	    sprintf (buf, "%s/%s", path, dp->d_name);
487 
488 	    /* See comment in unlink_file_dir explanation of why we use
489 	       isdir instead of just calling unlink and checking the
490 	       status.  */
491 	    if (isdir(buf))
492 	    {
493 		if (deep_remove_dir(buf))
494 		{
495 		    closedir(dirp);
496 		    return -1;
497 		}
498 	    }
499 	    else
500 	    {
501 		if (unlink (buf) != 0)
502 		{
503 		    closedir(dirp);
504 		    return -1;
505 		}
506 	    }
507 	}
508 	closedir (dirp);
509 	return rmdir (path);
510 	}
511 
512     /* Was able to remove the directory return 0 */
513     return 0;
514 }
515 
516 /* Read NCHARS bytes from descriptor FD into BUF.
517    Return the number of characters successfully read.
518    The number returned is always NCHARS unless end-of-file or error.  */
519 static size_t
520 block_read (fd, buf, nchars)
521     int fd;
522     char *buf;
523     size_t nchars;
524 {
525     char *bp = buf;
526     size_t nread;
527 
528     do
529     {
530 	nread = read (fd, bp, nchars);
531 	if (nread == (size_t)-1)
532 	{
533 #ifdef EINTR
534 	    if (errno == EINTR)
535 		continue;
536 #endif
537 	    return (size_t)-1;
538 	}
539 
540 	if (nread == 0)
541 	    break;
542 
543 	bp += nread;
544 	nchars -= nread;
545     } while (nchars != 0);
546 
547     return bp - buf;
548 }
549 
550 
551 /*
552  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
553  */
554 int
555 xcmp (file1, file2)
556     const char *file1;
557     const char *file2;
558 {
559     char *buf1, *buf2;
560     struct stat sb1, sb2;
561     int fd1, fd2;
562     int ret;
563 
564     if ((fd1 = open (file1, O_RDONLY)) < 0)
565 	error (1, errno, "cannot open file %s for comparing", file1);
566     if ((fd2 = open (file2, O_RDONLY)) < 0)
567 	error (1, errno, "cannot open file %s for comparing", file2);
568     if (fstat (fd1, &sb1) < 0)
569 	error (1, errno, "cannot fstat %s", file1);
570     if (fstat (fd2, &sb2) < 0)
571 	error (1, errno, "cannot fstat %s", file2);
572 
573     /* A generic file compare routine might compare st_dev & st_ino here
574        to see if the two files being compared are actually the same file.
575        But that won't happen in CVS, so we won't bother. */
576 
577     if (sb1.st_size != sb2.st_size)
578 	ret = 1;
579     else if (sb1.st_size == 0)
580 	ret = 0;
581     else
582     {
583 	/* FIXME: compute the optimal buffer size by computing the least
584 	   common multiple of the files st_blocks field */
585 	size_t buf_size = 8 * 1024;
586 	size_t read1;
587 	size_t read2;
588 
589 	buf1 = xmalloc (buf_size);
590 	buf2 = xmalloc (buf_size);
591 
592 	do
593 	{
594 	    read1 = block_read (fd1, buf1, buf_size);
595 	    if (read1 == (size_t)-1)
596 		error (1, errno, "cannot read file %s for comparing", file1);
597 
598 	    read2 = block_read (fd2, buf2, buf_size);
599 	    if (read2 == (size_t)-1)
600 		error (1, errno, "cannot read file %s for comparing", file2);
601 
602 	    /* assert (read1 == read2); */
603 
604 	    ret = memcmp(buf1, buf2, read1);
605 	} while (ret == 0 && read1 == buf_size);
606 
607 	free (buf1);
608 	free (buf2);
609     }
610 
611     (void) close (fd1);
612     (void) close (fd2);
613     return (ret);
614 }
615 
616 /* Just in case this implementation does not define this.  */
617 #ifndef L_tmpnam
618 #define	L_tmpnam 50
619 #endif
620 
621 #ifdef LOSING_TMPNAM_FUNCTION
622 char *
623 cvs_temp_name ()
624 {
625     char value[L_tmpnam + 1];
626 
627     /* FIXME: Should be using TMPDIR.  */
628     strcpy (value, "/tmp/cvsXXXXXX");
629     mktemp (value);
630     return xstrdup (value);
631 }
632 #else
633 /* Generate a unique temporary filename.  Returns a pointer to a newly
634    malloc'd string containing the name.  Returns successfully or not at
635    all.  */
636 char *
637 cvs_temp_name ()
638 {
639     char value[L_tmpnam + 1];
640     char *retval;
641 
642     /* FIXME: should be using TMPDIR, perhaps by using tempnam on systems
643        which have it.  */
644     retval = tmpnam (value);
645     if (retval == NULL)
646 	error (1, errno, "cannot generate temporary filename");
647     return xstrdup (retval);
648 }
649 #endif
650 
651 /* Return non-zero iff FILENAME is absolute.
652    Trivial under Unix, but more complicated under other systems.  */
653 int
654 isabsolute (filename)
655     const char *filename;
656 {
657     return filename[0] == '/';
658 }
659 
660 
661 /* Return a pointer into PATH's last component.  */
662 char *
663 last_component (path)
664     char *path;
665 {
666     char *last = strrchr (path, '/');
667 
668     if (last)
669         return last + 1;
670     else
671         return path;
672 }
673 
674 /* Return the home directory.  Returns a pointer to storage
675    managed by this function or its callees (currently getenv).  */
676 char *
677 get_homedir ()
678 {
679     static char home[PATH_MAX];
680     char *env = getenv ("HOME");
681     struct passwd *pw;
682 
683     if (env)
684 	strcpy (home, env);
685     else if ((pw = (struct passwd *) getpwuid (getuid ()))
686 	     && pw->pw_dir)
687 	strcpy (home, pw->pw_dir);
688     else
689 	return 0;
690 
691     return home;
692 }
693 
694 /* See cvs.h for description.  On unix this does nothing, because the
695    shell expands the wildcards.  */
696 void
697 expand_wild (argc, argv, pargc, pargv)
698     int argc;
699     char **argv;
700     int *pargc;
701     char ***pargv;
702 {
703     int i;
704     *pargc = argc;
705     *pargv = (char **) xmalloc (argc * sizeof (char *));
706     for (i = 0; i < argc; ++i)
707 	(*pargv)[i] = xstrdup (argv[i]);
708 }
709