]> Dogcows Code - chaz/tar/blobdiff - src/rtapelib.c
(decode_options): Set newer_time_option to TYPE_MINIMUM, so that
[chaz/tar] / src / rtapelib.c
index 7361bb245cb5217c9f5bae8260d961142835e2ef..6bbcbd9e1f4944cfd83d3721a14425de2882fa19 100644 (file)
    Originally written by Jeff Lee, modified some by Arnold Robbins.  Redone
    as a library that can replace open, read, write, etc., by Fred Fish, with
    some additional work by Arnold Robbins.  Modified to make all rmt* calls
-   into macros for speed by Jay Fenlason.  Use -DHAVE_NETDB_H for rexec
+   into macros for speed by Jay Fenlason.  Use -DWITH_REXEC for rexec
    code, courtesy of Dan Kegel.  */
 
 #include "system.h"
 
+#include "basename.h"
+#include "safe-read.h"
+
 /* Try hard to get EOPNOTSUPP defined.  486/ISC has it in net/errno.h,
    3B2/SVR3 has it in sys/inet.h.  Otherwise, like on MSDOS, use EINVAL.  */
 
@@ -112,14 +115,14 @@ _rmt_shutdown (int handle, int errno_value)
 static int
 do_command (int handle, const char *buffer)
 {
-  int length;
+  size_t length;
   RETSIGTYPE (*pipe_handler) ();
 
   /* Save the current pipe handler and try to make the request.  */
 
   pipe_handler = signal (SIGPIPE, SIG_IGN);
   length = strlen (buffer);
-  if (write (WRITE_SIDE (handle), buffer, (size_t) length) == length)
+  if (full_write (WRITE_SIDE (handle), buffer, length) == length)
     {
       signal (SIGPIPE, pipe_handler);
       return 0;
@@ -132,15 +135,9 @@ do_command (int handle, const char *buffer)
   return -1;
 }
 
-/*----------------------------------------------------------------------.
-| Read and return the status from remote tape connection HANDLE.  If an |
-| error occurred, return -1 and set errno.                             |
-`----------------------------------------------------------------------*/
-
-static int
-get_status (int handle)
+static char *
+get_status_string (int handle, char *command_buffer)
 {
-  char command_buffer[COMMAND_BUFFER_SIZE];
   char *cursor;
   int counter;
 
@@ -150,10 +147,10 @@ get_status (int handle)
        counter < COMMAND_BUFFER_SIZE;
        counter++, cursor++)
     {
-      if (read (READ_SIDE (handle), cursor, 1) != 1)
+      if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
        {
          _rmt_shutdown (handle, EIO);
-         return -1;
+         return 0;
        }
       if (*cursor == '\n')
        {
@@ -165,7 +162,7 @@ get_status (int handle)
   if (counter == COMMAND_BUFFER_SIZE)
     {
       _rmt_shutdown (handle, EIO);
-      return -1;
+      return 0;
     }
 
   /* Check the return status.  */
@@ -186,7 +183,7 @@ get_status (int handle)
       {
        char character;
 
-       while (read (READ_SIDE (handle), &character, 1) == 1)
+       while (safe_read (READ_SIDE (handle), &character, 1) == 1)
          if (character == '\n')
            break;
       }
@@ -194,7 +191,7 @@ get_status (int handle)
       if (*cursor == 'F')
        _rmt_shutdown (handle, errno);
 
-      return -1;
+      return 0;
     }
 
   /* Check for mis-synced pipes.  */
@@ -202,15 +199,70 @@ get_status (int handle)
   if (*cursor != 'A')
     {
       _rmt_shutdown (handle, EIO);
-      return -1;
+      return 0;
     }
 
   /* Got an `A' (success) response.  */
 
-  return atoi (cursor + 1);
+  return cursor + 1;
 }
 
-#if HAVE_NETDB_H
+/*----------------------------------------------------------------------.
+| Read and return the status from remote tape connection HANDLE.  If an |
+| error occurred, return -1 and set errno.                             |
+`----------------------------------------------------------------------*/
+
+static long
+get_status (int handle)
+{
+  char command_buffer[COMMAND_BUFFER_SIZE];
+  const char *status = get_status_string (handle, command_buffer);
+  return status ? atol (status) : -1L;
+}
+
+static off_t
+get_status_off (int handle)
+{
+  char command_buffer[COMMAND_BUFFER_SIZE];
+  const char *status = get_status_string (handle, command_buffer);
+
+  if (! status)
+    return -1;
+  else
+    {
+      /* Parse status, taking care to check for overflow.
+        We can't use standard functions,
+        since off_t might be longer than long.  */
+
+      off_t count = 0;
+      int negative;
+
+      for (;  *status == ' ' || *status == '\t';  status++)
+       continue;
+      
+      negative = *status == '-';
+      status += negative || *status == '+';
+      
+      for (;;)
+       {
+         int digit = *status++ - '0';
+         if (9 < (unsigned) digit)
+           break;
+         else
+           {
+             off_t c10 = 10 * count;
+             off_t nc = negative ? c10 - digit : c10 + digit;
+             if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
+               return -1;
+             count = nc;
+           }
+       }
+
+      return count;
+    }
+}
+
+#if WITH_REXEC
 
 /*-------------------------------------------------------------------------.
 | Execute /etc/rmt as user USER on remote system HOST using rexec.  Return |
@@ -227,8 +279,8 @@ get_status (int handle)
 static int
 _rmt_rexec (char *host, char *user)
 {
-  int saved_stdin = dup (fileno (stdin));
-  int saved_stdout = dup (fileno (stdout));
+  int saved_stdin = dup (STDIN_FILENO);
+  int saved_stdout = dup (STDOUT_FILENO);
   struct servent *rexecserv;
   int result;
 
@@ -258,7 +310,7 @@ _rmt_rexec (char *host, char *user)
   return result;
 }
 
-#endif /* HAVE_NETDB_H */
+#endif /* WITH_REXEC */
 
 /*------------------------------------------------------------------------.
 | Open a file (a magnetic tape device?) on the system specified in PATH,  |
@@ -331,7 +383,7 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
   if (remote_user && *remote_user == '\0')
     remote_user = NULL;
 
-#if HAVE_NETDB_H
+#if WITH_REXEC
 
   /* Execute the remote command using rexec.  */
 
@@ -344,10 +396,10 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
 
   WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
 
-#else /* not HAVE_NETDB_H */
+#else /* not WITH_REXEC */
   {
     const char *remote_shell_basename;
-    int status;
+    pid_t status;
 
     /* Identify the remote command to be executed.  */
 
@@ -361,7 +413,7 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
        return -1;
 #endif
       }
-    remote_shell_basename = strrchr (remote_shell, '/');
+    remote_shell_basename = base_name (remote_shell);
     if (remote_shell_basename)
       remote_shell_basename++;
     else
@@ -387,12 +439,12 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
       {
        /* Child.  */
 
-       close (0);
+       close (STDIN_FILENO);
        dup (to_remote[remote_pipe_number][PREAD]);
        close (to_remote[remote_pipe_number][PREAD]);
        close (to_remote[remote_pipe_number][PWRITE]);
 
-       close (1);
+       close (STDOUT_FILENO);
        dup (from_remote[remote_pipe_number][PWRITE]);
        close (from_remote[remote_pipe_number][PREAD]);
        close (from_remote[remote_pipe_number][PWRITE]);
@@ -420,7 +472,7 @@ rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
     close (from_remote[remote_pipe_number][PWRITE]);
     close (to_remote[remote_pipe_number][PREAD]);
   }
-#endif /* not HAVE_NETDB_H */
+#endif /* not WITH_REXEC */
 
   /* Attempt to open the tape device.  */
 
@@ -464,22 +516,22 @@ rmt_close__ (int handle)
 | Return the number of bytes read on success, -1 on error.                |
 `-------------------------------------------------------------------------*/
 
-int
-rmt_read__ (int handle, char *buffer, unsigned int length)
+ssize_t
+rmt_read__ (int handle, char *buffer, size_t length)
 {
   char command_buffer[COMMAND_BUFFER_SIZE];
-  int status;
-  int counter;
+  ssize_t status, rlen;
+  size_t counter;
 
-  sprintf (command_buffer, "R%d\n", length);
+  sprintf (command_buffer, "R%lu\n", (unsigned long) length);
   if (do_command (handle, command_buffer) == -1
       || (status = get_status (handle)) == -1)
     return -1;
 
-  for (counter = 0; counter < status; counter += length, buffer += length)
+  for (counter = 0; counter < status; counter += rlen, buffer += rlen)
     {
-      length = read (READ_SIDE (handle), buffer, (size_t) (status - counter));
-      if (length <= 0)
+      rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
+      if (rlen <= 0)
        {
          _rmt_shutdown (handle, EIO);
          return -1;
@@ -494,18 +546,18 @@ rmt_read__ (int handle, char *buffer, unsigned int length)
 | the number of bytes written on success, -1 on error.                    |
 `-------------------------------------------------------------------------*/
 
-int
-rmt_write__ (int handle, char *buffer, unsigned int length)
+ssize_t
+rmt_write__ (int handle, char *buffer, size_t length)
 {
   char command_buffer[COMMAND_BUFFER_SIZE];
   RETSIGTYPE (*pipe_handler) ();
 
-  sprintf (command_buffer, "W%d\n", length);
+  sprintf (command_buffer, "W%lu\n", (unsigned long) length);
   if (do_command (handle, command_buffer) == -1)
     return -1;
 
   pipe_handler = signal (SIGPIPE, SIG_IGN);
-  if (write (WRITE_SIDE (handle), buffer, length) == length)
+  if (full_write (WRITE_SIDE (handle), buffer, length) == length)
     {
       signal (SIGPIPE, pipe_handler);
       return get_status (handle);
@@ -523,16 +575,34 @@ rmt_write__ (int handle, char *buffer, unsigned int length)
 | Return the new file offset if successful, -1 if on error.              |
 `------------------------------------------------------------------------*/
 
-long
+off_t
 rmt_lseek__ (int handle, off_t offset, int whence)
 {
   char command_buffer[COMMAND_BUFFER_SIZE];
+  char operand_buffer[UINTMAX_STRSIZE_BOUND];
+  uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
+  char *p = operand_buffer + sizeof operand_buffer;
+
+  do
+    *--p = '0' + (int) (u % 10);
+  while ((u /= 10) != 0);
+  if (offset < 0)
+    *--p = '-';
+
+  switch (whence)
+    {
+    case SEEK_SET: whence = 0; break;
+    case SEEK_CUR: whence = 1; break;
+    case SEEK_END: whence = 2; break;
+    default: abort ();
+    }
+
+  sprintf (command_buffer, "L%s\n%d\n", p, whence);
 
-  sprintf (command_buffer, "L%ld\n%d\n", offset, whence);
   if (do_command (handle, command_buffer) == -1)
     return -1;
 
-  return get_status (handle);
+  return get_status_off (handle);
 }
 
 /*-----------------------------------------------------------------------.
@@ -553,16 +623,25 @@ rmt_ioctl__ (int handle, int operation, char *argument)
     case MTIOCTOP:
       {
        char command_buffer[COMMAND_BUFFER_SIZE];
+       char operand_buffer[UINTMAX_STRSIZE_BOUND];
+       uintmax_t u = (((struct mtop *) argument)->mt_count < 0
+                      ? - (uintmax_t) ((struct mtop *) argument)->mt_count
+                      : (uintmax_t) ((struct mtop *) argument)->mt_count);
+       char *p = operand_buffer + sizeof operand_buffer;
+       
+       do
+         *--p = '0' + (int) (u % 10);
+       while ((u /= 10) != 0);
+       if (((struct mtop *) argument)->mt_count < 0)
+         *--p = '-';
 
        /* MTIOCTOP is the easy one.  Nothing is transfered in binary.  */
 
-       sprintf (command_buffer, "I%d\n%d\n", ((struct mtop *) argument)->mt_op,
-                ((struct mtop *) argument)->mt_count);
+       sprintf (command_buffer, "I%d\n%s\n",
+                ((struct mtop *) argument)->mt_op, p);
        if (do_command (handle, command_buffer) == -1)
          return -1;
 
-       /* Return the count.  */
-
        return get_status (handle);
       }
 #endif /* MTIOCTOP */
@@ -570,8 +649,8 @@ rmt_ioctl__ (int handle, int operation, char *argument)
 #ifdef MTIOCGET
     case MTIOCGET:
       {
-       int status;
-       int counter;
+       ssize_t status;
+       ssize_t counter;
 
        /* Grab the status and read it directly into the structure.  This
           assumes that the status buffer is not padded and that 2 shorts
@@ -585,7 +664,8 @@ rmt_ioctl__ (int handle, int operation, char *argument)
 
        for (; status > 0; status -= counter, argument += counter)
          {
-           counter = read (READ_SIDE (handle), argument, (size_t) status);
+           counter = safe_read (READ_SIDE (handle),
+                                argument, (size_t) status);
            if (counter <= 0)
              {
                _rmt_shutdown (handle, EIO);
This page took 0.030404 seconds and 4 git commands to generate.