xref: /openbsd-src/gnu/usr.bin/cvs/src/filesubr.c (revision c2c6168287231ca1f2357af7564f6bed5739dfd2)
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 /*
294  * Change the mode of a file, either adding write permissions, or removing
295  * all write permissions.  Either change honors the current umask setting.
296  */
297 void
298 xchmod (fname, writable)
299     char *fname;
300     int writable;
301 {
302     struct stat sb;
303     mode_t mode, oumask;
304 
305     if (stat (fname, &sb) < 0)
306     {
307 	if (!noexec)
308 	    error (0, errno, "cannot stat %s", fname);
309 	return;
310     }
311     oumask = umask (0);
312     (void) umask (oumask);
313     if (writable)
314     {
315 	mode = sb.st_mode | (~oumask
316 			     & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
317 				| ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
318 				| ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
319     }
320     else
321     {
322 	mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
323     }
324 
325     if (trace)
326 #ifdef SERVER_SUPPORT
327 	(void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
328 			(server_active) ? 'S' : ' ', fname,
329 			(unsigned int) mode);
330 #else
331 	(void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
332 			(unsigned int) mode);
333 #endif
334     if (noexec)
335 	return;
336 
337     if (chmod (fname, mode) < 0)
338 	error (0, errno, "cannot change mode of file %s", fname);
339 }
340 
341 /*
342  * Rename a file and die if it fails
343  */
344 void
345 rename_file (from, to)
346     const char *from;
347     const char *to;
348 {
349     if (trace)
350 #ifdef SERVER_SUPPORT
351 	(void) fprintf (stderr, "%c-> rename(%s,%s)\n",
352 			(server_active) ? 'S' : ' ', from, to);
353 #else
354 	(void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
355 #endif
356     if (noexec)
357 	return;
358 
359     if (rename (from, to) < 0)
360 	error (1, errno, "cannot rename file %s to %s", from, to);
361 }
362 
363 /*
364  * link a file, if possible.  Warning: the Windows NT version of this
365  * function just copies the file, so only use this function in ways
366  * that can deal with either a link or a copy.
367  */
368 int
369 link_file (from, to)
370     const char *from;
371     const char *to;
372 {
373     if (trace)
374 #ifdef SERVER_SUPPORT
375 	(void) fprintf (stderr, "%c-> link(%s,%s)\n",
376 			(server_active) ? 'S' : ' ', from, to);
377 #else
378 	(void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
379 #endif
380     if (noexec)
381 	return (0);
382 
383     return (link (from, to));
384 }
385 
386 /*
387  * unlink a file, if possible.
388  */
389 int
390 unlink_file (f)
391     const char *f;
392 {
393     if (trace)
394 #ifdef SERVER_SUPPORT
395 	(void) fprintf (stderr, "%c-> unlink(%s)\n",
396 			(server_active) ? 'S' : ' ', f);
397 #else
398 	(void) fprintf (stderr, "-> unlink(%s)\n", f);
399 #endif
400     if (noexec)
401 	return (0);
402 
403     return (unlink (f));
404 }
405 
406 /*
407  * Unlink a file or dir, if possible.  If it is a directory do a deep
408  * removal of all of the files in the directory.  Return -1 on error
409  * (in which case errno is set).
410  */
411 int
412 unlink_file_dir (f)
413     const char *f;
414 {
415     if (trace)
416 #ifdef SERVER_SUPPORT
417 	(void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
418 			(server_active) ? 'S' : ' ', f);
419 #else
420 	(void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
421 #endif
422     if (noexec)
423 	return (0);
424 
425     /* For at least some unices, if root tries to unlink() a directory,
426        instead of doing something rational like returning EISDIR,
427        the system will gleefully go ahead and corrupt the filesystem.
428        So we first call isdir() to see if it is OK to call unlink().  This
429        doesn't quite work--if someone creates a directory between the
430        call to isdir() and the call to unlink(), we'll still corrupt
431        the filesystem.  Where is the Unix Haters Handbook when you need
432        it?  */
433     if (isdir(f))
434 	return deep_remove_dir(f);
435     else
436     {
437 	if (unlink (f) != 0)
438 	    return -1;
439     }
440     /* We were able to remove the file from the disk */
441     return 0;
442 }
443 
444 /* Remove a directory and everything it contains.  Returns 0 for
445  * success, -1 for failure (in which case errno is set).
446  */
447 
448 static int
449 deep_remove_dir (path)
450     const char *path;
451 {
452     DIR		  *dirp;
453     struct dirent *dp;
454     char	   buf[PATH_MAX];
455 
456     if (rmdir (path) != 0 && (errno == ENOTEMPTY || errno == EEXIST))
457     {
458 	if ((dirp = opendir (path)) == NULL)
459 	    /* If unable to open the directory return
460 	     * an error
461 	     */
462 	    return -1;
463 
464 	while ((dp = readdir (dirp)) != NULL)
465 	{
466 	    if (strcmp (dp->d_name, ".") == 0 ||
467 			strcmp (dp->d_name, "..") == 0)
468 		continue;
469 
470 	    sprintf (buf, "%s/%s", path, dp->d_name);
471 
472 	    /* See comment in unlink_file_dir explanation of why we use
473 	       isdir instead of just calling unlink and checking the
474 	       status.  */
475 	    if (isdir(buf))
476 	    {
477 		if (deep_remove_dir(buf))
478 		{
479 		    closedir(dirp);
480 		    return -1;
481 		}
482 	    }
483 	    else
484 	    {
485 		if (unlink (buf) != 0)
486 		{
487 		    closedir(dirp);
488 		    return -1;
489 		}
490 	    }
491 	}
492 	closedir (dirp);
493 	return rmdir (path);
494 	}
495 
496     /* Was able to remove the directory return 0 */
497     return 0;
498 }
499 
500 /* Read NCHARS bytes from descriptor FD into BUF.
501    Return the number of characters successfully read.
502    The number returned is always NCHARS unless end-of-file or error.  */
503 static size_t
504 block_read (fd, buf, nchars)
505     int fd;
506     char *buf;
507     size_t nchars;
508 {
509     char *bp = buf;
510     size_t nread;
511 
512     do
513     {
514 	nread = read (fd, bp, nchars);
515 	if (nread == (size_t)-1)
516 	{
517 #ifdef EINTR
518 	    if (errno == EINTR)
519 		continue;
520 #endif
521 	    return (size_t)-1;
522 	}
523 
524 	if (nread == 0)
525 	    break;
526 
527 	bp += nread;
528 	nchars -= nread;
529     } while (nchars != 0);
530 
531     return bp - buf;
532 }
533 
534 
535 /*
536  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
537  */
538 int
539 xcmp (file1, file2)
540     const char *file1;
541     const char *file2;
542 {
543     char *buf1, *buf2;
544     struct stat sb1, sb2;
545     int fd1, fd2;
546     int ret;
547 
548     if ((fd1 = open (file1, O_RDONLY)) < 0)
549 	error (1, errno, "cannot open file %s for comparing", file1);
550     if ((fd2 = open (file2, O_RDONLY)) < 0)
551 	error (1, errno, "cannot open file %s for comparing", file2);
552     if (fstat (fd1, &sb1) < 0)
553 	error (1, errno, "cannot fstat %s", file1);
554     if (fstat (fd2, &sb2) < 0)
555 	error (1, errno, "cannot fstat %s", file2);
556 
557     /* A generic file compare routine might compare st_dev & st_ino here
558        to see if the two files being compared are actually the same file.
559        But that won't happen in CVS, so we won't bother. */
560 
561     if (sb1.st_size != sb2.st_size)
562 	ret = 1;
563     else if (sb1.st_size == 0)
564 	ret = 0;
565     else
566     {
567 	/* FIXME: compute the optimal buffer size by computing the least
568 	   common multiple of the files st_blocks field */
569 	size_t buf_size = 8 * 1024;
570 	size_t read1;
571 	size_t read2;
572 
573 	buf1 = xmalloc (buf_size);
574 	buf2 = xmalloc (buf_size);
575 
576 	do
577 	{
578 	    read1 = block_read (fd1, buf1, buf_size);
579 	    if (read1 == (size_t)-1)
580 		error (1, errno, "cannot read file %s for comparing", file1);
581 
582 	    read2 = block_read (fd2, buf2, buf_size);
583 	    if (read2 == (size_t)-1)
584 		error (1, errno, "cannot read file %s for comparing", file2);
585 
586 	    /* assert (read1 == read2); */
587 
588 	    ret = memcmp(buf1, buf2, read1);
589 	} while (ret == 0 && read1 == buf_size);
590 
591 	free (buf1);
592 	free (buf2);
593     }
594 
595     (void) close (fd1);
596     (void) close (fd2);
597     return (ret);
598 }
599 
600 #ifdef LOSING_TMPNAM_FUNCTION
601 char *tmpnam(char *s)
602 {
603     static char value[L_tmpnam+1];
604 
605     if (s){
606        strcpy(s,"/tmp/cvsXXXXXX");
607        mktemp(s);
608        return s;
609     }else{
610        strcpy(value,"/tmp/cvsXXXXXX");
611        mktemp(s);
612        return value;
613     }
614 }
615 #endif
616 
617 /* Return non-zero iff FILENAME is absolute.
618    Trivial under Unix, but more complicated under other systems.  */
619 int
620 isabsolute (filename)
621     const char *filename;
622 {
623     return filename[0] == '/';
624 }
625 
626 
627 /* Return a pointer into PATH's last component.  */
628 char *
629 last_component (path)
630     char *path;
631 {
632     char *last = strrchr (path, '/');
633 
634     if (last)
635         return last + 1;
636     else
637         return path;
638 }
639 
640 /* Return the home directory.  Returns a pointer to storage
641    managed by this function or its callees (currently getenv).  */
642 char *
643 get_homedir ()
644 {
645     return getenv ("HOME");
646 }
647 
648 /* See cvs.h for description.  On unix this does nothing, because the
649    shell expands the wildcards.  */
650 void
651 expand_wild (argc, argv, pargc, pargv)
652     int argc;
653     char **argv;
654     int *pargc;
655     char ***pargv;
656 {
657     int i;
658     *pargc = argc;
659     *pargv = (char **) xmalloc (argc * sizeof (char *));
660     for (i = 0; i < argc; ++i)
661 	(*pargv)[i] = xstrdup (argv[i]);
662 }
663