home *** CD-ROM | disk | FTP | other *** search
- /*
- (c) Copyright 1992 Eric Backus
-
- This software may be used freely so long as this copyright notice is
- left intact. There is no warrantee on this software.
- */
-
- #include <sys/stat.h> /* For stat() */
- #include <fcntl.h> /* For O_RDONLY, etc. */
- #include <unistd.h> /* For read(), write(), etc. */
- #include <limits.h> /* For PATH_MAX */
- #include <utime.h> /* For utime() */
- #include <errno.h> /* For errno */
-
- extern void _fixpath(const char *, char *);
-
- /* Of course, DOS can't really do a link. We just do a copy instead,
- which is as close as DOS gets. Alternatively, we could always fail
- and return -1. I think this is slightly better. */
- int
- link(const char *path1, const char *path2)
- {
- struct stat statbuf;
- struct utimbuf times;
- char p1[PATH_MAX + 1], p2[PATH_MAX + 1];
- char buf[2048];
- int fd1, fd2, nbyte, status1, status2;
-
- /* Fail if either path is null */
- if (path1 == NULL || *path1 == '\0' ||
- path2 == NULL || *path2 == '\0')
- {
- errno = ENOENT;
- return -1;
- }
-
- _fixpath(path1, p1);
- _fixpath(path2, p2);
-
- /* Fail if path1 does not exist - stat() will set errno */
- if (stat(p1, &statbuf) < 0) return -1;
-
- /* Fail if path1 is not a regular file */
- if ((statbuf.st_mode & S_IFMT) != S_IFREG)
- {
- errno = EPERM;
- return -1;
- }
-
- /* Fail if path1 and path2 are on different devices */
- if (p1[0] != p2[0])
- {
- errno = EXDEV;
- return -1;
- }
-
- /* Fail if unable to open path1 - open() will set errno */
- fd1 = open(p1, O_RDONLY | O_BINARY);
- if (fd1 < 0) return -1;
-
- /* Fail if unable to create path2 - open() will set errno */
- fd2 = open(p2, O_WRONLY | O_BINARY | O_CREAT | O_EXCL, 0600);
- if (fd2 < 0)
- {
- (void) close(fd1);
- return -1;
- }
-
- /* Copy path1 to path2 */
- do
- {
- nbyte = read(fd1, buf, sizeof buf);
- if (nbyte <= 0) break;
- if (write(fd2, buf, nbyte) != nbyte) nbyte = -1;
- }
- while (nbyte > 0);
-
- /* Fail if the copy failed or we can't clean up */
- status1 = close(fd1);
- status2 = close(fd2);
- if (nbyte < 0 || status1 < 0 || status2 < 0)
- {
- (void) unlink(path2);
- return -1;
- }
-
- /* Success! */
-
- /* Set the mode to match the original, ignoring errors */
- (void) chmod(p2, statbuf.st_mode);
-
- /* Set the file time to match the original, ignoring errors */
- times.actime = statbuf.st_atime;
- times.modtime = statbuf.st_mtime;
- (void) utime(p2, ×);
-
- return 0;
- }
-