file.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1987-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Bell Laboratories
*
* pax file support
*/
#include "pax.h"
#include <tm.h>
/*
* "nocomment" is a hardwired "nocom"
* should be an sfio discipline
*/
#include "nocomment.c"
#if __STDC__
#endif
/*
* return read file descriptor for filtered current input file
*/
int
{
register int n;
char* arg;
int rfd;
int wfd;
{
return rfd;
}
{
return -1;
}
{
return -1;
}
f->checksum = 0;
{
if ((ip = sfopen(NiL, f->path, "r")) && (op = sfnew(NiL, NiL, SF_UNBOUND, wfd, SF_WRITE)) && (count = nocomment(ip, op)) < 0)
if (ip)
{
if (op)
else
}
else
{
return -1;
}
}
else
{
{
return -1;
}
{
{
break;
}
}
if (n < 0)
}
return rfd;
}
/*
* return read file descriptor for current input file
*/
int
{
register int n;
int rfd;
rfd = -1;
{
f->checksum = 0;
else
{
if (n < 0)
}
}
if (rfd < 0)
return rfd;
}
/*
* create directory and all path name components leading to directory
*/
static int
{
register char* s;
register char* t;
long pp;
s = f->name;
pathcanon(s, 0, 0);
{
{
{
}
return -1;
}
st = 0;
do
{
*t = 0;
{
*t = '/';
break;
}
*t = '/';
if (t)
{
do
{
*t = 0;
{
*t = '/';
return -1;
}
*t = '/';
}
}
return 0;
}
/*
* open file for writing, set all necessary info
*/
int
{
register int fd;
int exists;
int perm;
int c;
/*
* if not found and state.update then check down the view
*
* NOTE: VPATH in app code is ugly but the benefits of the
* combination with state.update win over beauty
*/
if (f->ro)
{
f->name = "PAX-INTERNAL-ERROR";
f->skip = 1;
exists = 0;
}
{
{
return -1;
}
}
else
{
typedef struct View
{
char* root;
} View_t;
char* s;
char* e;
static char* offset;
{
if (s = getenv("VPATH"))
{
if (!(s = strdup(s)))
nospace();
do
{
if (e = strchr(s, ':'))
*e++ = 0;
nospace();
{
}
else
{
}
if (view)
else
} while (s = e);
e = 0;
for (;;)
{
{
{
}
if (e)
*e = '/';
goto found;
}
if (e)
*e = '/';
else
e = s + strlen(s);
while (e > s && *--e != '/');
if (e <= s)
break;
*e = 0;
}
}
if (!offset)
offset = ".";
}
if (*f->name != '/')
{
break;
}
}
{
if (exists)
{
case X_IFDIR:
if (!f->ro)
{
else
listentry(f);
}
break;
default:
else
listentry(f);
break;
}
return -1;
}
{
{
return -1;
}
if (state.linkf && f->type != X_IFDIR && (state.linkf == pathsetlink || f->st->st_dev == state.dev))
{
if (exists)
{
{
return -1;
}
{
return -1;
}
}
return -2;
}
}
switch (f->type)
{
case X_IFDIR:
if (f->ro)
return -1;
{
{
return -1;
}
exists = 0;
}
{
return -1;
}
if (!exists || f->chmod || state.update && ((c = tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, &st))) > 0 || state.update == OPT_different && c))
{
listentry(f);
fd = -1;
}
else
{
fd = -1;
else
fd = -2;
}
return fd;
case X_IFLNK:
return -1;
if (!*f->linkpath)
return -2;
{
return -1;
}
{
return -1;
}
{
{
return -1;
}
{
return -1;
}
}
listentry(f);
return -1;
case X_IFSOCK:
/*FALLTHROUGH*/
case X_IFBLK:
case X_IFCHR:
case X_IFIFO:
return -1;
break;
case X_IFREG:
return -1;
break;
}
return -1;
switch (f->type)
{
case X_IFIFO:
{
return -1;
}
{
{
return -1;
}
{
return -1;
}
goto nofifo;
}
return -2;
case X_IFSOCK:
/*FALLTHROUGH*/
case X_IFBLK:
case X_IFCHR:
{
return -1;
}
{
{
error(ERROR_SYSTEM|2, "%s: cannot create %s special file", f->name, (f->type == X_IFBLK) ? "block" : "character");
return -1;
}
{
return -1;
}
goto nospecial;
}
return -2;
default:
/*FALLTHROUGH*/
case X_IFREG:
if (f->ro)
return dup(1);
if (state.intermediate)
{
char* d;
char* e;
int n;
int ifd;
/*
* copy to intermediate output file and rename
* to real file only on success - a handy
* backup option
*
* thanks to the amazing dr. ek
*/
{
return -1;
}
for (n = 0;; n++)
{
if (e)
*e = 0;
if (e)
*e = '/';
if (f->intermediate)
{
return ifd;
}
if (n)
{
return -1;
}
}
}
/*
* ok, the exists bits are only used right here
* you do the defines if its that important
*
* <chmod u+w><remove><missdir>
* 4 don't attempt
* 2 attempted and succeeded
* 1 attempted and failed
*/
if (!exists)
exists |= 0440;
exists |= 0400;
{
if (!(exists & 0007))
{
{
return -1;
}
exists |= 0002;
}
else if (!(exists & 0700))
{
{
exists |= 0100;
goto again;
}
exists |= 0200;
}
else if (!(exists & 0070))
{
{
exists |= 0010;
goto again;
}
exists ^= 0620;
}
else
{
error(ERROR_SYSTEM|2, "%s: cannot create%s%s", f->name, (exists & 0100) ? ERROR_translate(0, 0, 0, ", cannot enable user write") : "", (exists & 0010) ? ERROR_translate(0, 0, 0, ", cannot remove") : "");
return -1;
}
}
f->chmod = 1;
error(ERROR_SYSTEM|1, "%s: cannot restore original mode %s", f->name, fmtperm(st.st_mode & S_IPERM));
return fd;
}
}
/*
* close an openin() fd, doing atime reset if necessary
*/
int
{
int r;
r = 0;
r = -1;
{
}
return r;
}
/*
* close an openout() fd, doing the intermediate rename if needed
*/
int
{
register char* s;
int r;
r = 0;
r = -1;
r = -1;
if (s = f->intermediate)
{
f->intermediate = 0;
{
if (remove(s))
return -1;
}
{
return -1;
}
{
return -1;
}
}
return r;
}
/*
* get file info for output
*/
int
{
register char* name;
register int n;
char* e;
{
case FTW_NS:
return 0;
case FTW_DNR:
break;
case FTW_D:
case FTW_DNX:
case FTW_DP:
{
}
{
/*
* directory descendents already included; in posix
* omitting -d would result in duplicate output copies
* so we avoid the problem by peeking ahead and
* pruning all paths with this dir prefix
*/
name[n] = '/';
{
break;
}
name[n] = 0;
}
break;
}
return 0;
f->uidname = 0;
f->gidname = 0;
f->link = 0;
{
{
return 0;
}
{
return 0;
}
}
else
{
f->linkpath = 0;
f->linkpathsize = 0;
}
return 0;
{
}
f->longname = 0;
f->longlink = 0;
f->skip = 0;
{
if (*e)
}
{
if (*e)
}
message((-2, "getfile(): path=%s name=%s mode=%s size=%I*d mtime=%s", name, f->name, fmtmode(f->st->st_mode, 1), sizeof(f->st->st_size), f->st->st_size, fmttime("%K", f->st->st_mtime)));
return 1;
}
/*
* check that f is valid for archive output
*/
int
{
if (f->ro)
return 0;
switch (f->type)
{
case X_IFBLK:
case X_IFCHR:
break;
case X_IFREG:
break;
case X_IFDIR:
case X_IFIFO:
case X_IFLNK:
break;
}
}
/*
* add file which may be a link
* 0 returned if <dev,ino> already added
*/
int
{
register Link_t* p;
register char* s;
int n;
unsigned short us;
{
case IN:
{
}
{
}
break;
break;
/*FALLTHROUGH*/
case OUT:
{
goto toomany;
}
break;
}
return 0;
{
return 1;
}
{
return 1;
goto linked;
}
return 1;
{
{
return 1;
}
f->link = p;
return 0;
{
return 0;
}
{
s = f->linkpath;
{
f->skip = 1;
return 0;
}
{
}
{
{
return 0;
}
{
return -1;
}
}
listentry(f);
}
return 0;
}
goto toomany;
f->link = p;
p->namesize = n;
return -1;
if (!state.warnlinknum)
{
}
return -1;
}
/*
* get file uid and gid names given numbers
*/
void
getidnames(register File_t* f)
{
if (!f->uidname)
if (!f->gidname)
}
/*
* set file uid and gid numbers given names
*/
void
setidnames(register File_t* f)
{
register int id;
if (f->uidname)
{
{
f->uidname = 0;
}
}
if (f->gidname)
{
{
f->gidname = 0;
}
}
}
/*
* allocate and initialize new archive pointer
*/
{
nospace();
return ap;
}
/*
* return pointer to archive for op
*/
getarchive(int op)
{
if (!*app)
*app = initarchive(NiL, (op & OUT) ? (state.append ? (O_WRONLY|O_CREAT) : (O_WRONLY|O_CREAT|O_TRUNC)) : O_RDONLY);
return *app;
}
/*
* initialize file info with name and mode
*/
void
initfile(register Archive_t* ap, register File_t* f, struct stat* st, register char* name, int mode)
{
memzero(f, sizeof(*f));
if (name)
{
}
}
/*
* set copied file info
*/
void
{
register Post_t* p;
int updated;
return;
switch (f->type)
{
case X_IFLNK:
updated = 0;
#if _lib_lchown
{
{
}
else
{
}
}
#endif
#if _lib_lchmod
if (f->chmod)
{
int m;
{
}
}
#endif
return;
case X_IFDIR:
{
{
p->chmod = 1;
}
else
return;
}
break;
}
p = &post;
}
/*
* set access and modification times of file
*/
void
{
}
/*
* restore file status after processing
*/
int
{
int m;
if (!*name)
return 0;
{
{
}
}
if (p->chmod)
{
{
}
}
return 0;
}
/*
* return 1 if f output can be pruned
*/
int
{
int c;
{
return 0;
}
{
return 1;
if (state.update && (!(c = tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, st))) || state.update != OPT_different && c < 0))
{
return 1;
}
}
return 0;
}
/*
* write siz bytes of buf to fd checking for HOLE_MIN hole chunks
* we assume siz is rounded nicely until the end
*/
{
register char* t = (char*)buf;
register char* e = t + siz;
register char* b = 0;
register char* s;
ssize_t i;
ssize_t n = 0;
#if DEBUG
b = t;
else
#endif
while (t < e)
{
s = t;
if ((t += HOLE_MIN) > e)
t = e;
{
if (b)
{
{
return -1;
}
return i;
n += i;
b = 0;
}
n += t - s;
}
else if (!b)
b = s;
}
if (b)
{
{
return -1;
}
return i;
n += i;
}
return n;
}
/*
* make a seekable copy of ap->io input
*/
void
{
off_t m;
off_t z;
char* s;
int rfd;
int wfd;
z = 0;
do
{
z += m;
else
}