summaryrefslogtreecommitdiff
path: root/lib/cpio.c
diff options
context:
space:
mode:
authorjbj <devnull@localhost>2001-02-01 20:19:17 +0000
committerjbj <devnull@localhost>2001-02-01 20:19:17 +0000
commitac1a303d16136b4f1312ba4c1b6a1c5cba6c87f8 (patch)
tree189adbd61ae01ddfde4b727c6934f345e7db337a /lib/cpio.c
parent618184c4bf450b09f0fa82ac5b57460289b24cf6 (diff)
downloadrpm-ac1a303d16136b4f1312ba4c1b6a1c5cba6c87f8.tar.gz
rpm-ac1a303d16136b4f1312ba4c1b6a1c5cba6c87f8.tar.bz2
rpm-ac1a303d16136b4f1312ba4c1b6a1c5cba6c87f8.zip
Handle links correctly, wotta PITA. Now to clean up and find the double free ...
CVS patchset: 4512 CVS date: 2001/02/01 20:19:17
Diffstat (limited to 'lib/cpio.c')
-rw-r--r--lib/cpio.c472
1 files changed, 338 insertions, 134 deletions
diff --git a/lib/cpio.c b/lib/cpio.c
index 5a9b990de..2ef39f525 100644
--- a/lib/cpio.c
+++ b/lib/cpio.c
@@ -25,7 +25,7 @@
#define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
-static inline /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
+static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
if (this) free((void *)this);
return NULL;
}
@@ -54,11 +54,14 @@ struct cpioFileMapping {
struct hardLink {
/*@dependent@*/ struct hardLink * next;
/*@owned@*/ const char ** files; /* nlink of these, used by install */
+/*@owned@*/ const char ** nsuffix;
/*@owned@*/ const void ** fileMaps;
+/*@owned@*/ int * filex;
dev_t dev;
ino_t inode;
int nlink;
int linksLeft;
+ int linkIndex;
int createdPath;
const struct stat sb;
};
@@ -215,7 +218,7 @@ static inline /*@null@*/ void * mapFree(/*@only@*/ const void * this) {
struct dnli {
/*@dependent@*/ TFI_t fi;
/*@only@*/ /*@null@*/ char * active;
- int dc;
+ int reverse;
int i;
};
@@ -233,28 +236,79 @@ static /*@null@*/ void * dnlFreeIterator(/*@only@*/ /*@null@*/ const void * this
static int dnlCount(void * this)
{
struct dnli * dnli = this;
- return dnli->dc;
+ return (dnli ? dnli->fi->dc : 0);
}
+
+static int dnlIndex(void * this)
+{
+ struct dnli * dnli = this;
+ return (dnli ? dnli->i : -1);
+}
+
/**
*/
-static /*@only@*/ void * dnlInitIterator(/*@null@*/ const void * this)
+static /*@only@*/ void * dnlInitIterator(/*@null@*/ const void * this,
+ int reverse)
{
const struct mapi * mapi = this;
struct dnli * dnli;
TFI_t fi;
- int i;
+ int i, j;
if (mapi == NULL)
return NULL;
fi = mapi->fi;
dnli = xcalloc(1, sizeof(*dnli));
dnli->fi = fi;
- dnli->i = fi->dc;
- if (fi->dc) dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
- for (i = 0; i < fi->fc; i++)
- if (!XFA_SKIPPING(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
- for (i = 0, dnli->dc = 0; i < fi->dc; i++)
- if (dnli->active[i]) dnli->dc++;
+ dnli->reverse = reverse;
+ dnli->i = (reverse ? fi->dc : 0);
+
+ if (fi->dc) {
+ dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
+
+ /* Identify parent directories not skipped. */
+ for (i = 0; i < fi->fc; i++)
+ if (!XFA_SKIPPING(fi->actions[i])) dnli->active[fi->dil[i]] = 1;
+
+ /* Exclude parent directories that are explicitly included. */
+ for (i = 0; i < fi->fc; i++) {
+ int dil, dnlen, bnlen;
+ if (!S_ISDIR(fi->fmodes[i]))
+ continue;
+ dil = fi->dil[i];
+ dnlen = strlen(fi->dnl[dil]);
+ bnlen = strlen(fi->bnl[i]);
+ for (j = 0; j < fi->dc; j++) {
+ const char * dnl;
+ int jlen;
+ if (!dnli->active[j] || j == dil) continue;
+ dnl = fi->dnl[j];
+ jlen = strlen(dnl);
+ if (jlen != (dnlen+bnlen+1)) continue;
+ if (strncmp(dnl, fi->dnl[dil], dnlen)) continue;
+ if (strncmp(dnl+dnlen, fi->bnl[i], bnlen)) continue;
+ if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
+ continue;
+ dnli->active[j] = 0;
+ break;
+ }
+ }
+ /* Print only once per package. */
+ if (!reverse) {
+ j = 0;
+ for (i = 0; i < fi->dc; i++) {
+ if (!dnli->active[i]) continue;
+ if (j == 0) {
+ j = 1;
+ rpmMessage(RPMMESS_DEBUG,
+ _("========= Directories not explictly included in package:\n"));
+ }
+ rpmMessage(RPMMESS_DEBUG, _("%9d %s\n"), i, fi->dnl[i]);
+ }
+ if (j)
+ rpmMessage(RPMMESS_DEBUG, _("=========\n"));
+ }
+ }
return dnli;
}
@@ -266,9 +320,9 @@ static const char * dnlNextIterator(void * this) {
int i;
do {
- i = --dnli->i;
- } while (i >= 0 && !dnli->active[i]);
- return (i >= 0 ? fi->dnl[i] : NULL);
+ i = (!dnli->reverse ? dnli->i++ : --dnli->i);
+ } while (i >= 0 && i < dnli->fi->dc && !dnli->active[i]);
+ return (i >= 0 && i < dnli->fi->dc ? fi->dnl[i] : NULL);
}
/**
@@ -517,17 +571,22 @@ static /*@only@*/ struct hardLink * newHardLink(const struct stat * st,
li->nlink = st->st_nlink;
li->dev = st->st_dev;
li->inode = st->st_ino;
+ li->linkIndex = -1;
li->createdPath = -1;
+ li->filex = xcalloc(st->st_nlink, sizeof(li->filex[0]));
+ memset(li->filex, -1, (st->st_nlink * sizeof(li->filex[0])));
switch (hltype) {
- case HARDLINK_INSTALL:
+ case HARDLINK_BUILD:
li->linksLeft = st->st_nlink;
li->fileMaps = xcalloc(st->st_nlink, sizeof(li->fileMaps[0]));
+ li->nsuffix = NULL;
li->files = NULL;
break;
- case HARDLINK_BUILD:
+ case HARDLINK_INSTALL:
li->linksLeft = 0;
li->fileMaps = NULL;
+ li->nsuffix = xcalloc(st->st_nlink, sizeof(li->nsuffix[0]));
li->files = xcalloc(st->st_nlink, sizeof(*li->files));
break;
}
@@ -555,7 +614,9 @@ static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink * li
}
}
li->files = _free(li->files);
+ li->nsuffix = _free(li->nsuffix); /* XXX elements are shared */
li->fileMaps = _free(li->fileMaps);
+ li->filex = _free(li->filex);
}
return _free(li);
}
@@ -583,6 +644,8 @@ struct cpioHeader {
int ldnlen;
int ldnalloc;
int postpone;
+ int statdone;
+ int mkdirsdone;
mode_t dperms;
mode_t fperms;
int rc;
@@ -787,12 +850,6 @@ static int getNextHeader(FSM_t fsm, struct stat * st)
fsm->path = t;
}
- /* this is unecessary fsm->path[nameSize] = '\0'; */
-
-#ifdef DYING
- (void) fsmStage(fsm, FSM_POS);
-#endif
-
return 0;
}
@@ -813,7 +870,8 @@ static int expandRegular(FSM_t fsm)
int left = st->st_size;
int rc = 0;
- filemd5 = mapMd5sum(fsm->map);
+/* XXX HACK_ALERT: something fubar with linked files. */
+ filemd5 = (st->st_nlink == 1 ? mapMd5sum(fsm->map) : NULL);
{
const char * opath = fsm->opath;
@@ -825,7 +883,8 @@ static int expandRegular(FSM_t fsm)
if (rc == 0 && fsm->osuffix) {
fsm->opath = fsm->path;
fsm->path = mapFsPath(fsm->map, st, NULL, fsm->osuffix);
- (void) fsmStage(fsm, FSM_RENAME);
+ rc = fsmStage(fsm, FSM_RENAME);
+if (!rc)
rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"), fsm->opath, fsm->path);
fsm->path = _free(fsm->path);
fsm->opath = _free(fsm->opath);
@@ -885,6 +944,75 @@ rpmMessage(RPMMESS_WARNING, _("%s saved as %s\n"), fsm->opath, fsm->path);
return rc;
}
+static int fsmMakeLinks(FSM_t fsm)
+{
+ const char * path = fsm->path;
+ const char * opath = fsm->opath;
+ int rc = 0;
+ int i;
+
+ fsm->opath = fsm->li->files[fsm->li->createdPath];
+ for (i = 0; i < fsm->li->nlink; i++) {
+ if (fsm->li->filex[i] < 0) continue;
+ if (i == fsm->li->createdPath) continue;
+ if (fsm->li->files[i] == NULL) continue;
+
+ fsm->path = fsm->li->files[i];
+ rc = fsmStage(fsm, FSM_VERIFY);
+ if (!rc) continue;
+ if (rc != CPIOERR_LSTAT_FAILED) break;
+
+ /* XXX link(fsm->opath, fsm->path) */
+ rc = fsmStage(fsm, FSM_LINK);
+ if (rc) break;
+
+#ifdef DYING
+ /*@-unqualifiedtrans@*/
+ fsm->li->files[i] = _free(fsm->li->files[i]);
+ /*@=unqualifiedtrans@*/
+#endif
+ fsm->li->linksLeft--;
+ }
+
+ if (rc && fsm->failedFile && *fsm->failedFile == NULL)
+ *fsm->failedFile = xstrdup(fsm->path);
+
+ fsm->path = path;
+ fsm->opath = opath;
+
+ return rc;
+}
+
+static int fsmCommitLinks(FSM_t fsm)
+{
+ const char * path = fsm->path;
+ const char * nsuffix = fsm->nsuffix;
+ struct stat * st = &fsm->sb;
+ struct mapi * mapi = fsm->mapi;
+ int mapiIndex = mapi->i;
+ int rc = 0;
+ int i;
+
+ for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
+ if (fsm->li->inode == st->st_ino && fsm->li->dev == st->st_dev)
+ break;
+ }
+
+ for (i = 0; i < fsm->li->nlink; i++) {
+ if (fsm->li->files[i] == NULL) continue;
+ mapi->i = fsm->li->filex[i];
+ fsm->path = xstrdup(fsm->li->files[i]);
+ rc = fsmStage(fsm, FSM_FINALIZE);
+ fsm->path = _free(fsm->path);
+ fsm->li->filex[i] = -1;
+ }
+
+ mapi->i = mapiIndex;
+ fsm->nsuffix = nsuffix;
+ fsm->path = path;
+ return rc;
+}
+
int fsmStage(FSM_t fsm, fileStage stage)
{
#ifdef UNUSED
@@ -922,18 +1050,24 @@ int fsmStage(FSM_t fsm, fileStage stage)
break;
case FSM_CREATE:
fsm->path = NULL;
+ fsm->dnlx = _free(fsm->dnlx);
fsm->ldn = _free(fsm->ldn);
fsm->ldnalloc = fsm->ldnlen = 0;
+ fsm->mkdirsdone = 0;
fsm->map = NULL;
fsm->links = NULL;
- fsm->dnlx = NULL;
fsm->li = NULL;
errno = 0; /* XXX get rid of EBADF */
+
+#ifdef NOTYET
+ rc = fsmStage(fsm, FSM_MKDIRS);
+#endif
+
break;
case FSM_INIT:
fsm->path = _free(fsm->path);
- fsm->dnlx = _free(fsm->dnlx);
fsm->postpone = 0;
+ fsm->statdone = 0;
fsm->dperms = 0755;
fsm->fperms = 0644;
fsm->subdir = NULL;
@@ -941,11 +1075,18 @@ int fsmStage(FSM_t fsm, fileStage stage)
fsm->action = FA_UNKNOWN;
fsm->osuffix = NULL;
fsm->nsuffix = NULL;
+
if (fsm->cfd) {
+ /* Read next header from payload. */
rc = fsmStage(fsm, FSM_POS);
if (!rc)
rc = fsmStage(fsm, FSM_NEXT);
}
+
+ /* Remap mode/uid/gid/name of file from archive. */
+ if (!rc)
+ rc = fsmStage(fsm, FSM_MAP);
+
/* FSM_INIT -> {FSM_PRE,FSM_DESTROY} */
break;
case FSM_MAP:
@@ -971,9 +1112,10 @@ int fsmStage(FSM_t fsm, fileStage stage)
case FSM_MKDIRS:
{ const char * path = fsm->path;
mode_t st_mode = st->st_mode;
- void * dnli = dnlInitIterator(fsm->mapi);
+ void * dnli = dnlInitIterator(fsm->mapi, 0);
char dn[BUFSIZ]; /* XXX add to fsm */
int dc = dnlCount(dnli);
+ int i;
dn[0] = '\0';
fsm->dnlx = (dc ? xcalloc(dc, sizeof(*fsm->dnlx)) : NULL);
@@ -981,36 +1123,62 @@ int fsmStage(FSM_t fsm, fileStage stage)
int dnlen = strlen(fsm->path);
char * te;
- dc--;
+ dc = dnlIndex(dnli);
fsm->dnlx[dc] = dnlen;
if (dnlen <= 1)
continue;
- if (fsm->ldnlen >= dnlen && !strcmp(fsm->path, fsm->ldn))
+ if (dnlen <= fsm->ldnlen && !strcmp(fsm->path, fsm->ldn))
continue;
- if (fsm->ldnalloc < (dnlen + 1)) {
- fsm->ldnalloc = dnlen + 100;
- fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
- }
- strcpy(fsm->ldn, fsm->path);
- fsm->ldnlen = dnlen;
-
+ /* Copy to avoid const on fsm->path. */
(void) stpcpy(dn, fsm->path);
fsm->path = dn;
- st->st_mode = S_IFDIR | 0000; /* XXX abuse st->st_mode */
- for (te = dn + 1; *te; te++) {
+
+ /* Initial mode for created dirs is 0700 */
+ st->st_mode &= ~07777; /* XXX abuse st->st_mode */
+ st->st_mode |= 00700;
+
+ /* Assume '/' directory, otherwise "mkdir -p" */
+ for (i = 1, te = dn + 1; *te; te++, i++) {
if (*te != '/') continue;
+
*te = '\0';
- rc = fsmStage(fsm, FSM_VERIFY);
- /* Move verified path location forward. */
- if (rc == 0)
+ /* Already validated? */
+ if (i < fsm->ldnlen &&
+ (fsm->ldn[i] == '/' || fsm->ldn[i] == '\0') &&
+ !strncmp(fsm->path, fsm->ldn, i))
+ {
+ *te = '/';
+ /* Move pre-existing path marker forward. */
fsm->dnlx[dc] = (te - dn);
- else if (rc == CPIOERR_LSTAT_FAILED)
- rc = fsmStage(fsm, FSM_MKDIR);
+ continue;
+ }
+
+ /* Validate next component of path. */
+ rc = fsmStage(fsm, FSM_LSTAT);
*te = '/';
+
+ /* Directory already exists? */
+ if (rc == 0 && S_ISDIR(ost->st_mode)) {
+ /* Move pre-existing path marker forward. */
+ fsm->dnlx[dc] = (te - dn);
+ } else if (rc == CPIOERR_LSTAT_FAILED) {
+ *te = '\0';
+ rc = fsmStage(fsm, FSM_MKDIR);
+ *te = '/';
+ }
if (rc) break;
}
+ if (rc) break;
+
+ /* Save last validated path. */
+ if (fsm->ldnalloc < (dnlen + 1)) {
+ fsm->ldnalloc = dnlen + 100;
+ fsm->ldn = xrealloc(fsm->ldn, fsm->ldnalloc);
+ }
+ strcpy(fsm->ldn, fsm->path);
+ fsm->ldnlen = dnlen;
}
dnli = dnlFreeIterator(dnli);
fsm->path = path;
@@ -1020,7 +1188,7 @@ int fsmStage(FSM_t fsm, fileStage stage)
case FSM_RMDIRS:
if (fsm->dnlx) {
const char * path = fsm->path;
- void * dnli = dnlInitIterator(fsm->mapi);
+ void * dnli = dnlInitIterator(fsm->mapi, 1);
char dn[BUFSIZ]; /* XXX add to fsm */
int dc = dnlCount(dnli);
@@ -1028,12 +1196,16 @@ int fsmStage(FSM_t fsm, fileStage stage)
while ((fsm->path = dnlNextIterator(dnli)) != NULL) {
int dnlen = strlen(fsm->path);
char * te;
- dc--;
- if (fsm->dnlx[dc] == 0 || fsm->dnlx[dc] >= dnlen)
+
+ dc = dnlIndex(dnli);
+ if (fsm->dnlx[dc] < 1 || fsm->dnlx[dc] >= dnlen)
continue;
+ /* Copy to avoid const on fsm->path. */
te = stpcpy(dn, fsm->path) - 1;
fsm->path = dn;
+
+ /* Remove generated directories. */
do {
if (*te == '/') {
*te = '\0';
@@ -1049,27 +1221,51 @@ int fsmStage(FSM_t fsm, fileStage stage)
}
break;
case FSM_PRE:
- /* Remap mode/uid/gid/name of file from archive. */
- (void) fsmStage(fsm, FSM_MAP);
-
- /*
- * This won't get hard linked symlinks right, but I can't seem
- * to create those anyway.
- */
if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
for (fsm->li = fsm->links; fsm->li; fsm->li = fsm->li->next) {
if (fsm->li->inode == st->st_ino && fsm->li->dev == st->st_dev)
break;
}
+ /* Save new hard link set. */
if (fsm->li == NULL) {
- fsm->li = newHardLink(st, HARDLINK_BUILD);
+ fsm->li = newHardLink(st, HARDLINK_INSTALL);
fsm->li->next = fsm->links;
fsm->links = fsm->li;
}
- fsm->li->files[fsm->li->linksLeft++] = xstrdup(fsm->path);
+ fsm->li->filex[fsm->li->linksLeft] = fsmGetIndex(fsm);
+ fsm->li->files[fsm->li->linksLeft] = xstrdup(fsm->path);
+ /* XXX this is just an observer pointer. */
+ fsm->li->nsuffix[fsm->li->linksLeft] = fsm->nsuffix;
+fprintf(stderr, "*** %p link[%d:%d] %d filex %d %s\n", fsm->li, fsm->li->linksLeft, st->st_nlink, (int)st->st_size, fsm->li->filex[fsm->li->linksLeft], fsm->li->files[fsm->li->linksLeft]);
+ fsm->li->linksLeft++;
+
+ if (!(st->st_size || fsm->li->linksLeft == st->st_nlink)) {
+ fsm->postpone = 1;
+ } else {
+ TFI_t fi = fsmGetFi(fsm);
+ int j;
+
+ /* Here come the bits, time to choose a non-skipped file name. */
+ for (j = fsm->li->linksLeft - 1; j >= 0; j--) {
+ i = fsm->li->filex[j];
+ if (i < 0 || XFA_SKIPPING(fi->actions[i]))
+ continue;
+ break;
+ }
+ /* Are all links skipped or not encountered yet? */
+ if (j < 0) {
+ /* XXX W2DO? */
+ fsm->postpone = 1;
+ } else {
+ fsm->li->linkIndex = j;
+ fsm->path = _free(fsm->path);
+ fsm->path = xstrdup(fsm->li->files[j]);
+ }
+ }
}
+#ifdef DYING
/* XXX FIXME 0 length hard linked files are broke here. */
if (S_ISREG(st->st_mode) && st->st_nlink > 1 &&
@@ -1080,23 +1276,21 @@ int fsmStage(FSM_t fsm, fileStage stage)
fsm->li->createdPath != -1)
{
rc = fsmStage(fsm, FSM_MKLINKS);
-
-#ifdef DYING
- /*
- * This only happens for cpio archives which contain
- * hardlinks w/ the contents of each hardlink being
- * listed (intead of the data being given just once. This
- * shouldn't happen, but I've made it happen w/ buggy
- * code, so what the heck? GNU cpio handles this well fwiw.
- */
- (void) fsmStage(fsm, FSM_EAT);
-#endif
fsm->postpone = 1; /* defer file creation */
- } else {
+ }
+#endif
+
+ else {
+#ifndef DYING
/* @todo This makes all dir paths, only needs doing once. */
- rc = fsmStage(fsm, FSM_MKDIRS);
+ if (!fsm->mkdirsdone) {
+ rc = fsmStage(fsm, FSM_MKDIRS);
+ fsm->mkdirsdone = 1;
+ }
+#endif
fsm->postpone = XFA_SKIPPING(fsm->action);
}
+
if (fsm->postpone) {
if (fsm->cfd) {
(void) fsmStage(fsm, FSM_POS);
@@ -1104,11 +1298,11 @@ int fsmStage(FSM_t fsm, fileStage stage)
}
/* FSM_PRE -> FSM_INIT */
}
+ if (fsm->cfd)
+ (void) fsmStage(fsm, FSM_POS);
/* FSM_PRE -> FSM_PROCESS */
break;
case FSM_PROCESS:
- if (fsm->cfd)
- (void) fsmStage(fsm, FSM_POS);
if (fsm->postpone)
break;
if (S_ISREG(st->st_mode)) {
@@ -1118,13 +1312,20 @@ int fsmStage(FSM_t fsm, fileStage stage)
mode_t st_mode = st->st_mode;
rc = fsmStage(fsm, FSM_VERIFY);
if (rc == CPIOERR_LSTAT_FAILED) {
+#ifdef DYING
st->st_mode = S_IFDIR | 0000; /* XXX abuse st->st_mode */
+#else
+ st->st_mode &= ~07777; /* XXX abuse st->st_mode */
+ st->st_mode |= 00700;
+#endif
rc = fsmStage(fsm, FSM_MKDIR);
st->st_mode = st_mode; /* XXX restore st->st_mode */
}
+#ifdef DYING
/* XXX check old dir perms and warn */
if (!rc)
rc = fsmStage(fsm, FSM_CHMOD);
+#endif
} else if (S_ISLNK(st->st_mode)) {
const char * opath = fsm->opath;
char buf[2048]; /* XXX add to fsm */
@@ -1166,23 +1367,19 @@ int fsmStage(FSM_t fsm, fileStage stage)
case FSM_POST:
if (fsm->postpone)
break;
-#ifdef DYING
- if (S_ISLNK(st->st_mode)) {
- if (!getuid()) rc = fsmStage(fsm, FSM_LCHOWN);
- } else {
- if (!getuid()) rc = fsmStage(fsm, FSM_CHOWN);
- if (!rc) rc = fsmStage(fsm, FSM_CHMOD);
- if (!rc) rc = fsmStage(fsm, FSM_UTIME);
- }
-#endif
/* XXX nlink > 1, insure that path/createdPath is non-skipped. */
if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
+#ifdef DYING
fsm->li->createdPath = --fsm->li->linksLeft;
+#else
+ fsm->li->createdPath = fsm->li->linkIndex;
+#endif
rc = fsmStage(fsm, FSM_MKLINKS);
}
/* FSM_POST -> {FSM_COMMIT,FSM_UNDO} */
break;
case FSM_MKLINKS:
+#ifdef DYING
{ const char * path = fsm->path;
const char * opath = fsm->opath;
@@ -1210,6 +1407,9 @@ int fsmStage(FSM_t fsm, fileStage stage)
fsm->path = path;
fsm->opath = opath;
}
+#else
+ rc = fsmMakeLinks(fsm);
+#endif
break;
case FSM_NOTIFY: /* XXX move from fsm to psm -> tsm */
{ rpmTransactionSet ts = fsmGetTs(fsm);
@@ -1238,31 +1438,47 @@ int fsmStage(FSM_t fsm, fileStage stage)
/* FSM_UNDO -> FSM_INIT */
break;
case FSM_COMMIT:
- if (fsm->postpone)
- break;
- if (mapCommit(fsm->map)) {
- if (!S_ISDIR(st->st_mode) && (fsm->subdir || fsm->suffix)) {
- fsm->opath = fsm->path;
- fsm->path = mapFsPath(fsm->map, st, NULL, fsm->nsuffix);
- rc = fsmStage(fsm, FSM_RENAME);
+ if (!fsm->postpone && mapCommit(fsm->map)) {
+ if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
+ rc = fsmCommitLinks(fsm);
+ } else {
+ rc = fsmStage(fsm, FSM_FINALIZE);
+ }
+ }
+ fsm->path = _free(fsm->path);
+ memset(st, 0, sizeof(*st));
+ /* FSM_COMMIT -> FSM_INIT */
+ break;
+ case FSM_FINALIZE:
+ if (!S_ISDIR(st->st_mode) && (fsm->subdir || fsm->suffix)) {
+ fsm->opath = fsm->path;
+ fsm->path = mapFsPath(fsm->map, st, NULL, fsm->nsuffix);
+ rc = fsmStage(fsm, FSM_RENAME);
if (!rc && fsm->nsuffix) {
-const char * opath = mapFsPath(fsm->map, st, NULL, opath);
+const char * opath = mapFsPath(fsm->map, st, NULL, NULL);
rpmMessage(RPMMESS_WARNING, _("%s created as %s\n"), opath, fsm->path);
opath = _free(opath);
}
- fsm->opath = _free(fsm->opath);
- }
- if (S_ISLNK(st->st_mode)) {
- if (!rc && !getuid()) rc = fsmStage(fsm, FSM_LCHOWN);
- } else {
- if (!rc && !getuid()) rc = fsmStage(fsm, FSM_CHOWN);
- if (!rc) rc = fsmStage(fsm, FSM_CHMOD);
- if (!rc) rc = fsmStage(fsm, FSM_UTIME);
- }
- /* Notify on success. */
- if (!rc) rc = fsmStage(fsm, FSM_NOTIFY);
+ fsm->opath = _free(fsm->opath);
}
- /* FSM_COMMIT -> FSM_INIT */
+ if (S_ISLNK(st->st_mode)) {
+ if (!rc && !getuid() &&
+ !(fsm->statdone && st->st_mode == ost->st_mode))
+ rc = fsmStage(fsm, FSM_LCHOWN);
+ } else {
+ if (!rc && !getuid() &&
+ !(fsm->statdone && st->st_uid == ost->st_uid
+ && st->st_uid == ost->st_uid))
+ rc = fsmStage(fsm, FSM_CHOWN);
+ if (!rc &&
+ !(fsm->statdone &&
+ (st->st_mode & 07777) == (ost->st_mode & 07777)))
+ rc = fsmStage(fsm, FSM_CHMOD);
+ if (!rc)
+ rc = fsmStage(fsm, FSM_UTIME);
+ }
+ /* Notify on success. */
+ if (!rc) rc = fsmStage(fsm, FSM_NOTIFY);
break;
case FSM_DESTROY:
fsm->path = _free(fsm->path);
@@ -1270,12 +1486,15 @@ opath = _free(opath);
while ((fsm->li = fsm->links) != NULL) {
fsm->links = fsm->li->next;
fsm->li->next = NULL;
- /* XXX adjust for %lang hardlinks. */
- if (rc == 0 && fsm->li->linksLeft) {
- if (fsm->li->createdPath != -1)
- rc = fsmStage(fsm, FSM_MKLINKS);
- } else {
- rc = CPIOERR_MISSING_HARDLINK;
+ if (fsm->li->linksLeft) {
+ for (i = 0 ; i < fsm->li->linksLeft; i++) {
+ if (fsm->li->filex[i] < 0) continue;
+ rc = CPIOERR_MISSING_HARDLINK;
+ if (!(fsm->li->files && fsm->li->files[i])) continue;
+ if (fsm->failedFile && *fsm->failedFile == NULL)
+ *fsm->failedFile = xstrdup(fsm->li->files[i]);
+ break;
+ }
}
fsm->li = freeHardLink(fsm->li);
}
@@ -1287,8 +1506,7 @@ opath = _free(opath);
if (rc < 0 && errno == ENOENT)
errno = saveerrno;
if (rc < 0) return CPIOERR_LSTAT_FAILED;
-
- /* XXX handle upgrade actions right here? */
+ fsm->statdone = 1;
if (S_ISREG(st->st_mode)) {
char * path = alloca(strlen(fsm->path) + sizeof("-RPMDELETE"));
@@ -1311,6 +1529,7 @@ opath = _free(opath);
} else if (S_ISDIR(st->st_mode)) {
if (S_ISDIR(ost->st_mode)) return 0;
if (S_ISLNK(ost->st_mode)) {
+ fsm->statdone = 0;
rc = stat(fsm->path, ost);
if (rc < 0 && errno != ENOENT)
return CPIOERR_STAT_FAILED;
@@ -1337,7 +1556,7 @@ opath = _free(opath);
}
/* XXX shouldn't do this with commit/undo. */
rc = 0;
- if (stage == FSM_PROCESS) rc = fsmStage(fsm, FSM_UNLINK);
+ if (fsm->stage == FSM_PROCESS) rc = fsmStage(fsm, FSM_UNLINK);
if (rc == 0) rc = CPIOERR_LSTAT_FAILED;
return (rc ? rc : CPIOERR_LSTAT_FAILED); /* XXX HACK */
break;
@@ -1609,29 +1828,14 @@ int cpioInstallArchive(FSM_t fsm)
/* Abort on error. */
if (rc) goto exit;
-#ifdef DYING
- /* Remap mode/uid/gid/name of file from archive. */
- (void) fsmStage(fsm, FSM_MAP);
-
- if (fsm->mapi && fsm->map == NULL) {
- rc = fsmStage(fsm, FSM_EAT);
- } else
-#endif
- {
- /* Create any directories in path. */
- rc = fsmStage(fsm, FSM_PRE);
-
- /* Extract file from archive. */
- if (!rc) rc = fsmStage(fsm, FSM_PROCESS);
+ /* Create any directories in path. */
+ rc = fsmStage(fsm, FSM_PRE);
- /* If successfully extracted, set final file info. */
- if (!rc) rc = fsmStage(fsm, FSM_POST);
- }
+ /* Extract file from archive. */
+ if (!rc) rc = fsmStage(fsm, FSM_PROCESS);
-#ifdef DYING
- /* Position to next item in payload. */
- (void) fsmStage(fsm, FSM_POS);
-#endif
+ /* If successfully extracted, set final file info. */
+ if (!rc) rc = fsmStage(fsm, FSM_POST);
/* Notify on success. */
if (!rc) (void) fsmStage(fsm, FSM_NOTIFY);
@@ -1845,7 +2049,7 @@ static int writeLinkedFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
map = hlink->fileMaps[i];
if ((rc = writeFile(ts, fi, cfd, &hlink->sb, map, &size, 0)) != 0) {
- if (failedFile)
+ if (failedFile && *failedFile == NULL)
*failedFile = mapFsPath(map, NULL, NULL, NULL);
goto exit;
}
@@ -1860,7 +2064,7 @@ static int writeLinkedFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
if ((rc = writeFile(ts, fi, cfd, &hlink->sb, map, &size, 1))) {
if (sizep)
*sizep = total;
- if (failedFile)
+ if (failedFile && *failedFile == NULL)
*failedFile = mapFsPath(map, NULL, NULL, NULL);
goto exit;
}
@@ -1903,7 +2107,7 @@ int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
rc = Lstat(fsPath, st);
if (rc) {
- if (failedFile)
+ if (failedFile && *failedFile == NULL)
*failedFile = fsPath;
return CPIOERR_STAT_FAILED;
}
@@ -1914,7 +2118,7 @@ int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
(hlink->dev != st->st_dev || hlink->inode != st->st_ino))
hlink = hlink->next;
if (hlink == NULL) {
- hlink = newHardLink(st, HARDLINK_INSTALL);
+ hlink = newHardLink(st, HARDLINK_BUILD);
hlink->next = hlinkList.next;
hlinkList.next = hlink;
}
@@ -1943,7 +2147,7 @@ int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
}
} else {
if ((rc = writeFile(ts, fi, cfd, st, map, &size, 1))) {
- if (failedFile)
+ if (failedFile && *failedFile == NULL)
*failedFile = fsPath;
return rc;
}