6f8f2709e505e0577dd6d5c924508a3e26089ef1
[apt.git] / apt-pkg / rpm / rpmrecords.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 /* ######################################################################
4    
5    RPM Package Records - Parser for RPM package records
6      
7    ##################################################################### 
8  */
9                                                                         /*}}}*/
10 // Include Files                                                        /*{{{*/
11 #ifdef __GNUG__
12 #pragma implementation "apt-pkg/rpmrecords.h"
13 #endif
14
15 #include <config.h>
16
17 #ifdef HAVE_RPM
18
19 #include <assert.h>
20
21 #include <apt-pkg/rpmrecords.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/rpmhandler.h>
24 #include <apt-pkg/rpmsystem.h>
25
26 #include <apti18n.h>
27
28 // RecordParser::rpmRecordParser - Constructor                          /*{{{*/
29 // ---------------------------------------------------------------------
30 /* */
31 rpmRecordParser::rpmRecordParser(string File, pkgCache &Cache)
32    : Handler(0), HeaderP(0), Buffer(0), BufSize(0), BufUsed(0)
33 {
34    if (File == RPMDBHandler::DataPath(false)) {
35       IsDatabase = true;
36       Handler = rpmSys.GetDBHandler();
37    } else {
38       IsDatabase = false;
39       struct stat Buf;
40       if (stat(File.c_str(),&Buf) == 0 && S_ISDIR(Buf.st_mode))
41          Handler = new RPMDirHandler(File);
42       else if (flExtension(File) == "rpm")
43          Handler = new RPMSingleFileHandler(File);
44       else
45          Handler = new RPMFileHandler(File);
46    }
47 }
48                                                                         /*}}}*/
49 // RecordParser::~rpmRecordParser - Destructor                          /*{{{*/
50 // ---------------------------------------------------------------------
51 /* */
52 rpmRecordParser::~rpmRecordParser()
53 {
54    // Can't use Handler->IsDatabase here, since the RPMDBHandler
55    // could already have been destroyed.
56    if (IsDatabase == false)
57       delete Handler;
58    free(Buffer);
59 }
60                                                                         /*}}}*/
61 // RecordParser::Jump - Jump to a specific record                       /*{{{*/
62 // ---------------------------------------------------------------------
63 /* */
64 bool rpmRecordParser::Jump(pkgCache::VerFileIterator const &Ver)
65 {
66    Handler->Jump(Ver->Offset);
67    HeaderP = Handler->GetHeader();
68    return (HeaderP != NULL);
69 }
70                                                                         /*}}}*/
71 // RecordParser::FileName - Return the archive filename on the site     /*{{{*/
72 // ---------------------------------------------------------------------
73 /* */
74 string rpmRecordParser::FileName()
75 {
76    string Dir = Handler->Directory();
77    if (Dir.empty() == true)
78       return Handler->FileName();
79    return flCombine(Dir, Handler->FileName());
80 }
81                                                                         /*}}}*/
82 // RecordParser::Name - Return the package name                         /*{{{*/
83 // ---------------------------------------------------------------------
84 /* */
85 string rpmRecordParser::Name()
86 {
87    char *str;
88    int_32 count, type;
89    assert(HeaderP != NULL);
90    int rc = headerGetEntry(HeaderP, RPMTAG_NAME,
91                            &type, (void**)&str, &count);
92    return string(rc?str:"");
93 }
94                                                                         /*}}}*/
95 // RecordParser::MD5Hash - Return the archive hash                      /*{{{*/
96 // ---------------------------------------------------------------------
97 /* */
98 string rpmRecordParser::MD5Hash()
99 {
100    return Handler->MD5Sum();
101 }
102                                                                         /*}}}*/
103 // RecordParser::Maintainer - Return the maintainer email               /*{{{*/
104 // ---------------------------------------------------------------------
105 /* */
106 string rpmRecordParser::Maintainer()
107 {
108    char *str;
109    int_32 count, type;
110    assert(HeaderP != NULL);
111    int rc = headerGetEntry(HeaderP, RPMTAG_PACKAGER,
112                            &type, (void**)&str, &count);
113    return string(rc?str:"");
114 }
115                                                                         /*}}}*/
116 // RecordParser::ShortDesc - Return a 1 line description                /*{{{*/
117 // ---------------------------------------------------------------------
118 /* */
119 string rpmRecordParser::ShortDesc()
120 {
121    char *str;
122    int_32 count, type;
123    assert(HeaderP != NULL);
124    int rc = headerGetEntry(HeaderP, RPMTAG_SUMMARY,
125                            &type, (void**)&str, &count);
126    if (rc != 1)
127       return string();
128    else
129       return string(str,0,string(str).find('\n'));
130 }
131                                                                         /*}}}*/
132 // RecordParser::LongDesc - Return a longer description                 /*{{{*/
133 // ---------------------------------------------------------------------
134 /* */
135 string rpmRecordParser::LongDesc()
136 {
137    char *str, *ret, *x, *y;
138    int_32 count, type;
139    int len;
140    assert(HeaderP != NULL);
141    int rc = headerGetEntry(HeaderP, RPMTAG_DESCRIPTION,
142                            &type, (void**)&str, &count);
143    if (rc != 1)
144       return "";
145
146    // Count size plus number of newlines
147    for (x = str, len = 0; *x; x++, len++)
148       if (*x == '\n')
149          len++;
150    
151    ret = (char*)malloc(len+1);
152    if (ret == NULL)
153       return "out of mem";
154
155    // Copy string, inserting a space after each newline
156    for (x = str, y = ret; *x; x++, y++)
157    {
158       *y = *x;
159       if (*x == '\n')
160          *++y = ' ';
161    }
162    *y = 0;
163
164    // Remove spaces and newlines from end of string
165    for (y--; y > ret && (*y == ' ' || *y == '\n'); y--)
166       *y = 0;
167    
168    string Ret = string(ret);
169    free(ret);
170    
171    return Ret;
172 }
173                                                                         /*}}}*/
174 // RecordParser::SourcePkg - Return the source package name if any      /*{{{*/
175 // ---------------------------------------------------------------------
176 /* */
177 string rpmRecordParser::SourcePkg()
178 {
179    // This must be the *package* name, not the *file* name. We have no
180    // current way to extract it safely from the file name.
181    return "";
182 }
183                                                                         /*}}}*/
184
185 void rpmRecordParser::BufCat(const char *text)
186 {
187    if (text != NULL)
188       BufCat(text, text+strlen(text));
189 }
190
191 void rpmRecordParser::BufCat(const char *begin, const char *end)
192 {
193    unsigned len = end - begin;
194     
195    if (BufUsed+len+1 >= BufSize)
196    {
197       BufSize += 512;
198       char *tmp = (char*)realloc(Buffer, BufSize);
199       if (tmp == NULL)
200       {
201          _error->Errno("realloc", _("Could not allocate buffer for record text"));
202          return;
203       }
204       Buffer = tmp;
205    }
206
207    strncpy(Buffer+BufUsed, begin, len);
208    BufUsed += len;
209 }
210
211 void rpmRecordParser::BufCatTag(const char *tag, const char *value)
212 {
213    BufCat(tag);
214    BufCat(value);
215 }
216
217 void rpmRecordParser::BufCatDep(const char *pkg,
218                                 const char *version,
219                                 int flags)
220 {
221    char buf[16];
222    char *ptr = buf;
223
224    BufCat(pkg);
225    if (*version) 
226    {
227       int c = 0;
228       *ptr++ = ' ';
229       *ptr++ = '(';
230       if (flags & RPMSENSE_LESS)
231       {
232          *ptr++ = '<';
233          c = '<';
234       }
235       if (flags & RPMSENSE_GREATER) 
236       {
237          *ptr++ = '>';
238          c = '>';
239       }
240       if (flags & RPMSENSE_EQUAL) 
241       {
242          *ptr++ = '=';
243       }/* else {
244          if (c)
245            fputc(c, f);
246       }*/
247       *ptr++ = ' ';
248       *ptr = '\0';
249
250       BufCat(buf);
251       BufCat(version);
252       BufCat(")");
253    }
254 }
255
256 void rpmRecordParser::BufCatDescr(const char *descr)
257 {
258    const char *begin = descr;
259
260    while (*descr) 
261    {
262       if (*descr=='\n') 
263       {
264          BufCat(" ");
265          BufCat(begin, descr+1);
266          begin = descr+1;
267       }
268       descr++;
269    }
270    BufCat(" ");
271    BufCat(begin, descr);
272    BufCat("\n");
273 }
274
275
276 // RecordParser::GetRec - The record in raw text, in std Debian format  /*{{{*/
277 // ---------------------------------------------------------------------
278 void rpmRecordParser::GetRec(const char *&Start,const char *&Stop) 
279 {
280    // FIXME: This method is leaking memory from headerGetEntry().
281    int type, type2, type3, count;
282    char *str;
283    char **strv;
284    char **strv2;
285    int_32 *numv;
286    char buf[32];
287
288    BufUsed = 0;
289
290    assert(HeaderP != NULL);
291    
292    headerGetEntry(HeaderP, RPMTAG_NAME, &type, (void **)&str, &count);
293    BufCatTag("Package: ", str);
294
295    headerGetEntry(HeaderP, RPMTAG_GROUP, &type, (void **)&str, &count);
296    BufCatTag("\nSection: ", str);
297
298    headerGetEntry(HeaderP, RPMTAG_SIZE, &type, (void **)&numv, &count);
299    snprintf(buf, sizeof(buf), "%d", numv[0]);
300    BufCatTag("\nInstalled Size: ", buf);
301
302    str = NULL;
303    headerGetEntry(HeaderP, RPMTAG_PACKAGER, &type, (void **)&str, &count);
304    if (!str)
305        headerGetEntry(HeaderP, RPMTAG_VENDOR, &type, (void **)&str, &count);
306    BufCatTag("\nMaintainer: ", str);
307    
308    BufCat("\nVersion: ");
309    headerGetEntry(HeaderP, RPMTAG_VERSION, &type, (void **)&str, &count);
310    if (headerGetEntry(HeaderP, RPMTAG_EPOCH, &type, (void **)&numv, &count)==1)
311        snprintf(buf, sizeof(buf), "%i:%s-", numv[0], str);
312    else
313        snprintf(buf, sizeof(buf), "%s-", str);
314    BufCat(buf);
315    headerGetEntry(HeaderP, RPMTAG_RELEASE, &type, (void **)&str, &count);
316    BufCat(str);
317
318 //   headerGetEntry(HeaderP, RPMTAG_DISTRIBUTION, &type, (void **)&str, &count);
319 //   fprintf(f, "Distribution: %s\n", str);
320
321    headerGetEntry(HeaderP, RPMTAG_REQUIRENAME, &type, (void **)&strv, &count);
322    assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
323
324    headerGetEntry(HeaderP, RPMTAG_REQUIREVERSION, &type2, (void **)&strv2, &count);
325    headerGetEntry(HeaderP, RPMTAG_REQUIREFLAGS, &type3, (void **)&numv, &count);
326    
327    if (count > 0)
328    {
329       int i, j;
330
331       for (j = i = 0; i < count; i++) 
332       {
333          if ((numv[i] & RPMSENSE_PREREQ))
334          {
335             if (j == 0) 
336                 BufCat("\nPre-Depends: ");
337             else
338                 BufCat(", ");
339             BufCatDep(strv[i], strv2[i], numv[i]);
340             j++;
341          }
342       }
343
344       for (j = 0, i = 0; i < count; i++) 
345       {
346          if (!(numv[i] & RPMSENSE_PREREQ)) 
347          {
348             if (j == 0)
349                 BufCat("\nDepends: ");
350             else
351                 BufCat(", ");
352             BufCatDep(strv[i], strv2[i], numv[i]);
353             j++;
354          }
355       }
356    }
357    
358    headerGetEntry(HeaderP, RPMTAG_CONFLICTNAME, &type, (void **)&strv, &count);
359    assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
360
361    headerGetEntry(HeaderP, RPMTAG_CONFLICTVERSION, &type2, (void **)&strv2, &count);
362    headerGetEntry(HeaderP, RPMTAG_CONFLICTFLAGS, &type3, (void **)&numv, &count);
363    
364    if (count > 0) 
365    {
366       BufCat("\nConflicts: ");
367       for (int i = 0; i < count; i++) 
368       {
369          if (i > 0)
370              BufCat(", ");
371          BufCatDep(strv[i], strv2[i], numv[i]);
372       }
373    }
374
375    headerGetEntry(HeaderP, RPMTAG_PROVIDENAME, &type, (void **)&strv, &count);
376    assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
377
378    headerGetEntry(HeaderP, RPMTAG_PROVIDEVERSION, &type2, (void **)&strv2, &count);
379    headerGetEntry(HeaderP, RPMTAG_PROVIDEFLAGS, &type3, (void **)&numv, &count);
380    
381    if (count > 0) 
382    {
383       BufCat("\nProvides: ");
384       for (int i = 0; i < count; i++) 
385       {
386          if (i > 0)
387              BufCat(", ");
388          BufCatDep(strv[i], strv2[i], numv[i]);
389       }
390    }
391
392    headerGetEntry(HeaderP, RPMTAG_OBSOLETENAME, &type, (void **)&strv, &count);
393    assert(type == RPM_STRING_ARRAY_TYPE || count == 0);
394
395    headerGetEntry(HeaderP, RPMTAG_OBSOLETEVERSION, &type2, (void **)&strv2, &count);
396    headerGetEntry(HeaderP, RPMTAG_OBSOLETEFLAGS, &type3, (void **)&numv, &count);
397    if (count > 0) {
398       BufCat("\nObsoletes: ");
399       for (int i = 0; i < count; i++) 
400       {
401          if (i > 0)
402              BufCat(", ");
403          BufCatDep(strv[i], strv2[i], numv[i]);
404       }
405    }
406
407    headerGetEntry(HeaderP, RPMTAG_ARCH, &type, (void **)&str, &count);
408    BufCatTag("\nArchitecture: ", str);
409    
410    snprintf(buf, sizeof(buf), "%d", Handler->FileSize());
411    BufCatTag("\nSize: ", buf);
412
413    BufCatTag("\nMD5Sum: ", Handler->MD5Sum().c_str());
414
415    BufCatTag("\nFilename: ", Handler->FileName().c_str());
416
417    headerGetEntry(HeaderP, RPMTAG_SUMMARY, &type, (void **)&str, &count);
418    BufCatTag("\nDescription: ", str);
419    BufCat("\n");
420    headerGetEntry(HeaderP, RPMTAG_DESCRIPTION, &type, (void **)&str, &count);
421    BufCatDescr(str);
422    BufCat("\n");
423    
424    Start = Buffer;
425    Stop = Buffer + BufUsed;
426 }
427                                                                         /*}}}*/
428
429 bool rpmRecordParser::HasFile(const char *File)
430 {
431    if (*File == '\0')
432       return false;
433    char **names = NULL;
434    int_32 count = 0;
435    rpmHeaderGetEntry(HeaderP, RPMTAG_OLDFILENAMES,
436                      NULL, (void **) &names, &count);
437    while (count--) 
438    {
439       char *name = names[count];
440       if (strcmp(name, File) == 0)
441          return true;
442    }
443    free(names);
444    return false;
445 }
446
447 #endif /* HAVE_RPM */
448
449 // vim:sts=3:sw=3