bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

touch --inside: new option for gzipped files


From: Bruno Haible
Subject: touch --inside: new option for gzipped files
Date: Tue, 27 May 2003 13:32:05 +0200 (CEST)

Hi,

For many files downloaded from the internet - among them many .gz files -,
the download time is less significant than the creation time of the file.
So it's quite handy to have a program that gives back to a file the
original modification time. It seems to me that "touch" is the right
program for this, because a user will look there for the functionality.

Here is a patch implementing this. Relative to coreutils-5.0.

2003-05-25  Bruno Haible  <address@hidden>

        * src/touch.c (look_inside): New variable.
        (longopts): Add --inside.
        (time_from_inside): New function.
        (touch): Handle look_inside case.
        (usage): Document option -i.
        (main): Recognize option -i.
        * doc/coreutils.texi (touch invocation): Document option -i.

diff -r -c3 coreutils-5.0/doc/coreutils.texi 
coreutils-5.0-touch/doc/coreutils.texi
*** coreutils-5.0/doc/coreutils.texi    2003-04-02 20:19:11.000000000 +0200
--- coreutils-5.0-touch/doc/coreutils.texi      2003-05-25 20:56:00.000000000 
+0200
***************
*** 7836,7841 ****
--- 7836,7850 ----
  @cindex BSD @command{touch} compatibility
  Ignored; for compatibility with BSD versions of @command{touch}.
  
+ @item -i
+ @itemx --inside
+ @opindex -i
+ @opindex --inside
+ Use the time found inside the file instead of the current time.  This
+ works for files in GZIP format; support for other file formats may be
+ added at a later date.  If the file is not of one of the supported formats
+ or doesn't have a timestamp inside it, it is not touched.
+ 
  @item -m
  @itemx --time=mtime
  @itemx --time=modify
diff -r -c3 coreutils-5.0/src/touch.c coreutils-5.0-touch/src/touch.c
*** coreutils-5.0/src/touch.c   2002-12-20 21:09:22.000000000 +0100
--- coreutils-5.0-touch/src/touch.c     2003-05-25 21:39:54.000000000 +0200
***************
*** 1,5 ****
  /* touch -- change modification and access times of files
!    Copyright (C) 87, 1989-1991, 1995-2002 Free Software Foundation, Inc.
  
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
--- 1,5 ----
  /* touch -- change modification and access times of files
!    Copyright (C) 87, 1989-1991, 1995-2003 Free Software Foundation, Inc.
  
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
***************
*** 30,36 ****
  #include "posixtm.h"
  #include "posixver.h"
  #include "quote.h"
! #include "safe-read.h"
  
  /* The official name of this program (e.g., no `g' prefix).  */
  #define PROGRAM_NAME "touch"
--- 30,36 ----
  #include "posixtm.h"
  #include "posixver.h"
  #include "quote.h"
! #include "full-read.h"
  
  /* The official name of this program (e.g., no `g' prefix).  */
  #define PROGRAM_NAME "touch"
***************
*** 74,79 ****
--- 74,82 ----
  /* (-d) If nonzero, date supplied on command line in get_date formats. */
  static int flexible_date;
  
+ /* (-i) If nonzero, look for a time stamp inside the file.  */
+ static int look_inside;
+ 
  /* (-r) If nonzero, use times from a reference file. */
  static int use_ref;
  
***************
*** 108,113 ****
--- 111,117 ----
    {"time", required_argument, 0, TIME_OPTION},
    {"no-create", no_argument, 0, 'c'},
    {"date", required_argument, 0, 'd'},
+   {"inside", no_argument, 0, 'i'},
    {"file", required_argument, 0, 'r'}, /* FIXME: phase out --file */
    {"reference", required_argument, 0, 'r'},
    {GETOPT_HELP_OPTION_DECL},
***************
*** 127,132 ****
--- 131,182 ----
    CH_ATIME, CH_ATIME, CH_ATIME, CH_MTIME, CH_MTIME
  };
  
+ /* Attempts to retrieve a timestamp from inside the file.
+    Returns 0 and sets *found if successful, otherwise returns 1.  */
+ 
+ static int
+ time_from_inside (const char *file, time_t *found)
+ {
+   int fd = open (file, O_RDONLY,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ 
+   if (fd < 0)
+     return 1;
+ 
+   /* First supported file format: GZIP.  */
+   {
+     unsigned char buf[8];
+ 
+     /* Not needed since this is the first access right after open().  */
+     /* lseek (fd, 0, SEEK_SET); */
+ 
+     /* Read the first 8 bytes of the file.  */
+     if (full_read (fd, buf, 8) == 8
+       /* Test for the gzip magic.  */
+       && buf[0] == 0x1f && buf[1] == 0x8b)
+       {
+       unsigned long time =
+         ((((((unsigned long) buf[7] << 8)
+             | (unsigned long) buf[6]) << 8)
+           | (unsigned long) buf[5]) << 8)
+         | (unsigned long) buf[4];
+ 
+       if (time)
+         {
+           *found = time;
+           close (fd);
+           return 0;
+         }
+       }
+   }
+ 
+   /* Other file formats can be added here.  */
+ 
+   /* After trying all supported file formats, this function fails.  */
+   close (fd);
+   return 1;
+ }
+ 
  /* Update the time of file FILE according to the options given.
     Return 0 if successful, 1 if an error occurs. */
  
***************
*** 194,200 ****
         better than 1-second resolution, so discard any fractional
         part of the source timestamp.  */
  
!       if (use_ref)
        {
          utb.actime = ref_stats.st_atime;
          utb.modtime = ref_stats.st_mtime;
--- 245,274 ----
         better than 1-second resolution, so discard any fractional
         part of the source timestamp.  */
  
!       if (look_inside)
!       {
!         time_t found;
! 
!         if (time_from_inside (file, &found) == 0)
!           utb.actime = utb.modtime = found;
!         else
!           {
!             /* Looking into the file has modified its access time.
!                If here we "return 0;" the st_atime remains modified,
!                but the st_ctime is unchanged.  Whereas if we set
!                "utb.actime = sbuf.st_atime; utb.modtime = sbuf.st_mtime;"
!                the st_atime will be unchanged, but the st_ctime is
!                changed.  The latter is more in line with touch's general
!                behaviour.  */
!             utb.actime = sbuf.st_atime;
!             utb.modtime = sbuf.st_mtime;
!             utime (file, &utb);
!             /* Ignore the return value from utime() here, since it didn't
!                attempt to set a date given by the user.  */
!             return 0;
!           }
!       }
!       else if (use_ref)
        {
          utb.actime = ref_stats.st_atime;
          utb.modtime = ref_stats.st_mtime;
***************
*** 254,259 ****
--- 328,334 ----
    -c, --no-create        do not create any files\n\
    -d, --date=STRING      parse STRING and use it instead of current time\n\
    -f                     (ignored)\n\
+   -i, --inside           use timestamp inside the file instead of current 
time\n\
    -m                     change only the modification time\n\
  "), stdout);
        fputs (_("\
***************
*** 289,295 ****
  
    change_times = no_create = use_ref = posix_date = flexible_date = 0;
  
!   while ((c = getopt_long (argc, argv, "acd:fmr:t:", longopts, NULL)) != -1)
      {
        switch (c)
        {
--- 364,370 ----
  
    change_times = no_create = use_ref = posix_date = flexible_date = 0;
  
!   while ((c = getopt_long (argc, argv, "acd:fimr:t:", longopts, NULL)) != -1)
      {
        switch (c)
        {
***************
*** 315,320 ****
--- 390,400 ----
        case 'f':
          break;
  
+       case 'i':
+         look_inside = 1;
+         date_set++;
+         break;
+ 
        case 'm':
          change_times |= CH_MTIME;
          break;
***************
*** 349,356 ****
    if (change_times == 0)
      change_times = CH_ATIME | CH_MTIME;
  
!   if ((use_ref && (posix_date || flexible_date))
!       || (posix_date && flexible_date))
      {
        error (0, 0, _("cannot specify times from more than one source"));
        usage (EXIT_FAILURE);
--- 429,437 ----
    if (change_times == 0)
      change_times = CH_ATIME | CH_MTIME;
  
!   if ((use_ref ? 1 : 0) + (posix_date ? 1 : 0) + (flexible_date ? 1 : 0)
!       + (look_inside ? 1 : 0)
!       > 1)
      {
        error (0, 0, _("cannot specify times from more than one source"));
        usage (EXIT_FAILURE);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]