The patch only includes sysmacros for linux, the only target with gnu libc to avoid regression issues.
679 lines
15 KiB
C
679 lines
15 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: misc.c /main/3 1995/11/01 17:01:03 rswiston $ */
|
|
/***************************************************************
|
|
* *
|
|
* AT&T - PROPRIETARY *
|
|
* *
|
|
* THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
|
|
* AT&T CORP. *
|
|
* *
|
|
* Copyright (c) 1995 AT&T Corp. *
|
|
* All Rights Reserved *
|
|
* *
|
|
* This software is licensed by AT&T Corp. *
|
|
* under the terms and conditions of the license in *
|
|
* http://www.research.att.com/orgs/ssr/book/reuse *
|
|
* *
|
|
* This software was created by the *
|
|
* Software Engineering Research Department *
|
|
* AT&T Bell Laboratories *
|
|
* *
|
|
* For further information contact *
|
|
* gsf@research.att.com *
|
|
* *
|
|
***************************************************************/
|
|
|
|
/* : : generated by proto : : */
|
|
|
|
#if !defined(__PROTO__)
|
|
#if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
|
|
#if defined(__cplusplus)
|
|
#define __MANGLE__ "C"
|
|
#else
|
|
#define __MANGLE__
|
|
#endif
|
|
#define __STDARG__
|
|
#define __PROTO__(x) x
|
|
#define __OTORP__(x)
|
|
#define __PARAM__(n,o) n
|
|
#if !defined(__STDC__) && !defined(__cplusplus)
|
|
#if !defined(c_plusplus)
|
|
#define const
|
|
#endif
|
|
#define signed
|
|
#define void int
|
|
#define volatile
|
|
#define __V_ char
|
|
#else
|
|
#define __V_ void
|
|
#endif
|
|
#else
|
|
#define __PROTO__(x) ()
|
|
#define __OTORP__(x) x
|
|
#define __PARAM__(n,o) o
|
|
#define __MANGLE__
|
|
#define __V_ char
|
|
#define const
|
|
#define signed
|
|
#define void int
|
|
#define volatile
|
|
#endif
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
#define __VARARG__ ...
|
|
#else
|
|
#define __VARARG__
|
|
#endif
|
|
#if defined(__STDARG__)
|
|
#define __VA_START__(p,a) va_start(p,a)
|
|
#else
|
|
#define __VA_START__(p,a) va_start(p)
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__linux__)
|
|
#include <sys/sysmacros.h>
|
|
#endif
|
|
|
|
#include "pax.h"
|
|
#include "options.h"
|
|
|
|
#include <sfdisc.h>
|
|
|
|
/*
|
|
* return format index given format name
|
|
*/
|
|
|
|
int
|
|
getformat __PARAM__((char* name), (name)) __OTORP__(char* name;){
|
|
int i;
|
|
|
|
strlower(name);
|
|
for (i = 0; format[i].name; i++)
|
|
if (streq(name, format[i].name))
|
|
break;
|
|
return(format[i].name ? i : streq(name, "-") || streq(name, "pax") ? OUT_DEFAULT : -1);
|
|
}
|
|
|
|
/*
|
|
* path name strcmp()
|
|
*/
|
|
|
|
static int
|
|
pathcmp __PARAM__((const char* s, const char* t), (s, t)) __OTORP__(const char* s; const char* t;){
|
|
int sc;
|
|
int tc;
|
|
|
|
for (;;)
|
|
{
|
|
tc = *t++;
|
|
if (!(sc = *s++))
|
|
return(tc ? -1 : 0);
|
|
if (sc != tc)
|
|
{
|
|
if (tc == 0 || tc == '/')
|
|
return(1);
|
|
if (sc == '/')
|
|
return(-1);
|
|
return(strcoll(s - 1, t - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* check base archive ordering
|
|
*/
|
|
|
|
static void
|
|
ordered __PARAM__((Archive_t* ap, const char* prv, const char* cur), (ap, prv, cur)) __OTORP__(Archive_t* ap; const char* prv; const char* cur;){
|
|
if (pathcmp(prv, cur) > 0)
|
|
error(3, "%s: %s: archive member must appear before %s", ap->name, prv, cur);
|
|
}
|
|
|
|
/*
|
|
* check f with patterns given on cmd line
|
|
*/
|
|
|
|
int
|
|
selectfile __PARAM__((Archive_t* ap, File_t* f), (ap, f)) __OTORP__(Archive_t* ap; File_t* f;){
|
|
Archive_t* bp;
|
|
Member_t* d;
|
|
int linked = 0;
|
|
|
|
if (f->skip || f->namesize <= 1)
|
|
return(0);
|
|
if (state.ordered)
|
|
{
|
|
ordered(ap, ap->path.prev, f->name);
|
|
strcpy(ap->path.prev, f->name);
|
|
}
|
|
if (f->record.format && state.record.pattern)
|
|
{
|
|
static char fmt[2];
|
|
|
|
fmt[0] = f->record.format;
|
|
if (!strmatch(fmt, state.record.pattern))
|
|
return(0);
|
|
}
|
|
if (state.append || ap->parent)
|
|
{
|
|
linked = 1;
|
|
addlink(ap, f);
|
|
if (!ap->parent)
|
|
return(0);
|
|
if (!(d = newof(0, Member_t, 1, 0)))
|
|
error(3, "%s: out of space", f->name);
|
|
d->dev = f->st->st_dev;
|
|
d->ino = f->st->st_ino;
|
|
d->mtime = f->st->st_mtime;
|
|
d->offset = ap->io.offset + ap->io.count;
|
|
d->size = f->st->st_size;
|
|
d->expand = f->delta.size;
|
|
if (!(d->info = (File_t*)memdup(f, sizeof(File_t))) || !(d->info->st = (struct stat*)memdup(f->st, sizeof(struct stat))))
|
|
error(3, "%s: out of space", f->name);
|
|
d->info->name = d->info->path = hashput(ap->parent->delta->tab, f->name, d);
|
|
if (d->info->uidname) d->info->uidname = strdup(d->info->uidname);
|
|
if (d->info->gidname) d->info->gidname = strdup(d->info->gidname);
|
|
d->info->delta.base = d;
|
|
if (!state.ordered)
|
|
return(0);
|
|
}
|
|
if (!match(f->name) || state.verify && f->type != X_IFDIR && !verify(ap, f))
|
|
return(0);
|
|
ap->selected++;
|
|
if (state.list && !linked)
|
|
addlink(ap, f);
|
|
if (state.ordered && ap->delta && ap->delta->format != COMPRESS && (bp = ap->delta->base))
|
|
{
|
|
int n;
|
|
int m;
|
|
|
|
for (;;)
|
|
{
|
|
if (bp->peek) bp->peek = 0;
|
|
else
|
|
{
|
|
if (bp->skip && bp->skip == bp->io.offset + bp->io.count)
|
|
fileskip(bp, &bp->file);
|
|
if (!getheader(bp, &bp->file)) break;
|
|
bp->skip = bp->io.offset + bp->io.count;
|
|
}
|
|
ordered(bp, bp->path.prev, bp->file.name);
|
|
if ((m = pathcmp(bp->file.name, f->name)) > 0)
|
|
{
|
|
bp->peek = 1;
|
|
break;
|
|
}
|
|
n = selectfile(bp, &bp->file);
|
|
if (!m) break;
|
|
if (n && !state.list)
|
|
{
|
|
if (ap->io.mode)
|
|
{
|
|
File_t tmp;
|
|
|
|
initfile(ap, &tmp, bp->file.name, X_IFREG);
|
|
tmp.delta.op = DELTA_delete;
|
|
putheader(ap, &tmp);
|
|
puttrailer(ap, &tmp);
|
|
}
|
|
else
|
|
{
|
|
struct stat st;
|
|
|
|
if (!(*state.statf)(f->name, &st))
|
|
{
|
|
if (S_ISDIR(st.st_mode))
|
|
{
|
|
if (!streq(f->name, ".") && !streq(f->name, ".."))
|
|
{
|
|
if (rmdir(f->name)) error(ERROR_SYSTEM|2, "%s: cannot remove directory", f->name);
|
|
else listentry(f);
|
|
}
|
|
}
|
|
else if (remove(f->name)) error(ERROR_SYSTEM|2, "%s: cannot remove file", f->name);
|
|
else listentry(f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* verify action on file
|
|
*
|
|
* EOF exit
|
|
* NULL skip file
|
|
* . keep file
|
|
* <else> rename file
|
|
*/
|
|
|
|
int
|
|
verify __PARAM__((Archive_t* ap, File_t* f), (ap, f)) __OTORP__(Archive_t* ap; File_t* f;){
|
|
char* prompt;
|
|
char* name;
|
|
|
|
NoP(ap);
|
|
if (state.yesno) switch (state.operation)
|
|
{
|
|
case IN:
|
|
prompt = "Read";
|
|
break;
|
|
case OUT:
|
|
prompt = "Write";
|
|
break;
|
|
default:
|
|
prompt = "Pass";
|
|
break;
|
|
}
|
|
else prompt = "Rename";
|
|
sfprintf(state.wtty, "%s %s: " , prompt, f->name);
|
|
if (!(name = sfgetr(state.rtty, '\n', 1)))
|
|
{
|
|
sfputc(state.wtty, '\n');
|
|
finish(2);
|
|
}
|
|
if (state.yesno)
|
|
return(*name == 'y');
|
|
switch (*name)
|
|
{
|
|
case 0:
|
|
return(0);
|
|
case '.':
|
|
if (!*(name + 1)) break;
|
|
/*FALLTHROUGH*/
|
|
default:
|
|
f->namesize = pathcanon(f->name = name, 0) - name + 1;
|
|
break;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* check for file name mapping
|
|
* static data possibly returned
|
|
* two simultaneous calls supported
|
|
*/
|
|
|
|
char*
|
|
map __PARAM__((char* name), (name)) __OTORP__(char* name;){
|
|
Map_t* mp;
|
|
char* to;
|
|
char* from;
|
|
|
|
static char filebuffer[4][PATH_MAX];
|
|
static int filename = 0;
|
|
|
|
filename ^= 2;
|
|
from = to = name;
|
|
for (mp = state.maps; mp; mp = mp->next)
|
|
if (reexec(mp->re, from))
|
|
{
|
|
filename ^= 1;
|
|
to = filebuffer[filename];
|
|
resub(mp->re, from, mp->into, to, mp->flags);
|
|
if (mp->flags & RE_VERBOSE) sfprintf(sfstderr, "%s >> %s\n", from, to);
|
|
if (mp->flags & RE_STOP) break;
|
|
from = to;
|
|
}
|
|
return(to);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
Archive_t* archive;
|
|
File_t* file;
|
|
} List_handle_t;
|
|
|
|
/*
|
|
* sfkeyprintf() lookup
|
|
*/
|
|
|
|
static int
|
|
listlookup __PARAM__((__V_* handle, const char* name, const char* arg, int cc, char** ps, long* pn), (handle, name, arg, cc, ps, pn)) __OTORP__(__V_* handle; const char* name; const char* arg; int cc; char** ps; long* pn;){
|
|
List_handle_t* gp = (List_handle_t*)handle;
|
|
File_t* f = gp->file;
|
|
struct stat* st = f->st;
|
|
char* s = 0;
|
|
long n = 0;
|
|
Option_t* op;
|
|
|
|
static Sfio_t* mp;
|
|
static const char fmt_time[] = "time=%?%l";
|
|
static const char fmt_mode[] = "mode";
|
|
|
|
static char buf[PATH_MAX];
|
|
static char huh[8];
|
|
|
|
if (!(op = (Option_t*)hashget(state.options, name)))
|
|
{
|
|
if (*name != '$')
|
|
return(0);
|
|
if (!(op = newof(0, Option_t, 1, 0)))
|
|
error(3, "out of space [option]");
|
|
op->name = hashput(state.options, 0, op);
|
|
op->macro = getenv(name + 1);
|
|
op->index = OPT_environ;
|
|
op->flags |= OPT_DISABLE;
|
|
}
|
|
if (op->macro && !(op->flags & OPT_DISABLE))
|
|
{
|
|
op->flags |= OPT_DISABLE;
|
|
if (!mp && !(mp = sfstropen()))
|
|
error(3, "out of space [macro]");
|
|
sfkeyprintf(mp, handle, op->macro, listlookup, NiL);
|
|
s = sfstruse(mp);
|
|
op->flags &= ~OPT_DISABLE;
|
|
}
|
|
else switch (op->index)
|
|
{
|
|
case OPT_atime:
|
|
n = st->st_atime;
|
|
if (!arg)
|
|
arg = fmt_time;
|
|
break;
|
|
case OPT_charset:
|
|
s = "ASCII";
|
|
break;
|
|
case OPT_chksum:
|
|
case OPT_magic:
|
|
case OPT_typeflag:
|
|
case OPT_version:
|
|
if (!gp->archive || gp->archive->format != PAX && gp->archive->format != TAR && gp->archive->format != USTAR)
|
|
return(0);
|
|
switch (op->index)
|
|
{
|
|
case OPT_chksum:
|
|
s = tar_header.chksum;
|
|
break;
|
|
case OPT_magic:
|
|
s = tar_header.magic;
|
|
break;
|
|
case OPT_typeflag:
|
|
n = tar_header.typeflag;
|
|
break;
|
|
case OPT_version:
|
|
s = tar_header.version;
|
|
break;
|
|
}
|
|
break;
|
|
case OPT_ctime:
|
|
n = st->st_ctime;
|
|
if (!arg)
|
|
arg = fmt_time;
|
|
break;
|
|
case OPT_delta:
|
|
switch (f->delta.op)
|
|
{
|
|
case 0:
|
|
case DELTA_pass:
|
|
return(0);
|
|
case DELTA_create:
|
|
s = "create";
|
|
break;
|
|
case DELTA_delete:
|
|
s = "delete";
|
|
break;
|
|
case DELTA_update:
|
|
s = "update";
|
|
break;
|
|
case DELTA_verify:
|
|
s = "verify";
|
|
break;
|
|
default:
|
|
sfsprintf(s = huh, sizeof(huh), "[op=%c]", f->delta.op);
|
|
break;
|
|
}
|
|
break;
|
|
case OPT_device:
|
|
if (f->type == X_IFBLK || f->type == X_IFCHR)
|
|
s = fmtdev(st);
|
|
else return(0);
|
|
break;
|
|
case OPT_devmajor:
|
|
n = major(st->st_dev);
|
|
break;
|
|
case OPT_devminor:
|
|
n = minor(st->st_dev);
|
|
break;
|
|
case OPT_environ:
|
|
if (!(s = op->macro))
|
|
return(0);
|
|
break;
|
|
case OPT_gname:
|
|
if (f->gidname)
|
|
{
|
|
if (cc == 's') s = f->gidname;
|
|
else n = strgid(f->gidname);
|
|
}
|
|
else if (cc == 's') s = fmtgid(st->st_gid);
|
|
else n = st->st_gid;
|
|
break;
|
|
case OPT_ino:
|
|
n = st->st_ino;
|
|
break;
|
|
case OPT_linkop:
|
|
switch (f->linktype)
|
|
{
|
|
case HARDLINK:
|
|
s = "==";
|
|
break;
|
|
case SOFTLINK:
|
|
s = "->";
|
|
break;
|
|
default:
|
|
return(0);
|
|
}
|
|
break;
|
|
case OPT_linkpath:
|
|
if (f->linktype == NOLINK)
|
|
return(0);
|
|
s = f->linkname;
|
|
break;
|
|
case OPT_mark:
|
|
if (f->linktype == HARDLINK)
|
|
s = "=";
|
|
else if (f->linktype == SOFTLINK)
|
|
s = "@";
|
|
else if (f->type == X_IFDIR)
|
|
s = "/";
|
|
else if (f->type == X_IFIFO || f->type == X_IFSOCK)
|
|
s = "|";
|
|
else if (f->type == X_IFBLK || f->type == X_IFCHR)
|
|
s = "$";
|
|
else if (st->st_mode & (X_IXUSR|X_IXGRP|X_IXOTH))
|
|
s = "*";
|
|
else return(0);
|
|
break;
|
|
case OPT_mode:
|
|
n = st->st_mode;
|
|
if (!arg)
|
|
arg = fmt_mode;
|
|
break;
|
|
case OPT_mtime:
|
|
n = st->st_mtime;
|
|
if (!arg)
|
|
arg = fmt_time;
|
|
break;
|
|
case OPT_name:
|
|
if (s = strrchr(f->name, '/')) s++;
|
|
else s = f->name;
|
|
break;
|
|
case OPT_nlink:
|
|
n = st->st_nlink;
|
|
break;
|
|
case OPT_path:
|
|
s = f->name;
|
|
break;
|
|
case OPT_sequence:
|
|
sfsprintf(s = buf, sizeof(buf), "%d-%d", gp->archive->volume, gp->archive->entry);
|
|
break;
|
|
case OPT_size:
|
|
if (f->linktype == SOFTLINK) n = f->linknamesize - 1;
|
|
else if (f->delta.size != -1) n = f->delta.size;
|
|
else n = st->st_size;
|
|
break;
|
|
case OPT_uname:
|
|
if (f->uidname)
|
|
{
|
|
if (cc == 's') s = f->uidname;
|
|
else n = strgid(f->uidname);
|
|
}
|
|
else if (cc == 's') s = fmtuid(st->st_uid);
|
|
else n = st->st_uid;
|
|
break;
|
|
default:
|
|
return(0);
|
|
}
|
|
if (s) *ps = s;
|
|
else if (cc == 's' && arg)
|
|
{
|
|
if (strneq(arg, fmt_mode, 4))
|
|
*ps = fmtmode(n, 1);
|
|
else if (strneq(arg, fmt_time, 4))
|
|
*ps = fmttime((*(arg + 4) == '=' ? arg : fmt_time) + 5, n);
|
|
}
|
|
else *pn = n;
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* set up lookup() handle and call sfkeyprintf()
|
|
*/
|
|
|
|
int
|
|
listprintf __PARAM__((Sfio_t* sp, Archive_t* ap, File_t* f, const char* format), (sp, ap, f, format)) __OTORP__(Sfio_t* sp; Archive_t* ap; File_t* f; const char* format;){
|
|
List_handle_t list;
|
|
|
|
NoP(ap);
|
|
list.archive = state.in;
|
|
list.file = f;
|
|
return(sfkeyprintf(sp, &list, format, listlookup, NiL));
|
|
}
|
|
|
|
/*
|
|
* list entry information based on state.drop, state.list and state.verbose
|
|
*/
|
|
|
|
void
|
|
listentry __PARAM__((File_t* f), (f)) __OTORP__(File_t* f;){
|
|
if (!f->extended && !f->skip && (state.drop || state.list || state.verbose))
|
|
{
|
|
if (state.drop)
|
|
{
|
|
if (++state.dropcount >= 50)
|
|
{
|
|
state.dropcount = 0;
|
|
sfprintf(sfstderr, ".\n");
|
|
}
|
|
else
|
|
{
|
|
sfprintf(sfstderr, ".");
|
|
sfsync(sfstderr);
|
|
}
|
|
}
|
|
else listprintf(state.list ? sfstdout : sfstderr, state.in, f, state.listformat);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* prepare patterns for match()
|
|
*/
|
|
|
|
char**
|
|
initmatch __PARAM__((char** p), (p)) __OTORP__(char** p;){
|
|
char** a;
|
|
|
|
a = p;
|
|
while (*a)
|
|
pathcanon(*a++, 0);
|
|
return(p);
|
|
}
|
|
|
|
/*
|
|
* determine if file s matches input patterns
|
|
*/
|
|
|
|
int
|
|
match __PARAM__((char* s), (s)) __OTORP__(char* s;){
|
|
char** p;
|
|
char* t;
|
|
int n;
|
|
|
|
if (!(p = state.patterns)) return(state.matchsense);
|
|
if (state.exact)
|
|
{
|
|
n = 0;
|
|
while (t = *p++)
|
|
if (*t)
|
|
{
|
|
if (streq(s, t))
|
|
{
|
|
*--p = "";
|
|
return(1);
|
|
}
|
|
n = 1;
|
|
}
|
|
if (!n) finish(0);
|
|
}
|
|
else while (t = *p++)
|
|
{
|
|
if (state.descend && dirprefix(t, s) || strmatch(s, t))
|
|
return(state.matchsense);
|
|
}
|
|
return(!state.matchsense);
|
|
}
|
|
|
|
/*
|
|
* return 1 if p is a directory prefix of s
|
|
*/
|
|
|
|
int
|
|
dirprefix __PARAM__((char* p, char* s), (p, s)) __OTORP__(char* p; char* s;){
|
|
if (*p == '.' && !*(p + 1) && *s != '/' && (*s != '.' || *(s + 1) != '.' || *(s + 2) && *(s + 2) != '/'))
|
|
return(1);
|
|
if (*p == '/' && !*(p + 1))
|
|
return(*s == '/');
|
|
while (*p)
|
|
if (*p++ != *s++)
|
|
return(0);
|
|
return(!*s || *s == '/');
|
|
}
|
|
|
|
/*
|
|
* return 1 if s is a portable string
|
|
*/
|
|
|
|
int
|
|
portable __PARAM__((const char* s), (s)) __OTORP__(const char* s;){
|
|
unsigned char* u = (unsigned char*)s;
|
|
int c;
|
|
|
|
while (c = *s++)
|
|
if (c > 0177)
|
|
return(0);
|
|
return(1);
|
|
}
|