[BACK]Return to xinstall.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / xinstall

Diff for /src/usr.bin/xinstall/xinstall.c between version 1.16 and 1.17

version 1.16, 1998/09/26 09:04:43 version 1.17, 1998/12/16 19:55:57
Line 80 
Line 80 
 #define SETFLAGS        0x02            /* Tell install to set flags. */  #define SETFLAGS        0x02            /* Tell install to set flags. */
 #define NOCHANGEBITS    (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)  #define NOCHANGEBITS    (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
   
 void    copy __P((int, char *, int, char *, off_t));  void    copy __P((int, char *, int, char *, off_t, int));
 int     compare __P((int, const char *, size_t, int, const char *, size_t));  int     compare __P((int, const char *, size_t, int, const char *, size_t));
 void    install __P((char *, char *, u_long, u_int));  void    install __P((char *, char *, u_long, u_int));
 void    install_dir __P((char *));  void    install_dir __P((char *));
Line 89 
Line 89 
 void    usage __P((void));  void    usage __P((void));
 int     create_newfile __P((char *, struct stat *));  int     create_newfile __P((char *, struct stat *));
 int     create_tempfile __P((char *, char *, size_t));  int     create_tempfile __P((char *, char *, size_t));
   int     file_write __P((int, char *, register int, int *, int *, int));
   
 int  int
 main(argc, argv)  main(argc, argv)
Line 281 
Line 282 
                 }                  }
                 if (!files_match)                  if (!files_match)
                         copy(from_fd, from_name, to_fd,                          copy(from_fd, from_name, to_fd,
                              safecopy ? tempfile : to_name, from_sb.st_size);                               safecopy ? tempfile : to_name, from_sb.st_size,
                                ((off_t)from_sb.st_blocks * S_BLKSIZE < from_sb.st_size));
         }          }
   
         if (dostrip) {          if (dostrip) {
Line 397 
Line 399 
  *      copy from one file to another   *      copy from one file to another
  */   */
 void  void
 copy(from_fd, from_name, to_fd, to_name, size)  copy(from_fd, from_name, to_fd, to_name, size, sparse)
         register int from_fd, to_fd;          register int from_fd, to_fd;
         char *from_name, *to_name;          char *from_name, *to_name;
         off_t size;          off_t size;
           int sparse;
 {  {
         register int nr, nw;          register int nr, nw;
         int serrno;          int serrno;
         char *p, buf[MAXBSIZE];          char *p, buf[MAXBSIZE];
         volatile size_t siz;  
   
         /* Rewind file descriptors. */          /* Rewind file descriptors. */
         if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)          if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
Line 416 
Line 418 
         /*          /*
          * Mmap and write if less than 8M (the limit is so we don't totally           * Mmap and write if less than 8M (the limit is so we don't totally
          * trash memory on big files.  This is really a minor hack, but it           * trash memory on big files.  This is really a minor hack, but it
          * wins some CPU back.           * wins some CPU back.  Sparse files need special treatment.
          */           */
         if (size <= 8 * 1048576) {          if (!sparse && size <= 8 * 1048576) {
                   volatile size_t siz;
   
                 if ((p = mmap(NULL, (size_t)size, PROT_READ,                  if ((p = mmap(NULL, (size_t)size, PROT_READ,
                     MAP_PRIVATE, from_fd, (off_t)0)) == (char *)-1) {                      MAP_PRIVATE, from_fd, (off_t)0)) == (char *)-1) {
                         serrno = errno;                          serrno = errno;
Line 434 
Line 438 
                 }                  }
                 (void) munmap(p, (size_t)size);                  (void) munmap(p, (size_t)size);
         } else {          } else {
                 while ((nr = read(from_fd, buf, sizeof(buf))) > 0)                  int sz, rem, isem = 1;
                         if ((nw = write(to_fd, buf, nr)) != nr) {                  struct stat sb;
   
                   /*
                    * Pass the blocksize of the file being written to the write
                    * routine.  if the size is zero, use the default S_BLKSIZE.
                    */
                   if (fstat(to_fd, &sb) != 0 || sb.st_blksize == 0)
                           sz = S_BLKSIZE;
                   else
                           sz = sb.st_blksize;
   
                   while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
                           if (sparse)
                                   nw = file_write(to_fd, buf, nr, &rem, &isem, sz);
                           else
                                   nw = write(to_fd, buf, nr);
                           if (nw != nr) {
                                 serrno = errno;                                  serrno = errno;
                                 (void)unlink(to_name);                                  (void)unlink(to_name);
                                 errx(EX_OSERR, "%s: %s",                                  errx(EX_OSERR, "%s: %s",
                                     to_name, strerror(nw > 0 ? EIO : serrno));                                      to_name, strerror(nw > 0 ? EIO : serrno));
                         }                          }
                   }
                 if (nr != 0) {                  if (nr != 0) {
                         serrno = errno;                          serrno = errno;
                         (void)unlink(to_name);                          (void)unlink(to_name);
Line 621 
Line 642 
         (void)unlink(path);          (void)unlink(path);
   
         return(open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));          return(open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
   }
   
   /*
    * file_write()
    *      Write/copy a file (during copy or archive extract). This routine knows
    *      how to copy files with lseek holes in it. (Which are read as file
    *      blocks containing all 0's but do not have any file blocks associated
    *      with the data). Typical examples of these are files created by dbm
    *      variants (.pag files). While the file size of these files are huge, the
    *      actual storage is quite small (the files are sparse). The problem is
    *      the holes read as all zeros so are probably stored on the archive that
    *      way (there is no way to determine if the file block is really a hole,
    *      we only know that a file block of all zero's can be a hole).
    *      At this writing, no major archive format knows how to archive files
    *      with holes. However, on extraction (or during copy, -rw) we have to
    *      deal with these files. Without detecting the holes, the files can
    *      consume a lot of file space if just written to disk. This replacement
    *      for write when passed the basic allocation size of a file system block,
    *      uses lseek whenever it detects the input data is all 0 within that
    *      file block. In more detail, the strategy is as follows:
    *      While the input is all zero keep doing an lseek. Keep track of when we
    *      pass over file block boundries. Only write when we hit a non zero
    *      input. once we have written a file block, we continue to write it to
    *      the end (we stop looking at the input). When we reach the start of the
    *      next file block, start checking for zero blocks again. Working on file
    *      block boundries significantly reduces the overhead when copying files
    *      that are NOT very sparse. This overhead (when compared to a write) is
    *      almost below the measurement resolution on many systems. Without it,
    *      files with holes cannot be safely copied. It does has a side effect as
    *      it can put holes into files that did not have them before, but that is
    *      not a problem since the file contents are unchanged (in fact it saves
    *      file space). (Except on paging files for diskless clients. But since we
    *      cannot determine one of those file from here, we ignore them). If this
    *      ever ends up on a system where CTG files are supported and the holes
    *      are not desired, just do a conditional test in those routines that
    *      call file_write() and have it call write() instead. BEFORE CLOSING THE
    *      FILE, make sure to call file_flush() when the last write finishes with
    *      an empty block. A lot of file systems will not create an lseek hole at
    *      the end. In this case we drop a single 0 at the end to force the
    *      trailing 0's in the file.
    *      ---Parameters---
    *      rem: how many bytes left in this file system block
    *      isempt: have we written to the file block yet (is it empty)
    *      sz: basic file block allocation size
    *      cnt: number of bytes on this write
    *      str: buffer to write
    * Return:
    *      number of bytes written, -1 on write (or lseek) error.
    */
   
   int
   file_write(fd, str, cnt, rem, isempt, sz)
           int fd;
           char *str;
           register int cnt;
           int *rem;
           int *isempt;
           int sz;
   {
           register char *pt;
           register char *end;
           register int wcnt;
           register char *st = str;
   
           /*
            * while we have data to process
            */
           while (cnt) {
                   if (!*rem) {
                           /*
                            * We are now at the start of file system block again
                            * (or what we think one is...). start looking for
                            * empty blocks again
                            */
                           *isempt = 1;
                           *rem = sz;
                   }
   
                   /*
                    * only examine up to the end of the current file block or
                    * remaining characters to write, whatever is smaller
                    */
                   wcnt = MIN(cnt, *rem);
                   cnt -= wcnt;
                   *rem -= wcnt;
                   if (*isempt) {
                           /*
                            * have not written to this block yet, so we keep
                            * looking for zero's
                            */
                           pt = st;
                           end = st + wcnt;
   
                           /*
                            * look for a zero filled buffer
                            */
                           while ((pt < end) && (*pt == '\0'))
                                   ++pt;
   
                           if (pt == end) {
                                   /*
                                    * skip, buf is empty so far
                                    */
                                   if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {
                                           warn("lseek");
                                           return(-1);
                                   }
                                   st = pt;
                                   continue;
                           }
                           /*
                            * drat, the buf is not zero filled
                            */
                           *isempt = 0;
                   }
   
                   /*
                    * have non-zero data in this file system block, have to write
                    */
                   if (write(fd, st, wcnt) != wcnt) {
                           warn("write");
                           return(-1);
                   }
                   st += wcnt;
           }
           return(st - str);
 }  }

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17