home *** CD-ROM | disk | FTP | other *** search
- From: chip@chinacat.Unicom.COM (Chip Rosenthal)
- Newsgroups: comp.unix.questions,alt.sources
- Subject: Re: how to compare file modification time (whole dir tree?)
- Message-ID: <1446@chinacat.Unicom.COM>
- Date: 30 Jul 90 23:36:41 GMT
-
- Attached at the bottom is a command-line interface to the stat() system
- call. To do the file compare, you could do:
-
- time1=`stat -M $file1`
- time2=`stat -M $file2`
- if [ $time1 -gt $time2 ] ; then
- echo "$file1 is newer than $file2"
- else
- echo "$file2 is newer than $file1" # well...could be same time...
- fi
-
- In article <1990Jul27.153223.12416@chinet.chi.il.us>
- les@chinet.chi.il.us (Leslie Mikesell) writes:
- >Also, is there a handy way to set the timestamp on a directory to that
- >of the newest file below it?
-
- Assuming you've got a "settime" command, this would work:
-
- DIR=/tmp/foo
- settime -f `stat -M $DIR/* | sort -rn +1 | sed -e 's/:.*//' -e q` $DIR
-
- This sets the directory's modified time to that of the newest file in
- that directory. A little more complexity is needed if you want to find
- the newest file in the entire directory tree.
-
- The stat program has been tested on SCO XENIX 386. I wouldn't be surprised
- if there are some system dependancies in the include files or data types
- of the stat structure elements, but it should be very simple to fix up.
- (The whole thing is driven by a single table.)
-
- #! /bin/sh
- # this is a "shar" archive - run through "/bin/sh" to extract 4 files:
- # README stat.c stat.man Makefile
- # Wrapped by bin@chinacat on Sun Jul 29 20:19:14 CDT 1990
- # Unpacking this archive requires: sed test wc (possibly mkdir)
- # Existing files will not be clobbered unless "-c" is specified on the cmd line.
- if test -f README -a "$1" != "-c" ; then
- echo "README: file exists - will not be overwritten"
- else
- echo "x - README (file 1 of 4, 586 chars)"
- sed -e 's/^X//' << 'END_OF_FILE_README' > README
- Xstat displays information on a file - the same information available
- Xthrough the stat() system call. For example, to see all the information
- Xon /etc/termcap you can do:
- X
- X % stat -x /etc/termcap
- X DEV=1,40
- X INODE=3087
- X MODE=644
- X NLINK=4
- X UID=bin
- X GID=bin
- X RDEV=103,181
- X SIZE=94032
- X ATIME=Sun Jul 29 18:36:18 1990
- X MTIME=Sun Apr 30 22:53:31 1989
- X CTIME=Sun Nov 5 02:23:55 1989
- X
- XThe "-x" option returns all available things. You can request individual
- Xitems, for example:
- X
- X % stat -u /etc/termcap
- X bin
- X
- XChip Rosenthal
- X<chip@chinacat.Unicom.COM>
- END_OF_FILE_README
- size="`wc -c < README`"
- if test 586 -ne "$size" ; then
- echo "README: extraction error - got $size chars"
- fi
- fi
- if test -f stat.c -a "$1" != "-c" ; then
- echo "stat.c: file exists - will not be overwritten"
- else
- echo "x - stat.c (file 2 of 4, 7223 chars)"
- sed -e 's/^X//' << 'END_OF_FILE_stat.c' > stat.c
- X/*
- X * stat - User-level interface to file information.
- X *
- X * This program is table driven through the "Stat_tab[]" list, which contains
- X * all of the items we can display. Each table entry specifies the command
- X * line option which selects it, a pointer to pick the appropriate value out
- X * of a stat structure, and a pointer to the procedure to format and print the
- X * information. Hacking this program should just be a matter of adding table
- X * entries, and possibly new formatting procedures.
- X *
- X * Sun Jul 29 20:16:50 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
- X * Commented for posting to alt.sources.
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/sysmacros.h>
- X#include <pwd.h>
- X#include <grp.h>
- X
- X/*
- X * Used to mark what kind of data item we are looking at.
- X */
- X#define TYPE_DEV_T 1
- X#define TYPE_INO_T 2
- X#define TYPE_OFF_T 3
- X#define TYPE_SHORT 4
- X#define TYPE_TIME_T 5
- X#define TYPE_USHORT 6
- X
- X/*
- X * The following procedures take a "long" value and format it as required.
- X */
- Xvoid pr_decvalue(); /* print as a decimal value */
- Xvoid pr_octvalue(); /* print as an octal value */
- Xvoid pr_perms(); /* strip and print permissions in octal */
- Xvoid pr_device(); /* print device number as "major,minor" */
- Xvoid pr_user(); /* lookup and print as a user name */
- Xvoid pr_group(); /* lookup and print as a group name */
- Xvoid pr_time(); /* print as a formatted time string */
- Xvoid pr_days(); /* print as number of days ago */
- X
- X/*
- X * The file status will be loaded into this buffer.
- X */
- Xstruct stat Stat_buf;
- X
- X/*
- X * Table of things we can do.
- X */
- Xstruct stat_desc {
- X int sd_enabled; /* will be set nonzero to do this entry */
- X char *sd_optlist; /* list of cmd line options which enable this */
- X char *sd_descrip; /* text for item label */
- X void *sd_ptr; /* pointer to item datum within "Stat_buf" */
- X int sd_datatype; /* indicates what "sd_ptr" points to */
- X void (*sd_func)(); /* procedure to format and print the item */
- X} Stat_tab[] = {
- X /*** lower case options ************************************************/
- X { 0, "dx", "DEV", (void*)&Stat_buf.st_dev, TYPE_DEV_T, pr_device },
- X { 0, "ix", "INODE", (void*)&Stat_buf.st_ino, TYPE_INO_T, pr_decvalue },
- X { 0, "px", "MODE", (void*)&Stat_buf.st_mode, TYPE_USHORT, pr_perms },
- X { 0, "nx", "NLINK", (void*)&Stat_buf.st_nlink, TYPE_SHORT, pr_decvalue },
- X { 0, "ux", "UID", (void*)&Stat_buf.st_uid, TYPE_USHORT, pr_user },
- X { 0, "gx", "GID", (void*)&Stat_buf.st_gid, TYPE_USHORT, pr_group },
- X { 0, "rx", "RDEV", (void*)&Stat_buf.st_rdev, TYPE_DEV_T, pr_device },
- X { 0, "sx", "SIZE", (void*)&Stat_buf.st_size, TYPE_OFF_T, pr_decvalue },
- X { 0, "ax", "ATIME", (void*)&Stat_buf.st_atime, TYPE_TIME_T, pr_time },
- X { 0, "mx", "MTIME", (void*)&Stat_buf.st_mtime, TYPE_TIME_T, pr_time },
- X { 0, "cx", "CTIME", (void*)&Stat_buf.st_ctime, TYPE_TIME_T, pr_time },
- X { 0, "f", "MTIME", (void*)&Stat_buf.st_mtime, TYPE_TIME_T, pr_days },
- X /*** upper case options ************************************************/
- X { 0, "DX", "DEV", (void*)&Stat_buf.st_dev, TYPE_DEV_T, pr_decvalue },
- X { 0, "IX", "INODE", (void*)&Stat_buf.st_ino, TYPE_INO_T, pr_decvalue },
- X { 0, "PX", "MODE", (void*)&Stat_buf.st_mode, TYPE_USHORT, pr_octvalue },
- X { 0, "NX", "NLINK", (void*)&Stat_buf.st_nlink, TYPE_SHORT, pr_decvalue },
- X { 0, "UX", "UID", (void*)&Stat_buf.st_uid, TYPE_USHORT, pr_decvalue },
- X { 0, "GX", "GID", (void*)&Stat_buf.st_gid, TYPE_USHORT, pr_decvalue },
- X { 0, "RX", "RDEV", (void*)&Stat_buf.st_rdev, TYPE_DEV_T, pr_decvalue },
- X { 0, "SX", "SIZE", (void*)&Stat_buf.st_size, TYPE_OFF_T, pr_decvalue },
- X { 0, "AX", "ATIME", (void*)&Stat_buf.st_atime, TYPE_TIME_T, pr_decvalue },
- X { 0, "MX", "MTIME", (void*)&Stat_buf.st_mtime, TYPE_TIME_T, pr_decvalue },
- X { 0, "CX", "CTIME", (void*)&Stat_buf.st_ctime, TYPE_TIME_T, pr_decvalue },
- X { 0, NULL, NULL, (void*)0, 0, 0 },
- X};
- X
- Xmain(argc,argv)
- Xint argc;
- Xchar *argv[];
- X{
- X char *s;
- X int print_titles, print_files, argi, ocount, i;
- X long value;
- X char *strchr();
- X
- X /*
- X * Crack the command line options.
- X */
- X for ( argi = 1 ; argi < argc && *(s=argv[argi]) == '-' ; ++argi ) {
- X while ( *++s != '\0' ) {
- X ocount = 0;
- X for ( i = 0 ; Stat_tab[i].sd_optlist != NULL ; ++i ) {
- X if ( strchr(Stat_tab[i].sd_optlist,*s) != NULL ) {
- X ++Stat_tab[i].sd_enabled;
- X ++ocount;
- X }
- X }
- X if ( ocount == 0 ) {
- X fprintf(stderr,"%s: unknown option '%c'\n",argv[0],*s);
- X exit(1);
- X }
- X }
- X }
- X
- X /*
- X * If more than one item is printed, then titles should be shown.
- X * Note that if you double an option (i.e. "-dd") this will cause titles
- X * to be printed. Consider it an undocumented feature...
- X */
- X switch ( ocount ) {
- X case 0: fprintf(stderr,"%s: no options specified\n",argv[0]); exit(1);
- X case 1: print_titles = 0; break;
- X default: print_titles = 1; break;
- X }
- X
- X /*
- X * If more than one file is to be done, then names should be shown.
- X */
- X switch ( argc-argi ) {
- X case 0: fprintf(stderr,"%s: no files specified\n",argv[0]); exit(1);
- X case 1: print_files = 0; break;
- X default: print_files = 1; break;
- X }
- X
- X /*
- X * Go through the remaining command line items and get their status.
- X */
- X for ( ; argi < argc ; ++argi ) {
- X
- X if ( stat(argv[argi],&Stat_buf) != 0 ) {
- X fprintf(stderr,"%s: could not get file status of '%s'\n",
- X argv[0],argv[argi]);
- X continue;
- X }
- X
- X for ( i = 0 ; Stat_tab[i].sd_optlist != NULL ; ++i ) {
- X if ( !Stat_tab[i].sd_enabled )
- X continue;
- X switch ( Stat_tab[i].sd_datatype ) {
- X case TYPE_DEV_T: value = *((dev_t *)Stat_tab[i].sd_ptr); break;
- X case TYPE_INO_T: value = *((ino_t *)Stat_tab[i].sd_ptr); break;
- X case TYPE_OFF_T: value = *((off_t *)Stat_tab[i].sd_ptr); break;
- X case TYPE_SHORT: value = *((short *)Stat_tab[i].sd_ptr); break;
- X case TYPE_TIME_T: value = *((time_t *)Stat_tab[i].sd_ptr); break;
- X case TYPE_USHORT: value = *((ushort *)Stat_tab[i].sd_ptr); break;
- X }
- X if ( print_files )
- X printf("%s: ", argv[argi]);
- X if ( print_titles )
- X printf("%s=", Stat_tab[i].sd_descrip);
- X (*Stat_tab[i].sd_func)(value);
- X }
- X
- X }
- X
- X exit(0);
- X}
- X
- X
- Xvoid pr_decvalue(value)
- Xlong value;
- X{
- X printf("%ld\n", value);
- X}
- X
- Xvoid pr_octvalue(value)
- Xlong value;
- X{
- X printf("%lo\n",value);
- X}
- X
- Xvoid pr_perms(value)
- Xlong value;
- X{
- X printf("%lo\n", (value&~S_IFMT) );
- X}
- X
- Xvoid pr_device(value)
- Xlong value;
- X{
- X printf("%ld,%ld\n", major(value), minor(value));
- X}
- X
- Xvoid pr_user(value)
- Xlong value;
- X{
- X struct passwd *pw, *getpwuid();
- X if ( (pw=getpwuid((int)value)) == NULL )
- X printf("%ld\n", value);
- X else
- X puts(pw->pw_name);
- X}
- X
- Xvoid pr_group(value)
- Xlong value;
- X{
- X struct group *gr, *getgrgid();
- X if ( (gr=getgrgid((int)value)) == NULL )
- X printf("%ld\n", value);
- X else
- X puts(gr->gr_name);
- X}
- X
- Xvoid pr_time(value)
- Xlong value;
- X{
- X char *ctime();
- X fputs(ctime(&value),stdout);
- X}
- X
- Xvoid pr_days(value)
- Xlong value;
- X{
- X time_t clock, time();
- X (void) time(&clock);
- X printf("%ld\n", ((long)clock-value)/86400L);
- X}
- X
- END_OF_FILE_stat.c
- size="`wc -c < stat.c`"
- if test 7223 -ne "$size" ; then
- echo "stat.c: extraction error - got $size chars"
- fi
- fi
- if test -f stat.man -a "$1" != "-c" ; then
- echo "stat.man: file exists - will not be overwritten"
- else
- echo "x - stat.man (file 3 of 4, 2468 chars)"
- sed -e 's/^X//' << 'END_OF_FILE_stat.man' > stat.man
- X.TH STAT 1L
- X.SH NAME
- Xstat - Displays file status.
- X.SH SYNTAX
- X.B stat
- X-options file ...
- X.SH DESCRIPTION
- XThe
- X.I stat
- Xcommand obtains information on a file. A plethora of options select which
- Xitems to display. Most items have two alternatives: a lower case letter
- Xwhich displays the item in a useful format, and an upper case letter which
- Xdisplays the item in a numeric format. Programmers will recognize these
- Xitems as the values returned by the
- X.I stat(2)
- Xsystem call. The available options are:
- X.sp
- X.nf
- X.ta \n(.iuC +8 +4n +22n +4n
- X.de XX
- X \f2\\$1\fP \f3\\$2\fP \\$3 \f3\\$4\fP \\$5
- X..
- X.XX dev -d "device major,minor" -D "decimal value"
- X.XX inode -i "inode number number" -I "(same information)"
- X.XX mode -p "permissions in octal" -P "full mode in octal"
- X.XX nlink -n "number of links" -N "(same information)"
- X.XX uid -u "name of owning user" -U "number of owning user"
- X.XX gid -g "name of owning group" -G "number of owning group"
- X.XX rdev -r "device major,minor" -R "decimal value"
- X.XX size -s "size in bytes" -S "(same information)"
- X.XX atime -a "last access time" -A "seconds since epoch"
- X.XX mtime -m "last modify time" -M "seconds since epoch"
- X.XX ctime -c "last change time" -C "seconds since epoch"
- X.XX "" -x "all above items" -X "all above items"
- X.XX mtime -f "days ago" "" ""
- X.fi
- X.P
- XPlease see the
- X.I stat(2)
- Xmanual page for the details on the items as listed in column one above.
- X.P
- XIf
- X.I stat
- Xis invoked for a single piece of information on one file, just that
- Xitem is printed. If more than one piece of information is requested,
- Xit will be labelled, for example:
- X.RS
- X.sp
- XUID=root
- X.sp
- X.RE
- XThe labels are derived from the column 1 names, with the "st" prefix
- Xdropped and the result converted to upper case. If information on
- Xmore than one file is requested, the filename will precede each line of output.
- X.P
- XNote there are three special options:
- X.B "-x"
- Xand
- X.B "-X"
- Xwhich request a number of options to be used, and the
- X.B "-f"
- Xoption which requests the modify time in a special format. The difference
- Xbetween the lower-case time options and upper-case time options is that
- Xthe former print the date as text, and the latter print the date in number
- Xof seconds since the ``epoch''. The lower-case device options print the
- Xdevice major and minor numbers seperated by commas, the upper-case
- Xdevice options show a single decimal value.
- X
- X
- X.SH SEE ALSO
- Xchgrp(1), chmod(1), chown(1), ls(1), stat(2)
- X.SH AUTHOR
- XChip Rosenthal
- X.br
- X<chip@chinacat.unicom.com>
- END_OF_FILE_stat.man
- size="`wc -c < stat.man`"
- if test 2468 -ne "$size" ; then
- echo "stat.man: extraction error - got $size chars"
- fi
- fi
- if test -f Makefile -a "$1" != "-c" ; then
- echo "Makefile: file exists - will not be overwritten"
- else
- echo "x - Makefile (file 4 of 4, 1260 chars)"
- sed -e 's/^X//' << 'END_OF_FILE_Makefile' > Makefile
- X
- X# %Z% %M% %I% %E% %U%
- X# Makefile for "stat" (generated by makemake version 1.00.09)
- X# Created by bin@chinacat on Sun Jul 29 20:15:19 CDT 1990
- X
- XSHELL = /bin/sh
- XCC = cc
- XDEFS =
- XCOPTS = -O
- XLOPTS =
- XLIBS =
- XDEBUG = -g -DDEBUG
- XLINTFLAGS = -DLINT
- X
- XTARG = stat
- XOTHERS =
- X
- XSRCS = stat.c
- X
- XOBJS = stat.o
- X
- X# Any edits below this line will be lost if "makemake" is rerun!
- X# Commands may be inserted after the '#%custom' line at the end of this file.
- X
- XCFLAGS = $(COPTS) $(DEFS) # $(DEBUG)
- XLFLAGS = $(LOPTS) # $(DEBUG)
- X
- Xall: $(TARG) $(OTHERS)
- Xinstall: all ; inst Install
- Xclean: ; rm -f $(TARG) $(OBJS) a.out core $(TARG).lint
- Xclobber: clean ; inst -u Install
- Xlint: $(TARG).lint
- X
- X$(TARG): $(OBJS)
- X $(CC) $(LFLAGS) -o $@ $(OBJS) $(LIBS)
- X
- X$(TARG).lint: $(TARG)
- X lint $(LINTFLAGS) $(DEFS) $(SRCS) $(LIBS) > $@
- X
- Xstat.o: stat.c
- X
- Xmake: ;
- X makemake -i -v1.00.09 -aMakefile \
- X -DSHELL='$(SHELL)' -DCC='$(CC)' -DDEFS='$(DEFS)' \
- X -DCOPTS='$(COPTS)' -DLOPTS='$(LOPTS)' -DLIBS='$(LIBS)' \
- X -DDEBUG='$(DEBUG)' -DLINTFLAGS='$(LINTFLAGS)' \
- X -DOTHERS='$(OTHERS)' $(TARG) $(SRCS)
- X
- X#%custom - commands below this line will be maintained if 'makemake' is rerun
- X
- Xshar: stat.shar
- X
- XLIST = README stat.c stat.man Makefile
- X
- Xstat.shar: $(LIST)
- X shar $(LIST) > $@
- X
- END_OF_FILE_Makefile
- size="`wc -c < Makefile`"
- if test 1260 -ne "$size" ; then
- echo "Makefile: extraction error - got $size chars"
- fi
- fi
- echo "done - 4 files extracted"
- exit 0
- --
- Chip Rosenthal | You aren't some icon carved out
- chip@chinacat.Unicom.COM | of soap, sent down here to clean
- Unicom Systems Development, 512-482-8260 | up my reputation. -John Hiatt
-