2000-08-28 03:18:25 +08:00
|
|
|
/** \ingroup payload rpmio
|
|
|
|
* \file lib/cpio.c
|
2000-03-23 23:49:50 +08:00
|
|
|
* Handle cpio payloads within rpm packages.
|
|
|
|
*
|
2000-08-28 03:18:25 +08:00
|
|
|
* \warning FIXME: We don't translate between cpio and system mode bits! These
|
2000-03-23 23:49:50 +08:00
|
|
|
* should both be the same, but really odd things are going to happen if
|
|
|
|
* that's not true!
|
|
|
|
*/
|
|
|
|
|
1998-07-26 05:00:26 +08:00
|
|
|
#include "system.h"
|
2001-01-23 03:11:19 +08:00
|
|
|
#include <rpmlib.h>
|
|
|
|
|
2001-01-25 05:35:52 +08:00
|
|
|
#include "rollback.h"
|
2001-01-04 04:19:27 +08:00
|
|
|
#include "rpmerr.h"
|
2000-12-13 04:03:45 +08:00
|
|
|
#include "debug.h"
|
1997-05-06 04:46:58 +08:00
|
|
|
|
2000-12-13 04:03:45 +08:00
|
|
|
/*@access FD_t@*/
|
2001-01-27 01:06:09 +08:00
|
|
|
/*@access rpmTransactionSet@*/
|
|
|
|
/*@access TFI_t@*/
|
2000-03-23 23:49:50 +08:00
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
#define CPIO_NEWC_MAGIC "070701"
|
1997-01-04 10:48:55 +08:00
|
|
|
#define CPIO_CRC_MAGIC "070702"
|
|
|
|
#define TRAILER "TRAILER!!!"
|
|
|
|
|
2001-01-24 07:03:28 +08:00
|
|
|
/** \ingroup payload
|
|
|
|
* Defines a single file to be included in a cpio payload.
|
|
|
|
*/
|
|
|
|
struct cpioFileMapping {
|
|
|
|
/*@dependent@*/ const char * archivePath; /*!< Path to store in cpio archive. */
|
|
|
|
/*@dependent@*/ const char * dirName; /*!< Payload file directory. */
|
|
|
|
/*@dependent@*/ const char * baseName; /*!< Payload file base name. */
|
|
|
|
/*@dependent@*/ const char * md5sum; /*!< File MD5 sum (NULL disables). */
|
|
|
|
mode_t finalMode; /*!< Mode of payload file (from header). */
|
|
|
|
uid_t finalUid; /*!< Uid of payload file (from header). */
|
|
|
|
gid_t finalGid; /*!< Gid of payload file (from header). */
|
|
|
|
cpioMapFlags mapFlags;
|
|
|
|
};
|
|
|
|
|
2000-08-28 03:18:25 +08:00
|
|
|
/** \ingroup payload
|
2000-08-23 20:39:49 +08:00
|
|
|
* Keeps track of set of all hard linked files in archive.
|
|
|
|
*/
|
1997-05-07 01:38:05 +08:00
|
|
|
struct hardLink {
|
1997-07-24 02:07:46 +08:00
|
|
|
struct hardLink * next;
|
1999-09-18 05:31:38 +08:00
|
|
|
const char ** files; /* nlink of these, used by install */
|
2001-01-23 03:11:19 +08:00
|
|
|
const void ** fileMaps;
|
1997-05-07 01:38:05 +08:00
|
|
|
dev_t dev;
|
|
|
|
ino_t inode;
|
2000-03-23 23:49:50 +08:00
|
|
|
int nlink;
|
1997-05-07 01:38:05 +08:00
|
|
|
int linksLeft;
|
|
|
|
int createdPath;
|
2000-05-18 20:11:51 +08:00
|
|
|
const struct stat sb;
|
1997-05-07 01:38:05 +08:00
|
|
|
};
|
|
|
|
|
2000-08-28 09:08:57 +08:00
|
|
|
/** \ingroup payload
|
|
|
|
*/
|
|
|
|
enum hardLinkType {
|
|
|
|
HARDLINK_INSTALL=1,
|
|
|
|
HARDLINK_BUILD
|
|
|
|
};
|
2000-03-23 23:49:50 +08:00
|
|
|
|
2000-08-28 03:18:25 +08:00
|
|
|
/** \ingroup payload
|
2000-08-23 20:39:49 +08:00
|
|
|
* Cpio archive header information.
|
2000-08-28 09:08:57 +08:00
|
|
|
* @todo Add support for tar (soon) and ar (eventually) archive formats.
|
2000-08-23 20:39:49 +08:00
|
|
|
*/
|
1997-01-04 10:48:55 +08:00
|
|
|
struct cpioCrcPhysicalHeader {
|
|
|
|
char magic[6];
|
|
|
|
char inode[8];
|
|
|
|
char mode[8];
|
|
|
|
char uid[8];
|
|
|
|
char gid[8];
|
|
|
|
char nlink[8];
|
|
|
|
char mtime[8];
|
|
|
|
char filesize[8];
|
|
|
|
char devMajor[8];
|
|
|
|
char devMinor[8];
|
|
|
|
char rdevMajor[8];
|
|
|
|
char rdevMinor[8];
|
|
|
|
char namesize[8];
|
|
|
|
char checksum[8]; /* ignored !! */
|
|
|
|
};
|
|
|
|
|
2000-08-28 09:08:57 +08:00
|
|
|
#define PHYS_HDR_SIZE 110 /*!< Don't depend on sizeof(struct) */
|
1998-12-04 03:30:32 +08:00
|
|
|
|
2000-08-28 03:18:25 +08:00
|
|
|
/** \ingroup payload
|
2000-08-23 20:39:49 +08:00
|
|
|
* File name and stat information.
|
|
|
|
*/
|
1997-01-04 10:48:55 +08:00
|
|
|
struct cpioHeader {
|
2001-01-26 04:26:35 +08:00
|
|
|
/*@owned@*/ const char * path;
|
|
|
|
FD_t cfd;
|
2001-01-27 01:06:09 +08:00
|
|
|
/*@owned@*/ void * mapi;
|
2001-01-28 01:42:24 +08:00
|
|
|
/*@dependent@*/ const void * map;
|
|
|
|
/*@owned@*/ struct hardLink * links;
|
|
|
|
/*@dependent@*/ struct hardLink * li;
|
|
|
|
/*@dependent@*/ const char ** failedFile;
|
|
|
|
int postpone;
|
|
|
|
int rc;
|
|
|
|
fileStage a;
|
2000-03-23 23:49:50 +08:00
|
|
|
struct stat sb;
|
1997-01-04 10:48:55 +08:00
|
|
|
};
|
|
|
|
|
2000-05-18 20:11:51 +08:00
|
|
|
#if 0
|
|
|
|
static void prtli(const char *msg, struct hardLink * li)
|
|
|
|
{
|
|
|
|
if (msg) fprintf(stderr, "%s", msg);
|
|
|
|
fprintf(stderr, " next %p files %p fileMaps %p dev %x ino %x nlink %d left %d createdPath %d size %d\n", li->next, li->files, li->fileMaps, (unsigned)li->dev, (unsigned)li->inode, li->nlink, li->linksLeft, li->createdPath, li->sb.st_size);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-22 07:48:09 +08:00
|
|
|
static int mapFlags(const void * this, cpioMapFlags mask) {
|
|
|
|
const struct cpioFileMapping * map = this;
|
|
|
|
return (map->mapFlags & mask);
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-23 03:11:19 +08:00
|
|
|
static /*@only@*/ const char * mapArchivePath(const void * this) {
|
2001-01-22 07:48:09 +08:00
|
|
|
const struct cpioFileMapping * map = this;
|
2001-01-23 03:11:19 +08:00
|
|
|
return xstrdup(map->archivePath);
|
2001-01-22 07:48:09 +08:00
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-22 07:48:09 +08:00
|
|
|
static /*@only@*/ const char * mapFsPath(const void * this) {
|
|
|
|
const struct cpioFileMapping * map = this;
|
|
|
|
char * t = xmalloc( strlen(map->dirName) + strlen(map->baseName) + 1);
|
|
|
|
(void) stpcpy( stpcpy(t, map->dirName), map->baseName);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-22 07:48:09 +08:00
|
|
|
static mode_t mapFinalMode(const void * this) {
|
|
|
|
const struct cpioFileMapping * map = this;
|
|
|
|
return map->finalMode;
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-22 07:48:09 +08:00
|
|
|
static uid_t mapFinalUid(const void * this) {
|
|
|
|
const struct cpioFileMapping * map = this;
|
|
|
|
return map->finalUid;
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-22 07:48:09 +08:00
|
|
|
static gid_t mapFinalGid(const void * this) {
|
|
|
|
const struct cpioFileMapping * map = this;
|
|
|
|
return map->finalGid;
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-27 01:06:09 +08:00
|
|
|
static /*@observer@*/ const char * const mapMd5sum(const void * this) {
|
2001-01-22 07:48:09 +08:00
|
|
|
const struct cpioFileMapping * map = this;
|
|
|
|
return map->md5sum;
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-22 07:48:09 +08:00
|
|
|
struct mapi {
|
2001-01-27 01:06:09 +08:00
|
|
|
/*@dependent@*/ rpmTransactionSet ts;
|
|
|
|
/*@dependent@*/ TFI_t fi;
|
2001-01-22 07:48:09 +08:00
|
|
|
int i;
|
2001-01-24 07:03:28 +08:00
|
|
|
struct cpioFileMapping map;
|
2001-01-22 07:48:09 +08:00
|
|
|
};
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-23 03:11:19 +08:00
|
|
|
static const void * mapLink(const void * this) {
|
2001-01-24 07:03:28 +08:00
|
|
|
const struct cpioFileMapping * omap = this;
|
2001-01-28 01:42:24 +08:00
|
|
|
struct cpioFileMapping * nmap = xcalloc(1, sizeof(*nmap));
|
2001-01-24 07:03:28 +08:00
|
|
|
*nmap = *omap; /* structure assignment */
|
|
|
|
return nmap;
|
2001-01-23 03:11:19 +08:00
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-27 01:06:09 +08:00
|
|
|
static void mapFree(/*@only@*/ const void * this) {
|
2001-01-24 07:03:28 +08:00
|
|
|
free((void *)this);
|
2001-01-23 03:11:19 +08:00
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static void mapFreeIterator(/*@only@*/ const void * this)
|
|
|
|
{
|
|
|
|
struct mapi * mapi;
|
|
|
|
rpmTransactionSet ts;
|
|
|
|
TFI_t fi;
|
|
|
|
|
|
|
|
if (this == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mapi = (void *)this;
|
|
|
|
ts = mapi->ts;
|
|
|
|
fi = mapi->fi;
|
|
|
|
|
|
|
|
if (ts && ts->notify) {
|
|
|
|
unsigned int archiveSize = (fi->archiveSize ? fi->archiveSize : 100);
|
|
|
|
(void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
|
|
|
|
archiveSize, archiveSize,
|
|
|
|
(fi->ap ? fi->ap->key : NULL), ts->notifyData);
|
|
|
|
}
|
|
|
|
free((void *)this);
|
2001-01-23 03:11:19 +08:00
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-27 01:06:09 +08:00
|
|
|
static void *
|
|
|
|
mapInitIterator(/*@kept@*/ const void * this, /*@kept@*/ const void * that)
|
2001-01-26 04:26:35 +08:00
|
|
|
{
|
2001-01-23 03:11:19 +08:00
|
|
|
struct mapi * mapi;
|
2001-01-26 04:26:35 +08:00
|
|
|
rpmTransactionSet ts = (void *)this;
|
|
|
|
TFI_t fi = (void *)that;
|
2001-01-23 03:11:19 +08:00
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
if (fi == NULL)
|
2001-01-23 03:11:19 +08:00
|
|
|
return NULL;
|
2001-01-28 01:42:24 +08:00
|
|
|
mapi = xcalloc(1, sizeof(*mapi));
|
2001-01-26 04:26:35 +08:00
|
|
|
mapi->ts = ts;
|
|
|
|
mapi->fi = fi;
|
2001-01-22 07:48:09 +08:00
|
|
|
mapi->i = 0;
|
2001-01-26 04:26:35 +08:00
|
|
|
|
|
|
|
if (ts && ts->notify) {
|
|
|
|
(void)ts->notify(fi->h, RPMCALLBACK_INST_START, 0, fi->archiveSize,
|
|
|
|
(fi->ap ? fi->ap->key : NULL), ts->notifyData);
|
|
|
|
}
|
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
return mapi;
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-23 03:11:19 +08:00
|
|
|
static const void * mapNextIterator(void * this) {
|
|
|
|
struct mapi * mapi = this;
|
2001-01-24 07:03:28 +08:00
|
|
|
TFI_t fi = mapi->fi;
|
|
|
|
struct cpioFileMapping * map = &mapi->map;
|
|
|
|
int i = mapi->i;
|
2001-01-22 07:48:09 +08:00
|
|
|
|
2001-01-24 07:03:28 +08:00
|
|
|
do {
|
2001-01-28 01:42:24 +08:00
|
|
|
if (!((i = mapi->i) < fi->fc))
|
2001-01-24 07:03:28 +08:00
|
|
|
return NULL;
|
2001-01-28 01:42:24 +08:00
|
|
|
mapi->i++;
|
2001-01-24 07:03:28 +08:00
|
|
|
} while (fi->actions && XFA_SKIPPING(fi->actions[i]));
|
|
|
|
|
|
|
|
/* src rpms have simple base name in payload. */
|
|
|
|
map->archivePath = (fi->apath ? fi->apath[i] + fi->striplen : fi->bnl[i]);
|
|
|
|
map->dirName = fi->dnl[fi->dil[i]];
|
|
|
|
map->baseName = fi->bnl[i];
|
|
|
|
map->md5sum = (fi->fmd5s ? fi->fmd5s[i] : NULL);
|
|
|
|
map->finalMode = fi->fmodes[i];
|
|
|
|
map->finalUid = (fi->fuids ? fi->fuids[i] : fi->uid); /* XXX chmod u-s */
|
|
|
|
map->finalGid = (fi->fgids ? fi->fgids[i] : fi->gid); /* XXX chmod g-s */
|
|
|
|
map->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
|
2001-01-22 07:48:09 +08:00
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-24 07:03:28 +08:00
|
|
|
static int cpioStrCmp(const void * a, const void * b) {
|
|
|
|
const char * afn = *(const char **)a;
|
|
|
|
const char * bfn = *(const char **)b;
|
|
|
|
|
|
|
|
/* Match rpm-4.0 payloads with ./ prefixes. */
|
|
|
|
if (afn[0] == '.' && afn[1] == '/') afn += 2;
|
|
|
|
if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
|
|
|
|
|
|
|
|
/* If either path is absolute, make it relative. */
|
|
|
|
if (afn[0] == '/') afn += 1;
|
|
|
|
if (bfn[0] == '/') bfn += 1;
|
|
|
|
|
|
|
|
return strcmp(afn, bfn);
|
|
|
|
}
|
|
|
|
|
2001-01-24 23:58:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-24 07:03:28 +08:00
|
|
|
static const void * mapFind(void * this, const char * hdrPath) {
|
|
|
|
struct mapi * mapi = this;
|
|
|
|
const TFI_t fi = mapi->fi;
|
|
|
|
const char ** p;
|
|
|
|
|
|
|
|
p = bsearch(&hdrPath, fi->apath, fi->fc, sizeof(hdrPath), cpioStrCmp);
|
|
|
|
if (p == NULL) {
|
|
|
|
fprintf(stderr, "*** not mapped %s\n", hdrPath);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
mapi->i = p - fi->apath;
|
|
|
|
return mapNextIterator(this);
|
|
|
|
}
|
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
/**
|
|
|
|
*/
|
2001-01-28 01:42:24 +08:00
|
|
|
static void pkgCallback(const struct cpioHeader * hdr)
|
2001-01-26 04:26:35 +08:00
|
|
|
{
|
|
|
|
struct mapi * mapi = hdr->mapi;
|
|
|
|
rpmTransactionSet ts;
|
|
|
|
TFI_t fi;
|
|
|
|
|
|
|
|
if (mapi == NULL)
|
|
|
|
return;
|
|
|
|
ts = mapi->ts;
|
|
|
|
fi = mapi->fi;
|
|
|
|
|
|
|
|
if (ts && ts->notify)
|
|
|
|
(void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS,
|
|
|
|
fdGetCpioPos(hdr->cfd), fi->archiveSize,
|
|
|
|
(fi->ap ? fi->ap->key : NULL), ts->notifyData);
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Read data from payload.
|
|
|
|
* @param cfd payload file handle
|
|
|
|
* @retval vbuf data from read
|
|
|
|
* @param amount no. bytes to read
|
|
|
|
* @return no. bytes read
|
|
|
|
*/
|
1999-10-28 07:18:10 +08:00
|
|
|
static inline off_t saferead(FD_t cfd, /*@out@*/void * vbuf, size_t amount)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd, *vbuf @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1998-07-25 23:33:15 +08:00
|
|
|
off_t rc = 0;
|
|
|
|
char * buf = vbuf;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
while (amount > 0) {
|
|
|
|
size_t nb;
|
1999-10-28 07:18:10 +08:00
|
|
|
|
1999-11-11 06:09:49 +08:00
|
|
|
nb = Fread(buf, sizeof(buf[0]), amount, cfd);
|
1998-07-25 23:33:15 +08:00
|
|
|
if (nb <= 0)
|
|
|
|
return nb;
|
|
|
|
rc += nb;
|
|
|
|
if (rc >= amount)
|
|
|
|
break;
|
|
|
|
buf += nb;
|
|
|
|
amount -= nb;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Read data from payload and update number of bytes read.
|
|
|
|
* @param cfd payload file handle
|
|
|
|
* @retval buf data from read
|
|
|
|
* @param size no. bytes to read
|
|
|
|
* @return no. bytes read
|
|
|
|
*/
|
1999-10-28 07:18:10 +08:00
|
|
|
static inline off_t ourread(FD_t cfd, /*@out@*/void * buf, size_t size)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd, *buf @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1998-07-25 23:33:15 +08:00
|
|
|
off_t i = saferead(cfd, buf, size);
|
|
|
|
if (i > 0)
|
1999-11-02 22:33:14 +08:00
|
|
|
fdSetCpioPos(cfd, fdGetCpioPos(cfd) + i);
|
1997-01-04 10:48:55 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Align input payload handle, skipping input bytes.
|
|
|
|
* @param cfd payload file handle
|
|
|
|
* @param modulo data alignment
|
|
|
|
*/
|
1999-10-28 07:18:10 +08:00
|
|
|
static inline void padinfd(FD_t cfd, int modulo)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1997-01-04 10:48:55 +08:00
|
|
|
int buf[10];
|
|
|
|
int amount;
|
2000-03-23 23:49:50 +08:00
|
|
|
|
1999-11-02 22:33:14 +08:00
|
|
|
amount = (modulo - fdGetCpioPos(cfd) % modulo) % modulo;
|
1998-11-17 05:40:28 +08:00
|
|
|
(void)ourread(cfd, buf, amount);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Write data to payload.
|
|
|
|
* @param cfd payload file handle
|
|
|
|
* @param vbuf data to write
|
|
|
|
* @param amount no. bytes to write
|
|
|
|
* @return no. bytes written
|
|
|
|
*/
|
1999-10-28 07:18:10 +08:00
|
|
|
static inline off_t safewrite(FD_t cfd, const void * vbuf, size_t amount)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1998-07-25 23:33:15 +08:00
|
|
|
off_t rc = 0;
|
1999-09-18 05:31:38 +08:00
|
|
|
const char * buf = vbuf;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
while (amount > 0) {
|
|
|
|
size_t nb;
|
1999-10-28 07:18:10 +08:00
|
|
|
|
1999-11-11 06:09:49 +08:00
|
|
|
nb = Fwrite(buf, sizeof(buf[0]), amount, cfd);
|
1998-07-25 23:33:15 +08:00
|
|
|
if (nb <= 0)
|
|
|
|
return nb;
|
|
|
|
rc += nb;
|
|
|
|
if (rc >= amount)
|
|
|
|
break;
|
|
|
|
buf += nb;
|
|
|
|
amount -= nb;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
return rc;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Align output payload handle, padding with zeroes.
|
|
|
|
* @param cfd payload file handle
|
|
|
|
* @param modulo data alignment
|
|
|
|
* @return 0 on success, CPIOERR_WRITE_FAILED
|
|
|
|
*/
|
1999-10-28 07:18:10 +08:00
|
|
|
static inline int padoutfd(FD_t cfd, size_t * where, int modulo)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd, *where @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1998-07-25 23:33:15 +08:00
|
|
|
static int buf[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
1997-07-24 02:07:46 +08:00
|
|
|
int amount;
|
2000-03-23 23:49:50 +08:00
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
amount = (modulo - *where % modulo) % modulo;
|
|
|
|
*where += amount;
|
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if (safewrite(cfd, buf, amount) != amount)
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_WRITE_FAILED;
|
1997-07-24 02:07:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Convert string to unsigned integer (with buffer size check).
|
|
|
|
* @param input string
|
|
|
|
* @retval address of 1st character not processed
|
|
|
|
* @param base numerical conversion base
|
|
|
|
* @param num max no. of bytes to read
|
|
|
|
* @return converted integer
|
|
|
|
*/
|
1999-09-18 05:31:38 +08:00
|
|
|
static int strntoul(const char *str, /*@out@*/char **endptr, int base, int num)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies *endptr @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1998-03-28 01:23:20 +08:00
|
|
|
char * buf, * end;
|
1998-03-28 01:41:19 +08:00
|
|
|
unsigned long ret;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
buf = alloca(num + 1);
|
|
|
|
strncpy(buf, str, num);
|
|
|
|
buf[num] = '\0';
|
|
|
|
|
1998-03-28 01:23:20 +08:00
|
|
|
ret = strtoul(buf, &end, base);
|
|
|
|
if (*end)
|
1998-12-06 07:22:41 +08:00
|
|
|
*endptr = ((char *)str) + (end - buf); /* XXX discards const */
|
1998-03-28 01:23:20 +08:00
|
|
|
else
|
1999-09-19 08:29:44 +08:00
|
|
|
*endptr = ((char *)str) + strlen(str);
|
1998-03-28 01:23:20 +08:00
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
return ret;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define GET_NUM_FIELD(phys, log) \
|
|
|
|
log = strntoul(phys, &end, 16, sizeof(phys)); \
|
1998-12-06 07:22:41 +08:00
|
|
|
if (*end) return CPIOERR_BAD_HEADER;
|
1997-07-24 02:07:46 +08:00
|
|
|
#define SET_NUM_FIELD(phys, val, space) \
|
|
|
|
sprintf(space, "%8.8lx", (unsigned long) (val)); \
|
|
|
|
memcpy(phys, space, 8);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Process next cpio heasder.
|
|
|
|
* @retval hdr file name and stat info
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static int getNextHeader(struct cpioHeader * hdr)
|
|
|
|
/*@modifies hdr->cfd, hdr->path, hdr->sb @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1997-01-04 10:48:55 +08:00
|
|
|
struct cpioCrcPhysicalHeader physHeader;
|
2000-03-23 23:49:50 +08:00
|
|
|
struct stat * st = &hdr->sb;
|
1997-01-04 10:48:55 +08:00
|
|
|
int nameSize;
|
|
|
|
char * end;
|
|
|
|
int major, minor;
|
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
if (ourread(hdr->cfd, &physHeader, PHYS_HDR_SIZE) != PHYS_HDR_SIZE)
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_READ_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1999-09-08 06:49:45 +08:00
|
|
|
if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, sizeof(CPIO_CRC_MAGIC)-1) &&
|
|
|
|
strncmp(CPIO_NEWC_MAGIC, physHeader.magic, sizeof(CPIO_NEWC_MAGIC)-1))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_BAD_MAGIC;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
GET_NUM_FIELD(physHeader.inode, st->st_ino);
|
|
|
|
GET_NUM_FIELD(physHeader.mode, st->st_mode);
|
|
|
|
GET_NUM_FIELD(physHeader.uid, st->st_uid);
|
|
|
|
GET_NUM_FIELD(physHeader.gid, st->st_gid);
|
|
|
|
GET_NUM_FIELD(physHeader.nlink, st->st_nlink);
|
|
|
|
GET_NUM_FIELD(physHeader.mtime, st->st_mtime);
|
|
|
|
GET_NUM_FIELD(physHeader.filesize, st->st_size);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
GET_NUM_FIELD(physHeader.devMajor, major);
|
|
|
|
GET_NUM_FIELD(physHeader.devMinor, minor);
|
2000-03-23 23:49:50 +08:00
|
|
|
st->st_dev = /*@-shiftsigned@*/ makedev(major, minor) /*@=shiftsigned@*/ ;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
GET_NUM_FIELD(physHeader.rdevMajor, major);
|
|
|
|
GET_NUM_FIELD(physHeader.rdevMinor, minor);
|
2000-03-23 23:49:50 +08:00
|
|
|
st->st_rdev = /*@-shiftsigned@*/ makedev(major, minor) /*@=shiftsigned@*/ ;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
GET_NUM_FIELD(physHeader.namesize, nameSize);
|
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
{ char * t = xmalloc(nameSize + 1);
|
2001-01-26 04:26:35 +08:00
|
|
|
if (ourread(hdr->cfd, t, nameSize) != nameSize) {
|
2000-03-23 23:49:50 +08:00
|
|
|
free(t);
|
|
|
|
hdr->path = NULL;
|
|
|
|
return CPIOERR_BAD_HEADER;
|
|
|
|
}
|
|
|
|
hdr->path = t;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
/* this is unecessary hdr->path[nameSize] = '\0'; */
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
padinfd(hdr->cfd, 4);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This could trash files in the path! I'm not sure that's a good thing */
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* @param path directory path
|
|
|
|
* @param perms directory permissions
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2000-03-23 23:49:50 +08:00
|
|
|
static int createDirectory(const char * path, mode_t perms)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies fileSystem @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2001-01-22 07:48:09 +08:00
|
|
|
struct stat st;
|
1997-05-06 04:46:58 +08:00
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
if (!lstat(path, &st)) {
|
|
|
|
if (S_ISDIR(st.st_mode))
|
1997-01-04 10:48:55 +08:00
|
|
|
return 0;
|
2001-01-22 07:48:09 +08:00
|
|
|
if (S_ISLNK(st.st_mode)) {
|
|
|
|
if (stat(path, &st)) {
|
2000-03-23 23:49:50 +08:00
|
|
|
if (errno != ENOENT)
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_STAT_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
} else {
|
2001-01-22 07:48:09 +08:00
|
|
|
if (S_ISDIR(st.st_mode))
|
1997-01-04 10:48:55 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
if (unlink(path))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_UNLINK_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mkdir(path, 000))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_MKDIR_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
if (perms != 000 && chmod(path, perms))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_CHMOD_FAILED;
|
1997-05-15 02:32:18 +08:00
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Set owner, group, and modify/access times.
|
|
|
|
* @param hdr file name and stat info
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static int setInfo(const struct cpioHeader * hdr)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies fileSystem @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1997-01-04 10:48:55 +08:00
|
|
|
int rc = 0;
|
1998-03-05 00:52:59 +08:00
|
|
|
struct utimbuf stamp;
|
2001-01-26 04:26:35 +08:00
|
|
|
const struct stat * st = &hdr->sb;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
stamp.actime = st->st_mtime;
|
|
|
|
stamp.modtime = st->st_mtime;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if (!S_ISLNK(st->st_mode)) {
|
|
|
|
if (!getuid() && chown(hdr->path, st->st_uid, st->st_gid))
|
1998-12-06 07:22:41 +08:00
|
|
|
rc = CPIOERR_CHOWN_FAILED;
|
2000-03-23 23:49:50 +08:00
|
|
|
if (!rc && chmod(hdr->path, st->st_mode & 07777))
|
1998-12-06 07:22:41 +08:00
|
|
|
rc = CPIOERR_CHMOD_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
if (!rc && utime(hdr->path, &stamp))
|
1998-12-06 07:22:41 +08:00
|
|
|
rc = CPIOERR_UTIME_FAILED;
|
1997-05-15 23:19:56 +08:00
|
|
|
} else {
|
1998-03-05 00:52:59 +08:00
|
|
|
# if ! CHOWN_FOLLOWS_SYMLINK
|
2000-03-23 23:49:50 +08:00
|
|
|
if (!getuid() && !rc && lchown(hdr->path, st->st_uid, st->st_gid))
|
1998-12-06 07:22:41 +08:00
|
|
|
rc = CPIOERR_CHOWN_FAILED;
|
1998-03-05 00:52:59 +08:00
|
|
|
# endif
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Create directories in file path (like "mkdir -p").
|
|
|
|
* @param filename file path
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2000-08-23 20:39:49 +08:00
|
|
|
static int inline checkDirectory(const char * filename) /*@*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1999-10-21 05:40:10 +08:00
|
|
|
/*@only@*/ static char * lastDir = NULL; /* XXX memory leak */
|
1997-01-04 10:48:55 +08:00
|
|
|
static int lastDirLength = 0;
|
|
|
|
static int lastDirAlloced = 0;
|
|
|
|
int length = strlen(filename);
|
|
|
|
char * buf;
|
|
|
|
char * chptr;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
buf = alloca(length + 1);
|
|
|
|
strcpy(buf, filename);
|
|
|
|
|
|
|
|
for (chptr = buf + length - 1; chptr > buf; chptr--) {
|
|
|
|
if (*chptr == '/') break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chptr == buf) return 0; /* /filename - no directories */
|
|
|
|
|
|
|
|
*chptr = '\0'; /* buffer is now just directories */
|
|
|
|
|
|
|
|
length = strlen(buf);
|
|
|
|
if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
|
|
|
|
|
|
|
|
if (lastDirAlloced < (length + 1)) {
|
|
|
|
lastDirAlloced = length + 100;
|
1999-09-22 01:21:57 +08:00
|
|
|
lastDir = xrealloc(lastDir, lastDirAlloced); /* XXX memory leak */
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(lastDir, buf);
|
|
|
|
lastDirLength = length;
|
|
|
|
|
|
|
|
for (chptr = buf + 1; *chptr; chptr++) {
|
|
|
|
if (*chptr == '/') {
|
|
|
|
*chptr = '\0';
|
1997-05-15 02:32:18 +08:00
|
|
|
rc = createDirectory(buf, 0755);
|
1997-01-04 10:48:55 +08:00
|
|
|
*chptr = '/';
|
|
|
|
if (rc) return rc;
|
|
|
|
}
|
|
|
|
}
|
1997-05-15 02:32:18 +08:00
|
|
|
rc = createDirectory(buf, 0755);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Create file from payload stream.
|
2000-12-03 05:53:44 +08:00
|
|
|
* @todo Legacy: support brokenEndian MD5 checks?
|
2000-10-24 21:46:51 +08:00
|
|
|
* @param hdr file name and stat info
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-28 01:42:24 +08:00
|
|
|
static int expandRegular(const struct cpioHeader * hdr)
|
2001-01-26 04:26:35 +08:00
|
|
|
/*@modifies fileSystem, hdr->cfd @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2001-01-28 01:42:24 +08:00
|
|
|
const char * filemd5;
|
1999-10-28 07:18:10 +08:00
|
|
|
FD_t ofd;
|
1999-11-11 06:09:49 +08:00
|
|
|
char buf[BUFSIZ];
|
1997-01-04 10:48:55 +08:00
|
|
|
int bytesRead;
|
2000-05-18 20:11:51 +08:00
|
|
|
const struct stat * st = &hdr->sb;
|
2000-03-23 23:49:50 +08:00
|
|
|
int left = st->st_size;
|
1997-01-04 10:48:55 +08:00
|
|
|
int rc = 0;
|
1997-05-06 23:27:46 +08:00
|
|
|
struct stat sb;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
filemd5 = mapMd5sum(hdr->map);
|
1999-02-19 01:21:50 +08:00
|
|
|
/* Rename the old file before attempting unlink to avoid EBUSY errors */
|
|
|
|
if (!lstat(hdr->path, &sb)) {
|
|
|
|
strcpy(buf, hdr->path);
|
1999-02-19 23:23:34 +08:00
|
|
|
strcat(buf, "-RPMDELETE");
|
1999-02-19 01:21:50 +08:00
|
|
|
if (rename(hdr->path, buf)) {
|
2001-01-04 04:19:27 +08:00
|
|
|
rpmError(RPMERR_RENAME, _("can't rename %s to %s: %s\n"),
|
1999-02-19 01:21:50 +08:00
|
|
|
hdr->path, buf, strerror(errno));
|
|
|
|
return CPIOERR_UNLINK_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlink(buf)) {
|
2001-01-04 04:19:27 +08:00
|
|
|
rpmError(RPMERR_UNLINK, _("can't unlink %s: %s\n"),
|
1999-02-19 01:21:50 +08:00
|
|
|
buf, strerror(errno));
|
|
|
|
#if 0
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_UNLINK_FAILED;
|
1999-02-19 01:21:50 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1999-11-25 00:16:17 +08:00
|
|
|
ofd = Fopen(hdr->path, "w.ufdio");
|
|
|
|
if (ofd == NULL || Ferror(ofd))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_OPEN_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-12-03 05:53:44 +08:00
|
|
|
/* XXX This doesn't support brokenEndian checks. */
|
2000-10-24 21:46:51 +08:00
|
|
|
if (filemd5)
|
2000-12-03 05:53:44 +08:00
|
|
|
fdInitMD5(ofd, 0);
|
2000-10-24 21:46:51 +08:00
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
while (left) {
|
2001-01-26 04:26:35 +08:00
|
|
|
bytesRead = ourread(hdr->cfd, buf, left < sizeof(buf) ? left : sizeof(buf));
|
1997-01-04 10:48:55 +08:00
|
|
|
if (bytesRead <= 0) {
|
1998-12-06 07:22:41 +08:00
|
|
|
rc = CPIOERR_READ_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1999-11-11 06:09:49 +08:00
|
|
|
if (Fwrite(buf, sizeof(buf[0]), bytesRead, ofd) != bytesRead) {
|
1998-12-06 07:22:41 +08:00
|
|
|
rc = CPIOERR_COPY_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
left -= bytesRead;
|
1997-05-06 23:27:46 +08:00
|
|
|
|
|
|
|
/* don't call this with fileSize == fileComplete */
|
2001-01-26 04:26:35 +08:00
|
|
|
if (!rc && left)
|
2001-01-28 01:42:24 +08:00
|
|
|
pkgCallback(hdr);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
if (filemd5) {
|
2000-10-29 01:16:25 +08:00
|
|
|
const char * md5sum = NULL;
|
2000-10-24 21:46:51 +08:00
|
|
|
|
|
|
|
Fflush(ofd);
|
|
|
|
fdFiniMD5(ofd, (void **)&md5sum, NULL, 1);
|
|
|
|
|
2000-10-29 01:16:25 +08:00
|
|
|
if (md5sum == NULL) {
|
2000-10-24 21:46:51 +08:00
|
|
|
rc = CPIOERR_MD5SUM_MISMATCH;
|
2000-10-29 01:16:25 +08:00
|
|
|
} else {
|
|
|
|
if (strcmp(md5sum, filemd5))
|
|
|
|
rc = CPIOERR_MD5SUM_MISMATCH;
|
2000-12-13 04:03:45 +08:00
|
|
|
free((void *)md5sum);
|
2000-10-29 01:16:25 +08:00
|
|
|
}
|
2000-10-24 21:46:51 +08:00
|
|
|
}
|
|
|
|
|
1999-10-28 07:18:10 +08:00
|
|
|
Fclose(ofd);
|
2000-03-23 23:49:50 +08:00
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Create symlink from payload stream.
|
|
|
|
* @param hdr file name and stat info
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static int expandSymlink(const struct cpioHeader * hdr)
|
|
|
|
/*@modifies fileSystem, hdr->cfd @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1997-07-16 09:56:14 +08:00
|
|
|
char buf[2048], buf2[2048];
|
1997-05-06 23:27:46 +08:00
|
|
|
struct stat sb;
|
2000-05-18 20:11:51 +08:00
|
|
|
const struct stat * st = &hdr->sb;
|
1997-07-16 09:56:14 +08:00
|
|
|
int len;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if ((st->st_size + 1)> sizeof(buf))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_HDR_SIZE;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
if (ourread(hdr->cfd, buf, st->st_size) != st->st_size)
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_READ_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
buf[st->st_size] = '\0';
|
1997-01-04 10:48:55 +08:00
|
|
|
|
1997-07-16 09:56:14 +08:00
|
|
|
if (!lstat(hdr->path, &sb)) {
|
|
|
|
if (S_ISLNK(sb.st_mode)) {
|
|
|
|
len = readlink(hdr->path, buf2, sizeof(buf2) - 1);
|
|
|
|
if (len > 0) {
|
|
|
|
buf2[len] = '\0';
|
|
|
|
if (!strcmp(buf, buf2)) return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlink(hdr->path))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_UNLINK_FAILED;
|
1997-07-16 09:56:14 +08:00
|
|
|
}
|
|
|
|
|
1997-07-16 09:38:55 +08:00
|
|
|
if (symlink(buf, hdr->path) < 0)
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_SYMLINK_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Create fifo from payload stream.
|
|
|
|
* @param hdr file name and stat info
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static int expandFifo(const struct cpioHeader * hdr)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies fileSystem @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1997-01-04 10:48:55 +08:00
|
|
|
struct stat sb;
|
|
|
|
|
1997-05-06 23:27:46 +08:00
|
|
|
if (!lstat(hdr->path, &sb)) {
|
1997-01-04 10:48:55 +08:00
|
|
|
if (S_ISFIFO(sb.st_mode)) return 0;
|
|
|
|
|
|
|
|
if (unlink(hdr->path))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_UNLINK_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mkfifo(hdr->path, 0))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_MKFIFO_FAILED;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
return 0;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Create fifo from payload stream.
|
|
|
|
* @param hdr file name and stat info
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static int expandDevice(const struct cpioHeader * hdr)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies fileSystem @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2000-05-18 20:11:51 +08:00
|
|
|
const struct stat * st = &hdr->sb;
|
1997-05-06 23:27:46 +08:00
|
|
|
struct stat sb;
|
|
|
|
|
1997-07-16 09:56:14 +08:00
|
|
|
if (!lstat(hdr->path, &sb)) {
|
2000-03-23 23:49:50 +08:00
|
|
|
if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) &&
|
|
|
|
(sb.st_rdev == st->st_rdev))
|
1997-07-16 09:56:14 +08:00
|
|
|
return 0;
|
1997-01-04 10:48:55 +08:00
|
|
|
if (unlink(hdr->path))
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_UNLINK_FAILED;
|
1997-07-16 09:56:14 +08:00
|
|
|
}
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if ( /*@-unrecog@*/ mknod(hdr->path, st->st_mode & (~0777), st->st_rdev) /*@=unrecog@*/ )
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_MKNOD_FAILED;
|
2000-03-23 23:49:50 +08:00
|
|
|
|
1997-01-04 10:48:55 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Create and initialize set of hard links.
|
|
|
|
* @param st link stat info
|
|
|
|
* @param hltype type of hard link set to create
|
|
|
|
* @return pointer to set of hard links
|
|
|
|
*/
|
2000-03-23 23:49:50 +08:00
|
|
|
static /*@only@*/ struct hardLink * newHardLink(const struct stat * st,
|
2000-08-23 20:39:49 +08:00
|
|
|
enum hardLinkType hltype) /*@*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2000-03-23 23:49:50 +08:00
|
|
|
struct hardLink * li = xmalloc(sizeof(*li));
|
|
|
|
|
|
|
|
li->next = NULL;
|
|
|
|
li->nlink = st->st_nlink;
|
|
|
|
li->dev = st->st_dev;
|
|
|
|
li->inode = st->st_ino;
|
|
|
|
li->createdPath = -1;
|
|
|
|
|
|
|
|
switch (hltype) {
|
|
|
|
case HARDLINK_INSTALL:
|
|
|
|
li->linksLeft = st->st_nlink;
|
2001-01-28 01:42:24 +08:00
|
|
|
li->fileMaps = xcalloc(st->st_nlink, sizeof(li->fileMaps[0]));
|
2000-03-23 23:49:50 +08:00
|
|
|
li->files = NULL;
|
|
|
|
break;
|
|
|
|
case HARDLINK_BUILD:
|
|
|
|
li->linksLeft = 0;
|
|
|
|
li->fileMaps = NULL;
|
|
|
|
li->files = xcalloc(st->st_nlink, sizeof(*li->files));
|
|
|
|
break;
|
|
|
|
}
|
2000-05-18 20:11:51 +08:00
|
|
|
|
|
|
|
{ struct stat * myst = (struct stat *) &li->sb;
|
|
|
|
*myst = *st; /* structure assignment */
|
|
|
|
}
|
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
return li;
|
|
|
|
}
|
1997-05-07 01:38:05 +08:00
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Destroy set of hard links.
|
|
|
|
* @param li set of hard links
|
|
|
|
*/
|
2000-03-23 23:49:50 +08:00
|
|
|
static void freeHardLink( /*@only@*/ struct hardLink * li)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (li->files) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < li->nlink; i++) {
|
|
|
|
if (li->files[i] == NULL) continue;
|
|
|
|
/*@-unqualifiedtrans@*/ free((void *)li->files[i]) /*@=unqualifiedtrans@*/ ;
|
|
|
|
li->files[i] = NULL;
|
|
|
|
}
|
|
|
|
free(li->files);
|
|
|
|
li->files = NULL;
|
|
|
|
}
|
|
|
|
if (li->fileMaps) {
|
|
|
|
free(li->fileMaps);
|
|
|
|
li->fileMaps = NULL;
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
2000-03-23 23:49:50 +08:00
|
|
|
free(li);
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Create hard links to existing file.
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-28 01:42:24 +08:00
|
|
|
static int createLinks(struct cpioHeader * hdr)
|
|
|
|
/*@modifies hdr, fileSystem @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1997-05-07 01:38:05 +08:00
|
|
|
struct stat sb;
|
2001-01-28 01:42:24 +08:00
|
|
|
int i;
|
1997-05-07 01:38:05 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
for (i = 0; i < hdr->li->nlink; i++) {
|
|
|
|
if (i == hdr->li->createdPath) continue;
|
|
|
|
if (hdr->li->files[i] == NULL) continue;
|
1997-05-07 01:38:05 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
if (!lstat(hdr->li->files[i], &sb)) {
|
|
|
|
if (unlink(hdr->li->files[i])) {
|
|
|
|
if (hdr->failedFile)
|
|
|
|
*hdr->failedFile = xstrdup(hdr->li->files[i]);
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_UNLINK_FAILED;
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
if (link(hdr->li->files[hdr->li->createdPath], hdr->li->files[i])) {
|
|
|
|
if (hdr->failedFile)
|
|
|
|
*hdr->failedFile = xstrdup(hdr->li->files[i]);
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_LINK_FAILED;
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
/*@-unqualifiedtrans@*/ free((void *)hdr->li->files[i]) /*@=unqualifiedtrans@*/ ;
|
|
|
|
hdr->li->files[i] = NULL;
|
|
|
|
hdr->li->linksLeft--;
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Skip amount bytes on input payload stream.
|
|
|
|
* @param cfd payload file handle
|
|
|
|
* @param amount no. bytes to skip
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
1999-10-28 07:18:10 +08:00
|
|
|
static int eatBytes(FD_t cfd, int amount)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
1997-05-23 23:18:15 +08:00
|
|
|
char buf[4096];
|
|
|
|
int bite;
|
2000-03-23 23:49:50 +08:00
|
|
|
|
1997-05-23 23:18:15 +08:00
|
|
|
while (amount) {
|
|
|
|
bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
|
1998-07-25 23:33:15 +08:00
|
|
|
if (ourread(cfd, buf, bite) != bite)
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_READ_FAILED;
|
1997-05-23 23:18:15 +08:00
|
|
|
amount -= bite;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
/**
|
|
|
|
* Cpio archive extraction state machine.
|
|
|
|
*/
|
|
|
|
static int hdrStage(struct cpioHeader * hdr, fileStage a)
|
|
|
|
{
|
|
|
|
#ifdef UNUSED
|
|
|
|
const char * const prev = fileStageString(hdr->a);
|
|
|
|
#endif
|
|
|
|
const char * const cur = fileStageString(a);
|
|
|
|
struct stat * st = &hdr->sb;
|
|
|
|
int rc = hdr->rc;
|
|
|
|
|
|
|
|
switch (a) {
|
|
|
|
case FI_CREATE:
|
|
|
|
memset(hdr, 0, sizeof(*hdr));
|
|
|
|
hdr->path = NULL;
|
|
|
|
hdr->map = NULL;
|
|
|
|
hdr->links = NULL;
|
|
|
|
hdr->li = NULL;
|
|
|
|
break;
|
|
|
|
case FI_INIT:
|
|
|
|
if (hdr->path) {
|
|
|
|
free((void *)hdr->path); hdr->path = NULL;
|
|
|
|
}
|
|
|
|
hdr->postpone = 0;
|
|
|
|
rc = getNextHeader(hdr);
|
|
|
|
break;
|
|
|
|
case FI_MAP:
|
|
|
|
if (hdr->mapi) {
|
|
|
|
hdr->map = mapFind(hdr->mapi, hdr->path);
|
|
|
|
if (hdr->map) {
|
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_PATH)) {
|
|
|
|
if (hdr->path) free((void *)hdr->path);
|
|
|
|
hdr->path = mapFsPath(hdr->map);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_MODE))
|
|
|
|
st->st_mode = mapFinalMode(hdr->map);
|
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_UID))
|
|
|
|
st->st_uid = mapFinalUid(hdr->map);
|
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_GID))
|
|
|
|
st->st_gid = mapFinalGid(hdr->map);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("\t%s path %s\n"), cur, hdr->path);
|
|
|
|
break;
|
|
|
|
case FI_SKIP:
|
|
|
|
eatBytes(hdr->cfd, st->st_size);
|
|
|
|
break;
|
|
|
|
case FI_PRE:
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("\t%s mkdir/rename %s.TID\n"),
|
|
|
|
cur, hdr->path);
|
|
|
|
/*
|
|
|
|
* 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 (hdr->li = hdr->links; hdr->li; hdr->li = hdr->li->next) {
|
|
|
|
if (hdr->li->inode == st->st_ino && hdr->li->dev == st->st_dev)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hdr->li == NULL) {
|
|
|
|
hdr->li = newHardLink(st, HARDLINK_BUILD);
|
|
|
|
hdr->li->next = hdr->links;
|
|
|
|
hdr->links = hdr->li;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr->li->files[hdr->li->linksLeft++] = xstrdup(hdr->path);
|
|
|
|
|
|
|
|
/* XXX FIXME 0 length hard linked files are broke. */
|
|
|
|
if (st->st_size && hdr->li->createdPath == -1) {
|
|
|
|
createLinks(hdr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
eatBytes(hdr->cfd, st->st_size);
|
|
|
|
}
|
|
|
|
hdr->postpone = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* XXX diddle hdr->path. */
|
|
|
|
/* XXX keep track of created directories. */
|
|
|
|
rc = checkDirectory(hdr->path);
|
|
|
|
break;
|
|
|
|
case FI_PROCESS:
|
|
|
|
if (hdr->postpone)
|
|
|
|
break;
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("\t%s install %s.TID\n"), cur, hdr->path);
|
|
|
|
if (S_ISREG(st->st_mode))
|
|
|
|
rc = expandRegular(hdr);
|
|
|
|
else if (S_ISDIR(st->st_mode))
|
|
|
|
rc = createDirectory(hdr->path, 000);
|
|
|
|
else if (S_ISLNK(st->st_mode))
|
|
|
|
rc = expandSymlink(hdr);
|
|
|
|
else if (S_ISFIFO(st->st_mode))
|
|
|
|
rc = expandFifo(hdr);
|
|
|
|
else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
|
|
|
|
rc = expandDevice(hdr);
|
|
|
|
else if (S_ISSOCK(st->st_mode))
|
|
|
|
/* this mimics cpio but probably isnt' right */
|
|
|
|
rc = expandFifo(hdr);
|
|
|
|
else
|
|
|
|
rc = CPIOERR_UNKNOWN_FILETYPE;
|
|
|
|
break;
|
|
|
|
case FI_POST:
|
|
|
|
if (hdr->postpone)
|
|
|
|
break;
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("\t%s set info %s.TID\n"), cur, hdr->path);
|
|
|
|
if (!rc)
|
|
|
|
rc = setInfo(hdr);
|
|
|
|
|
|
|
|
if (!rc && S_ISREG(st->st_mode) && st->st_nlink > 1) {
|
|
|
|
hdr->li->createdPath = --hdr->li->linksLeft;
|
|
|
|
rc = createLinks(hdr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FI_NOTIFY:
|
|
|
|
pkgCallback(hdr);
|
|
|
|
break;
|
|
|
|
case FI_UNDO:
|
|
|
|
{ int olderrno = errno;
|
|
|
|
(void) unlink(hdr->path);
|
|
|
|
/* XXX remove created directories. */
|
|
|
|
errno = olderrno;
|
|
|
|
if (hdr->failedFile && *hdr->failedFile == NULL)
|
|
|
|
*hdr->failedFile = xstrdup(hdr->path);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FI_COMMIT:
|
|
|
|
rpmMessage(RPMMESS_DEBUG, _("\t%s rename/rmdir %s\n"), cur, hdr->path);
|
|
|
|
break;
|
|
|
|
case FI_DESTROY:
|
|
|
|
if (hdr->path) {
|
|
|
|
free((void *)hdr->path); hdr->path = NULL;
|
|
|
|
}
|
|
|
|
/* Create any remaining links (if no error), and clean up. */
|
|
|
|
rc = hdr->rc;
|
|
|
|
while ((hdr->li = hdr->links) != NULL) {
|
|
|
|
hdr->links = hdr->li->next;
|
|
|
|
hdr->li->next = NULL;
|
|
|
|
if (rc == 0 && hdr->li->linksLeft)
|
|
|
|
rc = (hdr->li->createdPath != -1)
|
|
|
|
? createLinks(hdr) : CPIOERR_MISSING_HARDLINK;
|
|
|
|
freeHardLink(hdr->li);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr->a = a;
|
|
|
|
hdr->rc = rc;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/** @todo Verify payload MD5 sum. */
|
2001-01-26 04:26:35 +08:00
|
|
|
int cpioInstallArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
|
|
|
|
const char ** failedFile)
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2000-03-23 23:49:50 +08:00
|
|
|
struct cpioHeader ch, *hdr = &ch;
|
2001-01-28 01:42:24 +08:00
|
|
|
#ifdef DYING
|
2001-01-23 03:11:19 +08:00
|
|
|
const void * map = NULL;
|
1997-05-07 01:38:05 +08:00
|
|
|
struct hardLink * links = NULL;
|
|
|
|
struct hardLink * li = NULL;
|
2001-01-28 01:42:24 +08:00
|
|
|
#endif
|
2000-04-16 04:21:15 +08:00
|
|
|
int rc = 0;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
#ifdef NOTYET
|
|
|
|
char * md5sum = NULL;
|
|
|
|
|
2000-12-03 05:53:44 +08:00
|
|
|
fdInitMD5(cfd, 0);
|
2000-10-24 21:46:51 +08:00
|
|
|
#endif
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
/* Initialize hdr. */
|
|
|
|
rc = hdrStage(hdr, FI_CREATE);
|
|
|
|
#ifdef DYING
|
2001-01-26 04:26:35 +08:00
|
|
|
memset(hdr, 0, sizeof(*hdr));
|
|
|
|
hdr->path = NULL;
|
2001-01-28 01:42:24 +08:00
|
|
|
hdr->map = NULL;
|
|
|
|
hdr->links = NULL;
|
|
|
|
hdr->li = NULL;
|
|
|
|
#endif
|
2001-01-26 04:26:35 +08:00
|
|
|
hdr->cfd = fdLink(cfd, "persist (cpioInstallArchive");
|
|
|
|
fdSetCpioPos(hdr->cfd, 0);
|
2001-01-28 01:42:24 +08:00
|
|
|
hdr->mapi = mapInitIterator(ts, fi);
|
|
|
|
hdr->failedFile = failedFile;
|
|
|
|
if (hdr->failedFile)
|
|
|
|
*hdr->failedFile = NULL;
|
1997-05-07 01:38:05 +08:00
|
|
|
|
2000-04-16 04:21:15 +08:00
|
|
|
do {
|
2001-01-28 01:42:24 +08:00
|
|
|
#ifdef DYING
|
2000-03-23 23:49:50 +08:00
|
|
|
struct stat * st;
|
|
|
|
|
|
|
|
if (hdr->path) {
|
2000-12-13 04:03:45 +08:00
|
|
|
free((void *)hdr->path);
|
2000-03-23 23:49:50 +08:00
|
|
|
hdr->path = NULL;
|
|
|
|
}
|
2001-01-28 01:42:24 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Clean hdr, free'ing memory, and read next archive header. */
|
|
|
|
rc = hdrStage(hdr, FI_INIT);
|
|
|
|
#ifdef DYING
|
|
|
|
rc = getNextHeader(hdr);
|
|
|
|
#endif
|
|
|
|
if (rc) {
|
1999-01-22 01:18:38 +08:00
|
|
|
#if 0 /* XXX this is the failure point for an unreadable rpm */
|
2001-01-04 04:19:27 +08:00
|
|
|
rpmError(RPMERR_BADPACKAGE, _("getNextHeader: %s\n"),
|
|
|
|
cpioStrerror(rc));
|
1999-01-22 01:18:38 +08:00
|
|
|
#endif
|
2001-01-23 03:11:19 +08:00
|
|
|
goto exit;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if (!strcmp(hdr->path, TRAILER))
|
1997-01-04 10:48:55 +08:00
|
|
|
break;
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
#ifdef DYING
|
|
|
|
st = &hdr->sb;
|
|
|
|
#endif
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
/* Remap mode/uid/gid/name of file from archive. */
|
|
|
|
(void) hdrStage(hdr, FI_MAP);
|
|
|
|
#ifdef DYING
|
|
|
|
if (hdr->mapi) {
|
|
|
|
hdr->map = mapFind(hdr->mapi, hdr->path);
|
|
|
|
if (hdr->map) {
|
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_PATH)) {
|
2000-12-13 04:03:45 +08:00
|
|
|
if (hdr->path) free((void *)hdr->path);
|
2001-01-28 01:42:24 +08:00
|
|
|
hdr->path = mapFsPath(hdr->map);
|
2000-03-23 23:49:50 +08:00
|
|
|
}
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_MODE))
|
|
|
|
st->st_mode = mapFinalMode(hdr->map);
|
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_UID))
|
|
|
|
st->st_uid = mapFinalUid(hdr->map);
|
|
|
|
if (mapFlags(hdr->map, CPIO_MAP_GID))
|
|
|
|
st->st_gid = mapFinalGid(hdr->map);
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
2001-01-28 01:42:24 +08:00
|
|
|
}
|
|
|
|
#endif
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
if (hdr->mapi && hdr->map == NULL) {
|
|
|
|
rc = hdrStage(hdr, FI_SKIP);
|
|
|
|
#ifdef DYING
|
|
|
|
eatBytes(hdr->cfd, st->st_size);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
#ifdef DYING
|
2001-01-26 04:26:35 +08:00
|
|
|
/*
|
|
|
|
* This won't get hard linked symlinks right, but I can't seem
|
|
|
|
* to create those anyway.
|
|
|
|
*/
|
2000-03-23 23:49:50 +08:00
|
|
|
if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
|
2001-01-28 01:42:24 +08:00
|
|
|
for (hdr->li = hdr->links; hdr->li; hdr->li = hdr->li->next) {
|
|
|
|
if (hdr->li->inode == st->st_ino &&
|
|
|
|
hdr->li->dev == st->st_dev)
|
|
|
|
break;
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
if (hdr->li == NULL) {
|
|
|
|
hdr->li = newHardLink(st, HARDLINK_BUILD);
|
|
|
|
hdr->li->next = hdr->links;
|
|
|
|
hdr->links = hdr->li;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
1997-05-07 01:38:05 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
hdr->li->files[hdr->li->linksLeft++] = xstrdup(hdr->path);
|
2000-03-23 23:49:50 +08:00
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
/* XXX FIXME 0 length hard linked files are broke. */
|
2001-01-28 01:42:24 +08:00
|
|
|
if (st->st_size && hdr->li->createdPath == -1) {
|
|
|
|
createLinks(hdr);
|
2001-01-26 04:26:35 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
eatBytes(hdr->cfd, st->st_size);
|
|
|
|
}
|
2001-01-28 01:42:24 +08:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2001-01-26 04:26:35 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
/* Create any directories in path. */
|
|
|
|
rc = hdrStage(hdr, FI_PRE);
|
|
|
|
#ifdef DYING */
|
2000-03-23 23:49:50 +08:00
|
|
|
rc = checkDirectory(hdr->path);
|
2001-01-28 01:42:24 +08:00
|
|
|
#endif
|
1997-05-07 01:38:05 +08:00
|
|
|
|
|
|
|
if (!rc) {
|
2001-01-28 01:42:24 +08:00
|
|
|
/* Extract file from archive. */
|
|
|
|
rc = hdrStage(hdr, FI_PROCESS);
|
|
|
|
#ifdef DYING
|
2000-03-23 23:49:50 +08:00
|
|
|
if (S_ISREG(st->st_mode))
|
2001-01-28 01:42:24 +08:00
|
|
|
rc = expandRegular(hdr);
|
2000-03-23 23:49:50 +08:00
|
|
|
else if (S_ISDIR(st->st_mode))
|
|
|
|
rc = createDirectory(hdr->path, 000);
|
|
|
|
else if (S_ISLNK(st->st_mode))
|
2001-01-26 04:26:35 +08:00
|
|
|
rc = expandSymlink(hdr);
|
2000-03-23 23:49:50 +08:00
|
|
|
else if (S_ISFIFO(st->st_mode))
|
2001-01-26 04:26:35 +08:00
|
|
|
rc = expandFifo(hdr);
|
2000-03-23 23:49:50 +08:00
|
|
|
else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
|
2001-01-26 04:26:35 +08:00
|
|
|
rc = expandDevice(hdr);
|
2000-03-23 23:49:50 +08:00
|
|
|
else if (S_ISSOCK(st->st_mode)) {
|
2001-01-26 04:26:35 +08:00
|
|
|
/* this mimics cpio but probably isnt' right */
|
|
|
|
rc = expandFifo(hdr);
|
1997-05-07 01:38:05 +08:00
|
|
|
} else {
|
1999-05-12 04:05:43 +08:00
|
|
|
rc = CPIOERR_UNKNOWN_FILETYPE;
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
2001-01-28 01:42:24 +08:00
|
|
|
#endif
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
/* If successfully extracted, set final file info. */
|
|
|
|
if (!rc)
|
|
|
|
rc = hdrStage(hdr, FI_POST);
|
|
|
|
#ifdef DYING
|
1997-05-07 01:38:05 +08:00
|
|
|
if (!rc)
|
2000-03-23 23:49:50 +08:00
|
|
|
rc = setInfo(hdr);
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
if (!rc && S_ISREG(st->st_mode) && st->st_nlink > 1) {
|
2000-04-16 04:21:15 +08:00
|
|
|
li->createdPath = --li->linksLeft;
|
2001-01-28 01:42:24 +08:00
|
|
|
rc = createLinks(hdr);
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
2001-01-28 01:42:24 +08:00
|
|
|
#endif
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
#ifdef DYING
|
|
|
|
if (rc && hdr->failedFile && *hdr->failedFile == NULL) {
|
2000-04-16 04:21:15 +08:00
|
|
|
int olderrno;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
*hdr->failedFile = xstrdup(hdr->path);
|
2000-04-16 04:21:15 +08:00
|
|
|
olderrno = errno;
|
2000-03-23 23:49:50 +08:00
|
|
|
unlink(hdr->path);
|
2000-04-16 04:21:15 +08:00
|
|
|
errno = olderrno;
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
2001-01-28 01:42:24 +08:00
|
|
|
#endif
|
1997-01-04 10:48:55 +08:00
|
|
|
}
|
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
padinfd(hdr->cfd, 4);
|
1997-05-06 23:27:46 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
/* Notify on success. */
|
2001-01-26 04:26:35 +08:00
|
|
|
if (!rc)
|
2001-01-28 01:42:24 +08:00
|
|
|
#ifdef DYING
|
|
|
|
pkgCallback(hdr);
|
|
|
|
#else
|
|
|
|
(void) hdrStage(hdr, FI_NOTIFY);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
(void) hdrStage(hdr, (rc ? FI_UNDO : FI_COMMIT));
|
1997-05-06 23:27:46 +08:00
|
|
|
|
2000-04-16 04:21:15 +08:00
|
|
|
} while (rc == 0);
|
2000-03-23 23:49:50 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
rc = hdrStage(hdr, FI_DESTROY);
|
|
|
|
#ifdef DYING
|
|
|
|
(void) hdrStage(hdr, FI_UNKNOWN);
|
2000-03-23 23:49:50 +08:00
|
|
|
if (hdr->path) {
|
2000-12-13 04:03:45 +08:00
|
|
|
free((void *)hdr->path);
|
2000-03-23 23:49:50 +08:00
|
|
|
hdr->path = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create any remaining links (if no error), and clean up. */
|
2001-01-28 01:42:24 +08:00
|
|
|
while ((hdr->li = hdr->links) != NULL) {
|
|
|
|
hdr->links = hdr->li->next;
|
|
|
|
hdr->li->next = NULL;
|
1997-01-04 10:48:55 +08:00
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
if (rc == 0 && hdr->li->linksLeft) {
|
|
|
|
if (hdr->li->createdPath == -1)
|
1999-05-12 04:05:43 +08:00
|
|
|
rc = CPIOERR_MISSING_HARDLINK;
|
2000-03-23 23:49:50 +08:00
|
|
|
else
|
2001-01-28 01:42:24 +08:00
|
|
|
rc = createLinks(hdr);
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
|
|
|
|
2001-01-28 01:42:24 +08:00
|
|
|
freeHardLink(hdr->li);
|
1997-05-07 01:38:05 +08:00
|
|
|
}
|
2001-01-28 01:42:24 +08:00
|
|
|
#endif
|
1997-05-07 01:38:05 +08:00
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
#ifdef NOTYET
|
2001-01-26 04:26:35 +08:00
|
|
|
fdFiniMD5(hdr->cfd, (void **)&md5sum, NULL, 1);
|
2000-10-24 21:46:51 +08:00
|
|
|
|
|
|
|
if (md5sum)
|
|
|
|
free(md5sum);
|
|
|
|
#endif
|
|
|
|
|
2001-01-23 03:11:19 +08:00
|
|
|
exit:
|
2001-01-28 01:42:24 +08:00
|
|
|
if (hdr->cfd) {
|
|
|
|
fdFree(hdr->cfd, "persist (cpioInstallArchive");
|
|
|
|
hdr->cfd = NULL;
|
|
|
|
}
|
2001-01-26 04:26:35 +08:00
|
|
|
if (hdr->mapi)
|
|
|
|
mapFreeIterator(hdr->mapi);
|
1997-01-04 10:48:55 +08:00
|
|
|
return rc;
|
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Write next item to payload stream.
|
2001-01-26 04:26:35 +08:00
|
|
|
* @param ts transaction set
|
|
|
|
* @param fi transaction element file info
|
2000-10-24 21:46:51 +08:00
|
|
|
* @param cfd payload file handle
|
|
|
|
* @param st stat info for item
|
|
|
|
* @param map mapping name and flags for item
|
|
|
|
* @retval sizep address of no. bytes written
|
|
|
|
* @param writeData should data be written?
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static int writeFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
|
|
|
|
const struct stat * st, const void * map, /*@out@*/ size_t * sizep,
|
2000-05-18 20:11:51 +08:00
|
|
|
int writeData)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd, *sizep @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2001-01-22 07:48:09 +08:00
|
|
|
const char * fsPath = mapFsPath(map);
|
2001-01-23 03:11:19 +08:00
|
|
|
const char * archivePath = NULL;
|
|
|
|
const char * hdrPath = !mapFlags(map, CPIO_MAP_PATH)
|
|
|
|
? fsPath : (archivePath = mapArchivePath(map));
|
1997-07-24 02:07:46 +08:00
|
|
|
struct cpioCrcPhysicalHeader hdr;
|
|
|
|
char buf[8192], symbuf[2048];
|
|
|
|
dev_t num;
|
1998-11-19 05:41:05 +08:00
|
|
|
FD_t datafd;
|
2000-05-18 20:11:51 +08:00
|
|
|
size_t st_size = st->st_size; /* XXX hard links need size preserved */
|
|
|
|
mode_t st_mode = st->st_mode;
|
|
|
|
uid_t st_uid = st->st_uid;
|
|
|
|
gid_t st_gid = st->st_gid;
|
1997-07-25 21:57:17 +08:00
|
|
|
size_t size, amount = 0;
|
2000-04-16 04:21:15 +08:00
|
|
|
int rc;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
if (mapFlags(map, CPIO_MAP_MODE))
|
|
|
|
st_mode = (st_mode & S_IFMT) | mapFinalMode(map);
|
|
|
|
if (mapFlags(map, CPIO_MAP_UID))
|
|
|
|
st_uid = mapFinalUid(map);
|
|
|
|
if (mapFlags(map, CPIO_MAP_GID))
|
|
|
|
st_gid = mapFinalGid(map);
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2000-05-18 20:11:51 +08:00
|
|
|
if (!writeData || S_ISDIR(st_mode)) {
|
|
|
|
st_size = 0;
|
|
|
|
} else if (S_ISLNK(st_mode)) {
|
2001-01-22 07:48:09 +08:00
|
|
|
/*
|
|
|
|
* While linux puts the size of a symlink in the st_size field,
|
|
|
|
* I don't think that's a specified standard.
|
|
|
|
*/
|
2001-01-21 23:43:32 +08:00
|
|
|
amount = Readlink(fsPath, symbuf, sizeof(symbuf));
|
1997-07-24 02:07:46 +08:00
|
|
|
if (amount <= 0) {
|
2001-01-22 07:48:09 +08:00
|
|
|
rc = CPIOERR_READLINK_FAILED;
|
|
|
|
goto exit;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
2000-05-18 20:11:51 +08:00
|
|
|
st_size = amount;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
|
2000-03-23 23:49:50 +08:00
|
|
|
SET_NUM_FIELD(hdr.inode, st->st_ino, buf);
|
2000-05-18 20:11:51 +08:00
|
|
|
SET_NUM_FIELD(hdr.mode, st_mode, buf);
|
|
|
|
SET_NUM_FIELD(hdr.uid, st_uid, buf);
|
|
|
|
SET_NUM_FIELD(hdr.gid, st_gid, buf);
|
2000-03-23 23:49:50 +08:00
|
|
|
SET_NUM_FIELD(hdr.nlink, st->st_nlink, buf);
|
|
|
|
SET_NUM_FIELD(hdr.mtime, st->st_mtime, buf);
|
2000-05-18 20:11:51 +08:00
|
|
|
SET_NUM_FIELD(hdr.filesize, st_size, buf);
|
2000-03-23 23:49:50 +08:00
|
|
|
|
|
|
|
num = major((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMajor, num, buf);
|
|
|
|
num = minor((unsigned)st->st_dev); SET_NUM_FIELD(hdr.devMinor, num, buf);
|
|
|
|
num = major((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMajor, num, buf);
|
|
|
|
num = minor((unsigned)st->st_rdev); SET_NUM_FIELD(hdr.rdevMinor, num, buf);
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2001-01-23 03:11:19 +08:00
|
|
|
num = strlen(hdrPath) + 1; SET_NUM_FIELD(hdr.namesize, num, buf);
|
1997-07-24 02:07:46 +08:00
|
|
|
memcpy(hdr.checksum, "00000000", 8);
|
|
|
|
|
1998-12-06 03:18:43 +08:00
|
|
|
if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
|
2001-01-22 07:48:09 +08:00
|
|
|
goto exit;
|
2001-01-23 03:11:19 +08:00
|
|
|
if ((rc = safewrite(cfd, hdrPath, num)) != num)
|
2001-01-22 07:48:09 +08:00
|
|
|
goto exit;
|
1998-12-04 03:30:32 +08:00
|
|
|
size = PHYS_HDR_SIZE + num;
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = padoutfd(cfd, &size, 4)))
|
2001-01-22 07:48:09 +08:00
|
|
|
goto exit;
|
2000-03-23 23:49:50 +08:00
|
|
|
|
2000-05-18 20:11:51 +08:00
|
|
|
if (writeData && S_ISREG(st_mode)) {
|
1999-01-14 06:10:00 +08:00
|
|
|
char *b;
|
|
|
|
#if HAVE_MMAP
|
|
|
|
void *mapped;
|
|
|
|
size_t nmapped;
|
|
|
|
#endif
|
|
|
|
|
1999-11-05 05:26:08 +08:00
|
|
|
/* XXX unbuffered mmap generates *lots* of fdio debugging */
|
2001-01-21 23:43:32 +08:00
|
|
|
datafd = Fopen(fsPath, "r.ufdio");
|
2001-01-22 07:48:09 +08:00
|
|
|
if (datafd == NULL || Ferror(datafd)) {
|
|
|
|
rc = CPIOERR_OPEN_FAILED;
|
|
|
|
goto exit;
|
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1999-01-14 06:10:00 +08:00
|
|
|
#if HAVE_MMAP
|
|
|
|
nmapped = 0;
|
2000-05-18 20:11:51 +08:00
|
|
|
mapped = mmap(NULL, st_size, PROT_READ, MAP_SHARED, Fileno(datafd), 0);
|
1999-01-14 06:10:00 +08:00
|
|
|
if (mapped != (void *)-1) {
|
|
|
|
b = (char *)mapped;
|
2000-05-18 20:11:51 +08:00
|
|
|
nmapped = st_size;
|
1999-01-14 06:10:00 +08:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
b = buf;
|
|
|
|
}
|
|
|
|
|
2000-05-18 20:11:51 +08:00
|
|
|
size += st_size;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2000-05-18 20:11:51 +08:00
|
|
|
while (st_size) {
|
1999-01-14 06:10:00 +08:00
|
|
|
#if HAVE_MMAP
|
|
|
|
if (mapped != (void *)-1) {
|
|
|
|
amount = nmapped;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
1999-11-11 06:09:49 +08:00
|
|
|
amount = Fread(b, sizeof(buf[0]),
|
2000-05-18 20:11:51 +08:00
|
|
|
(st_size > sizeof(buf) ? sizeof(buf) : st_size),
|
1999-11-11 06:09:49 +08:00
|
|
|
datafd);
|
1997-07-24 02:07:46 +08:00
|
|
|
if (amount <= 0) {
|
2000-04-16 04:21:15 +08:00
|
|
|
int olderrno = errno;
|
1999-10-28 07:18:10 +08:00
|
|
|
Fclose(datafd);
|
1997-07-24 02:07:46 +08:00
|
|
|
errno = olderrno;
|
2001-01-22 07:48:09 +08:00
|
|
|
rc = CPIOERR_READ_FAILED;
|
|
|
|
goto exit;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
1999-01-14 06:10:00 +08:00
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1999-01-14 06:10:00 +08:00
|
|
|
if ((rc = safewrite(cfd, b, amount)) != amount) {
|
2000-04-16 04:21:15 +08:00
|
|
|
int olderrno = errno;
|
1999-10-28 07:18:10 +08:00
|
|
|
Fclose(datafd);
|
1997-07-24 02:07:46 +08:00
|
|
|
errno = olderrno;
|
2001-01-22 07:48:09 +08:00
|
|
|
goto exit;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
2000-05-18 20:11:51 +08:00
|
|
|
st_size -= amount;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
1997-08-01 00:02:19 +08:00
|
|
|
|
1999-01-14 06:10:00 +08:00
|
|
|
#if HAVE_MMAP
|
|
|
|
if (mapped != (void *)-1) {
|
2000-03-23 23:49:50 +08:00
|
|
|
/*@-noeffect@*/ munmap(mapped, nmapped) /*@=noeffect@*/;
|
1999-01-14 06:10:00 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-10-28 07:18:10 +08:00
|
|
|
Fclose(datafd);
|
2000-05-18 20:11:51 +08:00
|
|
|
} else if (writeData && S_ISLNK(st_mode)) {
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = safewrite(cfd, symbuf, amount)) != amount)
|
2001-01-22 07:48:09 +08:00
|
|
|
goto exit;
|
1997-07-24 02:07:46 +08:00
|
|
|
size += amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this is a noop for most file types */
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = padoutfd(cfd, &size, 4)))
|
2001-01-22 07:48:09 +08:00
|
|
|
goto exit;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1999-09-18 05:31:38 +08:00
|
|
|
if (sizep)
|
|
|
|
*sizep = size;
|
2001-01-26 04:26:35 +08:00
|
|
|
|
|
|
|
if (ts && fi && ts->notify) {
|
|
|
|
(void)ts->notify(fi->h, RPMCALLBACK_INST_PROGRESS, size, size,
|
|
|
|
(fi->ap ? fi->ap->key : NULL), ts->notifyData);
|
|
|
|
}
|
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
rc = 0;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
exit:
|
|
|
|
if (fsPath) free((void *)fsPath);
|
|
|
|
return rc;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
2000-10-24 21:46:51 +08:00
|
|
|
/**
|
|
|
|
* Write set of linked files to payload stream.
|
2001-01-26 04:26:35 +08:00
|
|
|
* @param ts transaction set
|
|
|
|
* @param fi transaction element file info
|
2000-10-24 21:46:51 +08:00
|
|
|
* @param cfd payload file handle
|
|
|
|
* @param hlink set of linked files
|
|
|
|
* @retval sizep address of no. bytes written
|
|
|
|
* @retval failedFile on error, file name that failed
|
|
|
|
* @return 0 on success
|
|
|
|
*/
|
2001-01-26 04:26:35 +08:00
|
|
|
static int writeLinkedFile(const rpmTransactionSet ts, TFI_t fi, FD_t cfd,
|
|
|
|
const struct hardLink * hlink, /*@out@*/size_t * sizep,
|
|
|
|
/*@out@*/const char ** failedFile)
|
2000-08-23 20:39:49 +08:00
|
|
|
/*@modifies cfd, *sizep, *failedFile @*/
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2001-01-23 03:11:19 +08:00
|
|
|
const void * map = NULL;
|
2001-01-21 23:43:32 +08:00
|
|
|
size_t total = 0;
|
|
|
|
size_t size;
|
2001-01-23 03:11:19 +08:00
|
|
|
int rc = 0;
|
|
|
|
int i;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
|
|
|
for (i = hlink->nlink - 1; i > hlink->linksLeft; i--) {
|
2001-01-22 07:48:09 +08:00
|
|
|
map = hlink->fileMaps[i];
|
2001-01-26 04:26:35 +08:00
|
|
|
if ((rc = writeFile(ts, fi, cfd, &hlink->sb, map, &size, 0)) != 0) {
|
2001-01-22 07:48:09 +08:00
|
|
|
if (failedFile)
|
2001-01-23 03:11:19 +08:00
|
|
|
*failedFile = mapFsPath(map);
|
|
|
|
goto exit;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
1999-09-18 05:31:38 +08:00
|
|
|
total += size;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2001-01-23 03:11:19 +08:00
|
|
|
mapFree(map); map = NULL;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
2001-01-21 23:43:32 +08:00
|
|
|
i = hlink->linksLeft;
|
2001-01-22 07:48:09 +08:00
|
|
|
map = hlink->fileMaps[i];
|
2001-01-26 04:26:35 +08:00
|
|
|
if ((rc = writeFile(ts, fi, cfd, &hlink->sb, map, &size, 1))) {
|
1999-09-18 05:31:38 +08:00
|
|
|
if (sizep)
|
|
|
|
*sizep = total;
|
2001-01-22 07:48:09 +08:00
|
|
|
if (failedFile)
|
2001-01-23 03:11:19 +08:00
|
|
|
*failedFile = mapFsPath(map);
|
|
|
|
goto exit;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
1999-09-18 05:31:38 +08:00
|
|
|
total += size;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1999-09-18 05:31:38 +08:00
|
|
|
if (sizep)
|
|
|
|
*sizep = total;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2001-01-23 03:11:19 +08:00
|
|
|
rc = 0;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2001-01-23 03:11:19 +08:00
|
|
|
exit:
|
|
|
|
if (map)
|
|
|
|
mapFree(map);
|
|
|
|
return rc;
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
int cpioBuildArchive(const rpmTransactionSet ts, const TFI_t fi, FD_t cfd,
|
|
|
|
unsigned int * archiveSize, const char ** failedFile)
|
1999-09-18 05:31:38 +08:00
|
|
|
{
|
2001-01-26 04:26:35 +08:00
|
|
|
void * mapi = mapInitIterator(ts, fi);
|
2001-01-23 03:11:19 +08:00
|
|
|
const void * map;
|
1998-11-20 03:10:23 +08:00
|
|
|
/*@-fullinitblock@*/
|
1997-07-24 02:07:46 +08:00
|
|
|
struct hardLink hlinkList = { NULL };
|
1998-11-20 03:10:23 +08:00
|
|
|
/*@=fullinitblock@*/
|
2000-05-18 20:11:51 +08:00
|
|
|
struct stat * st = (struct stat *) &hlinkList.sb;
|
2000-03-23 23:49:50 +08:00
|
|
|
struct hardLink * hlink;
|
2001-01-23 03:11:19 +08:00
|
|
|
size_t totalsize = 0;
|
|
|
|
size_t size;
|
|
|
|
int rc;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
1997-07-31 22:04:56 +08:00
|
|
|
hlinkList.next = NULL;
|
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
while ((map = mapNextIterator(mapi)) != NULL) {
|
|
|
|
const char * fsPath;
|
2000-05-18 20:11:51 +08:00
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
fsPath = mapFsPath(map);
|
2000-05-18 20:11:51 +08:00
|
|
|
|
2001-01-22 07:48:09 +08:00
|
|
|
if (mapFlags(map, CPIO_FOLLOW_SYMLINKS))
|
2001-01-21 23:43:32 +08:00
|
|
|
rc = Stat(fsPath, st);
|
1997-07-31 22:04:56 +08:00
|
|
|
else
|
2001-01-21 23:43:32 +08:00
|
|
|
rc = Lstat(fsPath, st);
|
1997-07-31 22:04:56 +08:00
|
|
|
|
1997-08-01 00:02:19 +08:00
|
|
|
if (rc) {
|
1999-09-18 05:31:38 +08:00
|
|
|
if (failedFile)
|
2001-01-22 07:48:09 +08:00
|
|
|
*failedFile = fsPath;
|
1998-12-06 07:22:41 +08:00
|
|
|
return CPIOERR_STAT_FAILED;
|
1997-08-01 00:02:19 +08:00
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
|
1997-07-24 02:07:46 +08:00
|
|
|
hlink = hlinkList.next;
|
2000-03-23 23:49:50 +08:00
|
|
|
while (hlink &&
|
|
|
|
(hlink->dev != st->st_dev || hlink->inode != st->st_ino))
|
|
|
|
hlink = hlink->next;
|
|
|
|
if (hlink == NULL) {
|
|
|
|
hlink = newHardLink(st, HARDLINK_INSTALL);
|
1997-07-24 02:07:46 +08:00
|
|
|
hlink->next = hlinkList.next;
|
|
|
|
hlinkList.next = hlink;
|
|
|
|
}
|
|
|
|
|
2001-01-23 03:11:19 +08:00
|
|
|
hlink->fileMaps[--hlink->linksLeft] = mapLink(map);
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if (hlink->linksLeft == 0) {
|
|
|
|
struct hardLink * prev;
|
2001-01-26 04:26:35 +08:00
|
|
|
rc = writeLinkedFile(ts, fi, cfd, hlink, &size, failedFile);
|
2001-01-22 07:48:09 +08:00
|
|
|
if (rc) {
|
|
|
|
free((void *)fsPath);
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
2001-01-22 07:48:09 +08:00
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
|
|
|
totalsize += size;
|
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
prev = &hlinkList;
|
|
|
|
do {
|
|
|
|
if (prev->next != hlink)
|
|
|
|
continue;
|
|
|
|
prev->next = hlink->next;
|
|
|
|
hlink->next = NULL;
|
|
|
|
freeHardLink(hlink);
|
|
|
|
hlink = NULL;
|
|
|
|
break;
|
|
|
|
} while ((prev = prev->next) != NULL);
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
} else {
|
2001-01-26 04:26:35 +08:00
|
|
|
if ((rc = writeFile(ts, fi, cfd, st, map, &size, 1))) {
|
1999-09-18 05:31:38 +08:00
|
|
|
if (failedFile)
|
2001-01-22 07:48:09 +08:00
|
|
|
*failedFile = fsPath;
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
totalsize += size;
|
|
|
|
}
|
2001-01-22 07:48:09 +08:00
|
|
|
free((void *)fsPath);
|
|
|
|
fsPath = NULL;
|
2000-03-23 23:49:50 +08:00
|
|
|
}
|
2001-01-22 07:48:09 +08:00
|
|
|
mapFreeIterator(mapi);
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
rc = 0;
|
|
|
|
while ((hlink = hlinkList.next) != NULL) {
|
|
|
|
hlinkList.next = hlink->next;
|
|
|
|
hlink->next = NULL;
|
1997-10-04 00:08:20 +08:00
|
|
|
|
2000-03-23 23:49:50 +08:00
|
|
|
if (rc == 0) {
|
2001-01-26 04:26:35 +08:00
|
|
|
rc = writeLinkedFile(ts, fi, cfd, hlink, &size, failedFile);
|
2000-03-23 23:49:50 +08:00
|
|
|
totalsize += size;
|
|
|
|
}
|
|
|
|
freeHardLink(hlink);
|
1997-07-24 02:07:46 +08:00
|
|
|
}
|
2000-03-23 23:49:50 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
1997-07-24 02:07:46 +08:00
|
|
|
|
2001-01-26 04:26:35 +08:00
|
|
|
{ struct cpioCrcPhysicalHeader hdr;
|
|
|
|
memset(&hdr, '0', PHYS_HDR_SIZE);
|
|
|
|
memcpy(hdr.magic, CPIO_NEWC_MAGIC, sizeof(hdr.magic));
|
|
|
|
memcpy(hdr.nlink, "00000001", 8);
|
|
|
|
memcpy(hdr.namesize, "0000000b", 8);
|
|
|
|
if ((rc = safewrite(cfd, &hdr, PHYS_HDR_SIZE)) != PHYS_HDR_SIZE)
|
|
|
|
return rc;
|
|
|
|
if ((rc = safewrite(cfd, "TRAILER!!!", 11)) != 11)
|
|
|
|
return rc;
|
|
|
|
totalsize += PHYS_HDR_SIZE + 11;
|
|
|
|
}
|
1997-07-24 02:07:46 +08:00
|
|
|
|
|
|
|
/* GNU cpio pads to 512 bytes here, but we don't. I'm not sure if
|
|
|
|
it matters or not */
|
2000-03-23 23:49:50 +08:00
|
|
|
|
1998-07-25 23:33:15 +08:00
|
|
|
if ((rc = padoutfd(cfd, &totalsize, 4)))
|
1997-07-24 02:07:46 +08:00
|
|
|
return rc;
|
|
|
|
|
1997-08-25 22:38:48 +08:00
|
|
|
if (archiveSize) *archiveSize = totalsize;
|
|
|
|
|
1997-07-24 02:07:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
1998-12-06 07:22:41 +08:00
|
|
|
|
2001-01-21 23:43:32 +08:00
|
|
|
const char *const cpioStrerror(int rc)
|
1998-12-06 07:22:41 +08:00
|
|
|
{
|
|
|
|
static char msg[256];
|
|
|
|
char *s;
|
|
|
|
int l, myerrno = errno;
|
|
|
|
|
|
|
|
strcpy(msg, "cpio: ");
|
|
|
|
switch (rc) {
|
|
|
|
default:
|
|
|
|
s = msg + strlen(msg);
|
1999-09-18 05:31:38 +08:00
|
|
|
sprintf(s, _("(error 0x%x)"), (unsigned)rc);
|
1998-12-06 07:22:41 +08:00
|
|
|
s = NULL;
|
|
|
|
break;
|
|
|
|
case CPIOERR_BAD_MAGIC: s = _("Bad magic"); break;
|
1999-01-22 01:18:38 +08:00
|
|
|
case CPIOERR_BAD_HEADER: s = _("Bad/unreadable header");break;
|
1998-12-06 07:22:41 +08:00
|
|
|
|
|
|
|
case CPIOERR_OPEN_FAILED: s = "open"; break;
|
|
|
|
case CPIOERR_CHMOD_FAILED: s = "chmod"; break;
|
|
|
|
case CPIOERR_CHOWN_FAILED: s = "chown"; break;
|
|
|
|
case CPIOERR_WRITE_FAILED: s = "write"; break;
|
|
|
|
case CPIOERR_UTIME_FAILED: s = "utime"; break;
|
|
|
|
case CPIOERR_UNLINK_FAILED: s = "unlink"; break;
|
|
|
|
case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
|
|
|
|
case CPIOERR_STAT_FAILED: s = "stat"; break;
|
|
|
|
case CPIOERR_MKDIR_FAILED: s = "mkdir"; break;
|
|
|
|
case CPIOERR_MKNOD_FAILED: s = "mknod"; break;
|
|
|
|
case CPIOERR_MKFIFO_FAILED: s = "mkfifo"; break;
|
|
|
|
case CPIOERR_LINK_FAILED: s = "link"; break;
|
|
|
|
case CPIOERR_READLINK_FAILED: s = "readlink"; break;
|
|
|
|
case CPIOERR_READ_FAILED: s = "read"; break;
|
|
|
|
case CPIOERR_COPY_FAILED: s = "copy"; break;
|
|
|
|
|
|
|
|
case CPIOERR_HDR_SIZE: s = _("Header size too big"); break;
|
|
|
|
case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
|
1999-05-12 04:05:43 +08:00
|
|
|
case CPIOERR_MISSING_HARDLINK: s = _("Missing hard link"); break;
|
2000-10-24 21:46:51 +08:00
|
|
|
case CPIOERR_MD5SUM_MISMATCH: s = _("MD5 sum mismatch"); break;
|
1999-05-12 04:05:43 +08:00
|
|
|
case CPIOERR_INTERNAL: s = _("Internal error"); break;
|
1998-12-06 07:22:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
l = sizeof(msg) - strlen(msg) - 1;
|
|
|
|
if (s != NULL) {
|
|
|
|
if (l > 0) strncat(msg, s, l);
|
|
|
|
l -= strlen(s);
|
|
|
|
}
|
2000-01-25 06:13:45 +08:00
|
|
|
if ((rc & CPIOERR_CHECK_ERRNO) && myerrno) {
|
1998-12-06 07:22:41 +08:00
|
|
|
s = _(" failed - ");
|
|
|
|
if (l > 0) strncat(msg, s, l);
|
|
|
|
l -= strlen(s);
|
|
|
|
if (l > 0) strncat(msg, strerror(myerrno), l);
|
|
|
|
}
|
|
|
|
return msg;
|
|
|
|
}
|