rpm  4.12.0.1
rpm2archive.c
Go to the documentation of this file.
1 /* rpmarchive: spit out the main archive portion of a package */
2 
3 #include "system.h"
4 const char *__progname;
5 
6 #include <rpm/rpmlib.h> /* rpmReadPackageFile .. */
7 #include <rpm/rpmfi.h>
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmio.h>
10 #include <rpm/rpmpgp.h>
11 
12 #include <rpm/rpmts.h>
13 
14 #include <archive.h>
15 #include <archive_entry.h>
16 
17 #include "debug.h"
18 
19 #define BUFSIZE (128*1024)
20 
21 static void fill_archive_entry(struct archive * a, struct archive_entry * entry, rpmfi fi)
22 {
23  archive_entry_clear(entry);
24 
25  char * filename = rstrscat(NULL, ".", rpmfiDN(fi), rpmfiBN(fi), NULL);
26  archive_entry_copy_pathname(entry, filename);
27  _free(filename);
28 
29  archive_entry_set_size(entry, rpmfiFSize(fi));
31  archive_entry_set_filetype(entry, mode & S_IFMT);
32  archive_entry_set_perm(entry, mode);
33 
34  archive_entry_set_uname(entry, rpmfiFUser(fi));
35  archive_entry_set_gname(entry, rpmfiFGroup(fi));
36  archive_entry_set_rdev(entry, rpmfiFRdev(fi));
37  archive_entry_set_mtime(entry, rpmfiFMtime(fi), 0);
38 
39  if (S_ISLNK(mode))
40  archive_entry_set_symlink(entry, rpmfiFLink(fi));
41 }
42 
43 static void write_file_content(struct archive * a, char * buf, rpmfi fi)
44 {
45  rpm_loff_t left = rpmfiFSize(fi);
46  size_t len, read;
47 
48  while (left) {
49  len = (left > BUFSIZE ? BUFSIZE : left);
50  read = rpmfiArchiveRead(fi, buf, len);
51  if (read==len) {
52  archive_write_data(a, buf, len);
53  } else {
54  fprintf(stderr, "Error reading file from rpm payload\n");
55  break;
56  }
57  left -= len;
58  }
59 }
60 
61 static int process_package(rpmts ts, char * filename)
62 {
63  FD_t fdi;
64  FD_t gzdi;
65  Header h;
66  int rc = 0;
67  char * rpmio_flags = NULL;
68  struct archive *a;
69  struct archive_entry *entry;
70 
71  if (!strcmp(filename, "-")) {
72  fdi = fdDup(STDIN_FILENO);
73  } else {
74  fdi = Fopen(filename, "r.ufdio");
75  }
76 
77  if (Ferror(fdi)) {
78  fprintf(stderr, "rpm2archive: %s: %s\n",
79  filename, Fstrerror(fdi));
80  exit(EXIT_FAILURE);
81  }
82 
83  rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h);
84 
85  switch (rc) {
86  case RPMRC_OK:
87  case RPMRC_NOKEY:
88  case RPMRC_NOTTRUSTED:
89  break;
90  case RPMRC_NOTFOUND:
91  fprintf(stderr, _("argument is not an RPM package\n"));
92  exit(EXIT_FAILURE);
93  break;
94  case RPMRC_FAIL:
95  default:
96  fprintf(stderr, _("error reading header from package\n"));
97  exit(EXIT_FAILURE);
98  break;
99  }
100 
101 
102  /* Retrieve payload size and compression type. */
103  { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
104  rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
105  }
106 
107  gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */
108  free(rpmio_flags);
109 
110  if (gzdi == NULL) {
111  fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
112  exit(EXIT_FAILURE);
113  }
114 
115  rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
117 
118  /* create archive */
119  a = archive_write_new();
120  archive_write_add_filter_gzip(a);
121  archive_write_set_format_pax_restricted(a);
122 
123  if (!strcmp(filename, "-")) {
124  archive_write_open_fd(a, 1);
125  } else {
126  char * outname = rstrscat(NULL, filename, ".tgz", NULL);
127  archive_write_open_filename(a, outname);
128  _free(outname);
129  // XXX error handling
130  }
131 
132  entry = archive_entry_new();
133 
134  char * buf = xmalloc(BUFSIZE);
135  char * hardlink = NULL;
136 
137  rc = 0;
138  while (rc >= 0) {
139  rc = rpmfiNext(fi);
140  if (rc == RPMERR_ITER_END) {
141  break;
142  }
143 
144  rpm_mode_t mode = rpmfiFMode(fi);
145  int nlink = rpmfiFNlink(fi);
146 
147  fill_archive_entry(a, entry, fi);
148 
149  if (nlink > 1) {
150  if (rpmfiArchiveHasContent(fi)) {
151  _free(hardlink);
152  hardlink = rstrscat(NULL, ".", rpmfiFN(fi), NULL);
153  } else {
154  archive_entry_set_hardlink(entry, hardlink);
155  }
156  }
157 
158  archive_write_header(a, entry);
159 
160  if (S_ISREG(mode) && (nlink == 1 || rpmfiArchiveHasContent(fi))) {
161  write_file_content(a, buf, fi);
162  }
163  }
164  _free(hardlink);
165 
166  Fclose(gzdi); /* XXX gzdi == fdi */
167  archive_entry_free(entry);
168  archive_write_close(a);
169  archive_write_free(a);
170  buf = _free(buf);
171  rpmfilesFree(files);
172  rpmfiFree(fi);
173  headerFree(h);
174  return rc;
175 }
176 
177 int main(int argc, char *argv[])
178 {
179  int rc;
180 
181  setprogname(argv[0]); /* Retrofit glibc __progname */
182  rpmReadConfigFiles(NULL, NULL);
183  char * filename;
184  if (argc == 1)
185  filename = "-";
186  else {
187  if (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")) {
188  fprintf(stderr, "Usage: rpm2archive file.rpm\n");
189  exit(EXIT_FAILURE);
190  } else {
191  filename = argv[1];
192  }
193  }
194 
195  rpmts ts = rpmtsCreate();
196  rpmVSFlags vsflags = 0;
197 
198  /* XXX retain the ageless behavior of rpm2cpio */
199  vsflags |= _RPMVSF_NODIGESTS;
200  vsflags |= _RPMVSF_NOSIGNATURES;
201  vsflags |= RPMVSF_NOHDRCHK;
202  (void) rpmtsSetVSFlags(ts, vsflags);
203 
204  rc = process_package(ts, filename);
205 
206  ts = rpmtsFree(ts);
207 
208  return rc;
209 }
#define setprogname(pn)
Definition: system.h:97
const char * rpmfiFLink(rpmfi fi)
Return current file linkto (i.e.
#define xmalloc(_size)
Definition: system.h:83
size_t rpmfiArchiveRead(rpmfi fi, void *buf, size_t size)
Read content from current file in archive.
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char *fn, Header *hdrp)
Return package header from file handle, verifying digests/signatures.
rpm_mode_t rpmfiFMode(rpmfi fi)
Return current file mode from file info set iterator.
rpmts rpmtsFree(rpmts ts)
Destroy transaction set, closing the database as well.
#define BUFSIZE
Definition: rpm2archive.c:19
Header headerFree(Header h)
Dereference a header instance.
struct rpmts_s * rpmts
The main types involved in transaction manipulation.
Definition: rpmtypes.h:63
#define _(Text)
Definition: system.h:110
rpm_rdev_t rpmfiFRdev(rpmfi fi)
Return current file rdev from file info set iterator.
rpmts rpmtsCreate(void)
Create an empty transaction set.
struct rpmfi_s * rpmfi
Definition: rpmtypes.h:66
const char * rpmfiFUser(rpmfi fi)
Return current file owner from file info set iterator.
struct _FD_s * FD_t
RPM IO file descriptor type.
Definition: rpmtypes.h:98
int rpmfiArchiveHasContent(rpmfi fi)
Has current file content stored in the archive.
int rpmReadConfigFiles(const char *file, const char *target)
Read macro configuration file(s) for a target.
static int rstreq(const char *s1, const char *s2)
Test for string equality.
Definition: rpmstring.h:113
const char * rpmfiFGroup(rpmfi fi)
Return current file group from file info set iterator.
const char * rpmfiBN(rpmfi fi)
Return current base name from file info set iterator.
char * rstrscat(char **dest, const char *arg,...) RPM_GNUC_NULL_TERMINATED
Concatenate multiple strings with dynamically (re)allocated memory.
FD_t Fdopen(FD_t ofd, const char *fmode)
struct headerToken_s * Header
RPM header and data retrieval types.
Definition: rpmtypes.h:24
const char * rpmfiFN(rpmfi fi)
Return current file name from file info set iterator.
rpm_loff_t rpmfiFSize(rpmfi fi)
Return current file size from file info set iterator.
rpmfi rpmfiFree(rpmfi fi)
Destroy a file info set iterator.
static void write_file_content(struct archive *a, char *buf, rpmfi fi)
Definition: rpm2archive.c:43
rpmFlags rpmVSFlags
Definition: rpmts.h:110
int main(int argc, char *argv[])
Definition: rpm2archive.c:177
static int process_package(rpmts ts, char *filename)
Definition: rpm2archive.c:61
rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
Set verify signatures flag(s).
static int mode
Definition: rpmdb.c:21
rpmfi rpmfiNewArchiveReader(FD_t fd, rpmfiles files, int itype)
Get new file iterator for looping over the archive content.
rpmfiles rpmfilesFree(rpmfiles fi)
Destroy a file info set.
int rpmfiNext(rpmfi fi)
Return next file iterator index.
#define _free(_ptr)
Definition: system.h:87
#define _RPMVSF_NOSIGNATURES
Definition: rpmts.h:118
const char * Fstrerror(FD_t fd)
strerror(3) clone.
FD_t fdDup(int fdno)
rpmfiles rpmfilesNew(rpmstrPool pool, Header h, rpmTagVal tagN, rpmfiFlags flags)
Create and load a file info set.
const char * rpmfiDN(rpmfi fi)
Return current directory name from file info set iterator.
FD_t Fopen(const char *path, const char *fmode)
fopen(3) clone.
#define __progname
Definition: system.h:96
static void fill_archive_entry(struct archive *a, struct archive_entry *entry, rpmfi fi)
Definition: rpm2archive.c:21
#define _RPMVSF_NODIGESTS
Definition: rpmts.h:112
uint16_t rpm_mode_t
Definition: rpmtypes.h:53
uint32_t rpmfiFNlink(rpmfi fi)
Return (calculated) current file nlink count from file info set iterator.
const char * headerGetString(Header h, rpmTagVal tag)
Return a simple string tag from header.
struct rpmfiles_s * rpmfiles
Definition: rpmtypes.h:67
uint64_t rpm_loff_t
Definition: rpmtypes.h:51
int Ferror(FD_t fd)
ferror(3) clone.
int Fclose(FD_t fd)
fclose(3) clone.
rpm_time_t rpmfiFMtime(rpmfi fi)
Return current file modify time from file info set iterator.