[comp.unix.shell] Retaining file modification times

phillips@FOZZIE.NRL.NAVY.MIL (Lee Phillips) (05/22/91)

I want to do something to a file without changing its modification
time.  I suppose I can write a script to get the time from ls, do the
modification, then restore the time (after converting it to numerical
format) with /usr/5bin/touch, but I'm hoping that there is an easier
way. (Csh solutions preferred.) 
--
                                           Lee Phillips
                                           phillips@fozzie.nrl.navy.mil
                                           phillips@lcp.nrl.navy.mil

martin@mwtech.UUCP (Martin Weitzel) (05/23/91)

In article <9105211828.AA12327@fozzie.nrl.navy.mil> phillips@FOZZIE.NRL.NAVY.MIL (Lee Phillips) writes:
>
>I want to do something to a file without changing its modification
>time.  I suppose I can write a script to get the time from ls, do the
>modification, then restore the time (after converting it to numerical
>format) with /usr/5bin/touch, but I'm hoping that there is an easier
>way. (Csh solutions preferred.) 

Not quite what you want, but maybe an idea how to solve this problem
in a general way: Write a C program (let's call it "cmtime") which
stat(2)-s all its arguments (maybe except the first one) and if an
argument is an existing file notes the st_mtime (and eventually st_atime)
together with the file name.

Then "cmtime" fork(2)-s a new process that exec(2)-s the program named
as first command line argument to "cmtime", passing all other command
line arguments. After the child terminates (for which the parent has
waited) the parent resets all the mtime-s to the values noted during the
startup phase.

Incidentally I have written "cmtime" several years ago and hence know
that it's no utterly complicated piece of software. (I don't have the
source on the system from which I'm posting this, otherwise I would have
included it.  If you're in *real* need for the source I could try to fetch
it from the other place.)
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

alex@am.sublink.org (Alex Martelli) (05/24/91)

phillips@FOZZIE.NRL.NAVY.MIL (Lee Phillips) writes:
:I want to do something to a file without changing its modification
:time.  I suppose I can write a script to get the time from ls, do the
:modification, then restore the time (after converting it to numerical
:format) with /usr/5bin/touch, but I'm hoping that there is an easier
:way. (Csh solutions preferred.) 

Would you settle for a C solution without the 'sh'?-)  I think it's
easier than transforming ls's output into a form acceptable for touch.
---cut here: ti.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
extern char*malloc();

int main(argc, argv) int argc; char **argv;
{
	struct utimbuf {time_t actime, modtime;} *timar=0;
	struct stat bufi;
	int i,pid,waitrc;
	unsigned int sonrc;

	if(argc<2) {
		fprintf(stderr,"Usage: %s command [files]\n",argv[0]);
		return 1;
	}
	if(argc>2) {
		timar=(struct utimbuf*)malloc((argc-2));
		for(i=2; i<argc; i++) {
			if(-1==stat(argv[i],&bufi))
				timar[i-2].actime=0;
			else {
				timar[i-2].actime=bufi.st_atime;
				timar[i-2].modtime=bufi.st_mtime;
			}
		}
	}
	if((pid=fork())==0) {	/* in child process, exec command */
		execvp(argv[1], argv+1);
		fprintf(stderr, "%s: ", argv[0]);
		perror(argv[1]);
	}
	waitrc=wait(&sonrc);
	for(i=2; i<argc; i++)
		if(timar[i-2].actime) utime(argv[i], &timar[i-2]);
	if(timar) free(timar);
	if(sonrc&0xFF) return sonrc;
	else return sonrc>>8;
}
---end cut: ti.c

This is rather a kludge, actually.  The syntax (after 'cc -o ti ti.c')
is 'ti command -maybe -some -options file arguments...', but I don't
want ti to have to "know" about the syntax of "command" to discern which
of the following words are filenames, and which are not.  So what ti
does is try to stat() *each* of its args; then, after fork/exec/wait of
command, it tries to restore actime and modtime for each arg that it was
originally able to stat successfully - I figured this would be mostly
harmless, i.e. even if you DO have a file called '-l', doing, say,
'ti ci -l a.c b.c c.c', the fact that '-l' is NOT being modified by
the (RCS check-in-then-check-out-again,locked) target command will not
normally be a problem (the times of file '-l' will be harmlessly
restored to what they already were...).
You may want to adopt some alternative approach, such as parsing
the target command's arguments according to some option-syntax
convention.
Other problems have to do with such commands as 'ti sort -ofo fi', where
file 'fo' is going to be modified but is not easily recognizable as a
part of the target command; also 'ti sort fi >fo', since the shell is
not going to let ti know that its output is redirected to fo...

Anyway, the main way I use it is just as in the first example above -
I definitely do NOT want source files' modtimes to be updated when
they are just, conceptually, being checked-in, not 'modified'... such
updates were impeding my intended usage of make+rcs before I came up
with this kludgey but basically workable solution.
-- 
Alex Martelli - (home snailmail:) v. Barontini 27, 40138 Bologna, ITALIA
Email: (work:) martelli@cadlab.sublink.org, (home:) alex@am.sublink.org
Phone: (work:) ++39 (51) 371099, (home:) ++39 (51) 250434; 
Fax: ++39 (51) 366964 (work only), Fidonet: 332/401.3 (home only).

phil@ux1.cso.uiuc.edu (Phil Howard KA9WGN) (05/25/91)

alex@am.sublink.org (Alex Martelli) writes:

>Other problems have to do with such commands as 'ti sort -ofo fi', where
>file 'fo' is going to be modified but is not easily recognizable as a
>part of the target command; also 'ti sort fi >fo', since the shell is
>not going to let ti know that its output is redirected to fo...

Also, ti can't catch the file names in programs that come up with their
own, such as in:

    ti find . -type f -exec touch {} \;

But I have found ti to be useful in transferring the date from one file
to another file with some handwaving from "mv".  Try:

    ti csh -fc 'mv a tmp;mv b a;mv tmp b' a b

>Anyway, the main way I use it is just as in the first example above -
>I definitely do NOT want source files' modtimes to be updated when
>they are just, conceptually, being checked-in, not 'modified'... such
>updates were impeding my intended usage of make+rcs before I came up
>with this kludgey but basically workable solution.

It might technically be a kludge, but I have found ti to be very useful.
-- 
 /***************************************************************************\
/ Phil Howard -- KA9WGN -- phil@ux1.cso.uiuc.edu   |  Guns don't aim guns at  \
\ Lietuva laisva -- Brivu Latviju -- Eesti vabaks  |  people; CRIMINALS do!!  /
 \***************************************************************************/

les@chinet.chi.il.us (Leslie Mikesell) (05/26/91)

In article <9105211828.AA12327@fozzie.nrl.navy.mil> phillips@FOZZIE.NRL.NAVY.MIL (Lee Phillips) writes:

>I want to do something to a file without changing its modification
>time.  I suppose I can write a script to get the time from ls, do the
>modification, then restore the time (after converting it to numerical
>format) with /usr/5bin/touch, but I'm hoping that there is an easier
>way. (Csh solutions preferred.) 

Perl is probably the only utility that has stat and utime implimented
in a way that is directly usable.  Other choices would requre C programming
or lots of contortions.

Les Mikesell
  les@chinet.chi.il.us