publish
[alioth/cvs.git] / emx / filesubr.c
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 #include <sys/param.h>
22
23 /*
24  * I don't know of a convenient way to test this at configure time, or else
25  * I'd certainly do it there.
26  */
27 #if defined(NeXT)
28 #define LOSING_TMPNAM_FUNCTION
29 #endif
30
31 static int deep_remove_dir( const char *path );
32
33 /*
34  * Copies "from" to "to".
35  */
36 void
37 copy_file (from, to)
38     const char *from;
39     const char *to;
40 {
41     struct stat sb;
42     struct utimbuf t;
43     int fdin, fdout;
44
45     if (trace)
46 #ifdef SERVER_SUPPORT
47         (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
48                         (server_active) ? 'S' : ' ', from, to);
49 #else
50         (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
51 #endif
52     if (noexec)
53         return;
54
55     if ((fdin = open (from, O_RDONLY | O_BINARY)) < 0)
56         error (1, errno, "cannot open %s for copying", from);
57     if (fstat (fdin, &sb) < 0)
58         error (1, errno, "cannot fstat %s", from);
59     if ((fdout = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
60                                            (int) sb.st_mode & 07777)) < 0)
61         error (1, errno, "cannot create %s for copying", to);
62     if (sb.st_size > 0)
63     {
64         char buf[BUFSIZ];
65         int n;
66
67         for (;;)
68         {
69             n = read (fdin, buf, sizeof(buf));
70             if (n == -1)
71             {
72 #ifdef EINTR
73                 if (errno == EINTR)
74                     continue;
75 #endif
76                 error (1, errno, "cannot read file %s for copying", from);
77             }
78             else if (n == 0)
79                 break;
80
81             if (write(fdout, buf, n) != n) {
82                 error (1, errno, "cannot write file %s for copying", to);
83             }
84         }
85
86 #ifdef HAVE_FSYNC
87         if (fsync (fdout))
88             error (1, errno, "cannot fsync file %s after copying", to);
89 #endif
90     }
91
92     if (close (fdin) < 0)
93         error (0, errno, "cannot close %s", from);
94     if (close (fdout) < 0)
95         error (1, errno, "cannot close %s", to);
96
97     /* now, set the times for the copied file to match those of the original */
98     memset ((char *) &t, 0, sizeof (t));
99     t.actime = sb.st_atime;
100     t.modtime = sb.st_mtime;
101     (void) utime (to, &t);
102 }
103
104 /* FIXME-krp: these functions would benefit from caching the char * &
105    stat buf.  */
106
107 /*
108  * Returns non-zero if the argument file is a directory, or is a symbolic
109  * link which points to a directory.
110  */
111 int
112 isdir (file)
113     const char *file;
114 {
115     struct stat sb;
116
117     if (stat (file, &sb) < 0)
118         return (0);
119     return (S_ISDIR (sb.st_mode));
120 }
121
122 /*
123  * Returns non-zero if the argument file is a symbolic link.
124  */
125 int
126 islink (file)
127     const char *file;
128 {
129 #ifdef S_ISLNK
130     struct stat sb;
131
132     if (lstat (file, &sb) < 0)
133         return (0);
134     return (S_ISLNK (sb.st_mode));
135 #else
136     return (0);
137 #endif
138 }
139
140 /*
141  * Returns non-zero if the argument file exists.
142  */
143 int
144 isfile (file)
145     const char *file;
146 {
147     return isaccessible(file, F_OK);
148 }
149
150 /*
151  * Returns non-zero if the argument file is readable.
152  */
153 int
154 isreadable (file)
155     const char *file;
156 {
157     return isaccessible(file, R_OK);
158 }
159
160 /*
161  * Returns non-zero if the argument file is writable.
162  */
163 int
164 iswritable (file)
165     const char *file;
166 {
167     return isaccessible(file, W_OK);
168 }
169
170 /*
171  * Returns non-zero if the argument file is accessable according to
172  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
173  * bits set.
174  */
175 int
176 isaccessible (file, mode)
177     const char *file;
178     const int mode;
179 {
180 #ifdef SETXID_SUPPORT
181     struct stat sb;
182     int umask = 0;
183     int gmask = 0;
184     int omask = 0;
185     int uid;
186
187     if (stat(file, &sb) == -1)
188         return 0;
189     if (mode == F_OK)
190         return 1;
191
192     uid = geteuid();
193     if (uid == 0)               /* superuser */
194     {
195         if (mode & X_OK)
196             return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
197         else
198             return 1;
199     }
200         
201     if (mode & R_OK)
202     {
203         umask |= S_IRUSR;
204         gmask |= S_IRGRP;
205         omask |= S_IROTH;
206     }
207     if (mode & W_OK)
208     {
209         umask |= S_IWUSR;
210         gmask |= S_IWGRP;
211         omask |= S_IWOTH;
212     }
213     if (mode & X_OK)
214     {
215         umask |= S_IXUSR;
216         gmask |= S_IXGRP;
217         omask |= S_IXOTH;
218     }
219
220     if (sb.st_uid == uid)
221         return (sb.st_mode & umask) == umask;
222     else if (sb.st_gid == getegid())
223         return (sb.st_mode & gmask) == gmask;
224     else
225         return (sb.st_mode & omask) == omask;
226 #else
227     return access(file, mode) == 0;
228 #endif
229 }
230
231
232
233 /*
234  * Make a directory and die if it fails
235  */
236 void
237 make_directory (name)
238     const char *name;
239 {
240     struct stat sb;
241
242     if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
243             error (0, 0, "%s already exists but is not a directory", name);
244     if (!noexec && mkdir (name, 0777) < 0)
245         error (1, errno, "cannot make directory %s", name);
246 }
247
248 /*
249  * Make a path to the argument directory, printing a message if something
250  * goes wrong.
251  */
252 void
253 make_directories (name)
254     const char *name;
255 {
256     char *cp;
257
258     if (noexec)
259         return;
260
261     if (mkdir (name, 0777) == 0 || errno == EEXIST)
262         return;
263     if (! existence_error (errno))
264     {
265         error (0, errno, "cannot make path to %s", name);
266         return;
267     }
268     if ((cp = strrchr (name, '/')) == NULL)
269         return;
270     *cp = '\0';
271     make_directories (name);
272     *cp++ = '/';
273     if (*cp == '\0')
274         return;
275     (void) mkdir (name, 0777);
276 }
277
278 /* Create directory NAME if it does not already exist; fatal error for
279    other errors.  Returns 0 if directory was created; 1 if it already
280    existed.  */
281 int
282 mkdir_if_needed (name)
283     char *name;
284 {
285     if (mkdir (name, 0777) < 0)
286     {
287         if (errno != EEXIST)
288             error (1, errno, "cannot make directory %s", name);
289         return 1;
290     }
291     return 0;
292 }
293
294 /*
295  * Change the mode of a file, either adding write permissions, or removing
296  * all write permissions.  Either change honors the current umask setting.
297  * The EMX doc (0.9c, emxlib.doc) says that chmod sets/clears the readonly
298  * bit.  But it always seemed to be a noop when I tried it.  Therefore,
299  * I've copied over the "attrib" code from os2/filesubr.c.
300  */
301 void
302 xchmod (fname, writable)
303     char *fname;
304     int writable;
305 {
306     char *attrib_cmd;
307     char *attrib_option;
308     char *whole_cmd;
309     char *p;
310     char *q;
311
312     if (!isfile (fname))
313     {
314         error (0, 0, "cannot change mode of file %s; it does not exist",
315                fname);
316         return;
317     }
318
319     attrib_cmd = "attrib "; /* No, really? */
320
321     if (writable)
322         attrib_option = "-r ";  /* make writeable */
323     else
324         attrib_option = "+r ";  /* make read-only */
325         
326     whole_cmd = xmalloc (strlen (attrib_cmd)
327                          + strlen (attrib_option)
328                          + strlen (fname)
329                          + 1);
330
331     strcpy (whole_cmd, attrib_cmd);
332     strcat (whole_cmd, attrib_option);
333
334     /* Copy fname to the end of whole_cmd, translating / to \.
335            Attrib doesn't take / but many parts of CVS rely
336        on being able to use it.  */
337     p = whole_cmd + strlen (whole_cmd);
338     q = fname;
339     while (*q)
340     {
341         if (*q == '/')
342             *p++ = '\\';
343         else
344             *p++ = *q;
345         ++q;
346     }
347     *p = '\0';
348
349     system (whole_cmd);
350     free (whole_cmd);
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     unlink_file (to);
372     if (rename (from, to) != 0)
373         error (1, errno, "cannot rename file %s to %s", from, to);
374 }
375
376 /*
377  * unlink a file, if possible.
378  */
379 int
380 unlink_file (f)
381     const char *f;
382 {
383     if (trace)
384 #ifdef SERVER_SUPPORT
385         (void) fprintf (stderr, "%c-> unlink(%s)\n",
386                         (server_active) ? 'S' : ' ', f);
387 #else
388         (void) fprintf (stderr, "-> unlink(%s)\n", f);
389 #endif
390     if (noexec)
391         return (0);
392
393     if (isfile (f))
394         xchmod ((char *)f, 1);
395     return (unlink (f));
396 }
397
398 /*
399  * Unlink a file or dir, if possible.  If it is a directory do a deep
400  * removal of all of the files in the directory.  Return -1 on error
401  * (in which case errno is set).
402  */
403 int
404 unlink_file_dir (f)
405     const char *f;
406 {
407     if (trace)
408 #ifdef SERVER_SUPPORT
409         (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
410                         (server_active) ? 'S' : ' ', f);
411 #else
412         (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
413 #endif
414     if (noexec)
415         return (0);
416
417     /* For at least some unices, if root tries to unlink() a directory,
418        instead of doing something rational like returning EISDIR,
419        the system will gleefully go ahead and corrupt the filesystem.
420        So we first call isdir() to see if it is OK to call unlink().  This
421        doesn't quite work--if someone creates a directory between the
422        call to isdir() and the call to unlink(), we'll still corrupt
423        the filesystem.  Where is the Unix Haters Handbook when you need
424        it?  */
425     if (isdir(f))
426         return deep_remove_dir(f);
427     else
428     {
429         if (unlink (f) != 0)
430             return -1;
431     }
432     /* We were able to remove the file from the disk */
433     return 0;
434 }
435
436 /* Remove a directory and everything it contains.  Returns 0 for
437  * success, -1 for failure (in which case errno is set).
438  */
439
440 static int
441 deep_remove_dir (path)
442     const char *path;
443 {
444     DIR           *dirp;
445     struct dirent *dp;
446     char           buf[PATH_MAX];
447
448     if (rmdir (path) != 0)
449     {
450         if (errno == ENOTEMPTY
451             || errno == EEXIST
452             /* Ugly workaround for ugly AIX 4.1 (and 3.2) header bug
453                (it defines ENOTEMPTY and EEXIST to 17 but actually
454                returns 87).  */
455             || (ENOTEMPTY == 17 && EEXIST == 17 && errno == 87))
456         {
457             if ((dirp = opendir (path)) == NULL)
458                 /* If unable to open the directory return
459                  * an error
460                  */
461                 return -1;
462
463             while ((dp = readdir (dirp)) != NULL)
464             {
465                 if (strcmp (dp->d_name, ".") == 0 ||
466                             strcmp (dp->d_name, "..") == 0)
467                     continue;
468
469                 sprintf (buf, "%s/%s", path, dp->d_name);
470
471                 /* See comment in unlink_file_dir explanation of why we use
472                    isdir instead of just calling unlink and checking the
473                    status.  */
474                 if (isdir(buf))
475                 {
476                     if (deep_remove_dir(buf))
477                     {
478                         closedir(dirp);
479                         return -1;
480                     }
481                 }
482                 else
483                 {
484                     if (unlink (buf) != 0)
485                     {
486                         closedir(dirp);
487                         return -1;
488                     }
489                 }
490             }
491             closedir (dirp);
492             return rmdir (path);
493         }
494         else
495             return -1;
496     }
497
498     /* Was able to remove the directory return 0 */
499     return 0;
500 }
501
502 /* Read NCHARS bytes from descriptor FD into BUF.
503    Return the number of characters successfully read.
504    The number returned is always NCHARS unless end-of-file or error.  */
505 static size_t
506 block_read (fd, buf, nchars)
507     int fd;
508     char *buf;
509     size_t nchars;
510 {
511     char *bp = buf;
512     size_t nread;
513
514     do
515     {
516         nread = read (fd, bp, nchars);
517         if (nread == (size_t)-1)
518         {
519 #ifdef EINTR
520             if (errno == EINTR)
521                 continue;
522 #endif
523             return (size_t)-1;
524         }
525
526         if (nread == 0)
527             break;
528
529         bp += nread;
530         nchars -= nread;
531     } while (nchars != 0);
532
533     return bp - buf;
534 }
535
536
537 /*
538  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
539  */
540 int
541 xcmp (file1, file2)
542     const char *file1;
543     const char *file2;
544 {
545     char *buf1, *buf2;
546     struct stat sb1, sb2;
547     int fd1, fd2;
548     int ret;
549
550     if ((fd1 = open (file1, O_RDONLY | O_BINARY)) < 0)
551         error (1, errno, "cannot open file %s for comparing", file1);
552     if ((fd2 = open (file2, O_RDONLY | O_BINARY)) < 0)
553         error (1, errno, "cannot open file %s for comparing", file2);
554     if (fstat (fd1, &sb1) < 0)
555         error (1, errno, "cannot fstat %s", file1);
556     if (fstat (fd2, &sb2) < 0)
557         error (1, errno, "cannot fstat %s", file2);
558
559     /* A generic file compare routine might compare st_dev & st_ino here
560        to see if the two files being compared are actually the same file.
561        But that won't happen in CVS, so we won't bother. */
562
563     if (sb1.st_size != sb2.st_size)
564         ret = 1;
565     else if (sb1.st_size == 0)
566         ret = 0;
567     else
568     {
569         /* FIXME: compute the optimal buffer size by computing the least
570            common multiple of the files st_blocks field */
571         size_t buf_size = 8 * 1024;
572         size_t read1;
573         size_t read2;
574
575         buf1 = xmalloc (buf_size);
576         buf2 = xmalloc (buf_size);
577
578         do
579         {
580             read1 = block_read (fd1, buf1, buf_size);
581             if (read1 == (size_t)-1)
582                 error (1, errno, "cannot read file %s for comparing", file1);
583
584             read2 = block_read (fd2, buf2, buf_size);
585             if (read2 == (size_t)-1)
586                 error (1, errno, "cannot read file %s for comparing", file2);
587
588             /* assert (read1 == read2); */
589
590             ret = memcmp(buf1, buf2, read1);
591         } while (ret == 0 && read1 == buf_size);
592
593         free (buf1);
594         free (buf2);
595     }
596         
597     (void) close (fd1);
598     (void) close (fd2);
599     return (ret);
600 }
601
602
603 /* Just in case this implementation does not define this.  */
604 #ifndef L_tmpnam
605 #define L_tmpnam 50
606 #endif
607
608
609 #ifdef LOSING_TMPNAM_FUNCTION
610 char *
611 cvs_temp_name ()
612 {
613     char value[L_tmpnam + 1];
614
615     /* FIXME: Should be using TMPDIR.  */
616     strcpy (value, "/tmp/cvsXXXXXX");
617     mktemp (value);
618     return xstrdup (value);
619 }
620 #else
621 /* Generate a unique temporary filename.  Returns a pointer to a newly
622    malloc'd string containing the name.  Returns successfully or not at
623    all.  */
624 char *
625 cvs_temp_name ()
626 {
627     char value[L_tmpnam + 1];
628     char *retval;
629
630     /* FIXME: should be using TMPDIR, perhaps by using tempnam on systems
631        which have it.  */
632     retval = tmpnam (value);
633     if (retval == NULL)
634         error (1, errno, "cannot generate temporary filename");
635     return xstrdup (retval);
636 }
637 #endif
638
639
640
641 /* char *
642  * xresolvepath ( const char *path )
643  *
644  * Like xreadlink(), but resolve all links in a path.
645  *
646  * INPUTS
647  *  path        The original path.
648  *
649  * RETURNS
650  *  The path with any symbolic links expanded.
651  *
652  * ERRORS
653  *  This function exits with a fatal error if it fails to read the link for
654  *  any reason.
655  */
656 char *
657 xresolvepath ( path )
658     const char *path;
659 {
660     char *hardpath;
661     char *owd;
662
663     /* assert ( isdir ( path ) ); */
664
665     /* FIXME - If HAVE_READLINK is defined, we should probably walk the path
666      * bit by bit calling xreadlink().
667      */
668
669     owd = xgetwd();
670     if ( CVS_CHDIR ( path ) < 0)
671         error ( 1, errno, "cannot chdir to %s", path );
672     if ( ( hardpath = xgetwd() ) == NULL )
673         error (1, errno, "cannot readlink %s", hardpath);
674     if ( CVS_CHDIR ( owd ) < 0)
675         error ( 1, errno, "cannot chdir to %s", owd );
676     free (owd);
677     return hardpath;
678 }
679
680 /* Return a pointer into PATH's last component.  */
681 char *
682 last_component (path)
683     char *path;
684 {
685     char *last;
686
687     /* We can't be sure here if 'path' is already slashified. */
688     _fnslashify (path);
689
690     last = strrchr (path, '/');
691
692     if (last && (last != path))
693         return last + 1;
694     else
695         return path;
696 }
697
698 /* Return the home directory.  Returns a pointer to storage
699    managed by this function or its callees (currently getenv).
700    This function will return the same thing every time it is
701    called.  */
702 char *
703 get_homedir ()
704 {
705     static char *home = NULL;
706     char *env = getenv ("HOME");
707     struct passwd *pw;
708
709     if (home != NULL)
710         return home;
711
712     if (env)
713         home = env;
714     else if ((pw = (struct passwd *) getpwuid (getuid ()))
715              && pw->pw_dir)
716         home = xstrdup (pw->pw_dir);
717     else
718         return 0;
719
720     return home;
721 }
722
723 /* See cvs.h for description.  On unix this does nothing, because the
724    shell expands the wildcards.  Under EMX, use _fnexplode to get the
725    expanded filenames */
726 void
727 expand_wild (argc, argv, pargc, pargv)
728     int argc;
729     char **argv;
730     int *pargc;
731     char ***pargv;
732 {
733     int i;
734     *pargc = argc;
735     *pargv = (char **) xmalloc (argc * sizeof (char *));
736     for (i = 0; i < argc; ++i)
737         (*pargv)[i] = xstrdup (argv[i]);
738 }
739
740 unsigned char
741 OS2_filename_classes[] =
742 {
743     0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
744     0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
745     0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17,
746     0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
747     0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27,
748     0x28,0x29,0x2a,0x2b, 0x2c,0x2d,0x2e,0x2f,
749     0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
750     0x38,0x39,0x3a,0x3b, 0x3c,0x3d,0x3e,0x3f,
751     0x40,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
752     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
753     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
754     0x78,0x79,0x7a,0x5b, 0x2f,0x5d,0x5e,0x5f,
755     0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67,
756     0x68,0x69,0x6a,0x6b, 0x6c,0x6d,0x6e,0x6f,
757     0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77,
758     0x78,0x79,0x7a,0x7b, 0x7c,0x7d,0x7e,0x7f,
759     0x80,0x81,0x82,0x83, 0x84,0x85,0x86,0x87,
760     0x88,0x89,0x8a,0x8b, 0x8c,0x8d,0x8e,0x8f,
761     0x90,0x91,0x92,0x93, 0x94,0x95,0x96,0x97,
762     0x98,0x99,0x9a,0x9b, 0x9c,0x9d,0x9e,0x9f,
763     0xa0,0xa1,0xa2,0xa3, 0xa4,0xa5,0xa6,0xa7,
764     0xa8,0xa9,0xaa,0xab, 0xac,0xad,0xae,0xaf,
765     0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
766     0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
767     0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
768     0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
769     0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
770     0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
771     0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
772     0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
773     0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
774     0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
775 };
776
777
778 /* Like strcmp, but with the appropriate tweaks for file names.
779    Under OS/2, filenames are case-insensitive but case-preserving, and
780    both \ and / are path element separators.  */
781 int
782 fncmp (const char *n1, const char *n2)
783 {
784     char fn1[MAXNAMLEN], fn2[MAXNAMLEN];
785
786     strcpy (fn1, n1); _fnslashify(fn1);
787     strcpy (fn2, n2); _fnslashify(fn2);
788
789     return _fncmp ((unsigned char *) fn1, (unsigned char *) fn2);
790 }
791
792
793 /* Fold characters in FILENAME to their canonical forms.
794    If FOLD_FN_CHAR is not #defined, the system provides a default
795    definition for this.  */
796 void
797 fnfold (char *filename)
798 {
799     while (*filename)
800     {
801         *filename = FOLD_FN_CHAR (*filename);
802         filename++;
803     }
804 }