1 /*
2  * Copyright (c) 2004 Michael Schroeder (mls@suse.de)
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 
14 #include "rpml.h"
15 #include "util.h"
16 #include "rpmhead.h"
17 
18 /****************************************************************
19  *
20  * rpml
21  *
22  */
23 
24 static int
rpmlget16(FILE * fp)25 rpmlget16(FILE *fp)
26 {
27   int r;
28   r = getc(fp);
29   r = r << 8 | getc(fp);
30   return r;
31 }
32 
33 static int
rpmlget32(FILE * fp)34 rpmlget32(FILE *fp)
35 {
36   int r;
37   r = getc(fp);
38   r = r << 8 | getc(fp);
39   r = r << 8 | getc(fp);
40   r = r << 8 | getc(fp);
41   return r;
42 }
43 
44 static char *
rpmlgetstr(FILE * fp)45 rpmlgetstr(FILE *fp)
46 {
47   int l;
48   char *s, *s2;
49 
50   l = getc(fp);
51   s = s2 = xmalloc(l + 2);
52   while(l-- > 0)
53     *s2++ = getc(fp);
54   *s2 = 0;
55   return s;
56 }
57 
58 static void
rpmlskip(FILE * fp,int l)59 rpmlskip(FILE *fp, int l)
60 {
61   while(l-- > 0)
62     (void)getc(fp);
63 }
64 
65 static char *
rpmlgetfn(FILE * fp,char ** lastfnp,int * lastfnlp)66 rpmlgetfn(FILE *fp, char **lastfnp, int *lastfnlp)
67 {
68   int ol, l;
69   char *n;
70   char *lastfn = *lastfnp;
71   int lastfnl = *lastfnlp;
72 
73   ol = getc(fp);
74   if (ol == EOF)
75     {
76       fprintf(stderr, "rpmlgetfn: EOF reached!\n");
77       exit(1);
78     }
79   l = getc(fp);
80   if (l == 255)
81     l = rpmlget16(fp);
82   if (l + ol + 1 > lastfnl)
83     {
84       lastfn = xrealloc(lastfn, l + ol + 1);
85       lastfnl = l + ol + 1;
86     }
87   n = lastfn + ol;
88   while(l-- > 0)
89     *n++ = getc(fp);
90   *n = 0;
91   *lastfnp = lastfn;
92   *lastfnlp = lastfnl;
93   return lastfn;
94 }
95 
96 char *
rpmlread(FILE * fp,char * fn,int nomagic,struct rpmlfile ** filesp,int * nfilesp)97 rpmlread(FILE *fp, char *fn, int nomagic, struct rpmlfile **filesp, int *nfilesp)
98 {
99   int lastfnl = 0;
100   char *lastfn = 0;
101   char *n, *name, *evr, *nevr;
102   char *buildhost;
103   unsigned int buildtime;
104   int patchescnt, filec, i;
105   struct rpmlfile *files = 0;
106   int nfiles = 0;
107   unsigned int mode, s, ogs;
108 
109   if (!nomagic && rpmlget32(fp) != 0x52504d4c)
110     {
111       fprintf(stderr, "%s: not an rpml file\n", fn);
112       exit(1);
113     }
114   name = rpmlgetstr(fp);
115   evr = rpmlgetstr(fp);
116   nevr = xmalloc(strlen(name) + strlen(evr) + 2);
117   sprintf(nevr, "%s-%s", name, evr);
118   buildhost = rpmlgetstr(fp);
119   buildtime = rpmlget32(fp);
120   patchescnt = rpmlget16(fp);
121   xfree(name);
122   xfree(evr);
123   xfree(buildhost);
124   if (patchescnt)
125     {
126       for (i = 0; i < patchescnt; i++)
127 	rpmlgetstr(fp);
128       filec = rpmlget32(fp);
129       for (i = 0; i < filec; i++)
130 	{
131 	  if ((nfiles & 15) == 0)
132 	    files = xrealloc(files, (nfiles + 16) * sizeof(*files));
133 	  n = rpmlgetfn(fp, &lastfn, &lastfnl);
134 	  files[nfiles].name = xmalloc(strlen(n) + 1);
135 	  strcpy(files[nfiles].name, n);
136 	  files[nfiles].mode = S_IFREG;
137 	  files[nfiles].fflags = FILE_UNPATCHED;
138 	  memset(files[nfiles].md5, 0, 16);
139 	  nfiles++;
140 	}
141     }
142   for (;;)
143     {
144       n = rpmlgetfn(fp, &lastfn, &lastfnl);
145       if (!*n)
146 	break;
147       if ((nfiles & 15) == 0)
148 	files = xrealloc(files, (nfiles + 16) * sizeof(*files));
149       if (*n == '.' && n[1] == '/')
150 	n += 2;
151       files[nfiles].name = xmalloc(strlen(n) + 1);
152       strcpy(files[nfiles].name, n);
153       files[nfiles].fflags = 0;
154       memset(files[nfiles].md5, 0, 16);
155       mode = rpmlget16(fp);
156       files[nfiles].mode = mode;
157       if (mode == 0)	/* hard link chain */
158 	{
159 	   nfiles++;
160 	   continue;
161 	}
162       ogs = getc(fp);
163       if (ogs == 0xff)
164 	{
165 	  unsigned int ogs2;
166 	  ogs2 = getc(fp);
167 	  ogs = getc(fp);
168 	  if (ogs2)
169 	    rpmlskip(fp, ogs2 + 1);
170 	  if (ogs & 0xfc)
171 	    rpmlskip(fp, (ogs >> 2 & 0x3f) + 1);
172 	}
173       else
174 	{
175 	  if (ogs & 0xe0)
176 	    rpmlskip(fp, (ogs >> 5 & 7) + 1);
177 	  if (ogs & 0x1c)
178 	    rpmlskip(fp, (ogs >> 2 & 7) + 1);
179 	}
180       if (S_ISCHR(mode) || S_ISBLK(mode))
181 	rpmlget32(fp);	/* rdev */
182       if (S_ISREG(mode) || S_ISLNK(mode))
183 	{
184 	  ogs &= 3;
185 	  s = 0;
186 	  if (ogs > 2)
187 	    s |= getc(fp) << 24;
188 	  if (ogs > 1)
189 	    s |= getc(fp) << 16;
190 	  if (ogs > 0)
191 	    s |= getc(fp) << 8;
192 	  s |= getc(fp);
193 	  if (s)
194 	    {
195 	      for (s = 0; s < 16; s++)
196 		files[nfiles].md5[s] = getc(fp);
197 	    }
198 	}
199       nfiles++;
200     }
201   *filesp = files;
202   *nfilesp = nfiles;
203   return nevr;
204 }
205