home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1632 < prev    next >
Internet Message Format  |  1990-12-28  |  15KB

  1. From: chip@chinacat.Unicom.COM (Chip Rosenthal)
  2. Newsgroups: comp.unix.questions,alt.sources
  3. Subject: Re: how to compare file modification time  (whole dir tree?)
  4. Message-ID: <1446@chinacat.Unicom.COM>
  5. Date: 30 Jul 90 23:36:41 GMT
  6.  
  7. Attached at the bottom is a command-line interface to the stat() system
  8. call.  To do the file compare, you could do:
  9.  
  10.     time1=`stat -M $file1`
  11.     time2=`stat -M $file2`
  12.     if [ $time1 -gt $time2 ] ; then
  13.     echo "$file1 is newer than $file2"
  14.     else
  15.     echo "$file2 is newer than $file1" # well...could be same time...
  16.     fi
  17.  
  18. In article <1990Jul27.153223.12416@chinet.chi.il.us>
  19.     les@chinet.chi.il.us (Leslie Mikesell) writes:
  20. >Also, is there a handy way to set the timestamp on a directory to that
  21. >of the newest file below it?
  22.  
  23. Assuming you've got a "settime" command, this would work:
  24.  
  25.     DIR=/tmp/foo
  26.     settime -f `stat -M $DIR/* | sort -rn +1 | sed -e 's/:.*//' -e q` $DIR
  27.  
  28. This sets the directory's modified time to that of the newest file in
  29. that directory.  A little more complexity is needed if you want to find
  30. the newest file in the entire directory tree.
  31.  
  32. The stat program has been tested on SCO XENIX 386.  I wouldn't be surprised
  33. if there are some system dependancies in the include files or data types
  34. of the stat structure elements, but it should be very simple to fix up.
  35. (The whole thing is driven by a single table.)
  36.  
  37. #! /bin/sh
  38. # this is a "shar" archive - run through "/bin/sh" to extract 4 files:
  39. #   README stat.c stat.man Makefile
  40. # Wrapped by bin@chinacat on Sun Jul 29 20:19:14 CDT 1990
  41. # Unpacking this archive requires:  sed test wc (possibly mkdir)
  42. # Existing files will not be clobbered unless "-c" is specified on the cmd line.
  43. if test -f README -a "$1" != "-c" ; then
  44.     echo "README: file exists - will not be overwritten"
  45. else
  46.     echo "x - README (file 1 of 4, 586 chars)"
  47.     sed -e 's/^X//' << 'END_OF_FILE_README' > README
  48. Xstat displays information on a file - the same information available
  49. Xthrough the stat() system call.  For example, to see all the information
  50. Xon /etc/termcap you can do:
  51. X
  52. X    % stat -x /etc/termcap
  53. X    DEV=1,40
  54. X    INODE=3087
  55. X    MODE=644
  56. X    NLINK=4
  57. X    UID=bin
  58. X    GID=bin
  59. X    RDEV=103,181
  60. X    SIZE=94032
  61. X    ATIME=Sun Jul 29 18:36:18 1990
  62. X    MTIME=Sun Apr 30 22:53:31 1989
  63. X    CTIME=Sun Nov  5 02:23:55 1989
  64. X
  65. XThe "-x" option returns all available things.  You can request individual
  66. Xitems, for example:
  67. X
  68. X    % stat -u /etc/termcap
  69. X    bin
  70. X
  71. XChip Rosenthal
  72. X<chip@chinacat.Unicom.COM>
  73. END_OF_FILE_README
  74.     size="`wc -c < README`"
  75.     if test 586 -ne "$size" ; then
  76.     echo "README: extraction error - got $size chars"
  77.     fi
  78. fi
  79. if test -f stat.c -a "$1" != "-c" ; then
  80.     echo "stat.c: file exists - will not be overwritten"
  81. else
  82.     echo "x - stat.c (file 2 of 4, 7223 chars)"
  83.     sed -e 's/^X//' << 'END_OF_FILE_stat.c' > stat.c
  84. X/*
  85. X * stat - User-level interface to file information.
  86. X *
  87. X * This program is table driven through the "Stat_tab[]" list, which contains
  88. X * all of the items we can display.  Each table entry specifies the command
  89. X * line option which selects it, a pointer to pick the appropriate value out
  90. X * of a stat structure, and a pointer to the procedure to format and print the
  91. X * information.  Hacking this program should just be a matter of adding table
  92. X * entries, and possibly new formatting procedures.
  93. X *
  94. X * Sun Jul 29 20:16:50 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
  95. X *    Commented for posting to alt.sources.
  96. X */
  97. X
  98. X#include <stdio.h>
  99. X#include <sys/types.h>
  100. X#include <sys/stat.h>
  101. X#include <sys/sysmacros.h>
  102. X#include <pwd.h>
  103. X#include <grp.h>
  104. X
  105. X/*
  106. X * Used to mark what kind of data item we are looking at.
  107. X */
  108. X#define TYPE_DEV_T    1
  109. X#define TYPE_INO_T    2
  110. X#define TYPE_OFF_T    3
  111. X#define TYPE_SHORT    4
  112. X#define TYPE_TIME_T    5
  113. X#define TYPE_USHORT    6
  114. X
  115. X/*
  116. X * The following procedures take a "long" value and format it as required.
  117. X */
  118. Xvoid pr_decvalue();    /* print as a decimal value        */
  119. Xvoid pr_octvalue();    /* print as an octal value        */
  120. Xvoid pr_perms();    /* strip and print permissions in octal    */
  121. Xvoid pr_device();    /* print device number as "major,minor"    */
  122. Xvoid pr_user();        /* lookup and print as a user name    */
  123. Xvoid pr_group();    /* lookup and print as a group name    */
  124. Xvoid pr_time();        /* print as a formatted time string    */
  125. Xvoid pr_days();        /* print as number of days ago        */
  126. X
  127. X/*
  128. X * The file status will be loaded into this buffer.
  129. X */
  130. Xstruct stat Stat_buf;
  131. X
  132. X/*
  133. X * Table of things we can do.
  134. X */
  135. Xstruct stat_desc {
  136. X    int sd_enabled;    /* will be set nonzero to do this entry        */
  137. X    char *sd_optlist;    /* list of cmd line options which enable this    */
  138. X    char *sd_descrip;    /* text for item label                */
  139. X    void *sd_ptr;    /* pointer to item datum within "Stat_buf"    */
  140. X    int sd_datatype;    /* indicates what "sd_ptr" points to        */
  141. X    void (*sd_func)();    /* procedure to format and print the item    */
  142. X} Stat_tab[] = {
  143. X    /*** lower case options ************************************************/
  144. X    { 0, "dx", "DEV",   (void*)&Stat_buf.st_dev,   TYPE_DEV_T,  pr_device   },
  145. X    { 0, "ix", "INODE", (void*)&Stat_buf.st_ino,   TYPE_INO_T,  pr_decvalue },
  146. X    { 0, "px", "MODE",  (void*)&Stat_buf.st_mode,  TYPE_USHORT, pr_perms    },
  147. X    { 0, "nx", "NLINK", (void*)&Stat_buf.st_nlink, TYPE_SHORT,  pr_decvalue },
  148. X    { 0, "ux", "UID",   (void*)&Stat_buf.st_uid,   TYPE_USHORT, pr_user     },
  149. X    { 0, "gx", "GID",   (void*)&Stat_buf.st_gid,   TYPE_USHORT, pr_group    },
  150. X    { 0, "rx", "RDEV",  (void*)&Stat_buf.st_rdev,  TYPE_DEV_T,  pr_device   },
  151. X    { 0, "sx", "SIZE",  (void*)&Stat_buf.st_size,  TYPE_OFF_T,  pr_decvalue },
  152. X    { 0, "ax", "ATIME", (void*)&Stat_buf.st_atime, TYPE_TIME_T, pr_time     },
  153. X    { 0, "mx", "MTIME", (void*)&Stat_buf.st_mtime, TYPE_TIME_T, pr_time     },
  154. X    { 0, "cx", "CTIME", (void*)&Stat_buf.st_ctime, TYPE_TIME_T, pr_time     },
  155. X    { 0, "f",  "MTIME", (void*)&Stat_buf.st_mtime, TYPE_TIME_T, pr_days     },
  156. X    /*** upper case options ************************************************/
  157. X    { 0, "DX", "DEV",   (void*)&Stat_buf.st_dev,   TYPE_DEV_T,  pr_decvalue },
  158. X    { 0, "IX", "INODE", (void*)&Stat_buf.st_ino,   TYPE_INO_T,  pr_decvalue },
  159. X    { 0, "PX", "MODE",  (void*)&Stat_buf.st_mode,  TYPE_USHORT, pr_octvalue },
  160. X    { 0, "NX", "NLINK", (void*)&Stat_buf.st_nlink, TYPE_SHORT,  pr_decvalue },
  161. X    { 0, "UX", "UID",   (void*)&Stat_buf.st_uid,   TYPE_USHORT, pr_decvalue },
  162. X    { 0, "GX", "GID",   (void*)&Stat_buf.st_gid,   TYPE_USHORT, pr_decvalue },
  163. X    { 0, "RX", "RDEV",  (void*)&Stat_buf.st_rdev,  TYPE_DEV_T,  pr_decvalue },
  164. X    { 0, "SX", "SIZE",  (void*)&Stat_buf.st_size,  TYPE_OFF_T,  pr_decvalue },
  165. X    { 0, "AX", "ATIME", (void*)&Stat_buf.st_atime, TYPE_TIME_T, pr_decvalue },
  166. X    { 0, "MX", "MTIME", (void*)&Stat_buf.st_mtime, TYPE_TIME_T, pr_decvalue },
  167. X    { 0, "CX", "CTIME", (void*)&Stat_buf.st_ctime, TYPE_TIME_T, pr_decvalue },
  168. X    { 0, NULL, NULL,    (void*)0,                  0,           0           },
  169. X};
  170. X
  171. Xmain(argc,argv)
  172. Xint argc;
  173. Xchar *argv[];
  174. X{
  175. X    char *s;
  176. X    int print_titles, print_files, argi, ocount, i;
  177. X    long value;
  178. X    char *strchr();
  179. X
  180. X    /*
  181. X     * Crack the command line options.
  182. X     */
  183. X    for ( argi = 1 ; argi < argc && *(s=argv[argi]) == '-' ; ++argi ) {
  184. X    while ( *++s != '\0' ) {
  185. X        ocount = 0;
  186. X        for ( i = 0 ; Stat_tab[i].sd_optlist != NULL ; ++i ) {
  187. X        if ( strchr(Stat_tab[i].sd_optlist,*s) != NULL ) {
  188. X            ++Stat_tab[i].sd_enabled;
  189. X            ++ocount;
  190. X        }
  191. X        }
  192. X        if ( ocount == 0 ) {
  193. X        fprintf(stderr,"%s: unknown option '%c'\n",argv[0],*s);
  194. X        exit(1);
  195. X        }
  196. X    }
  197. X    }
  198. X
  199. X    /*
  200. X     * If more than one item is printed, then titles should be shown.
  201. X     * Note that if you double an option (i.e. "-dd") this will cause titles
  202. X     * to be printed.  Consider it an undocumented feature...
  203. X     */
  204. X    switch ( ocount ) {
  205. X    case 0:  fprintf(stderr,"%s: no options specified\n",argv[0]); exit(1);
  206. X    case 1:  print_titles = 0; break;
  207. X    default: print_titles = 1; break;
  208. X    }
  209. X
  210. X    /*
  211. X     * If more than one file is to be done, then names should be shown.
  212. X     */
  213. X    switch ( argc-argi ) {
  214. X    case 0:  fprintf(stderr,"%s: no files specified\n",argv[0]); exit(1);
  215. X    case 1:  print_files = 0; break;
  216. X    default: print_files = 1; break;
  217. X    }
  218. X
  219. X    /*
  220. X     * Go through the remaining command line items and get their status.
  221. X     */
  222. X    for ( ; argi < argc ; ++argi ) {
  223. X
  224. X    if ( stat(argv[argi],&Stat_buf) != 0 ) {
  225. X        fprintf(stderr,"%s: could not get file status of '%s'\n",
  226. X        argv[0],argv[argi]);
  227. X        continue;
  228. X    }
  229. X
  230. X    for ( i = 0 ; Stat_tab[i].sd_optlist != NULL ; ++i ) {
  231. X        if ( !Stat_tab[i].sd_enabled )
  232. X        continue;
  233. X        switch ( Stat_tab[i].sd_datatype ) {
  234. X        case TYPE_DEV_T:  value = *((dev_t *)Stat_tab[i].sd_ptr);  break;
  235. X        case TYPE_INO_T:  value = *((ino_t *)Stat_tab[i].sd_ptr);  break;
  236. X        case TYPE_OFF_T:  value = *((off_t *)Stat_tab[i].sd_ptr);  break;
  237. X        case TYPE_SHORT:  value = *((short *)Stat_tab[i].sd_ptr);  break;
  238. X        case TYPE_TIME_T: value = *((time_t *)Stat_tab[i].sd_ptr); break;
  239. X        case TYPE_USHORT: value = *((ushort *)Stat_tab[i].sd_ptr); break;
  240. X        }
  241. X        if ( print_files )
  242. X        printf("%s: ", argv[argi]);
  243. X        if ( print_titles )
  244. X        printf("%s=", Stat_tab[i].sd_descrip);
  245. X        (*Stat_tab[i].sd_func)(value);
  246. X    }
  247. X
  248. X    }
  249. X
  250. X    exit(0);
  251. X}
  252. X
  253. X
  254. Xvoid pr_decvalue(value)
  255. Xlong value;
  256. X{
  257. X    printf("%ld\n", value);
  258. X}
  259. X
  260. Xvoid pr_octvalue(value)
  261. Xlong value;
  262. X{
  263. X    printf("%lo\n",value);
  264. X}
  265. X
  266. Xvoid pr_perms(value)
  267. Xlong value;
  268. X{
  269. X    printf("%lo\n", (value&~S_IFMT) );
  270. X}
  271. X
  272. Xvoid pr_device(value)
  273. Xlong value;
  274. X{
  275. X    printf("%ld,%ld\n", major(value), minor(value));
  276. X}
  277. X
  278. Xvoid pr_user(value)
  279. Xlong value;
  280. X{
  281. X    struct passwd *pw, *getpwuid();
  282. X    if ( (pw=getpwuid((int)value)) == NULL )
  283. X    printf("%ld\n", value);
  284. X    else
  285. X    puts(pw->pw_name);
  286. X}
  287. X
  288. Xvoid pr_group(value)
  289. Xlong value;
  290. X{
  291. X    struct group *gr, *getgrgid();
  292. X    if ( (gr=getgrgid((int)value)) == NULL )
  293. X    printf("%ld\n", value);
  294. X    else
  295. X    puts(gr->gr_name);
  296. X}
  297. X
  298. Xvoid pr_time(value)
  299. Xlong value;
  300. X{
  301. X    char *ctime();
  302. X    fputs(ctime(&value),stdout);
  303. X}
  304. X
  305. Xvoid pr_days(value)
  306. Xlong value;
  307. X{
  308. X    time_t clock, time();
  309. X    (void) time(&clock);
  310. X    printf("%ld\n", ((long)clock-value)/86400L);
  311. X}
  312. X
  313. END_OF_FILE_stat.c
  314.     size="`wc -c < stat.c`"
  315.     if test 7223 -ne "$size" ; then
  316.     echo "stat.c: extraction error - got $size chars"
  317.     fi
  318. fi
  319. if test -f stat.man -a "$1" != "-c" ; then
  320.     echo "stat.man: file exists - will not be overwritten"
  321. else
  322.     echo "x - stat.man (file 3 of 4, 2468 chars)"
  323.     sed -e 's/^X//' << 'END_OF_FILE_stat.man' > stat.man
  324. X.TH STAT 1L
  325. X.SH NAME
  326. Xstat - Displays file status.
  327. X.SH SYNTAX
  328. X.B stat
  329. X-options file ...
  330. X.SH DESCRIPTION
  331. XThe
  332. X.I stat
  333. Xcommand obtains information on a file.  A plethora of options select which
  334. Xitems to display.  Most items have two alternatives:  a lower case letter
  335. Xwhich displays the item in a useful format, and an upper case letter which
  336. Xdisplays the item in a numeric format.  Programmers will recognize these
  337. Xitems as the values returned by the
  338. X.I stat(2)
  339. Xsystem call.  The available options are:
  340. X.sp
  341. X.nf
  342. X.ta \n(.iuC +8 +4n +22n +4n
  343. X.de XX
  344. X    \f2\\$1\fP    \f3\\$2\fP    \\$3    \f3\\$4\fP    \\$5
  345. X..
  346. X.XX dev -d "device major,minor" -D "decimal value"
  347. X.XX inode -i "inode number number" -I "(same information)"
  348. X.XX mode -p "permissions in octal" -P "full mode in octal"
  349. X.XX nlink -n "number of links" -N "(same information)"
  350. X.XX uid -u "name of owning user" -U "number of owning user"
  351. X.XX gid -g "name of owning group" -G "number of owning group"
  352. X.XX rdev -r "device major,minor" -R "decimal value"
  353. X.XX size -s "size in bytes" -S "(same information)"
  354. X.XX atime -a "last access time" -A "seconds since epoch"
  355. X.XX mtime -m "last modify time" -M "seconds since epoch"
  356. X.XX ctime -c "last change time" -C "seconds since epoch"
  357. X.XX "" -x "all above items" -X "all above items"
  358. X.XX mtime -f "days ago" "" ""
  359. X.fi
  360. X.P
  361. XPlease see the
  362. X.I stat(2)
  363. Xmanual page for the details on the items as listed in column one above.
  364. X.P
  365. XIf
  366. X.I stat
  367. Xis invoked for a single piece of information on one file, just that
  368. Xitem is printed.  If more than one piece of information is requested,
  369. Xit will be labelled, for example:
  370. X.RS
  371. X.sp
  372. XUID=root
  373. X.sp
  374. X.RE
  375. XThe labels are derived from the column 1 names, with the "st" prefix
  376. Xdropped and the result converted to upper case.  If information on
  377. Xmore than one file is requested, the filename will precede each line of output.
  378. X.P
  379. XNote there are three special options:
  380. X.B "-x"
  381. Xand
  382. X.B "-X"
  383. Xwhich request a number of options to be used, and the
  384. X.B "-f"
  385. Xoption which requests the modify time in a special format.  The difference
  386. Xbetween the lower-case time options and upper-case time options is that
  387. Xthe former print the date as text, and the latter print the date in number
  388. Xof seconds since the ``epoch''.  The lower-case device options print the
  389. Xdevice major and minor numbers seperated by commas, the upper-case
  390. Xdevice options show a single decimal value.
  391. X
  392. X
  393. X.SH SEE ALSO
  394. Xchgrp(1), chmod(1), chown(1), ls(1), stat(2)
  395. X.SH AUTHOR
  396. XChip Rosenthal
  397. X.br
  398. X<chip@chinacat.unicom.com>
  399. END_OF_FILE_stat.man
  400.     size="`wc -c < stat.man`"
  401.     if test 2468 -ne "$size" ; then
  402.     echo "stat.man: extraction error - got $size chars"
  403.     fi
  404. fi
  405. if test -f Makefile -a "$1" != "-c" ; then
  406.     echo "Makefile: file exists - will not be overwritten"
  407. else
  408.     echo "x - Makefile (file 4 of 4, 1260 chars)"
  409.     sed -e 's/^X//' << 'END_OF_FILE_Makefile' > Makefile
  410. X
  411. X# %Z% %M% %I% %E% %U%
  412. X# Makefile for "stat" (generated by makemake version 1.00.09)
  413. X# Created by bin@chinacat on Sun Jul 29 20:15:19 CDT 1990
  414. X
  415. XSHELL = /bin/sh
  416. XCC = cc
  417. XDEFS = 
  418. XCOPTS = -O
  419. XLOPTS = 
  420. XLIBS = 
  421. XDEBUG = -g -DDEBUG
  422. XLINTFLAGS = -DLINT
  423. X
  424. XTARG = stat
  425. XOTHERS = 
  426. X
  427. XSRCS = stat.c
  428. X
  429. XOBJS = stat.o
  430. X
  431. X# Any edits below this line will be lost if "makemake" is rerun!
  432. X# Commands may be inserted after the '#%custom' line at the end of this file.
  433. X
  434. XCFLAGS = $(COPTS) $(DEFS) # $(DEBUG)
  435. XLFLAGS = $(LOPTS) # $(DEBUG)
  436. X
  437. Xall:        $(TARG) $(OTHERS)
  438. Xinstall:    all        ; inst Install
  439. Xclean:                ; rm -f $(TARG) $(OBJS) a.out core $(TARG).lint
  440. Xclobber:    clean        ; inst -u Install
  441. Xlint:        $(TARG).lint
  442. X
  443. X$(TARG):        $(OBJS)
  444. X        $(CC) $(LFLAGS) -o $@ $(OBJS) $(LIBS)
  445. X
  446. X$(TARG).lint:    $(TARG)
  447. X        lint $(LINTFLAGS) $(DEFS) $(SRCS) $(LIBS) > $@
  448. X
  449. Xstat.o: stat.c
  450. X
  451. Xmake:        ;
  452. X        makemake -i -v1.00.09 -aMakefile \
  453. X            -DSHELL='$(SHELL)' -DCC='$(CC)' -DDEFS='$(DEFS)' \
  454. X            -DCOPTS='$(COPTS)' -DLOPTS='$(LOPTS)' -DLIBS='$(LIBS)' \
  455. X            -DDEBUG='$(DEBUG)' -DLINTFLAGS='$(LINTFLAGS)' \
  456. X            -DOTHERS='$(OTHERS)' $(TARG) $(SRCS)
  457. X
  458. X#%custom - commands below this line will be maintained if 'makemake' is rerun
  459. X
  460. Xshar: stat.shar
  461. X
  462. XLIST = README stat.c stat.man Makefile
  463. X
  464. Xstat.shar:    $(LIST)
  465. X        shar $(LIST) > $@
  466. X
  467. END_OF_FILE_Makefile
  468.     size="`wc -c < Makefile`"
  469.     if test 1260 -ne "$size" ; then
  470.     echo "Makefile: extraction error - got $size chars"
  471.     fi
  472. fi
  473. echo "done - 4 files extracted"
  474. exit 0
  475. -- 
  476. Chip Rosenthal                            |  You aren't some icon carved out
  477. chip@chinacat.Unicom.COM                  |  of soap, sent down here to clean
  478. Unicom Systems Development, 512-482-8260  |  up my reputation.  -John Hiatt
  479.