#!mkcmd # Since time stamp file format (ksb) # $Id: sstamp.m,v 1.16 2011/03/09 23:51:45 ksb Exp $ from '' from '' from '' from '' from '' from '' from '"machine.h"' boolean 'n' { named "fUpdate" init "1" help "don't update target's length in the meta file" } require "util_errno.m" "util_ppm.m" %c static PPM_BUF since_PMLog; %% init 3 "util_ppm_init(& since_PMLog, 1, 0);" %hi #if !defined(SINCE_TS_VER) #define SINCE_TS_VER "2" /* version of stamp file */ typedef struct SSnode { time_t wwhen; /* last time we processed file */ off_t wlength; /* last length */ ino_t wnode; /* last inode number */ dev_t wdevice; /* last device number */ short int ffound; /* was a current stamp found? */ short int istamp; /* 0 == this lib, !0 == caller's */ /* internal fields -- don't look, touch, fold, spindle, etc. */ short int ialloc; short fopen; int iFd; char *pcdb; } SINCE_STAMP; extern SINCE_STAMP *since_from_log(SINCE_STAMP *, char *, struct stat *); extern int since_to_log(SINCE_STAMP *, char *); #endif %% %c /* since(1) time-stamp files have 3 line types: (ksb) * V%d\n * %lx L%lx I%x D%x\n * X____________________________________\n * the V line is the version marker * the %lx line is a valid (last we checked) time-stamp * the X_*\n line is free space in the file, if it is at the end * we can truncate the file back to the last line * * We always flock(2) or lockf(2) the file to access it. */ /* aquire the log file with a lock on it (ksb) */ static int since_aq_log(char *pcName, int fcreate) { register int fdRet; register int icreate; icreate = 0; if (fcreate) icreate = O_CREAT; /* LLL O_NONBLOCK should be a command line option */ #if USE_FLOCK if (-1 == (fdRet = open(pcName, O_RDWR|O_EXLOCK|icreate, 0666))) { return -1; } #else if (-1 == (fdRet = open(pcName, O_RDWR|icreate, 0666))) { return -1; } #if USE_LOCKF /* LLL F_TLOCK should be a command line option */ if (-1 == lockf(fdRet, F_LOCK, 0)) { register int iKeep; iKeep = errno; close(fdRet); errno = iKeep; return -1; } #endif #endif /* lock type */ return fdRet; } /* unlock the log file and close it (ksb) */ static void since_rl_log(int iFd) { close(iFd); } /* build a few (1 or more) since structures (ksb) * when you dispose of the first they all go away (calloc'd) */ SINCE_STAMP * since_new(unsigned int iCount) { register SINCE_STAMP *pSSRet; register unsigned int i; if ((SINCE_STAMP *)0 == (pSSRet = calloc(iCount, sizeof(SINCE_STAMP)))) { return (SINCE_STAMP *)0; } /* calloc zero'd the space, this is mostly redundant -- ksb */ for (i = 0; i < iCount; ++i) { pSSRet[i].istamp = 0; pSSRet[i].ffound = 0; pSSRet[i].ialloc = 0; pSSRet[i].fopen = 0; pSSRet[i].iFd = -1; pSSRet[i].pcdb = (char *)0; } pSSRet[0].ialloc = 1; return pSSRet; } /* reclaim any memory we allocated for this since node (ksb) */ void since_dispose(SINCE_STAMP *pSSHold) { if (0 != pSSHold->ialloc) { free((void *)pSSHold); } } /* Fill in the since struct for this file (ksb,petef) * open the log (locked), find our record */ SINCE_STAMP * since_from_log(SINCE_STAMP *pSS, char *pcLog, struct stat *pstThis) { auto struct stat stLog; register char *pcRecord, *pcCursor, *pcNext; register int fIgnore; auto time_t wWhen; auto unsigned long wLength, wT1, wT2; auto ino_t wNode; auto dev_t wDevice; if ((SINCE_STAMP *)0 == pSS) { pSS = since_new(1); if ((SINCE_STAMP *)0 == pSS) { return (SINCE_STAMP *)0; } } if (-1 == (pSS->iFd = since_aq_log(pcLog, 0))) { bail: since_dispose(pSS); return (SINCE_STAMP *)0; } pSS->fopen = 1; /* find our file, or not in file */ if (-1 == fstat(pSS->iFd, & stLog)) { close(pSS->iFd); goto bail; } pSS->pcdb = util_ppm_size(& since_PMLog, (stLog.st_size|15)+1); if (stLog.st_size != read(pSS->iFd, pSS->pcdb, stLog.st_size)) { close(pSS->iFd); goto bail; } pSS->pcdb[stLog.st_size] = '\000'; pSS->wnode = pstThis->st_ino; pSS->wdevice = pstThis->st_dev; pcRecord = ""; for (pcCursor = pSS->pcdb; '\000' != *pcCursor; /* middle */) { pcRecord = pcCursor; pcNext = strchr(pcCursor, '\n'); if ((char *)0 == pcNext) break; if ('V' != *pcCursor) { pcCursor = pcNext + 1; continue; } *pcNext = '\000'; fIgnore = 0 != strcmp(SINCE_TS_VER, pcCursor+1); *pcNext++ = '\n'; pcCursor = strchr(pcNext, '\n'); ++pcCursor; if (fIgnore) continue; if (4 != sscanf(pcNext, "%lx L%lx I%lx D%lx\n", &wWhen, &wLength, &wT1, &wT2)) continue; pSS->wwhen = wWhen; wNode = (ino_t)wT1; wDevice = (dev_t)wT2; if (wNode != pSS->wnode || wDevice != pSS->wdevice) continue; pSS->ffound = 1; if (wLength > pstThis->st_size) wLength = 0; pSS->wlength = wLength; break; } /* if we're just looking (-n), no need to remove our sincedb * entry -- just release the log */ if (! fUpdate) { since_rl_log(pSS->iFd); return pSS; } /* We have the entry. Delete it from our copy in memory. * We'll put the others back in the file when we're done. */ if (pSS->ffound) memmove(pcRecord, pcCursor, strlen(pcCursor) + 1); return pSS; } /* Fill in the since file for this struct (ksb,petef) * open the log (locked), add our record to the end */ int since_to_log(SINCE_STAMP *pSS, char *pcLog) { auto char acBuf[256]; /* Vver\n%x*4 + change\n */ register int iFd; auto struct timeval tv; if (! fUpdate) return -1; if ((SINCE_STAMP *)0 == pSS) return ENOENT; if (pSS->fopen && 0 <= pSS->iFd) { iFd = pSS->iFd; lseek(iFd, 0, SEEK_SET); } else if (-1 == (iFd = since_aq_log(pcLog, 1))) { fprintf(stderr, "%s: %s: open: %s\n", progname, pcLog, strerror(errno)); return errno; } ftruncate(iFd, 0); /* Write out our new record to the beginning of the file for easier * searching in the future. */ if (pSS->istamp) { tv.tv_sec = pSS->wwhen; } else if (0 != gettimeofday(&tv, (struct timezone *)0)) { fprintf(stderr, "%s: gettimeofday: %s\n", progname, strerror(errno)); return errno; } sprintf(acBuf, "V%s\n%lx L%lx I%lx D%lx\n", SINCE_TS_VER, (long)tv.tv_sec, (long)pSS->wlength, (long)pSS->wnode, (long)pSS->wdevice); write(iFd, acBuf, strlen(acBuf)); /* Write out all of the saved records after it */ if (pSS->fopen) write(iFd, pSS->pcdb, strlen(pSS->pcdb)); since_rl_log(iFd); return 0; } %%