home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / posix / unistd / link.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  2.4 KB  |  96 lines

  1. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  2. #include <libc/stubs.h>
  3. #include <sys/stat.h>        /* For stat() */
  4. #include <fcntl.h>        /* For O_RDONLY, etc. */
  5. #include <unistd.h>        /* For read(), write(), etc. */
  6. #include <limits.h>        /* For PATH_MAX */
  7. #include <utime.h>        /* For utime() */
  8. #include <errno.h>        /* For errno */
  9.  
  10. /* Of course, DOS can't really do a link.  We just do a copy instead,
  11.    which is as close as DOS gets.  Alternatively, we could always fail
  12.    and return -1.  I think this is slightly better. */
  13. int
  14. link(const char *path1, const char *path2)
  15. {
  16.   struct stat statbuf1, statbuf2;
  17.   struct utimbuf times;
  18.   char buf[16384];
  19.   int fd1, fd2, nbyte, status1, status2;
  20.  
  21.   /* Fail if either path is null */
  22.   if (path1 == NULL || path2 == NULL)
  23.   {
  24.     errno = EFAULT;
  25.     return -1;
  26.   }
  27.   if (*path1 == '\0' || *path2 == '\0')
  28.   {
  29.     errno = ENOENT;
  30.     return -1;
  31.   }
  32.  
  33.   /* Fail if path1 does not exist - stat() will set errno */
  34.   if (stat(path1, &statbuf1) < 0) return -1;
  35.  
  36.   /* Fail if path1 is not a regular file */
  37.   if (!S_ISREG(statbuf1.st_mode))
  38.   {
  39.     errno = EPERM;
  40.     return -1;
  41.   }
  42.  
  43.   /* Fail if unable to open path1 - open() will set errno */
  44.   fd1 = open(path1, O_RDONLY | O_BINARY);
  45.   if (fd1 < 0) return -1;
  46.  
  47.   /* Fail if unable to create path2 - open() will set errno */
  48.   fd2 = open(path2, O_WRONLY | O_BINARY | O_CREAT | O_EXCL, 0600);
  49.   if (fd2 < 0)
  50.   {
  51.     (void) close(fd1);
  52.     return -1;
  53.   }
  54.  
  55.   /* Fail if path1 and path2 are on different devices */
  56.   if (fstat(fd2, &statbuf2) < 0) return -1;
  57.   if (statbuf1.st_dev != statbuf2.st_dev)
  58.   {
  59.     (void)close(fd1);
  60.     (void)close(fd2);
  61.     (void)unlink(path2);
  62.     errno = EXDEV;
  63.     return -1;
  64.   }
  65.  
  66.   /* Copy path1 to path2 */
  67.   do
  68.   {
  69.     nbyte = read(fd1, buf, sizeof buf);
  70.     if (nbyte <= 0) break;
  71.     if (write(fd2, buf, nbyte) != nbyte) nbyte = -1;
  72.   }
  73.   while (nbyte > 0);
  74.  
  75.   /* Fail if the copy failed or we can't clean up */
  76.   status1 = close(fd1);
  77.   status2 = close(fd2);
  78.   if (nbyte < 0 || status1 < 0 || status2 < 0)
  79.   {
  80.     (void) unlink(path2);
  81.     return -1;
  82.   }
  83.  
  84.   /* Success! */
  85.  
  86.   /* Set the mode to match the original, ignoring errors */
  87.   (void) chmod(path2, statbuf1.st_mode);
  88.  
  89.   /* Set the file time to match the original, ignoring errors */
  90.   times.actime = statbuf1.st_atime;
  91.   times.modtime = statbuf1.st_mtime;
  92.   (void) utime(path2, ×);
  93.  
  94.   return 0;
  95. }
  96.