webmover.c
/*
* Program to fix web page links for CD-ROM (ISO-9660) or DOS (or UNIX)
*
* Oct. 1997 Written for UNIX by Greg Ward Larson, SGI
*/
/********************************************************************
This software has been tossed out into the public domain without
warranty or support. Use it in good health. If you like it, share it
with a friend. If you don't like it, delete it with the satisfaction
of knowing you'll never have to use it again. I made every effort to
ensure that it would not alter existing pages, only the new directory
tree it creates. If you delete your original pages without checking
the new ones thoroughly, I think we both know who to blame. If you
use it in checking mode only, it doesn't create anything and therefore
(all else being equal), should be harmless. Still, I can't make any
guarantee of safety or people will kill me and send their lawyers to
loot my estate. Caveat emptor, and that especially applies to things
that are free.
That said, if you find problems with this program or make improvements,
I wouldn't mind hearing about it. I don't promise to do anything, though,
since I wrote this program for a single use and I don't expect I'll need
it again real soon. The same may be true for you, which is why we need
to share these utilities when we create them, right?
Bon apetit!
-Greg Larson
*********************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
char NULLDEV[] = "/dev/null";
char DFLTFILE[] = "index";
#define UNIX 0
#define ISO 1
#define HTML 0
char suffix[][2][8] = {
"html", "htm",
"jpeg", "jpg",
"tiff", "tif",
"tar.Z", "trz",
"ps.Z", "psz",
"tar.gz", "tgz",
"ps.gz", "pgz",
"text", "txt",
"jfif", "jff",
"", ""
};
char anchor[][6] = {"HREF", "SRC", ""};
char anchars[] = "HShs"; /* any case versions of first letters above */
char isochar[128] = { /* ISO character translation */
'\0', '_', '_', '_', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_',
'_', '_', '_', '_', '_', '_', '_', '_', /* !"#$%&' */
'_', '_', '_', '_', '_', '_', '_', '_', /* ()*+,-./ */
'0', '1', '2', '3', '4', '5', '6', '7', /* 01234567 */
'8', '9', '_', '_', '_', '_', '_', '_', /* 89:;<=>? */
'_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* @ABCDEFG */
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* HIJKLMNO */
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* PQRSTUVW */
'x', 'y', 'z', '_', '_', '_', '_', '_', /* XYZ[\]^_ */
'_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* `abcdefg */
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* hijklmno */
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* pqrstuvw */
'x', 'y', 'z', '_', '_', '_', '_', '_', /* xyz{|}~ */
};
#define ISOLEN 8
#define ISOSUF 3
typedef struct pmove {
struct pmove *next; /* next in list */
mode_t mode; /* file mode and type */
ino_t inode; /* file inode number (link tracking) */
dev_t dev; /* device for this file (ditto) */
char *newp; /* new path name (NULL if none) */
char oldp[1]; /* old path name (extends struct) */
} PMOVE; /* a page movement record */
#define isdir(m) ((m) && S_ISDIR(m))
PMOVE *todolist = NULL, *donelist = NULL, *curpage = NULL;
#define pmdone(pm) (pm->next = donelist, donelist = pm)
#define pmtodo(pm) (pm->next = todolist, todolist = pm)
/* flags for what we're doing */
#define C2ISOFN 01
#define C2UNIXFN 02
#define C2DOSNL 04
#define C2UNIXNL 010
#define CVERBOSE 020
#define CCHKONLY 040
int cvtflags = 0;
char *progname, *orig_url;
FILE *infp, *outfp;
extern char *localpath(), *relpath(), *findsuff();
extern FILE *checkopen();
extern PMOVE *pmalloc(), *getdone(), *getany(), *mkmove(), *getnew();
main(argc, argv) /* check/rename web pages */
int argc;
char *argv[];
{
int i, n;
progname = argv[0];
for (i = 1; i < argc && argv[i][0] == '-'; i++)
switch (argv[i][1]) {
case 'u': /* UNIX destination */
cvtflags &= ~(C2DOSNL|C2ISOFN);
cvtflags |= C2UNIXFN|C2UNIXNL;
break;
case 'd': /* DOS destination */
cvtflags &= ~C2UNIXNL;
cvtflags |= C2DOSNL;
/* fall through */
case 'i': /* ISO destination */
cvtflags &= ~C2UNIXFN;
cvtflags |= C2ISOFN;
break;
case 'v': /* verbose */
cvtflags |= CVERBOSE;
break;
case 'h':
Help(stdout);
exit(0);
default:
goto userr;
}
if (i > argc-2 | i < argc-3)
goto userr;
/* get starting URL */
orig_url = argv[i];
if (strncmp("http://", orig_url, 7))
goto userr;
for (n = strlen(orig_url); orig_url[n-1] == '/'; orig_url[--n] = '\0')
;
if (n < 8)
goto userr;
/* initialize lists */
if (init(argv[i+1], argv[i+2]) < 0)
goto userr;
/* do all pages */
while (donext())
;
exit(0); /* done */
userr:
Usage(stderr);
exit(1);
}
Usage(fp) /* print usage message to fp */
FILE *fp;
{
fprintf(fp,
"Usage: %s [-u|-i|-d][-v] base_URL orig_dir/[html] [new_dir/[html]]\n",
progname);
fprintf(fp, " Or: %s -h[elp]\n", progname);
}
Help(fp) /* print helpful hints to fp */
register FILE *fp;
{
register int i;
fprintf(fp, "\nThis program prepares web pages for publication.\n\n");
Usage(fp);
fprintf(fp, "\nArguments to %s and their interpretation:\n", progname);
fprintf(fp, "base_URL\tThe starting point for this website (beginning with \"http://\")\n");
fprintf(fp, "orig_dir/[html]\tThe original directory [and front page] relative to base_URL\n");
fprintf(fp, "\t\tIf [html] is left off, then we assume \"%s.%s\"\n",
DFLTFILE, suffix[HTML][UNIX]);
fprintf(fp, "newdir/[html]\tThe destination directory [and front page] relative to base_URL\n");
fprintf(fp, "\t\tThis new directory must not exist.\n");
fprintf(fp, "\t\tIf this argument is left off, %s just checks pages.\n", progname);
fprintf(fp, "\nOptions to %s and their meanings:\n", progname);
fprintf(fp, "\t-u\tConvert to UNIX file naming conventions and EOL\n");
fprintf(fp, "\t-i\tConvert to ISO-9660 file naming conventions\n");
fprintf(fp, "\t-d\tConvert to DOS file naming conventions and EOL\n");
fprintf(fp, "\t-v\tVerbose reporting of progress to stdout\n");
fprintf(fp, "\nAssumptions made by %s:\n", progname);
fprintf(fp, "o Only move what front page references, directly and indirectly\n");
fprintf(fp, "o Overhead references (above front page directory) are not moved\n");
fprintf(fp, "o No non-printing, non-white characters are desired in pages\n");
fprintf(fp, "o Symbolic links are followed and not treated specially\n");
fprintf(fp, "o Hard links are made to destination whenever possible\n");
fprintf(fp, "o Hard links are preserved among files\n");
fprintf(fp, "\nThe following file suffixes are recognized:\n");
fprintf(fp, " ____UNIX____ISO____\n");
for (i = 0; suffix[i][0][0]; i++)
fprintf(fp, "\t%s\t%s\n", suffix[i][UNIX], suffix[i][ISO]);
fputc('\n', fp);
}
init(origh, newh) /* initialize our process lists */
char *origh, *newh;
{
char orig_dir[MAXPATHLEN], new_dir[MAXPATHLEN];
char orig_home[MAXNAMELEN], new_home[MAXNAMELEN];
char orig_path[MAXPATHLEN], new_path[MAXPATHLEN];
register PMOVE *pm;
if (!getstart(orig_dir, orig_home, origh))
return(-1);
if (!strcmp(orig_dir, ".")) { /* kill "." directory */
orig_dir[0] = '\0';
strcpy(orig_path, orig_home);
} else
sprintf(orig_path, "%s/%s", orig_dir, orig_home);
if (newh != NULL) {
if (!getstart(new_dir, new_home, newh))
return(-1);
pm = pmalloc(orig_dir, new_dir);
if (!isdir(pm->mode)) {
fprintf(stderr, "%s: %s: not a directory\n",
progname, orig_dir);
exit(1);
}
if (mkdir(new_dir, pm->mode) < 0) {
fprintf(stderr, "%s: mkdir: ", progname);
perror(new_dir);
exit(2);
}
pmdone(pm);
sprintf(new_path, "%s/%s", new_dir, new_home);
pm = pmalloc(orig_path, new_path);
pmtodo(pm);
} else {
cvtflags |= CCHKONLY;
pm = pmalloc(orig_dir, NULL);
pmdone(pm);
pm = pmalloc(orig_path, NULL);
pmtodo(pm);
}
return(0);
}
getstart(dir, hom, pth) /* extract directory and home page file name */
register char *dir, *hom, *pth;
{
register char *fn = NULL;
/* copy full path into dir */
while (*pth) {
if ((*dir = *pth++) == '/')
fn = dir;
dir++;
}
if (fn == NULL) /* make sure we got a directory */
return(0);
*fn++ = '\0'; /* separate out directory */
if (*fn) /* got filename also */
strcpy(hom, fn);
else { /* else use default */
for (fn = DFLTFILE; (*hom = *fn++); hom++)
;
*hom++ = '.';
strcpy(hom, suffix[HTML][UNIX]);
}
return(1);
}
donext() /* do next web page */
{
/* get page from to do list */
if (todolist == NULL)
return(0); /* return 0 if done */
curpage = todolist;
todolist = todolist->next;
curpage->next = NULL;
/* see if it can be linked */
if (linkdone(curpage)) {
pmdone(curpage);
curpage = NULL;
return(1);
}
/* open input file */
if ((infp = fopen(curpage->oldp, "r")) == NULL) {
fprintf(stderr, "%s: cannot open web page: ", progname);
perror(curpage->oldp);
exit(2);
} else if (cvtflags & CVERBOSE)
printf("Reading HTML from \"%s\"\n", curpage->oldp);
/* open output file */
if (curpage->newp == NULL)
outfp = fopen(NULLDEV, "w");
else if ((outfp = fopen(curpage->newp, "w")) == NULL) {
fprintf(stderr, "%s: cannot open new page: ", progname);
perror(curpage->newp);
exit(2);
} else if (cvtflags & CVERBOSE)
printf("Writing HTML to \"%s\"\n", curpage->newp);
/* process this page */
docurrent();
/* clean up */
fclose(infp); infp = NULL;
if (fclose(outfp) < 0) {
fprintf(stderr, "%s: close error: ", progname);
perror(curpage->newp);
exit(2);
}
outfp = NULL;
if (cvtflags & CVERBOSE)
printf("Done processing \"%s\"\n", curpage->oldp);
pmdone(curpage);
curpage = NULL;
return(1);
}
docurrent() /* process the current web page from infp */
{
#define INCOMMAND 1
#define INCOMMENT 2
#define INQUOTE 4
int state = 0, funnychars = 0, lineno = 0;
char buf[1024];
register int c, i;
int n;
while (fgets(buf, sizeof(buf), infp) != NULL) {
lineno++;
for (i = 0; (c=buf[i]); i++) {
switch(c) {
case '<':
state |= INCOMMAND;
break;
case '"':
if (state & INCOMMAND)
state ^= INQUOTE;
break;
case '!':
if ((state & (INCOMMAND|INQUOTE)) == INCOMMAND)
state |= INCOMMENT;
break;
case '>':
if (!(state & INQUOTE))
state &= ~(INCOMMAND|INCOMMENT);
break;
case '\r':
if (cvtflags & C2UNIXNL) {
if (!buf[i+1])
fputc('\n', outfp);
} else
break;
continue;
case '\n':
if (cvtflags & C2DOSNL &&
(i == 0 || buf[i-1] != '\r'))
fputc('\r', outfp);
break;
default:
if (state==INCOMMAND &&
(i == 0 || buf[i-1] == '<'
|| isspace(buf[i-1]))
&& strchr(anchars, c) != NULL
&& (n = processlink(buf+i))) {
i += n-1;
continue;
}
if (!isascii(c) ||
!(isprint(c) || isspace(c))) {
funnychars++;
continue;
}
break;
}
putc(c, outfp);
}
if (state & INQUOTE) {
fprintf(stderr,
"%s: warning - unbalanced quote at line %d in \"%s\"\n",
progname, lineno, curpage->oldp);
state &= ~INQUOTE;
}
}
if (funnychars)
fprintf(stderr,
"%s: warning - skipped %d non-printing characters in \"%s\"\n",
progname, funnychars, curpage->oldp);
#undef INCOMMAND
#undef INCOMMENT
#undef INQUOTE
}
#if 0
matchiso(isfn, name) /* see if name matches isfn using isochar */
register char *isfn, *name;
{
while (*isfn == isochar[*name++])
if (!*isfn++)
return(1);
return(0);
}
#endif
matchkey(key, s) /* see if a string matches a upper-case key */
register char *key, *s;
{
while (*key)
if (toupper(*s++) != *key++)
return(0);
return(1);
}
int
processlink(s) /* see if this is a link we can process */
char *s;
{
int i, n;
register char *cp, *cp2;
char *subfile;
PMOVE *pm;
char url[MAXPATHLEN];
/* find keyword */
for (i = 0; anchor[i][0]; i++)
if (matchkey(anchor[i], s))
break;
if (!(n = strlen(anchor[i])))
return(0);
/* find reference */
for (cp = s+n; *cp && isspace(*cp); cp++)
;
if (*cp != '=')
return(0);
for (cp++; *cp && isspace(*cp); cp++)
;
if ((n = *cp == '"')) /* quoted? */
cp++;
cp2 = url; /* extract URL */
while (*cp) {
if (n ? *cp == '"' : isspace(*cp) || *cp == '>')
break;
*cp2++ = *cp++;
}
if (cp2 == url)
return(0);
*cp2 = '\0';
n += cp - s; /* tricky length -- note boolean value of n */
/* separate subfile index, if any */
if ((subfile = strchr(url, '#')) != NULL)
*subfile++ = '\0';
/* check for internal ref. or remote URL */
if (!*url || (cp2 = localpath(url)) == NULL) {
fprintf(outfp, "%s=\"%s", anchor[i], url);
goto finish;
}
cp = findsuff(cp2); /* check suffix */
if (*cp++ == '.' && toupper(*cp++) == 'H' &&
toupper(*cp++) == 'T' && toupper(*cp++) == 'M') {
if (toupper(*cp) == 'L') cp++;
if (*cp)
cp = NULL; /* suffix not html */
} else
cp = NULL; /* not html */
pm = curpage; /* using as flag */
if (!*cp2 || !strncmp(cp2, "../", 3))
goto overhead;
/* see if we've logged it already */
if ((pm = getany(cp2)) == NULL) {
pm = mkmove(cp2); /* pick name and allocate */
if (pm == NULL)
goto overhead; /* above top directory */
if (pm->mode == 0)
pmdone(pm); /* missing file entry */
else if (cp != NULL)
pmtodo(pm); /* put HTML on to do list */
else {
cplink(pm); /* copy/link other files */
pmdone(pm);
}
}
if (pm->mode == 0) /* flag missing pages */
fprintf(stderr, "%s: %s: warning - dangling link \"%s\"\n",
progname, curpage->oldp, pm->oldp);
/* output relative path */
fprintf(outfp, "%s=\"%s", anchor[i], relpath(curpage->newp, pm->newp));
goto finish;
overhead: /* overhead link case */
fprintf(stderr, "%s: %s: warning - overhead link \"%s\" left as ",
progname, curpage->oldp, cp2);
if (pm == NULL) {
fprintf(stderr, "\"%s/%s\"\n", orig_url, cp2);
fprintf(outfp, "%s=\"%s/%s", anchor[i], orig_url, cp2);
} else {
fprintf(stderr, "\"%s\"\n", url);
fprintf(outfp, "%s=\"%s", anchor[i], url);
}
finish:
if (subfile != NULL) /* print subfile index, if any */
fprintf(outfp, "#%s", subfile);
fputc('"', outfp); /* close quote */
return(n);
}
islocal(s) /* check for local path vs. network URL */
register char *s;
{
if (!*s) return(0);
do {
if (*s == ':') return(0);
if (*s == '/') return(1);
} while (*++s);
return(1);
}
killparents(pth) /* remove "../" occurrences from pth */
char *pth;
{
register char *cp, *cp2;
int npar = 0;
/* eliminate "./" occurrences first! */
cp2 = pth;
while ((cp = strstr(cp2, "./")) != NULL) {
cp2 = cp + 2;
if (cp > pth && cp[-1] != '/')
continue;
while ((*cp++ = *cp2++))
;
cp2 = pth;
}
cp2 = pth;
while ((cp = strstr(cp2, "../")) != NULL) {
cp2 = cp + 3;
if (cp == pth)
return(-1); /* path begins with parent! */
if (*--cp != '/')
continue;
while (cp > pth && cp[-1] != '/')
cp--;
npar++;
while ((*cp++ = *cp2++))
;
cp2 = pth;
}
return(*pth ? npar : -1);
}
char *
localpath(url) /* determine if URL is local to us */
char *url;
{
static char locp[MAXPATHLEN];
register int n;
n = strlen(orig_url); /* check full URL */
if (!strncmp(url, orig_url, n) && url[n] == '/')
strcpy(locp, url+n+1);
else if (islocal(url)) { /* get local name */
strcpy(locp, curpage->oldp);
for (n = strlen(locp); n > 0 && locp[n-1] != '/'; n--)
;
strcpy(locp+n, url);
} else
return(NULL);
n = strlen(locp);
if (n == 0 || locp[n-1] == '/') { /* use default page */
strcpy(locp+n, DFLTFILE);
n += strlen(locp+n);
locp[n++] = '.';
if (cvtflags & C2UNIXFN)
strcpy(locp+n, suffix[HTML][ISO]);
else
strcpy(locp+n, suffix[HTML][UNIX]);
}
killparents(locp); /* eliminate "../" */
return(locp);
}
char *
relpath(curp, pth) /* from full path, find shortest route */
char *curp, *pth;
{
static char relp[MAXPATHLEN];
int npar;
register char *cp1, *cp2;
if (curp == NULL || pth == NULL)
return("NOPATH");
/* skip common prefix */
for (cp1 = curp, cp2 = pth; *cp1 && *cp1 == *cp2; cp1++, cp2++)
;
while (cp1 > curp && cp1[-1] != '/')
cp1--;
while (cp2 > pth && cp2[-1] != '/')
cp2--;
/* count uncommon components in curp */
for (npar = 0; *cp1; cp1++)
npar += *cp1 == '/';
/* prepend this many parents */
for (cp1 = relp; npar--; ) {
*cp1++ = '.'; *cp1++ = '.'; *cp1++ = '/';
}
/* the rest is where we left cp2 */
strcpy(cp1, cp2);
return(relp);
}
PMOVE *
pmalloc(op, np) /* allocate and assign new PMOVE structure */
char *op, *np;
{
register PMOVE *p; int n, n1;
struct stat stbuf;
if (stat(*op ? op : ".", &stbuf) < 0) { /* stat original */
fprintf(stderr, "%s: ", progname);
if (curpage != NULL)
fprintf(stderr, "%s: ", curpage->oldp);
perror(*op ? op : ".");
memset((char *)&stbuf, 0, sizeof(stbuf));
}
n1 = n = sizeof(PMOVE) + strlen(op); /* allocate struct */
if (np!=NULL) n += strlen(np)+1;
if ((p=(PMOVE *)malloc(n)) == NULL) {
fprintf(stderr, "%s: out of memory\n", progname);
exit(2);
}
strcpy(p->oldp, op); /* copy names */
if (np!=NULL) p->newp = strcpy((char *)p+n1, np);
else p->newp = NULL;
p->mode = stbuf.st_mode; /* record mode, etc. */
p->dev = stbuf.st_dev;
if (!isdir(stbuf.st_mode) && stbuf.st_nlink > 1)
p->inode = stbuf.st_ino;
else
p->inode = 0;
p->next = NULL;
return(p);
}
char *
findsuff(pn) /* find file suffix, return '.' position or end */
register char *pn;
{
register char *sf = NULL;
register int needsuff = 1;
while (*pn) {
if (*pn == '.') { /* potential suffix */
if (needsuff) {
sf = pn;
needsuff = 0;
}
} else if (*pn == '/') { /* new directory */
sf = NULL;
needsuff = 1;
} else if (sf != NULL) { /* else check suffix */
if (*pn == '#') /* don't go into index */
break;
needsuff |= isdigit(*pn); /* avoid digits */
}
pn++;
}
return(sf==NULL ? pn : sf);
}
incrfname(c0) /* increment number in file name */
register char *c0;
{
while (*c0 == '9') *c0-- = '0';
if (*c0 <= '0' || *c0 > '9') *c0 = '1';
else (*c0)++;
}
newpath(op, np) /* assign new path, creating directories as needed */
char *op, *np;
{
register char *cp1, *cp2;
PMOVE *p;
char origd[MAXPATHLEN];
/* identify old directory */
for (cp1 = op, cp2 = origd; (*cp2++ = *cp1++); )
;
while (cp2 > origd && *--cp2 != '/')
cp1--;
op = cp1; /* point to original file name */
*cp2 = '\0';
if ((p = getdone(origd)) == NULL) { /* need new directory */
p = mkmove(origd); /* mutually recursive */
if (p == NULL)
return(0);
pmdone(p); /* add to done list */
} /* copy new directory path */
for (cp1 = p->newp, cp2 = np; (*cp2 = *cp1++); cp2++)
;
*cp2++ = '/';
cp1 = op; /* rename file as indicated */
if (cvtflags & C2UNIXFN) {
while ((*cp2++ = *cp1) && *cp1++ != '.')
;
if (*cp1) /* check suffix */
if (!strcmp(cp1, suffix[HTML][ISO]))
strcpy(cp2, suffix[HTML][UNIX]);
else
strcpy(cp2, cp1);
} else if (cvtflags & C2ISOFN) {
char *nm = cp2, *suf;
register int i;
/* Check character set.
* Check length.
* Check suffix.
* Make sure new file name is unique.
*/
suf = findsuff(cp1);
while (*cp1) { /* map filename */
if (cp1 == suf)
*cp2++ = '.';
else if (cp1 > suf)
*cp2++ = *cp1;
else if (cp2 < nm+ISOLEN)
*cp2++ = isochar[*cp1 & 0x7f];
cp1++;
}
*cp2 = '\0';
suf = findsuff(nm);
if (suf == nm+ISOLEN && nm[ISOLEN-1] == '_')
nm[ISOLEN-1] = '0'; /* don't generate trailing _ */
if (*suf) { /* map extension */
for (i = 0; suffix[i][0][0]; i++)
if (!strcmp(suf+1, suffix[i][UNIX])) {
strcpy(suf+1, suffix[i][ISO]);
break;
}
if (!suffix[i][0][0]) { /* didn't match standard one */
for (i = 1; i <= ISOSUF; i++)
suf[i] = isochar[suf[i] & 0x7f];
suf[ISOSUF+1] = '\0';
}
}
while (getnew(np) != NULL) {
if (suf-nm < ISOLEN) {
for (i = ISOSUF+1; i--; )
nm[ISOLEN+i] = suf[i];
while (suf-nm < ISOLEN)
*suf++ = '0';
}
incrfname(suf-1);
}
} else
strcpy(cp2, cp1);
return(1);
}
PMOVE *
mkmove(oldname) /* determine new name and allocate PMOVE struct */
char *oldname;
{
register PMOVE *p;
char newname[MAXPATHLEN], *cp;
register int n;
if (cvtflags & CCHKONLY)
return(pmalloc(oldname, NULL));
n = strlen(oldname);
while (n > 0 && oldname[n-1] == '/')
oldname[--n] = '\0';
if (n == 0 || !newpath(oldname, newname))
return(NULL);
p = pmalloc(oldname, newname); /* allocate PMOVE */
/* create if dir. */
if (isdir(p->mode)) {
while (cvtflags & C2ISOFN && *(cp = findsuff(p->newp))) {
*cp = '_'; /* no extension */
while (cp > p->newp && cp[-1] != '/')
cp--;
cp[ISOLEN] = '\0'; /* may harm uniqueness */
}
if (mkdir(p->newp, p->mode) < 0) {
fprintf(stderr, "%s: %s: mkdir: ",
progname, curpage->oldp);
perror(p->newp);
exit(2);
} else if (cvtflags & CVERBOSE)
printf("Created directory \"%s\"\n", p->newp);
}
return(p);
}
PMOVE *
getnew(np) /* find PMOVE struct with same new path */
char *np;
{
register PMOVE *p;
if (curpage != NULL && !strcmp(curpage->newp, np))
return(curpage);
for (p = donelist; p != NULL; p = p->next)
if (!strcmp(p->newp, np))
return(p);
for (p = todolist; p != NULL; p = p->next)
if (!strcmp(p->newp, np))
return(p);
return(NULL);
}
PMOVE *
getdone(op) /* find finished PMOVE with this original path */
char *op;
{
register PMOVE *p;
for (p = donelist; p != NULL; p = p->next)
if (!strcmp(p->oldp, op))
return(p);
return(NULL);
}
PMOVE *
getany(op) /* find any PMOVE struct with this original path */
char *op;
{
register PMOVE *p;
if ((p = getdone(op)) != NULL)
return(p);
if (curpage != NULL && !strcmp(curpage->oldp, op))
return(curpage);
for (p = todolist; p != NULL; p = p->next)
if (!strcmp(p->oldp, op))
return(p);
return(NULL);
}
linkdone(pm) /* see if a page can be linked */
register PMOVE *pm;
{
register PMOVE *pl;
/* first, is it even linkable? */
if (pm->newp == NULL || pm->inode == 0)
return(0);
/* OK, see if we can find it */
for (pl = donelist; pl != NULL; pl = pl->next)
if (pl->inode == pm->inode && pl->dev == pm->dev)
break;
if (pl == NULL || pl->newp == NULL)
return(0); /* not found */
if (link(pl->newp, pm->newp) < 0) {
fprintf(stderr, "%s: %s: cannot link: ", progname, pl->newp);
perror(pm->newp);
exit(2);
} else if (cvtflags & CVERBOSE)
printf("Linked \"%s\" to \"%s\"\n", pl->newp, pm->newp);
return(1);
}
cplink(pm) /* copy or link a file to its new location */
register PMOVE *pm;
{
if (pm->newp == NULL)
return;
errno = 0;
if (link(pm->oldp, pm->newp) < 0)
if (errno == EXDEV) {
if (!linkdone(pm))
cpfile(pm->oldp, pm->newp);
} else {
fprintf(stderr, "%s: %s: cannot link: ",
progname, pm->oldp);
perror(pm->newp);
exit(2);
}
else if (cvtflags & CVERBOSE)
printf("Linked \"%s\" to \"%s\"\n", pm->oldp, pm->newp);
}
cpfile(oldf, newf) /* copy file contents */
char *oldf, *newf;
{
int infd, outfd, n;
char buf[BUFSIZ];
if ((infd = open(oldf, O_RDONLY)) < 0) {
fprintf(stderr, "%s: cannot open for reading: ", progname);
perror(oldf);
exit(2);
}
if ((outfd = open(newf, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) {
fprintf(stderr, "%s: cannot open for writing: ", progname);
perror(newf);
exit(2);
}
while ((n = read(infd, buf, BUFSIZ)) > 0)
if (write(outfd, buf, n) != n) {
fprintf(stderr, "%s: error writing: ", progname);
perror(newf);
exit(2);
}
if (n < 0) {
fprintf(stderr, "%s: error reading: ", progname);
perror(oldf);
exit(2);
}
close(infd);
close(outfd);
if (cvtflags & CVERBOSE)
printf("Copied \"%s\" to \"%s\"\n", oldf, newf);
}
by
admin
—
last modified
Apr 21, 2025 09:13 PM