home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / arc / Archiver / cpio / src / util.c < prev    next >
C/C++ Source or Header  |  1992-09-19  |  24KB  |  869 lines

  1. /* util.c - Several utility routines for cpio.
  2.    Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include "system.h"
  21. #include "cpiohdr.h"
  22. #include "dstring.h"
  23. #include "extern.h"
  24. #include "rmt.h"
  25.  
  26. #ifndef __MSDOS__
  27. #include <sys/ioctl.h>
  28. #else
  29. #include <io.h>
  30. #endif
  31.  
  32. #ifdef HAVE_MTIO_H
  33. #include <sys/mtio.h>
  34. #endif
  35.  
  36. static void empty_output_buffer_swap ();
  37. static void hash_insert ();
  38.  
  39. /* Write `output_size' bytes of `output_buffer' to file
  40.    descriptor OUT_DES and reset `output_size' and `out_buff'.  */
  41.  
  42. void
  43. empty_output_buffer (out_des)
  44.      int out_des;
  45. {
  46.   int bytes_written;
  47.  
  48.   if (swapping_halfwords || swapping_bytes)
  49.     {
  50.       empty_output_buffer_swap (out_des);
  51.       return;
  52.     }
  53.   bytes_written = rmtwrite (out_des, output_buffer, output_size);
  54.   if (bytes_written != output_size)
  55.     {
  56.       int rest_bytes_written;
  57.       int rest_output_size;
  58.  
  59.       if (output_is_special
  60.       && (bytes_written >= 0
  61.           || (bytes_written < 0
  62.           && (errno == ENOSPC || errno == EIO || errno == ENXIO))))
  63.     {
  64.       get_next_reel (out_des);
  65.       if (bytes_written > 0)
  66.         rest_output_size = output_size - bytes_written;
  67.       else
  68.         rest_output_size = output_size;
  69.       rest_bytes_written = rmtwrite (out_des, output_buffer,
  70.                      rest_output_size);
  71.       if (rest_bytes_written != rest_output_size)
  72.         error (1, errno, "write error");
  73.     }
  74.       else
  75.     error (1, errno, "write error");
  76.     }
  77.   output_bytes += output_size;
  78.   out_buff = output_buffer;
  79.   output_size = 0;
  80. }
  81.  
  82. /* Write `output_size' bytes of `output_buffer' to file
  83.    descriptor OUT_DES with byte and/or halfword swapping and reset
  84.    `output_size' and `out_buff'.  This routine should not be called
  85.    with `swapping_bytes' set unless the caller knows that the
  86.    file being written has an even number of bytes, and it should not be
  87.    called with `swapping_halfwords' set unless the caller knows
  88.    that the file being written has a length divisible by 4.  If either
  89.    of those restrictions are not met, bytes may be lost in the output
  90.    file.  OUT_DES must refer to a file that we are creating during
  91.    a process_copy_in, so we don't have to check for end of media
  92.    errors or be careful about only writing in blocks of `output_size'
  93.    bytes.  */
  94.  
  95. static void
  96. empty_output_buffer_swap (out_des)
  97.      int out_des;
  98. {
  99.   /* Since `output_size' might not be divisible by 4 or 2, we might
  100.      not be able to be able to swap all the bytes and halfwords in
  101.      `output_buffer' (e.g., if `output_size' is odd), so we might not be
  102.      able to write them all.  We will swap and write as many bytes as
  103.      we can, and save the rest in `left_overs' for the next time we are
  104.      called.  */
  105.   static char left_overs[4];
  106.   static int left_over_bytes = 0;
  107.  
  108.   int bytes_written;
  109.   int complete_halfwords;
  110.   int complete_words;
  111.   int extra_bytes;
  112.  
  113.   output_bytes += output_size;
  114.  
  115.   out_buff = output_buffer;
  116.  
  117.   if (swapping_halfwords)
  118.     {
  119.       if (left_over_bytes != 0)
  120.     {
  121.       while (output_size > 0 && left_over_bytes < 4)
  122.         {
  123.           left_overs[left_over_bytes++] = *out_buff++;
  124.           --output_size;
  125.         }
  126.       if (left_over_bytes < 4)
  127.         {
  128.           out_buff = output_buffer;
  129.           output_size = 0;
  130.           return;
  131.         }
  132.       swahw_array (left_overs, 1);
  133.       if (swapping_bytes)
  134.         swab_array (left_overs, 2);
  135.       bytes_written = rmtwrite (out_des, left_overs, 4);
  136.       if (bytes_written != 4)
  137.         error (1, errno, "write error");
  138.       left_over_bytes = 0;
  139.     }
  140.       complete_words = output_size / 4;
  141.       if (complete_words > 0)
  142.     {
  143.       swahw_array (out_buff, complete_words);
  144.       if (swapping_bytes)
  145.         swab_array (out_buff, 2 * complete_words);
  146.       bytes_written = rmtwrite (out_des, out_buff, 4 * complete_words);
  147.       if (bytes_written != (4 * complete_words))
  148.         error (1, errno, "write error");
  149.     }
  150.       out_buff += (4 * complete_words);
  151.       extra_bytes = output_size % 4;
  152.       while (extra_bytes > 0)
  153.     {
  154.       left_overs[left_over_bytes++] = *out_buff++;
  155.       --extra_bytes;
  156.     }
  157.  
  158.     }
  159.   else
  160.     {
  161.       if (left_over_bytes != 0)
  162.     {
  163.       while (output_size > 0 && left_over_bytes < 2)
  164.         {
  165.           left_overs[left_over_bytes++] = *out_buff++;
  166.           --output_size;
  167.         }
  168.       if (left_over_bytes < 2)
  169.         {
  170.           out_buff = output_buffer;
  171.           output_size = 0;
  172.           return;
  173.         }
  174.       swab_array (left_overs, 1);
  175.       bytes_written = rmtwrite (out_des, left_overs, 2);
  176.       if (bytes_written != 2)
  177.         error (1, errno, "write error");
  178.       left_over_bytes = 0;
  179.     }
  180.       complete_halfwords = output_size / 2;
  181.       if (complete_halfwords > 0)
  182.     {
  183.       swab_array (out_buff, complete_halfwords);
  184.       bytes_written = rmtwrite (out_des, out_buff, 2 * complete_halfwords);
  185.       if (bytes_written != (2 * complete_halfwords))
  186.         error (1, errno, "write error");
  187.     }
  188.       out_buff += (2 * complete_halfwords);
  189.       extra_bytes = output_size % 2;
  190.       while (extra_bytes > 0)
  191.     {
  192.       left_overs[left_over_bytes++] = *out_buff++;
  193.       --extra_bytes;
  194.     }
  195.     }
  196.  
  197.   out_buff = output_buffer;
  198.   output_size = 0;
  199. }
  200.  
  201. /* Exchange the halfwords of each element of the array of COUNT longs
  202.    starting at PTR.  PTR does not have to be aligned at a word
  203.    boundary.  */
  204.  
  205. void
  206. swahw_array (ptr, count)
  207.      char *ptr;
  208.      int count;
  209. {
  210.   char tmp;
  211.  
  212.   for (; count > 0; --count)
  213.     {
  214.       tmp = *ptr;
  215.       *ptr = *(ptr + 2);
  216.       *(ptr + 2) = tmp;
  217.       ++ptr;
  218.       tmp = *ptr;
  219.       *ptr = *(ptr + 2);
  220.       *(ptr + 2) = tmp;
  221.       ptr += 3;
  222.     }
  223. }
  224.  
  225. /* Read at most NUM_BYTES or `io_block_size' bytes, whichever is smaller,
  226.    into the start of `input_buffer' from file descriptor IN_DES.
  227.    Set `input_size' to the number of bytes read and reset `in_buff'.
  228.    Exit with an error if end of file is reached.  */
  229.  
  230. void
  231. fill_input_buffer (in_des, num_bytes)
  232.      int in_des;
  233.      int num_bytes;
  234. {
  235.   in_buff = input_buffer;
  236.   num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
  237.   input_size = rmtread (in_des, input_buffer, num_bytes);
  238.   if (input_size == 0 && input_is_special)
  239.     {
  240.       get_next_reel (in_des);
  241.       input_size = rmtread (in_des, input_buffer, num_bytes);
  242.     }
  243.   if (input_size < 0)
  244.     error (1, errno, "read error");
  245.   if (input_size == 0)
  246.     {
  247.       error (0, 0, "premature end of file");
  248.       exit (1);
  249.     }
  250.   input_bytes += input_size;
  251. }
  252.  
  253. /* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
  254.    When `out_buff' fills up, flush it to file descriptor OUT_DES.  */
  255.  
  256. void
  257. copy_buf_out (in_buf, out_des, num_bytes)
  258.      char *in_buf;
  259.      int out_des;
  260.      long num_bytes;
  261. {
  262.   register long bytes_left = num_bytes;    /* Bytes needing to be copied.  */
  263.   register long space_left;    /* Room left in output buffer.  */
  264.  
  265.   while (bytes_left > 0)
  266.     {
  267.       space_left = io_block_size - output_size;
  268.       if (space_left == 0)
  269.     empty_output_buffer (out_des);
  270.       else
  271.     {
  272.       if (bytes_left < space_left)
  273.         space_left = bytes_left;
  274.       bcopy (in_buf, out_buff, (unsigned) space_left);
  275.       out_buff += space_left;
  276.       output_size += space_left;
  277.       in_buf += space_left;
  278.       bytes_left -= space_left;
  279.     }
  280.     }
  281. }
  282.  
  283. /* Copy NUM_BYTES of buffer `in_buff' into IN_BUF.
  284.    `in_buff' may be partly full.
  285.    When `in_buff' is exhausted, refill it from file descriptor IN_DES.  */
  286.  
  287. void
  288. copy_in_buf (in_buf, in_des, num_bytes)
  289.      char *in_buf;
  290.      int in_des;
  291.      long num_bytes;
  292. {
  293.   register long bytes_left = num_bytes;    /* Bytes needing to be copied.  */
  294.   register long space_left;    /* Bytes to copy from input buffer.  */
  295.  
  296.   while (bytes_left > 0)
  297.     {
  298.       if (input_size == 0)
  299.     fill_input_buffer (in_des, io_block_size);
  300.       if (bytes_left < input_size)
  301.     space_left = bytes_left;
  302.       else
  303.     space_left = input_size;
  304.       bcopy (in_buff, in_buf, (unsigned) space_left);
  305.       in_buff += space_left;
  306.       in_buf += space_left;
  307.       input_size -= space_left;
  308.       bytes_left -= space_left;
  309.     }
  310. }
  311.  
  312. /* Copy the the next NUM_BYTES bytes of `input_buffer' into PEEK_BUF.
  313.    If NUM_BYTES bytes are not available, read the next `io_block_size' bytes
  314.    into the end of `input_buffer' and update `input_size'.
  315.  
  316.    Return the number of bytes copied into PEEK_BUF.
  317.    If the number of bytes returned is less than NUM_BYTES,
  318.    then EOF has been reached.  */
  319.  
  320. int
  321. peek_in_buf (peek_buf, in_des, num_bytes)
  322.      char *peek_buf;
  323.      int in_des;
  324.      int num_bytes;
  325. {
  326.   long tmp_input_size;
  327.   long got_bytes;
  328.   char *append_buf;
  329.  
  330.   while (input_size < num_bytes)
  331.     {
  332.       append_buf = in_buff + input_size;
  333.       tmp_input_size = rmtread (in_des, append_buf, io_block_size);
  334.       if (tmp_input_size == 0)
  335.     {
  336.       if (input_is_special)
  337.         {
  338.           get_next_reel (in_des);
  339.           tmp_input_size = rmtread (in_des, append_buf, io_block_size);
  340.         }
  341.       else
  342.         break;
  343.     }
  344.       if (tmp_input_size < 0)
  345.     error (1, errno, "read error");
  346.       input_bytes += tmp_input_size;
  347.       input_size += tmp_input_size;
  348.     }
  349.   if (num_bytes <= input_size)
  350.     got_bytes = num_bytes;
  351.   else
  352.     got_bytes = input_size;
  353.   bcopy (in_buff, peek_buf, (unsigned) got_bytes);
  354.   return got_bytes;
  355. }
  356.  
  357. /* Skip the next NUM_BYTES bytes of file descriptor IN_DES.  */
  358.  
  359. void
  360. toss_input (in_des, num_bytes)
  361.      int in_des;
  362.      long num_bytes;
  363. {
  364.   register long bytes_left = num_bytes;    /* Bytes needing to be copied.  */
  365.   register long space_left;    /* Bytes to copy from input buffer.  */
  366.  
  367.   while (bytes_left > 0)
  368.     {
  369.       if (input_size == 0)
  370.     fill_input_buffer (in_des, io_block_size);
  371.       if (bytes_left < input_size)
  372.     space_left = bytes_left;
  373.       else
  374.     space_left = input_size;
  375.       in_buff += space_left;
  376.       input_size -= space_left;
  377.       bytes_left -= space_left;
  378.     }
  379. }
  380.  
  381. /* Copy a file using the input and output buffers, which may start out
  382.    partly full.  After the copy, the files are not closed nor the last
  383.    block flushed to output, and the input buffer may still be partly
  384.    full.  If `crc_i_flag' is set, add each byte to `crc'.
  385.    IN_DES is the file descriptor for input;
  386.    OUT_DES is the file descriptor for output;
  387.    NUM_BYTES is the number of bytes to copy.  */
  388.  
  389. void
  390. copy_files (in_des, out_des, num_bytes)
  391.      int in_des;
  392.      int out_des;
  393.      long num_bytes;
  394. {
  395.   long size;
  396.   long k;
  397.  
  398.   while (num_bytes > 0)
  399.     {
  400.       if (input_size == 0)
  401.     fill_input_buffer (in_des, io_block_size);
  402.       size = (input_size < num_bytes) ? input_size : num_bytes;
  403.       if (crc_i_flag)
  404.     {
  405.       for (k = 0; k < size; ++k)
  406.         crc += in_buff[k] & 0xff;
  407.     }
  408.       copy_buf_out (in_buff, out_des, size);
  409.       num_bytes -= size;
  410.       input_size -= size;
  411.       in_buff += size;
  412.     }
  413. }
  414.  
  415. /* Create all directories up to but not including the last part of NAME.
  416.    Do not destroy any nondirectories while creating directories.  */
  417.  
  418. void
  419. create_all_directories (name)
  420.      char *name;
  421. {
  422.   char *dir;
  423.  
  424.   dir = dirname (name);
  425.   if (dir == NULL)
  426.     error (2, 0, "virtual memory exhausted");
  427.  
  428.   if (dir[0] != '.' || dir[1] != '\0')
  429.     make_path (dir, 0700, 0700, -1, -1, (char *) NULL);
  430.  
  431.   free (dir);
  432. }
  433.  
  434. /* Prepare to append to an archive.  We have been in
  435.    process_copy_in, keeping track of the position where
  436.    the last header started in `last_header_start'.  Now we
  437.    have the starting position of the last header (the TRAILER!!!
  438.    header, or blank record for tar archives) and we want to start
  439.    writing (appending) over the last header.  The last header may
  440.    be in the middle of a block, so to keep the buffering in sync
  441.    we lseek back to the start of the block, read everything up
  442.    to but not including the last header, lseek back to the start
  443.    of the block, and then do a copy_buf_out of what we read.
  444.    Actually, we probably don't have to worry so much about keeping the
  445.    buffering perfect since you can only append to archives that
  446.    are disk files.  */
  447.  
  448. void
  449. prepare_append (out_file_des)
  450.      int out_file_des;
  451. {
  452.   int start_of_header;
  453.   int start_of_block;
  454.   int useful_bytes_in_block;
  455.   char *tmp_buf;
  456.  
  457.   start_of_header = last_header_start;
  458.   /* Figure out how many bytes we will rewrite, and where they start.  */
  459.   useful_bytes_in_block = start_of_header % io_block_size;
  460.   start_of_block = start_of_header - useful_bytes_in_block;
  461.  
  462.   if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
  463.     error (1, errno, "cannot seek on output");
  464.   if (useful_bytes_in_block > 0)
  465.     {
  466.       tmp_buf = (char *) xmalloc (useful_bytes_in_block);
  467.       read (out_file_des, tmp_buf, useful_bytes_in_block);
  468.       if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
  469.     error (1, errno, "cannot seek on output");
  470.       copy_buf_out (tmp_buf, out_file_des, useful_bytes_in_block);
  471.       free (tmp_buf);
  472.     }
  473.  
  474.   /* We are done reading the archive, so clear these since they
  475.      will now be used for reading in files that we are appending
  476.      to the archive.  */
  477.   input_size = 0;
  478.   input_bytes = 0;
  479.   in_buff = input_buffer;
  480. }
  481.  
  482. /* Support for remembering inodes with multiple links.  Used in the
  483.    "copy in" and "copy pass" modes for making links instead of copying
  484.    the file.  */
  485.  
  486. struct inode_val
  487. {
  488.   unsigned long inode;
  489.   unsigned long major_num;
  490.   unsigned long minor_num;
  491.   char *file_name;
  492. };
  493.  
  494. /* Inode hash table.  Allocated by first call to add_inode.  */
  495. static struct inode_val **hash_table = NULL;
  496.  
  497. /* Size of current hash table.  Initial size is 47.  (47 = 2*22 + 3) */
  498. static int hash_size = 22;
  499.  
  500. /* Number of elements in current hash table.  */
  501. static int hash_num;
  502.  
  503. /* Find the file name associated with NODE_NUM.  If there is no file
  504.    associated with NODE_NUM, return NULL.  */
  505.  
  506. char *
  507. find_inode_file (node_num, major_num, minor_num)
  508.      unsigned long node_num;
  509.      unsigned long major_num;
  510.      unsigned long minor_num;
  511. {
  512. #ifndef __MSDOS__
  513.   int start;            /* Initial hash location.  */
  514.   int temp;            /* Rehash search variable.  */
  515.  
  516.   if (hash_table != NULL)
  517.     {
  518.       /* Hash function is node number modulo the table size.  */
  519.       start = node_num % hash_size;
  520.  
  521.       /* Initial look into the table.  */
  522.       if (hash_table[start] == NULL)
  523.     return NULL;
  524.       if (hash_table[start]->inode == node_num
  525.       && hash_table[start]->major_num == major_num
  526.       && hash_table[start]->minor_num == minor_num)
  527.     return hash_table[start]->file_name;
  528.  
  529.       /* The home position is full with a different inode record.
  530.      Do a linear search terminated by a NULL pointer.  */
  531.       for (temp = (start + 1) % hash_size;
  532.        hash_table[temp] != NULL && temp != start;
  533.        temp = (temp + 1) % hash_size)
  534.     {
  535.       if (hash_table[temp]->inode == node_num
  536.           && hash_table[start]->major_num == major_num
  537.           && hash_table[start]->minor_num == minor_num)
  538.         return hash_table[temp]->file_name;
  539.     }
  540.     }
  541. #endif
  542.   return NULL;
  543. }
  544.  
  545. /* Associate FILE_NAME with the inode NODE_NUM.  (Insert into hash table.)  */
  546.  
  547. void
  548. add_inode (node_num, file_name, major_num, minor_num)
  549.      unsigned long node_num;
  550.      char *file_name;
  551.      unsigned long major_num;
  552.      unsigned long minor_num;
  553. {
  554. #ifndef __MSDOS__
  555.   struct inode_val *temp;
  556.  
  557.   /* Create new inode record.  */
  558.   temp = (struct inode_val *) xmalloc (sizeof (struct inode_val));
  559.   temp->inode = node_num;
  560.   temp->major_num = major_num;
  561.   temp->minor_num = minor_num;
  562.   temp->file_name = xstrdup (file_name);
  563.  
  564.   /* Do we have to increase the size of (or initially allocate)
  565.      the hash table?  */
  566.   if (hash_num == hash_size || hash_table == NULL)
  567.     {
  568.       struct inode_val **old_table;    /* Pointer to old table.  */
  569.       int i;            /* Index for re-insert loop.  */
  570.  
  571.       /* Save old table.  */
  572.       old_table = hash_table;
  573.       if (old_table == NULL)
  574.     hash_num = 0;
  575.  
  576.       /* Calculate new size of table and allocate it.
  577.          Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ...
  578.      where 3197 and most of the sizes after 6397 are not prime.  The other
  579.      numbers listed are prime.  */
  580.       hash_size = 2 * hash_size + 3;
  581.       hash_table = (struct inode_val **)
  582.     xmalloc (hash_size * sizeof (struct inode_val *));
  583.       bzero (hash_table, hash_size * sizeof (struct inode_val *));
  584.  
  585.       /* Insert the values from the old table into the new table.  */
  586.       for (i = 0; i < hash_num; i++)
  587.     hash_insert (old_table[i]);
  588.  
  589.       if (old_table != NULL)
  590.     free (old_table);
  591.     }
  592.  
  593.   /* Insert the new record and increment the count of elements in the
  594.       hash table.  */
  595.   hash_insert (temp);
  596.   hash_num++;
  597. #endif /* __MSDOS__ */
  598. }
  599.  
  600. /* Do the hash insert.  Used in normal inserts and resizing the hash
  601.    table.  It is guaranteed that there is room to insert the item.
  602.    NEW_VALUE is the pointer to the previously allocated inode, file
  603.    name association record.  */
  604.  
  605. static void
  606. hash_insert (new_value)
  607.      struct inode_val *new_value;
  608. {
  609.   int start;            /* Home position for the value.  */
  610.   int temp;            /* Used for rehashing.  */
  611.  
  612.   /* Hash function is node number modulo the table size.  */
  613.   start = new_value->inode % hash_size;
  614.  
  615.   /* Do the initial look into the table.  */
  616.   if (hash_table[start] == NULL)
  617.     {
  618.       hash_table[start] = new_value;
  619.       return;
  620.     }
  621.  
  622.   /* If we get to here, the home position is full with a different inode
  623.      record.  Do a linear search for the first NULL pointer and insert
  624.      the new item there.  */
  625.   temp = (start + 1) % hash_size;
  626.   while (hash_table[temp] != NULL)
  627.     temp = (temp + 1) % hash_size;
  628.  
  629.   /* Insert at the NULL.  */
  630.   hash_table[temp] = new_value;
  631. }
  632.  
  633. /* Open FILE in the mode specified by the command line options
  634.    and return an open file descriptor for it,
  635.    or -1 if it can't be opened.  */
  636.  
  637. int
  638. open_archive (file)
  639.      char *file;
  640. {
  641.   int fd;
  642.   void (*copy_in) ();        /* Workaround for pcc bug.  */
  643.  
  644.   copy_in = process_copy_in;
  645.  
  646.   if (copy_function == copy_in)
  647.     fd = rmtopen (file, O_RDONLY | O_BINARY, 0666);
  648.   else
  649.     {
  650.       if (!append_flag)
  651.     fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  652.       else
  653.     fd = rmtopen (file, O_RDWR | O_BINARY, 0666);
  654.     }
  655.  
  656.   return fd;
  657. }
  658.  
  659. /* Attempt to rewind the tape drive on file descriptor TAPE_DES
  660.    and take it offline.  */
  661.  
  662. void
  663. tape_offline (tape_des)
  664.      int tape_des;
  665. {
  666. #if defined(MTIOCTOP) && defined(MTOFFL)
  667.   struct mtop control;
  668.  
  669.   control.mt_op = MTOFFL;
  670.   control.mt_count = 1;
  671.   rmtioctl (tape_des, MTIOCTOP, &control);    /* Don't care if it fails.  */
  672. #endif
  673. }
  674.  
  675. /* The file on file descriptor TAPE_DES is assumed to be magnetic tape
  676.    (or floppy disk or other device) and the end of the medium
  677.    has been reached.  Ask the user for to mount a new "tape" to continue
  678.    the processing.  If the user specified the device name on the
  679.    command line (with the -I, -O, -F or --file options), then we can
  680.    automatically re-open the same device to use the next medium.  If the
  681.    user did not specify the device name, then we have to ask them which
  682.    device to use.  */
  683.  
  684. void
  685. get_next_reel (tape_des)
  686.      int tape_des;
  687. {
  688.   static int reel_number = 1;
  689.   FILE *tty_in;            /* File for interacting with user.  */
  690.   FILE *tty_out;        /* File for interacting with user.  */
  691.   int old_tape_des;
  692.   char *next_archive_name;
  693.   dynamic_string new_name;
  694.   char *str_res;
  695.  
  696.   ds_init (&new_name, 128);
  697.  
  698.   /* Open files for interactive communication.  */
  699.   tty_in = fopen (CONSOLE, "r");
  700.   if (tty_in == NULL)
  701.     error (2, errno, CONSOLE);
  702.   tty_out = fopen (CONSOLE, "w");
  703.   if (tty_out == NULL)
  704.     error (2, errno, CONSOLE);
  705.  
  706.   old_tape_des = tape_des;
  707.   tape_offline (tape_des);
  708.   rmtclose (tape_des);
  709.  
  710.   /* Give message and wait for carrage return.  User should hit carrage return
  711.      only after loading the next tape.  */
  712.   ++reel_number;
  713.   if (new_media_message)
  714.     fprintf (tty_out, "%s", new_media_message);
  715.   else if (new_media_message_with_number)
  716.     fprintf (tty_out, "%s%d%s", new_media_message_with_number, reel_number,
  717.          new_media_message_after_number);
  718.   else if (archive_name)
  719.     fprintf (tty_out, "Found end of tape.  Load next tape and press RETURN. ");
  720.   else
  721.     fprintf (tty_out, "Found end of tape.  To continue, type device/file name when ready.\n");
  722.  
  723.   fflush (tty_out);
  724.  
  725.   if (archive_name)
  726.     {
  727.       int c;
  728.  
  729.       do
  730.     c = getc (tty_in);
  731.       while (c != EOF && c != '\n');
  732.  
  733.       tape_des = open_archive (archive_name);
  734.       if (tape_des == -1)
  735.     error (1, errno, "%s", archive_name);
  736.     }
  737.   else
  738.     {
  739.       do
  740.     {
  741.       if (tape_des < 0)
  742.         {
  743.           fprintf (tty_out,
  744.                "To continue, type device/file name when ready.\n");
  745.           fflush (tty_out);
  746.         }
  747.  
  748.       str_res = ds_fgets (tty_in, &new_name);
  749.       if (str_res == NULL || str_res[0] == '\0')
  750.         exit (1);
  751.       next_archive_name = str_res;
  752.  
  753.       tape_des = open_archive (next_archive_name);
  754.       if (tape_des == -1)
  755.         error (0, errno, "%s", next_archive_name);
  756.     }
  757.       while (tape_des < 0);
  758.     }
  759.  
  760.   /* We have to make sure that `tape_des' has not changed its value even
  761.      though we closed it and reopened it, since there are local
  762.      copies of it in other routines.  This works fine on Unix (even with
  763.      rmtread and rmtwrite) since open will always return the lowest
  764.      available file descriptor and we haven't closed any files (e.g.,
  765.      stdin, stdout or stderr) that were opened before we originally opened
  766.      the archive.  */
  767.  
  768.   if (tape_des != old_tape_des)
  769.     error (1, 0, "internal error: tape descriptor changed from %d to %d",
  770.        old_tape_des, tape_des);
  771.  
  772.   free (new_name.ds_string);
  773.   fclose (tty_in);
  774.   fclose (tty_out);
  775. }
  776.  
  777. /* If MESSAGE does not contain the string "%d", make `new_media_message'
  778.    a copy of MESSAGE.  If MESSAGES does contain the string "%d", make
  779.    `new_media_message_with_number' a copy of MESSAGE up to, but
  780.    not including, the string "%d", and make `new_media_message_after_number'
  781.    a copy of MESSAGE after the string "%d".  */
  782.  
  783. void
  784. set_new_media_message (message)
  785.      char *message;
  786. {
  787.   char *p;
  788.   int prev_was_percent;
  789.  
  790.   p = message;
  791.   prev_was_percent = 0;
  792.   while (*p != '\0')
  793.     {
  794.       if (*p == 'd' && prev_was_percent)
  795.     break;
  796.       prev_was_percent = (*p == '%');
  797.       ++p;
  798.     }
  799.   if (*p == '\0')
  800.     {
  801.       new_media_message = xstrdup (message);
  802.     }
  803.   else
  804.     {
  805.       int length = p - message - 1;
  806.  
  807.       new_media_message_with_number = xmalloc (length + 1);
  808.       strncpy (new_media_message_with_number, message, length);
  809.       new_media_message_with_number[length] = '\0';
  810.       length = strlen (p + 1);
  811.       new_media_message_after_number = xmalloc (length + 1);
  812.       strcpy (new_media_message_after_number, message);
  813.     }
  814. }
  815.  
  816. #ifdef __MSDOS__
  817. int
  818. chown (path, owner, group)
  819.      char *path;
  820.      int owner, group;
  821. {
  822.   return 0;
  823. }
  824. #endif
  825.  
  826. #ifdef __TURBOC__
  827. #include <time.h>
  828. #include <fcntl.h>
  829. #include <io.h>
  830.  
  831. int
  832. utime (char *filename, struct utimbuf *utb)
  833. {
  834.   extern int errno;
  835.   struct tm *tm;
  836.   struct ftime filetime;
  837.   time_t when;
  838.   int fd;
  839.   int status;
  840.  
  841.   if (utb == 0)
  842.       when = time (0);
  843.   else
  844.       when = utb->modtime;
  845.  
  846.     fd = _open (filename, O_RDWR);
  847.   if (fd == -1)
  848.       return -1;
  849.  
  850.     tm = localtime (&when);
  851.   if (tm->tm_year < 80)
  852.       filetime.ft_year = 0;
  853.   else
  854.       filetime.ft_year = tm->tm_year - 80;
  855.     filetime.ft_month = tm->tm_mon + 1;
  856.     filetime.ft_day = tm->tm_mday;
  857.   if (tm->tm_hour < 0)
  858.       filetime.ft_hour = 0;
  859.   else
  860.       filetime.ft_hour = tm->tm_hour;
  861.     filetime.ft_min = tm->tm_min;
  862.     filetime.ft_tsec = tm->tm_sec / 2;
  863.  
  864.     status = setftime (fd, &filetime);
  865.     _close (fd);
  866.     return status;
  867. }
  868. #endif
  869.