This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Implemented C and T modifiers for ar



Hi!

We noticed that the LSB spec requires 'C' and 'T' modifiers for ar,
which it imports from SUS. For compatibilty with SysV ar, we decided
to implement those modifiers in GNU ar, too. (Description of the
meaning of the mods at the beginning of the patch.)

Appended below is a patch for binutils-2.11.92.0.10. Most of the
changes are straightforward, except maybe the pathconf() call. I take
care to call it on the directory where file actually will be created,
as GNU ar supports pathnames in an archive, even if it cannot create
such archives itself.

Roman

------------------------------------------------------------------------------
--- binutils-2.11.92.0.10/binutils/doc/binutils.texi~	Tue Oct  2 00:25:22 2001
+++ binutils-2.11.92.0.10/binutils/doc/binutils.texi	Wed Oct 24 11:26:21 2001
@@ -420,6 +420,17 @@
 you do not specify this modifier, files extracted from the archive
 are stamped with the time of extraction.
 
+@item T
+Allow to truncate names of extracted files so they fit the maximum filename
+length of the target filesystem. Without the @samp{T}
+modifier, a file with a name that is too long is an error. A diagnostic
+message will be printed and the file will not be extracted.
+
+@item C
+Prevent extracted files from overwriting files with same name that already
+exist. This is particularily useful together with @samp{T}
+to avoid truncated names from replacing files with the same prefix.
+
 @item P
 Use the full path name when matching names in the archive.  @sc{gnu}
 @command{ar} can not create an archive with a full path name (such archives
--- binutils-2.11.92.0.10/binutils/ar.c~	Tue Oct  2 00:25:22 2001
+++ binutils-2.11.92.0.10/binutils/ar.c	Wed Oct 24 11:20:35 2001
@@ -162,7 +162,15 @@
    program.  */
 static boolean full_pathname = false;
 
+/* Whether to allow extract to overwrite existing, identically named files.  */
+static boolean do_not_overwrite = false;
+
+/* When extracting, truncate archive filenames that are longer than the
+   filesystem allows.  */
+static boolean allow_x_truncate = false;
+
 int interactive = 0;
+int delayed_error = 0;
 
 static void
 mri_emul ()
@@ -262,7 +270,7 @@
       fprintf (s, _("  q[f]         - quick append file(s) to the archive\n"));
       fprintf (s, _("  r[ab][f][u]  - replace existing or insert new file(s) into the archive\n"));
       fprintf (s, _("  t            - display contents of archive\n"));
-      fprintf (s, _("  x[o]         - extract file(s) from the archive\n"));
+      fprintf (s, _("  x[oCT]       - extract file(s) from the archive\n"));
       fprintf (s, _(" command specific modifiers:\n"));
       fprintf (s, _("  [a]          - put file(s) after [member-name]\n"));
       fprintf (s, _("  [b]          - put file(s) before [member-name] (same as [i])\n"));
@@ -270,6 +278,8 @@
       fprintf (s, _("  [f]          - truncate inserted file names\n"));
       fprintf (s, _("  [P]          - use full path names when matching\n"));
       fprintf (s, _("  [o]          - preserve original dates\n"));
+      fprintf (s, _("  [C]          - do not overwrite existing files\n"));
+      fprintf (s, _("  [T]          - allow truncation of extracted filenames\n"));
       fprintf (s, _("  [u]          - only replace files that are newer than current archive contents\n"));
       fprintf (s, _(" generic modifiers:\n"));
       fprintf (s, _("  [c]          - do not warn if the library had to be created\n"));
@@ -573,6 +583,12 @@
 	case 'P':
 	  full_pathname = true;
 	  break;
+	case 'C':
+	  do_not_overwrite = true;
+	  break;
+	case 'T':
+	  allow_x_truncate = true;
+	  break;
 	default:
 	  /* xgettext:c-format */
 	  non_fatal (_("illegal option -- %c"), c);
@@ -612,6 +628,9 @@
       if (newer_only && operation != replace)
 	fatal (_("`u' is only meaningful with the `r' option."));
 
+      if ((allow_x_truncate || do_not_overwrite) && operation != extract)
+	fatal (_("`C' and `T' are only meaningful with the `x' option."));
+
       arg_index = 2;
 
       if (postype != pos_default)
@@ -712,8 +731,8 @@
 
   END_PROGRESS (program_name);
 
-  xexit (0);
-  return 0;
+  xexit (delayed_error);
+  return delayed_error;
 }
 
 bfd *
@@ -853,6 +872,82 @@
   free (cbuf);
 }
 
+/* <roman@caldera.de>: In this function, the C and T modifiers are implemented.
+   First we have to call pathconf() to find out the maximum filename length
+   on the destination path.  (Please note the GNU ar supports directory names
+   in archives, though it cannot create such archives itself.)  If the name then
+   really is too long, it will be truncated (with T) or skipped (without T)
+   and a delayed error is flagged.  C is implemented by adding O_EXCL to the
+   open flags.  As one can't pass O_EXCL to fopen(), open(2) is used followed
+   by fdopen().  */
+   
+static FILE *
+extract_open_output_file (abfd)
+    bfd *abfd;
+{
+  int fd;
+  FILE *ostream;
+  char *name, *tmpname, *p;
+  int fn_offset;
+  int name_max;
+
+  name = bfd_get_filename (abfd);
+  tmpname = xstrdup (name);
+  p = strrchr (tmpname, '/');
+  fn_offset = p ? p+1-tmpname : 0;
+  
+  /* Get max. filename length of dir of file.  */
+  strcpy (tmpname+fn_offset, ".");
+  errno = 0;
+  name_max = pathconf (tmpname, _PC_NAME_MAX);
+  if (name_max == -1 && errno)
+    {
+      perror (tmpname);
+      xexit (1);
+    }
+
+  if (name_max > -1 && (unsigned)name_max < strlen(name+fn_offset))
+    {
+      /* Name is too long.  */
+      if (allow_x_truncate)
+	{
+	  strcpy (tmpname, name);
+	  tmpname[fn_offset+name_max] = '\0';
+	  name = tmpname;
+	  /* tmpname not freed, memory leak! */
+	}
+      else
+	{
+	  non_fatal (_("%s: filename too long"), name);
+	  delayed_error = 1;
+	  free (tmpname);
+	  /* extract_file() doesn't write if its stream is NULL.  */
+	  output_filename = NULL;
+	  return output_file = NULL;
+	}
+    }
+  else
+    free (tmpname);
+  
+  fd = open (name, O_WRONLY|O_CREAT|O_TRUNC | (do_not_overwrite ? O_EXCL : 0),
+	     S_IRWXU|S_IRWXG|S_IRWXO);
+  if (fd < 0)
+    {
+      perror (name);
+      xexit (1);
+    }
+  output_filename = name; 
+  
+  ostream = fdopen (fd, FOPEN_WB);
+  if (ostream == NULL)
+    {
+      perror (name);
+      xexit (1);
+    }
+
+  return output_file = ostream;
+}
+
 /* Extract a member of the archive into its own file.
 
    We defer opening the new file until after we have read a BUFSIZ chunk of the
@@ -890,19 +985,7 @@
 
   ostream = NULL;
   if (size == 0)
-    {
-      /* Seems like an abstraction violation, eh?  Well it's OK! */
-      output_filename = bfd_get_filename (abfd);
-
-      ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
-      if (ostream == NULL)
-	{
-	  perror (bfd_get_filename (abfd));
-	  xexit (1);
-	}
-
-      output_file = ostream;
-    }
+    ostream = extract_open_output_file (abfd);
   else
     while (ncopied < size)
       {
@@ -918,34 +1001,22 @@
 
 	/* See comment above; this saves disk arm motion */
 	if (ostream == NULL)
-	  {
-	    /* Seems like an abstraction violation, eh?  Well it's OK! */
-	    output_filename = bfd_get_filename (abfd);
-
-	    ostream = fopen (bfd_get_filename (abfd), FOPEN_WB);
-	    if (ostream == NULL)
-	      {
-		perror (bfd_get_filename (abfd));
-		xexit (1);
-	      }
-
-	    output_file = ostream;
-	  }
-	fwrite (cbuf, 1, nread, ostream);
+	  ostream = extract_open_output_file (abfd);
+	if (ostream != NULL)
+	  fwrite (cbuf, 1, nread, ostream);
 	ncopied += tocopy;
       }
 
   if (ostream != NULL)
     fclose (ostream);
 
+  chmod (output_filename, buf.st_mode);
+  if (preserve_dates)
+    set_times (output_filename, &buf);
+
   output_file = NULL;
   output_filename = NULL;
 
-  chmod (bfd_get_filename (abfd), buf.st_mode);
-
-  if (preserve_dates)
-    set_times (bfd_get_filename (abfd), &buf);
-
   free (cbuf);
 }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]