diff options
author | peter <peter@FreeBSD.org> | 1998-03-10 13:40:57 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1998-03-10 13:40:57 +0000 |
commit | a194b78bd292dd13f17cfe65c12fb5dee1bb9392 (patch) | |
tree | 83716acb7a6188c846ca3328958e0a93b9701795 /contrib/cvs/src/filesubr.c | |
parent | 39cd03a57045ca27b0e7323a52f287f7696fa947 (diff) | |
parent | 0c111e2b51cac7eead56494b30c5977e4ec9a8ea (diff) | |
download | FreeBSD-src-a194b78bd292dd13f17cfe65c12fb5dee1bb9392.zip FreeBSD-src-a194b78bd292dd13f17cfe65c12fb5dee1bb9392.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r34461,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/cvs/src/filesubr.c')
-rw-r--r-- | contrib/cvs/src/filesubr.c | 205 |
1 files changed, 161 insertions, 44 deletions
diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c index b5121a7..0ccc3df 100644 --- a/contrib/cvs/src/filesubr.c +++ b/contrib/cvs/src/filesubr.c @@ -43,46 +43,66 @@ copy_file (from, to) if (noexec) return; - if ((fdin = open (from, O_RDONLY)) < 0) - error (1, errno, "cannot open %s for copying", from); - if (fstat (fdin, &sb) < 0) - error (1, errno, "cannot fstat %s", from); - if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0) - error (1, errno, "cannot create %s for copying", to); - if (sb.st_size > 0) + /* If the file to be copied is a link or a device, then just create + the new link or device appropriately. */ + if (islink (from)) { - char buf[BUFSIZ]; - int n; + char *source = xreadlink (from); + symlink (source, to); + free (source); + return; + } - for (;;) + if (isdevice (from)) + { + if (stat (from, &sb) < 0) + error (1, errno, "cannot stat %s", from); + mknod (to, sb.st_mode, sb.st_rdev); + } + else + { + /* Not a link or a device... probably a regular file. */ + if ((fdin = open (from, O_RDONLY)) < 0) + error (1, errno, "cannot open %s for copying", from); + if (fstat (fdin, &sb) < 0) + error (1, errno, "cannot fstat %s", from); + if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0) + error (1, errno, "cannot create %s for copying", to); + if (sb.st_size > 0) { - n = read (fdin, buf, sizeof(buf)); - if (n == -1) + char buf[BUFSIZ]; + int n; + + for (;;) { + n = read (fdin, buf, sizeof(buf)); + if (n == -1) + { #ifdef EINTR - if (errno == EINTR) - continue; + if (errno == EINTR) + continue; #endif - error (1, errno, "cannot read file %s for copying", from); - } - else if (n == 0) - break; - - if (write(fdout, buf, n) != n) { - error (1, errno, "cannot write file %s for copying", to); + error (1, errno, "cannot read file %s for copying", from); + } + else if (n == 0) + break; + + if (write(fdout, buf, n) != n) { + error (1, errno, "cannot write file %s for copying", to); + } } - } #ifdef HAVE_FSYNC - if (fsync (fdout)) - error (1, errno, "cannot fsync file %s after copying", to); + if (fsync (fdout)) + error (1, errno, "cannot fsync file %s after copying", to); #endif - } + } - if (close (fdin) < 0) - error (0, errno, "cannot close %s", from); - if (close (fdout) < 0) - error (1, errno, "cannot close %s", to); + if (close (fdin) < 0) + error (0, errno, "cannot close %s", from); + if (close (fdout) < 0) + error (1, errno, "cannot close %s", to); + } /* now, set the times for the copied file to match those of the original */ memset ((char *) &t, 0, sizeof (t)); @@ -119,7 +139,7 @@ islink (file) #ifdef S_ISLNK struct stat sb; - if (lstat (file, &sb) < 0) + if (CVS_LSTAT (file, &sb) < 0) return (0); return (S_ISLNK (sb.st_mode)); #else @@ -128,6 +148,29 @@ islink (file) } /* + * Returns non-zero if the argument file is a block or + * character special device. + */ +int +isdevice (file) + const char *file; +{ + struct stat sb; + + if (CVS_LSTAT (file, &sb) < 0) + return (0); +#ifdef S_ISBLK + if (S_ISBLK (sb.st_mode)) + return 1; +#endif +#ifdef S_ISCHR + if (S_ISCHR (sb.st_mode)) + return 1; +#endif + return 0; +} + +/* * Returns non-zero if the argument file exists. */ int @@ -298,6 +341,9 @@ mkdir_if_needed (name) /* * Change the mode of a file, either adding write permissions, or removing * all write permissions. Either change honors the current umask setting. + * + * Don't do anything if PreservePermissions is set to `yes'. This may + * have unexpected consequences for some uses of xchmod. */ void xchmod (fname, writable) @@ -307,6 +353,9 @@ xchmod (fname, writable) struct stat sb; mode_t mode, oumask; + if (preserve_perms) + return; + if (stat (fname, &sb) < 0) { if (!noexec) @@ -417,6 +466,8 @@ int unlink_file_dir (f) const char *f; { + struct stat sb; + if (trace #ifdef SERVER_SUPPORT /* This is called by the server parent process in contexts where @@ -433,20 +484,23 @@ unlink_file_dir (f) /* For at least some unices, if root tries to unlink() a directory, instead of doing something rational like returning EISDIR, the system will gleefully go ahead and corrupt the filesystem. - So we first call isdir() to see if it is OK to call unlink(). This + So we first call stat() to see if it is OK to call unlink(). This doesn't quite work--if someone creates a directory between the - call to isdir() and the call to unlink(), we'll still corrupt + call to stat() and the call to unlink(), we'll still corrupt the filesystem. Where is the Unix Haters Handbook when you need it? */ - if (isdir(f)) - return deep_remove_dir(f); - else + if (stat (f, &sb) < 0) { - if (unlink (f) != 0) + if (existence_error (errno)) + { + /* The file or directory doesn't exist anyhow. */ return -1; + } } - /* We were able to remove the file from the disk */ - return 0; + else if (S_ISDIR (sb.st_mode)) + return deep_remove_dir (f); + + return unlink (f); } /* Remove a directory and everything it contains. Returns 0 for @@ -557,6 +611,8 @@ block_read (fd, buf, nchars) /* * Compare "file1" to "file2". Return non-zero if they don't compare exactly. + * If FILE1 and FILE2 are special files, compare their salient characteristics + * (i.e. major/minor device numbers, links, etc. */ int xcmp (file1, file2) @@ -568,14 +624,42 @@ xcmp (file1, file2) int fd1, fd2; int ret; + if (CVS_LSTAT (file1, &sb1) < 0) + error (1, errno, "cannot lstat %s", file1); + if (CVS_LSTAT (file2, &sb2) < 0) + error (1, errno, "cannot lstat %s", file2); + + /* If FILE1 and FILE2 are not the same file type, they are unequal. */ + if ((sb1.st_mode & S_IFMT) != (sb2.st_mode & S_IFMT)) + return 1; + + /* If FILE1 and FILE2 are symlinks, they are equal if they point to + the same thing. */ + if (S_ISLNK (sb1.st_mode) && S_ISLNK (sb2.st_mode)) + { + int result; + buf1 = xreadlink (file1); + buf2 = xreadlink (file2); + result = (strcmp (buf1, buf2) == 0); + free (buf1); + free (buf2); + return result; + } + + /* If FILE1 and FILE2 are devices, they are equal if their device + numbers match. */ + if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode)) + { + if (sb1.st_rdev == sb2.st_rdev) + return 0; + else + return 1; + } + if ((fd1 = open (file1, O_RDONLY)) < 0) error (1, errno, "cannot open file %s for comparing", file1); if ((fd2 = open (file2, O_RDONLY)) < 0) error (1, errno, "cannot open file %s for comparing", file2); - if (fstat (fd1, &sb1) < 0) - error (1, errno, "cannot fstat %s", file1); - if (fstat (fd2, &sb2) < 0) - error (1, errno, "cannot fstat %s", file2); /* A generic file compare routine might compare st_dev & st_ino here to see if the two files being compared are actually the same file. @@ -677,6 +761,39 @@ isabsolute (filename) return filename[0] == '/'; } +/* + * Return a string (dynamically allocated) with the name of the file to which + * LINK is symlinked. + */ +char * +xreadlink (link) + const char *link; +{ + char *file = NULL; + int buflen = BUFSIZ; + + if (!islink (link)) + return NULL; + + /* Get the name of the file to which `from' is linked. + FIXME: what portability issues arise here? Are readlink & + ENAMETOOLONG defined on all systems? -twp */ + do + { + file = xrealloc (file, buflen); + errno = 0; + readlink (link, file, buflen); + buflen *= 2; + } + while (errno == ENAMETOOLONG); + + if (errno) + error (1, errno, "cannot readlink %s", link); + + return file; +} + + /* Return a pointer into PATH's last component. */ char * @@ -684,8 +801,8 @@ last_component (path) char *path; { char *last = strrchr (path, '/'); - - if (last) + + if (last && (last != path)) return last + 1; else return path; |