[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: touch --inside: new option for gzipped files
From: |
Bruno Haible |
Subject: |
Re: touch --inside: new option for gzipped files |
Date: |
Tue, 27 May 2003 22:56:40 +0200 (CEST) |
> Here I would also mention that the time is that of the first member of
> in the GZIP archive. This normally doesn't matter for GNU gzip, but
> it can be an issue when you concatenate several gzipped files (which
> is allowed).
> This does not check for negative times (RFC1952 does not allow
> negative times). Also, POSIX allows an implementation where time_t
> would overflow;
OK, taking these suggestions into account, here is a revised patch.
Thanks Paul.
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 Wed Apr 2 20:19:11 2003
--- coreutils-5.0-touch/doc/coreutils.texi Tue May 27 22:49:43 2003
***************
*** 7836,7841 ****
--- 7836,7852 ----
@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. For files in GZIP format containing multiple
+ compressed entries (admittedly this is advanced usage of @code{gzip}),
+ the date of the first entry is used. 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 Fri Dec 20 21:09:22 2002
--- coreutils-5.0-touch/src/touch.c Tue May 27 22:53:30 2003
***************
*** 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,187 ----
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)
+ {
+ /* Gzipped files contain the date since 1970-01-01 in little-endian
+ format at byte position 4. For gzipped files containing multiple
+ compressed entries (rare), we simply use the first one. */
+ unsigned long time =
+ ((((((unsigned long) buf[7] << 8)
+ | (unsigned long) buf[6]) << 8)
+ | (unsigned long) buf[5]) << 8)
+ | (unsigned long) buf[4];
+
+ /* Ignore the time if it is 0x00000000 (some gzipped files have this)
+ or if it doesn't fit in a time_t. */
+ if ((time_t) time == time && (time_t) time > 0)
+ {
+ *found = (time_t) 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;
--- 249,278 ----
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 ****
--- 332,338 ----
-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)
{
--- 368,374 ----
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 ****
--- 394,404 ----
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);
--- 433,441 ----
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);