> 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 <[EMAIL PROTECTED]> * 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); _______________________________________________ Bug-coreutils mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-coreutils