diff options
Diffstat (limited to 'build/files.c')
-rw-r--r-- | build/files.c | 1800 |
1 files changed, 1036 insertions, 764 deletions
diff --git a/build/files.c b/build/files.c index 1159ff6f6..fe2023b40 100644 --- a/build/files.c +++ b/build/files.c @@ -1,651 +1,703 @@ -/* RPM - Copyright (C) 1995 Red Hat Software - * - * prepack.c - routines for packaging - */ - -#include "miscfn.h" - -#include <stdlib.h> -#include <unistd.h> #include <string.h> -#include <sys/stat.h> +#include <malloc.h> +#include <stdlib.h> +#include <glob.h> #include <time.h> #include "spec.h" -#include "specP.h" -#include "stringbuf.h" -#include "build.h" -#include "messages.h" -#include "md5.h" +#include "package.h" +#include "rpmlib.h" +#include "misc.h" +#include "lib/misc.h" #include "myftw.h" +#include "lib/cpio.h" #include "header.h" -#include "files.h" +#include "md5.h" #include "names.h" -#include "rpmlead.h" -#include "rpmlib.h" -#include "misc.h" +#include "messages.h" #include "macro.h" +#include "build.h" -#define BINARY_HEADER 0 -#define SOURCE_HEADER 1 - -struct file_entry { - char file[1024]; - int isdoc; - int conf; - int isspecfile; - int isghost; - int verify_flags; - char *uname; /* reference -- do not free */ - char *gname; /* reference -- do not free */ - struct stat statbuf; - struct file_entry *next; +#define MAXDOCDIR 1024 + +struct FileListRec { + char *diskName; /* get file from here */ + char *fileName; /* filename in cpio archive */ + mode_t mode; + uid_t uid; + gid_t gid; + dev_t device; + ino_t inode; + char *uname; + char *gname; + int flags; + int verifyFlags; + int size; + int mtime; + dev_t rdev; + char *lang; }; -static int add_file(struct file_entry **festack, const char *name, - int isdoc, int isconf, int isdir, int isghost, - int verify_flags, - char *Pmode, char *Uname, char *Gname, char *prefix); -static int compare_fe(const void *ap, const void *bp); -static int add_file_aux(const char *file, struct stat *sb, int flag); -static int glob_error(const char *foo, int bar); -static int glob_pattern_p (char *pattern); -static int parseForVerify(char *buf, int *verify_flags); -static int parseForConfig(char *buf, int *conf); -static int parseForAttr(char *origbuf, char **currPmode, - char **currUname, char **currGname); - -static void resetDocdir(void); -static void addDocdir(char *dirname); -static int isDoc(char *filename); +struct AttrRec { + char *PmodeString; + int Pmode; + char *PdirmodeString; + int Pdirmode; + char *Uname; + char *Gname; +}; -static int processFileListFailed; +struct FileList { + char *buildRoot; + char *prefix; -static void parseForDocFiles(struct PackageRec *package, char *line) -{ - if (! (line = strstr(line, "%doc"))) { - return; - } + int fileCount; + int totalFileSize; + int processingFailed; - line += 4; - if ((*line != ' ') && (*line != '\t')) { - return; - } - line += strspn(line, " \t\n"); - if ((! *line) || (*line == '/')) { - return; - } + int passedSpecialDoc; + int isSpecialDoc; - appendLineStringBuf(package->doc, "mkdir -p $DOCDIR"); - appendStringBuf(package->doc, "cp -pr "); - appendStringBuf(package->doc, line); - appendLineStringBuf(package->doc, " $DOCDIR"); -} + int isDir; + int inFtw; + int currentFlags; + int currentVerifyFlags; + struct AttrRec current; + struct AttrRec def; + int defVerifyFlags; + char *currentLang; + + /* Hard coded limit of MAXDOCDIR docdirs. */ + /* If you break it you are doing something wrong. */ + char *docDirs[MAXDOCDIR]; + int docDirCount; + + struct FileListRec *fileList; + int fileListRecsAlloced; + int fileListRecsUsed; +}; + +static int processPackageFiles(Spec spec, Package pkg, int installSpecialDoc); +static void freeFileList(struct FileListRec *fileList, int count); +static int compareFileListRecs(const void *ap, const void *bp); +static int isDoc(struct FileList *fl, char *fileName); +static int processBinaryFile(Package pkg, struct FileList *fl, char *fileName); +static int addFile(struct FileList *fl, char *name, struct stat *statp); +static int parseForSimple(Spec spec, Package pkg, char *buf, + struct FileList *fl, char **fileName); +static int parseForVerify(char *buf, struct FileList *fl); +static int parseForLang(char *buf, struct FileList *fl); +static int parseForAttr(char *buf, struct FileList *fl); +static int parseForConfig(char *buf, struct FileList *fl); +static int myGlobPatternP(char *pattern); +static int glob_error(const char *foo, int bar); +static void timeCheck(int tc, Header h); +static void genCpioListAndHeader(struct FileList *fl, + struct cpioFileMapping **cpioList, + int *cpioCount, Header h, int isSrc); -int finish_filelists(Spec spec) +int processSourceFiles(Spec spec) { - char buf[1024]; - FILE *file; - struct PackageRec *pr = spec->packages; - char *s, **files, **line; - char *version, *release, *packageVersion, *docs, *name; - - headerGetEntry(spec->packages->header, RPMTAG_VERSION, NULL, - (void *) &version, NULL); - headerGetEntry(spec->packages->header, RPMTAG_RELEASE, NULL, - (void *) &release, NULL); - - while (pr) { - if (pr->fileFile) { - sprintf(buf, "%s/%s/%s", rpmGetVar(RPMVAR_BUILDDIR), - build_subdir, pr->fileFile); - rpmMessage(RPMMESS_DEBUG, "Reading file names from: %s\n", buf); - if ((file = fopen(buf, "r")) == NULL) { - rpmError(RPMERR_BADSPEC, "unable to open filelist: %s\n", buf); - return(RPMERR_BADSPEC); + struct Source *srcPtr; + char buf[BUFSIZ]; + StringBuf sourceFiles; + int x, isSpec = 1; + struct FileList fl; + char *s, **files, **fp, *fn; + struct stat sb; + HeaderIterator hi; + int tag, type, count; + void * ptr; + + sourceFiles = newStringBuf(); + spec->sourceHeader = headerNew(); + + /* Only specific tags are added to the source package header */ + hi = headerInitIterator(spec->packages->header); + while (headerNextIterator(hi, &tag, &type, &ptr, &count)) { + switch (tag) { + case RPMTAG_NAME: + case RPMTAG_VERSION: + case RPMTAG_RELEASE: + case RPMTAG_SERIAL: + case RPMTAG_SUMMARY: + case RPMTAG_DESCRIPTION: + case RPMTAG_PACKAGER: + case RPMTAG_DISTRIBUTION: + case RPMTAG_VENDOR: + case RPMTAG_COPYRIGHT: + case RPMTAG_GROUP: + case RPMTAG_OS: + case RPMTAG_ARCH: + case RPMTAG_CHANGELOGTIME: + case RPMTAG_CHANGELOGNAME: + case RPMTAG_CHANGELOGTEXT: + case RPMTAG_URL: + headerAddEntry(spec->sourceHeader, tag, type, ptr, count); + break; + default: + /* do not copy */ + break; + } + if (type == RPM_STRING_ARRAY_TYPE) { + FREE(ptr); + } + } + headerFreeIterator(hi); + + /* Construct the file list and source entries */ + appendLineStringBuf(sourceFiles, spec->specFile); + srcPtr = spec->sources; + while (srcPtr) { + if (srcPtr->flags & RPMBUILD_ISSOURCE) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE, + RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1); + if (srcPtr->flags & RPMBUILD_ISNO) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE, + RPM_INT32_TYPE, &srcPtr->num, 1); } - while (fgets(buf, sizeof(buf), file)) { - expandMacros(buf); - appendStringBuf(pr->filelist, buf); + } + if (srcPtr->flags & RPMBUILD_ISPATCH) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH, + RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1); + if (srcPtr->flags & RPMBUILD_ISNO) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH, + RPM_INT32_TYPE, &srcPtr->num, 1); } - fclose(file); } + sprintf(buf, "%s%s/%s", + srcPtr->flags & RPMBUILD_ISNO ? "!" : "", + rpmGetVar(RPMVAR_SOURCEDIR), srcPtr->source); + appendLineStringBuf(sourceFiles, buf); + srcPtr = srcPtr->next; + } + + spec->sourceCpioList = NULL; + spec->sourceCpioCount = 0; - /* parse for %doc wierdness */ - s = getStringBuf(pr->filelist); - files = splitString(s, strlen(s), '\n'); - line = files; - while (*line) { - parseForDocFiles(pr, *line); - line++; + fl.fileList = malloc((spec->numSources + 1) * sizeof(struct FileListRec)); + fl.processingFailed = 0; + fl.fileListRecsUsed = 0; + fl.totalFileSize = 0; + fl.prefix = NULL; + + s = getStringBuf(sourceFiles); + files = splitString(s, strlen(s), '\n'); + fp = files; + + /* The first source file is the spec file */ + x = 0; + while (*fp) { + s = *fp; + SKIPSPACE(s); + if (! *s) { + fp++; continue; } - freeSplitString(files); - /* Handle subpackage version overrides */ - if (!headerGetEntry(pr->header, RPMTAG_VERSION, NULL, - (void *) &packageVersion, NULL)) { - packageVersion = version; + fl.fileList[x].flags = isSpec ? RPMFILE_SPECFILE : 0; + /* files with leading ! are no source files */ + if (*s == '!') { + fl.fileList[x].flags |= RPMFILE_GHOST; + s++; + } + fl.fileList[x].diskName = strdup(s); + fn = strrchr(s, '/'); + if (fn) { + fn++; + } else { + fn = s; } + fl.fileList[x].fileName = strdup(fn); + fl.fileList[x].verifyFlags = RPMVERIFY_ALL; + lstat(s, &sb); + fl.fileList[x].mode = sb.st_mode; + fl.fileList[x].uid = sb.st_uid; + fl.fileList[x].gid = sb.st_gid; + fl.fileList[x].uname = getUname(sb.st_uid); + fl.fileList[x].gname = getGname(sb.st_gid); + fl.fileList[x].size = sb.st_size; + fl.fileList[x].mtime = sb.st_mtime; + fl.fileList[x].rdev = sb.st_rdev; + fl.fileList[x].device = sb.st_dev; + fl.fileList[x].inode = sb.st_ino; + fl.fileList[x].lang = strdup(""); + + fl.totalFileSize += sb.st_size; + + if (! (fl.fileList[x].uname && fl.fileList[x].gname)) { + rpmError(RPMERR_BADSPEC, "Bad owner/group: %s", s); + fl.processingFailed = 1; + } + + isSpec = 0; + fp++; + x++; + } + fl.fileListRecsUsed = x; + FREE(files); - /* Generate the doc script */ - appendStringBuf(spec->doc, "DOCDIR=$RPM_ROOT_DIR/$RPM_DOC_DIR/"); - headerGetEntry(pr->header, RPMTAG_NAME, NULL, (void *) &name, NULL); - sprintf(buf, "%s-%s", name, packageVersion); - appendLineStringBuf(spec->doc, buf); - docs = getStringBuf(pr->doc); - if (*docs) { - appendLineStringBuf(spec->doc, "rm -rf $DOCDIR"); - appendLineStringBuf(spec->doc, docs); + if (! fl.processingFailed) { + genCpioListAndHeader(&fl, &(spec->sourceCpioList), + &(spec->sourceCpioCount), spec->sourceHeader, 1); + } + + freeStringBuf(sourceFiles); + freeFileList(fl.fileList, fl.fileListRecsUsed); + return fl.processingFailed; +} + +int processBinaryFiles(Spec spec, int installSpecialDoc) +{ + Package pkg; + int rc; + + pkg = spec->packages; + while (pkg) { + if (!pkg->fileList) { + pkg = pkg->next; + continue; + } + + if ((rc = processPackageFiles(spec, pkg, installSpecialDoc))) { + return rc; } - pr = pr->next; + pkg = pkg->next; } return 0; } -int process_filelist(Header header, struct PackageRec *pr, - StringBuf sb, int *size, char *name, - char *version, char *release, int type, - char *prefix, char *specFile) +static int processPackageFiles(Spec spec, Package pkg, int installSpecialDoc) { - char buf[1024]; - char **files, **fp; - struct file_entry *fes, *fest; - struct file_entry **file_entry_array; - int isdoc, conf, isdir, verify_flags, isghost; - char *currPmode=NULL; /* hold info from %attr() */ - char *currUname=NULL; /* hold info from %attr() */ - char *currGname=NULL; /* hold info from %attr() */ - char *filename, *s; - char *str; - int count = 0; - int c, x; - glob_t glob_result; - int special_doc; - int passed_special_doc = 0; - int tc; - char *tcs; - int currentTime; + struct FileList fl; + char *s, **files, **fp, *fileName; + char buf[BUFSIZ]; + FILE *f; - processFileListFailed = 0; - fes = NULL; - *size = 0; + struct AttrRec specialDocAttrRec; + char *specialDoc = NULL; + + pkg->cpioList = NULL; + pkg->cpioCount = 0; + + if (pkg->fileFile) { + sprintf(buf, "%s/%s/%s", rpmGetVar(RPMVAR_BUILDDIR), + spec->buildSubdir, pkg->fileFile); + if ((f = fopen(buf, "r")) == NULL) { + rpmError(RPMERR_BADFILENAME, + "Could not open %%files file: %s", pkg->fileFile); + return RPMERR_BADFILENAME; + } + while (fgets(buf, sizeof(buf), f)) { + expandMacros(&spec->macros, buf); + appendStringBuf(pkg->fileList, buf); + } + fclose(f); + } + + /* Init the file list structure */ + + fl.buildRoot = spec->buildRoot ? spec->buildRoot : ""; + if (headerGetEntry(pkg->header, RPMTAG_DEFAULTPREFIX, + NULL, (void *)&fl.prefix, NULL)) { + fl.prefix = strdup(fl.prefix); + } else { + fl.prefix = NULL; + } - resetDocdir(); + fl.fileCount = 0; + fl.totalFileSize = 0; + fl.processingFailed = 0; - str = getStringBuf(sb); - files = splitString(str, strlen(str), '\n'); + fl.passedSpecialDoc = 0; + + fl.current.PmodeString = NULL; + fl.current.PdirmodeString = NULL; + fl.current.Uname = NULL; + fl.current.Gname = NULL; + fl.def.PmodeString = NULL; + fl.def.PdirmodeString = NULL; + fl.def.Uname = NULL; + fl.def.Gname = NULL; + fl.currentLang = NULL; + + fl.defVerifyFlags = RPMVERIFY_ALL; + + fl.docDirCount = 0; + fl.docDirs[fl.docDirCount++] = strdup("/usr/doc"); + fl.docDirs[fl.docDirCount++] = strdup("/usr/man"); + fl.docDirs[fl.docDirCount++] = strdup("/usr/info"); + fl.docDirs[fl.docDirCount++] = strdup("/usr/X11R6/man"); + fl.docDirs[fl.docDirCount++] = strdup(spec->docDir); + + fl.fileList = NULL; + fl.fileListRecsAlloced = 0; + fl.fileListRecsUsed = 0; + + s = getStringBuf(pkg->fileList); + files = splitString(s, strlen(s), '\n'); fp = files; while (*fp) { - strcpy(buf, *fp); /* temp copy */ - isdoc = 0; - special_doc = 0; - conf = 0; - isdir = 0; - isghost = 0; - if (currPmode) { - free (currPmode); - currPmode = NULL; - } - if (currUname) { - free (currUname); - currUname = NULL; - } - if (currGname) { - free (currGname); - currGname = NULL; - } - verify_flags = RPMVERIFY_ALL; - filename = NULL; - - /* First preparse buf for %verify() */ - if (parseForVerify(buf, &verify_flags)) { - processFileListFailed = 1; + s = *fp; + SKIPSPACE(s); + if (! *s) { fp++; continue; } + fileName = NULL; + strcpy(buf, s); - /* Next parse for %attr() */ - if (parseForAttr(buf, &currPmode, &currUname, &currGname)) { - processFileListFailed = 1; - fp++; continue; + /* Reset for a new line in %files */ + fl.isDir = 0; + fl.inFtw = 0; + fl.currentFlags = 0; + fl.currentVerifyFlags = fl.defVerifyFlags; + fl.current.Pmode = fl.def.Pmode; + fl.current.Pdirmode = fl.def.Pdirmode; + fl.isSpecialDoc = 0; + FREE(fl.current.PmodeString); + FREE(fl.current.PdirmodeString); + FREE(fl.current.Uname); + FREE(fl.current.Gname); + FREE(fl.currentLang); + if (fl.def.PmodeString) { + fl.current.PmodeString = strdup(fl.def.PmodeString); + } + if (fl.def.PdirmodeString) { + fl.current.PdirmodeString = strdup(fl.def.PdirmodeString); + } + if (fl.def.Uname) { + fl.current.Uname = strdup(fl.def.Uname); + } + if (fl.def.Gname) { + fl.current.Gname = strdup(fl.def.Gname); } - /* Then parse for %config or %config() */ - if (parseForConfig(buf, &conf)) { - processFileListFailed = 1; + if (parseForVerify(buf, &fl)) { fp++; continue; } - - s = strtok(buf, " \t\n"); - while (s) { - if (!strcmp(s, "%docdir")) { - s = strtok(NULL, " \t\n"); - addDocdir(s); - break; - } else if (!strcmp(s, "%doc")) { - isdoc = 1; - } else if (!strcmp(s, "%dir")) { - isdir = 1; - } else if (!strcmp(s, "%ghost")) { - isghost = 1; - } else { - if (filename) { - /* We already got a file -- error */ - rpmError(RPMERR_BADSPEC, - "Two files on one line: %s", filename); - processFileListFailed = 1; - } - if (*s != '/') { - if (isdoc) { - special_doc = 1; - } else { - /* not in %doc, does not begin with / -- error */ - rpmError(RPMERR_BADSPEC, - "File must begin with \"/\": %s", s); - processFileListFailed = 1; - } - } else { - filename = s; - } - } - s = strtok(NULL, " \t\n"); + if (parseForAttr(buf, &fl)) { + fp++; continue; } - if (special_doc) { - if (passed_special_doc) { - fp++; - continue; - } else { - if (filename || conf || isdir || isghost) { - rpmError(RPMERR_BADSPEC, - "Can't mix special %%doc with other forms: %s", fp); - processFileListFailed = 1; - fp++; continue; - } - sprintf(buf, "%s/%s-%s", rpmGetVar(RPMVAR_DEFAULTDOCDIR), - name, version); - filename = buf; - passed_special_doc = 1; - } + if (parseForConfig(buf, &fl)) { + fp++; continue; } - if (! filename) { - fp++; - continue; + if (parseForLang(buf, &fl)) { + fp++; continue; + } + if (parseForSimple(spec, pkg, buf, &fl, &fileName)) { + fp++; continue; + } + if (! fileName) { + fp++; continue; } - if (type == RPMLEAD_BINARY) { - /* check that file starts with leading "/" */ - if (*filename != '/') { - rpmError(RPMERR_BADSPEC, - "File needs leading \"/\": %s", filename); - processFileListFailed = 1; - fp++; continue; + if (fl.isSpecialDoc) { + /* Save this stuff for last */ + specialDoc = strdup(fileName); + specialDocAttrRec = fl.current; + if (specialDocAttrRec.PmodeString) { + specialDocAttrRec.PmodeString = + strdup(specialDocAttrRec.PmodeString); } - - if (glob_pattern_p(filename)) { - char fullname[1024]; - - if (rpmGetVar(RPMVAR_ROOT)) { - sprintf(fullname, "%s%s", rpmGetVar(RPMVAR_ROOT), filename); - } else { - strcpy(fullname, filename); - } - - if (glob(fullname, 0, glob_error, &glob_result) || - (glob_result.gl_pathc < 1)) { - rpmError(RPMERR_BADSPEC, "No matches: %s", fullname); - processFileListFailed = 1; - globfree(&glob_result); - fp++; continue; - } - - c = 0; - x = 0; - while (x < glob_result.gl_pathc) { - int offset = strlen(rpmGetVar(RPMVAR_ROOT) ? : ""); - c += add_file(&fes, &(glob_result.gl_pathv[x][offset]), - isdoc, conf, isdir, isghost, verify_flags, - currPmode, currUname, currGname, prefix); - x++; - } - globfree(&glob_result); - } else { - c = add_file(&fes, filename, isdoc, conf, isdir, isghost, - verify_flags, currPmode, currUname, - currGname, prefix); + if (specialDocAttrRec.PdirmodeString) { + specialDocAttrRec.PdirmodeString = + strdup(specialDocAttrRec.PdirmodeString); } - } else { - /* Source package are the simple case */ - fest = malloc(sizeof(struct file_entry)); - fest->isdoc = 0; - fest->conf = 0; - fest->isghost = 0; - if (!strcmp(filename, specFile)) { - fest->isspecfile = 1; - } else { - fest->isspecfile = 0; + if (specialDocAttrRec.Uname) { + specialDocAttrRec.Uname = strdup(specialDocAttrRec.Uname); } - fest->verify_flags = 0; /* XXX - something else? */ - stat(filename, &fest->statbuf); - fest->uname = getUname(fest->statbuf.st_uid); - fest->gname = getGname(fest->statbuf.st_gid); - if (! (fest->uname && fest->gname)) { - rpmError(RPMERR_BADSPEC, "Bad owner/group: %s", filename); - fest->uname = ""; - fest->gname = ""; - processFileListFailed = 1; + if (specialDocAttrRec.Gname) { + specialDocAttrRec.Gname = strdup(specialDocAttrRec.Gname); } - strcpy(fest->file, filename); - fest->next = fes; - fes = fest; - c = 1; - } - - if (! c) { - rpmError(RPMERR_BADSPEC, "File not found: %s", filename); - processFileListFailed = 1; + } else { + processBinaryFile(pkg, &fl, fileName); } - count += c; fp++; } - /* If there are no files, don't add anything to the header */ - if (count) { - char ** fileList; - char ** fileMD5List; - char ** fileLinktoList; - int_32 * fileSizeList; - int_32 * fileUIDList; - int_32 * fileGIDList; - char ** fileUnameList; - char ** fileGnameList; - int_32 * fileMtimesList; - int_32 * fileFlagsList; - int_16 * fileModesList; - int_16 * fileRDevsList; - int_32 * fileVerifyFlagsList; - - fileList = malloc(sizeof(char *) * count); - fileLinktoList = malloc(sizeof(char *) * count); - fileMD5List = malloc(sizeof(char *) * count); - fileSizeList = malloc(sizeof(int_32) * count); - fileUIDList = malloc(sizeof(int_32) * count); - fileGIDList = malloc(sizeof(int_32) * count); - fileUnameList = malloc(sizeof(char *) * count); - fileGnameList = malloc(sizeof(char *) * count); - fileMtimesList = malloc(sizeof(int_32) * count); - fileFlagsList = malloc(sizeof(int_32) * count); - fileModesList = malloc(sizeof(int_16) * count); - fileRDevsList = malloc(sizeof(int_16) * count); - fileVerifyFlagsList = malloc(sizeof(int_32) * count); - - /* Build a reverse sorted file array. */ - /* This makes uninstalls a lot easier. */ - file_entry_array = malloc(sizeof(struct file_entry *) * count); - c = 0; - fest = fes; - while (fest) { - file_entry_array[c++] = fest; - fest = fest->next; - } - qsort(file_entry_array, count, sizeof(struct file_entry *), - compare_fe); - - /* Do timecheck */ - tc = 0; - currentTime = time(NULL); - if ((tcs = rpmGetVar(RPMVAR_TIMECHECK))) { - tc = strtoul(tcs, NULL, 10); + /* Now process special doc, if there is one */ + if (specialDoc) { + if (installSpecialDoc) { + doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, 0); } + fl.current = specialDocAttrRec; + processBinaryFile(pkg, &fl, specialDoc); + FREE(specialDoc); + FREE(specialDocAttrRec.PmodeString); + FREE(specialDocAttrRec.PdirmodeString); + FREE(specialDocAttrRec.Uname); + FREE(specialDocAttrRec.Gname); + } - c = 0; - while (c < count) { - fest = file_entry_array[c]; - if (type == RPMLEAD_BINARY) { - x = strlen(fest->file) - 1; - if (x && fest->file[x] == '/') { - fest->file[x] = '\0'; - } - fileList[c] = fest->file; - } else { - fileList[c] = strrchr(fest->file, '/') + 1; - } - if ((c > 0) && !strcmp(fileList[c], fileList[c-1])) { - rpmError(RPMERR_BADSPEC, "File listed twice: %s", fileList[c]); - processFileListFailed = 1; - } - - fileUnameList[c] = fest->uname; - fileGnameList[c] = fest->gname; - *size += fest->statbuf.st_size; - if (S_ISREG(fest->statbuf.st_mode)) { - if ((type == RPMLEAD_BINARY) && - rpmGetVar(RPMVAR_ROOT)) { - sprintf(buf, "%s%s", rpmGetVar(RPMVAR_ROOT), fest->file); - } else { - strcpy(buf, fest->file); - } - mdfile(buf, buf); - fileMD5List[c] = strdup(buf); - rpmMessage(RPMMESS_DEBUG, "md5(%s) = %s\n", fest->file, buf); - } else { - /* This is stupid */ - fileMD5List[c] = strdup(""); - } - fileSizeList[c] = fest->statbuf.st_size; - fileUIDList[c] = fest->statbuf.st_uid; - fileGIDList[c] = fest->statbuf.st_gid; - fileMtimesList[c] = fest->statbuf.st_mtime; - - /* Do timecheck */ - if (tc && (type == RPMLEAD_BINARY)) { - if (currentTime - fest->statbuf.st_mtime > tc) { - rpmMessage(RPMMESS_WARNING, "TIMECHECK failure: %s\n", - fest->file); - } - } - - fileFlagsList[c] = 0; - if (isDoc(fest->file)) - fileFlagsList[c] |= RPMFILE_DOC; - if (fest->isdoc) - fileFlagsList[c] |= RPMFILE_DOC; - if (fest->isghost) - fileFlagsList[c] |= RPMFILE_GHOST; - if (fest->conf && !(fest->statbuf.st_mode & S_IFDIR)) - fileFlagsList[c] |= fest->conf; - if (fest->isspecfile) - fileFlagsList[c] |= RPMFILE_SPECFILE; - - fileModesList[c] = fest->statbuf.st_mode; - fileRDevsList[c] = fest->statbuf.st_rdev; - if (! fest->isghost) { - fileVerifyFlagsList[c] = fest->verify_flags; - } else { - fileVerifyFlagsList[c] = fest->verify_flags & - ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | - RPMVERIFY_LINKTO | RPMVERIFY_MTIME); - } + FREE(files); - if (S_ISLNK(fest->statbuf.st_mode)) { - if (rpmGetVar(RPMVAR_ROOT)) { - sprintf(buf, "%s%s", rpmGetVar(RPMVAR_ROOT), fest->file); - } else { - strcpy(buf, fest->file); - } - buf[readlink(buf, buf, 1024)] = '\0'; - fileLinktoList[c] = strdup(buf); - } else { - /* This is stupid */ - fileLinktoList[c] = strdup(""); - } - c++; - } - - /* Add the header entries */ - c = count; - headerAddEntry(header, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE, fileList, c); - headerAddEntry(header, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE, - fileLinktoList, c); - headerAddEntry(header, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE, fileMD5List, c); - headerAddEntry(header, RPMTAG_FILESIZES, RPM_INT32_TYPE, fileSizeList, c); - headerAddEntry(header, RPMTAG_FILEUIDS, RPM_INT32_TYPE, fileUIDList, c); - headerAddEntry(header, RPMTAG_FILEGIDS, RPM_INT32_TYPE, fileGIDList, c); - headerAddEntry(header, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE, - fileUnameList, c); - headerAddEntry(header, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE, - fileGnameList, c); - headerAddEntry(header, RPMTAG_FILEMTIMES, RPM_INT32_TYPE, fileMtimesList, c); - headerAddEntry(header, RPMTAG_FILEFLAGS, RPM_INT32_TYPE, fileFlagsList, c); - headerAddEntry(header, RPMTAG_FILEMODES, RPM_INT16_TYPE, fileModesList, c); - headerAddEntry(header, RPMTAG_FILERDEVS, RPM_INT16_TYPE, fileRDevsList, c); - headerAddEntry(header, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE, - fileVerifyFlagsList, c); - - /* Free the allocated strings */ - c = count; - while (c--) { - free(fileMD5List[c]); - free(fileLinktoList[c]); - } - - /* Free all those lists */ - free(fileList); - free(fileLinktoList); - free(fileMD5List); - free(fileSizeList); - free(fileUIDList); - free(fileGIDList); - free(fileUnameList); - free(fileGnameList); - free(fileMtimesList); - free(fileFlagsList); - free(fileModesList); - free(fileRDevsList); - free(fileVerifyFlagsList); - - /* Free the file entry array */ - free(file_entry_array); - - /* Free the file entry stack */ - fest = fes; - while (fest) { - fes = fest->next; - free(fest); - fest = fes; + if (! fl.processingFailed) { + genCpioListAndHeader(&fl, &(pkg->cpioList), &(pkg->cpioCount), + pkg->header, 0); + + if (spec->timeCheck) { + timeCheck(spec->timeCheck, pkg->header); } } - freeSplitString(files); - return processFileListFailed; + /* Clean up */ + FREE(fl.prefix); + FREE(fl.current.PmodeString); + FREE(fl.current.PdirmodeString); + FREE(fl.current.Uname); + FREE(fl.current.Gname); + FREE(fl.def.PmodeString); + FREE(fl.def.PdirmodeString); + FREE(fl.def.Uname); + FREE(fl.def.Gname); + FREE(fl.currentLang); + freeFileList(fl.fileList, fl.fileListRecsUsed); + while (fl.docDirCount--) { + FREE(fl.docDirs[fl.docDirCount]); + } + return fl.processingFailed; } -/*************************************************************/ -/* */ -/* misc */ -/* */ -/*************************************************************/ - -static int compare_fe(const void *ap, const void *bp) +static void timeCheck(int tc, Header h) { - char *a, *b; + int *mtime; + char **file; + int count, x, currentTime; - a = (*(struct file_entry **)ap)->file; - b = (*(struct file_entry **)bp)->file; + headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &file, &count); + headerGetEntry(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL); - return strcmp(a, b); + currentTime = time(NULL); + + x = 0; + while (x < count) { + if (currentTime - mtime[x] > tc) { + rpmMessage(RPMMESS_WARNING, "TIMECHECK failure: %s\n", file[x]); + } + x++; + } } -/*************************************************************/ -/* */ -/* Doc dir stuff */ -/* */ -/*************************************************************/ - -/* XXX hard coded limit -- only 1024 %docdir allowed */ -static char *docdirs[1024]; -static int docdir_count; +static void genCpioListAndHeader(struct FileList *fl, + struct cpioFileMapping **cpioList, + int *cpioCount, Header h, int isSrc) +{ + int skipLen = 0; + struct FileListRec *p; + int count; + struct cpioFileMapping *cpioListPtr; + char *s, buf[BUFSIZ]; + + /* Sort the big list */ + qsort(fl->fileList, fl->fileListRecsUsed, + sizeof(*(fl->fileList)), compareFileListRecs); + + /* Generate the cpio list and the header */ + if (! isSrc) { + if (fl->prefix) { + skipLen = 1 + strlen(fl->prefix); + } else { + skipLen = 1; + } + } + *cpioList = malloc(sizeof(**cpioList) * fl->fileListRecsUsed); + *cpioCount = 0; + cpioListPtr = *cpioList; + p = fl->fileList; + count = fl->fileListRecsUsed; + while (count) { + if ((count > 1) && !strcmp(p->fileName, p[1].fileName)) { + rpmError(RPMERR_BADSPEC, "File listed twice: %s", p->fileName); + fl->processingFailed = 1; + } + + /* Make the cpio list */ + if (! (p->flags & RPMFILE_GHOST)) { + cpioListPtr->fsPath = strdup(p->diskName); + cpioListPtr->archivePath = strdup(p->fileName + skipLen); + cpioListPtr->finalMode = p->mode; + cpioListPtr->finalUid = p->uid; + cpioListPtr->finalGid = p->gid; + cpioListPtr->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE | + CPIO_MAP_UID | CPIO_MAP_GID; + cpioListPtr++; + (*cpioCount)++; + } + + /* Make the header */ + headerAddOrAppendEntry(h, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE, + &(p->fileName), 1); + headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE, + &(p->size), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE, + &(p->uname), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE, + &(p->gname), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE, + &(p->mtime), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE, + &(p->mode), 1); + headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE, + &(p->rdev), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE, + &(p->device), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE, + &(p->inode), 1); + headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE, + &(p->lang), 1); + + /* We used to add these, but they should not be needed */ + /* headerAddOrAppendEntry(h, RPMTAG_FILEUIDS, + * RPM_INT32_TYPE, &(p->uid), 1); + * headerAddOrAppendEntry(h, RPMTAG_FILEGIDS, + * RPM_INT32_TYPE, &(p->gid), 1); + */ + + buf[0] = '\0'; + s = buf; + if (S_ISREG(p->mode)) { + mdfile(p->diskName, buf); + } + headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE, + &s, 1); + + buf[0] = '\0'; + s = buf; + if (S_ISLNK(p->mode)) { + buf[readlink(p->diskName, buf, BUFSIZ)] = '\0'; + } + headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE, + &s, 1); + + if (p->flags & RPMFILE_GHOST) { + p->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | + RPMVERIFY_LINKTO | RPMVERIFY_MTIME); + } + headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE, + &(p->verifyFlags), 1); + + if (!isSrc && isDoc(fl, p->fileName)) { + p->flags |= RPMFILE_DOC; + } + if (p->mode & S_IFDIR) { + p->flags &= ~RPMFILE_CONFIG; + p->flags &= ~RPMFILE_DOC; + } + headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE, + &(p->flags), 1); + + p++; + count--; + } + headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, + &(fl->totalFileSize), 1); +} -static void resetDocdir(void) +static void freeFileList(struct FileListRec *fileList, int count) { - while (docdir_count--) { - free(docdirs[docdir_count]); - } - docdir_count = 0; - docdirs[docdir_count++] = strdup("/usr/doc"); - docdirs[docdir_count++] = strdup("/usr/man"); - docdirs[docdir_count++] = strdup("/usr/info"); - docdirs[docdir_count++] = strdup("/usr/X11R6/man"); + while (count--) { + FREE(fileList[count].diskName); + FREE(fileList[count].fileName); + FREE(fileList[count].lang); + } + FREE(fileList); } -static void addDocdir(char *dirname) +void freeCpioList(struct cpioFileMapping *cpioList, int cpioCount) { - if (docdir_count == 1024) { - fprintf(stderr, "RPMERR_INTERNAL: Hit limit in addDocdir()\n"); - exit(RPMERR_INTERNAL); + struct cpioFileMapping *p = cpioList; + + while (cpioCount--) { + rpmMessage(RPMMESS_DEBUG, "archive = %s, fs = %s\n", + p->archivePath, p->fsPath); + FREE(p->archivePath); + FREE(p->fsPath); + p++; } - docdirs[docdir_count++] = strdup(dirname); + FREE(cpioList); +} + +static int compareFileListRecs(const void *ap, const void *bp) +{ + char *a, *b; + + a = ((struct FileListRec *)ap)->fileName; + b = ((struct FileListRec *)bp)->fileName; + + return strcmp(a, b); } -static int isDoc(char *filename) +static int isDoc(struct FileList *fl, char *fileName) { - int x = 0; + int x = fl->docDirCount; - while (x < docdir_count) { - if (strstr(filename, docdirs[x]) == filename) { + while (x--) { + if (strstr(fileName, fl->docDirs[x]) == fileName) { return 1; } - x++; } return 0; } -/*************************************************************/ -/* */ -/* File stating / tree walk */ -/* */ -/*************************************************************/ - -/* Need a bunch of globals to keep track of things in ftw() */ -static int Gisdoc; -static int Gisghost; -static int Gconf; -static int Gverify_flags; -static int Gcount; -static char *GPmode; -static char *GUname; -static char *GGname; -static struct file_entry **Gfestack; -static char *Gprefix; - -static int add_file(struct file_entry **festack, const char *name, - int isdoc, int conf, int isdir, int isghost, - int verify_flags, - char *Pmode, char *Uname, char *Gname, char *prefix) +static int processBinaryFile(Package pkg, struct FileList *fl, char *fileName) +{ + char fullname[BUFSIZ]; + glob_t glob_result; + int x, offset, rc = 0; + + /* check that file starts with leading "/" */ + if (*fileName != '/') { + rpmError(RPMERR_BADSPEC, "File needs leading \"/\": %s", *fileName); + fl->processingFailed = 1; + return 1; + } + + if (myGlobPatternP(fileName)) { + if (fl->buildRoot) { + sprintf(fullname, "%s%s", fl->buildRoot, fileName); + offset = strlen(fl->buildRoot); + } else { + strcpy(fullname, fileName); + offset = 0; + } + + if (glob(fullname, 0, glob_error, &glob_result) || + (glob_result.gl_pathc < 1)) { + rpmError(RPMERR_BADSPEC, "File not found: %s", fullname); + fl->processingFailed = 1; + globfree(&glob_result); + return 1; + } + + x = 0; + while (x < glob_result.gl_pathc) { + rc = addFile(fl, &(glob_result.gl_pathv[x][offset]), NULL); + x++; + } + globfree(&glob_result); + } else { + rc = addFile(fl, fileName, NULL); + } + + return rc; +} + +static int addFile(struct FileList *fl, char *name, struct stat *statp) { - struct file_entry *p; - char *copyTo, copied; - const char *prefixTest, *prefixPtr; - const char *copyFrom; - char fullname[1024]; - int mode; - - /* Set these up for ftw() */ - Gfestack = festack; - Gisdoc = isdoc; - Gconf = conf; - Gisghost = isghost; - Gverify_flags = verify_flags; - GPmode = Pmode; - GUname = Uname; - GGname = Gname; - Gprefix = prefix; - - p = malloc(sizeof(struct file_entry)); - - copyTo = p->file; + char fileName[BUFSIZ]; + char diskName[BUFSIZ]; + char *copyTo, *copyFrom, copied; + char *prefixTest, *prefixPtr; + struct stat statbuf; + int_16 fileMode; + int fileUid, fileGid; + char *fileUname, *fileGname; + + /* Copy to fileName, eliminate duplicate "/" and trailing "/" */ + copyTo = fileName; copied = '\0'; copyFrom = name; while (*copyFrom) { @@ -655,178 +707,325 @@ static int add_file(struct file_entry **festack, const char *name, copyFrom++; } *copyTo = '\0'; + copyTo--; + if ((copyTo != fileName) && (*copyTo == '/')) { + *copyTo = '\0'; + } - p->isdoc = isdoc; - p->conf = conf; - p->isghost = isghost; - p->isspecfile = 0; /* source packages are done by hand */ - p->verify_flags = verify_flags; - if (rpmGetVar(RPMVAR_ROOT)) { - sprintf(fullname, "%s%s", rpmGetVar(RPMVAR_ROOT), name); + if (fl->inFtw) { + /* Any buildRoot is already prepended */ + strcpy(diskName, fileName); + if (fl->buildRoot) { + strcpy(fileName, diskName + strlen(fl->buildRoot)); + } } else { - strcpy(fullname, name); + if (fl->buildRoot) { + sprintf(diskName, "%s%s", fl->buildRoot, fileName); + } else { + strcpy(diskName, fileName); + } } /* If we are using a prefix, validate the file */ - if (prefix) { - prefixTest = name; - prefixPtr = prefix; - while (*prefixTest == '/') { - prefixTest++; /* Skip leading "/" */ - } + if (!fl->inFtw && fl->prefix) { + prefixTest = fileName; + prefixPtr = fl->prefix; + while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) { prefixPtr++; prefixTest++; } - if (*prefixPtr) { + if (*prefixPtr || (*prefixTest && *prefixTest != '/')) { rpmError(RPMERR_BADSPEC, "File doesn't match prefix (%s): %s", - prefix, name); - return 0; + fl->prefix, fileName); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } } - /* OK, finally stat() the file */ - if (lstat(fullname, &p->statbuf)) { - return 0; - } - - /* - * If %attr() was specified, then use those values instead of - * what lstat() returned. - */ - if (Pmode && strcmp(Pmode, "-")) { - sscanf(Pmode, "%o", &mode); - mode |= p->statbuf.st_mode & S_IFMT; - p->statbuf.st_mode = (unsigned short)mode; + if (! statp) { + statp = &statbuf; + if (lstat(diskName, statp)) { + rpmError(RPMERR_BADSPEC, "File not found: %s", diskName); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } } - if (Uname && strcmp(Uname, "-")) { - p->uname = getUnameS(Uname); - } else { - p->uname = getUname(p->statbuf.st_uid); - } - - if (Gname && strcmp(Gname, "-")) { - p->gname = getGnameS(Gname); - } else { - p->gname = getGname(p->statbuf.st_gid); - } - - if (! (p->uname && p->gname)) { - rpmError(RPMERR_BADSPEC, "Bad owner/group: %s\n", fullname); - p->uname = ""; - p->gname = ""; - return 0; - } - - if ((! isdir) && S_ISDIR(p->statbuf.st_mode)) { - /* This means we need to descend with ftw() */ - Gcount = 0; - + if ((! fl->isDir) && S_ISDIR(statp->st_mode)) { /* We use our own ftw() call, because ftw() uses stat() */ /* instead of lstat(), which causes it to follow symlinks! */ - myftw(fullname, add_file_aux, 16); + /* It also has better callback support. */ - free(p); - - return Gcount; + fl->inFtw = 1; /* Flag to indicate file has buildRoot prefixed */ + fl->isDir = 1; /* Keep it from following myftw() again */ + myftw(diskName, 16, addFile, fl); + fl->isDir = 0; + fl->inFtw = 0; } else { - /* Link it in */ - p->next = *festack; - *festack = p; + fileMode = statp->st_mode; + fileUid = statp->st_uid; + fileGid = statp->st_gid; + + /* %attr ? */ + if (S_ISDIR(fileMode) && fl->current.PdirmodeString) { + if (fl->current.PdirmodeString[0] != '-') { + fileMode &= S_IFMT; + fileMode |= fl->current.Pdirmode; + } + } else { + if (fl->current.PmodeString) { + fileMode &= S_IFMT; + fileMode |= fl->current.Pmode; + } + } + if (fl->current.Uname) { + fileUname = getUnameS(fl->current.Uname); + } else { + fileUname = getUname(fileUid); + } + if (fl->current.Gname) { + fileGname = getGnameS(fl->current.Gname); + } else { + fileGname = getGname(fileGid); + } + + if (! (fileUname && fileGname)) { + rpmError(RPMERR_BADSPEC, "Bad owner/group: %s\n", diskName); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + + rpmMessage(RPMMESS_DEBUG, "File %d: %s\n", fl->fileCount, fileName); + + /* Add to the file list */ + if (fl->fileListRecsUsed == fl->fileListRecsAlloced) { + fl->fileListRecsAlloced += 128; + fl->fileList = realloc(fl->fileList, + fl->fileListRecsAlloced * + sizeof(*(fl->fileList))); + } + + fl->fileList[fl->fileListRecsUsed].fileName = strdup(fileName); + fl->fileList[fl->fileListRecsUsed].diskName = strdup(diskName); + fl->fileList[fl->fileListRecsUsed].mode = fileMode; + fl->fileList[fl->fileListRecsUsed].uid = fileUid; + fl->fileList[fl->fileListRecsUsed].gid = fileGid; + fl->fileList[fl->fileListRecsUsed].uname = fileUname; + fl->fileList[fl->fileListRecsUsed].gname = fileGname; + + fl->fileList[fl->fileListRecsUsed].lang = + strdup(fl->currentLang ? fl->currentLang : ""); + + fl->fileList[fl->fileListRecsUsed].flags = fl->currentFlags; + fl->fileList[fl->fileListRecsUsed].verifyFlags = + fl->currentVerifyFlags; + fl->fileList[fl->fileListRecsUsed].size = statp->st_size; + fl->fileList[fl->fileListRecsUsed].mtime = statp->st_mtime; + fl->fileList[fl->fileListRecsUsed].rdev = statp->st_rdev; + fl->fileList[fl->fileListRecsUsed].device = statp->st_dev; + fl->fileList[fl->fileListRecsUsed].inode = statp->st_ino; + fl->fileListRecsUsed++; + + fl->totalFileSize += statp->st_size; + fl->fileCount++; + } - rpmMessage(RPMMESS_DEBUG, "ADDING: %s\n", name); + return 0; +} - /* return number of entries added */ - return 1; +static int parseForSimple(Spec spec, Package pkg, char *buf, + struct FileList *fl, char **fileName) +{ + char *s; + int res, specialDoc = 0; + char *name, *version; + char specialDocBuf[BUFSIZ]; + + specialDocBuf[0] = '\0'; + *fileName = NULL; + res = 0; + s = strtok(buf, " \t\n"); + while (s) { + if (!strcmp(s, "%docdir")) { + s = strtok(NULL, " \t\n"); + if (fl->docDirCount == MAXDOCDIR) { + rpmError(RPMERR_INTERNAL, "Hit limit for %%docdir"); + fl->processingFailed = 1; + res = 1; + } + fl->docDirs[fl->docDirCount++] = strdup(s); + if (strtok(NULL, " \t\n")) { + rpmError(RPMERR_INTERNAL, "Only one arg for %%docdir"); + fl->processingFailed = 1; + res = 1; + } + break; + } else if (!strcmp(s, "%doc")) { + fl->currentFlags |= RPMFILE_DOC; + } else if (!strcmp(s, "%ghost")) { + fl->currentFlags |= RPMFILE_GHOST; + } else if (!strcmp(s, "%dir")) { + fl->isDir = 1; + } else { + if (*fileName) { + /* We already got a file -- error */ + rpmError(RPMERR_BADSPEC, + "Two files on one line: %s", *fileName); + fl->processingFailed = 1; + res = 1; + } + if (*s != '/') { + if (fl->currentFlags & RPMFILE_DOC) { + specialDoc = 1; + strcat(specialDocBuf, " "); + strcat(specialDocBuf, s); + } else { + /* not in %doc, does not begin with / -- error */ + rpmError(RPMERR_BADSPEC, + "File must begin with \"/\": %s", s); + fl->processingFailed = 1; + res = 1; + } + } else { + *fileName = s; + } + } + s = strtok(NULL, " \t\n"); + } + + if (specialDoc) { + if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) { + rpmError(RPMERR_BADSPEC, + "Can't mix special %%doc with other forms: %s", + *fileName); + fl->processingFailed = 1; + res = 1; + } else { + headerGetEntry(pkg->header, RPMTAG_NAME, NULL, + (void *) &name, NULL); + headerGetEntry(pkg->header, RPMTAG_VERSION, NULL, + (void *) &version, NULL); + sprintf(buf, "%s/%s-%s", spec->docDir, name, version); + + if (! fl->passedSpecialDoc) { + pkg->specialDoc = newStringBuf(); + appendStringBuf(pkg->specialDoc, + "export DOCDIR=$RPM_BUILD_ROOT"); + appendLineStringBuf(pkg->specialDoc, buf); + appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR"); + appendLineStringBuf(pkg->specialDoc, "mkdir -p $DOCDIR"); + + *fileName = buf; + fl->passedSpecialDoc = 1; + fl->isSpecialDoc = 1; + } + + appendStringBuf(pkg->specialDoc, "cp -pr "); + appendStringBuf(pkg->specialDoc, specialDocBuf); + appendLineStringBuf(pkg->specialDoc, " $DOCDIR"); + } } + + return res; } -static int add_file_aux(const char *file, struct stat *sb, int flag) +static int parseForVerify(char *buf, struct FileList *fl) { - const char *name = file; + char *p, *start, *end, *name; + char ourbuf[BUFSIZ]; + int not, verifyFlags; + int *resultVerify; - if (rpmGetVar(RPMVAR_ROOT)) { - name += strlen(rpmGetVar(RPMVAR_ROOT)); + if (!(p = start = strstr(buf, "%verify"))) { + if (!(p = start = strstr(buf, "%defverify"))) { + return 0; + } + name = "%defverify"; + resultVerify = &(fl->defVerifyFlags); + p += 10; + } else { + name = "%verify"; + resultVerify = &(fl->currentVerifyFlags); + p += 7; } - /* The 1 will cause add_file() to *not* descend */ - /* directories -- ftw() is already doing it! */ - Gcount += add_file(Gfestack, name, Gisdoc, Gconf, 1, Gisghost, - Gverify_flags, - GPmode, GUname, GGname, Gprefix); + SKIPSPACE(p); - return 0; /* for ftw() */ -} + if (*p != '(') { + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + p++; -/*************************************************************/ -/* */ -/* globbing */ -/* */ -/*************************************************************/ + end = p; + while (*end && *end != ')') { + end++; + } -/* glob_pattern_p() taken from bash - * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc. - */ + if (! *end) { + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } -/* Return nonzero if PATTERN has any special globbing chars in it. */ -static int glob_pattern_p (char *pattern) -{ - register char *p = pattern; - register char c; - int open = 0; - - while ((c = *p++) != '\0') - switch (c) { - case '?': - case '*': - return (1); - case '[': /* Only accept an open brace if there is a close */ - open++; /* brace to match it. Bracket expressions must be */ - continue; /* complete, according to Posix.2 */ - case ']': - if (open) - return (1); - continue; - case '\\': - if (*p++ == '\0') - return (0); + strncpy(ourbuf, p, end-p); + ourbuf[end-p] = '\0'; + while (start <= end) { + *start++ = ' '; + } + + p = strtok(ourbuf, ", \n\t"); + not = 0; + verifyFlags = RPMVERIFY_NONE; + while (p) { + if (!strcmp(p, "not")) { + not = 1; + } else if (!strcmp(p, "md5")) { + verifyFlags |= RPMVERIFY_MD5; + } else if (!strcmp(p, "size")) { + verifyFlags |= RPMVERIFY_FILESIZE; + } else if (!strcmp(p, "link")) { + verifyFlags |= RPMVERIFY_LINKTO; + } else if (!strcmp(p, "user")) { + verifyFlags |= RPMVERIFY_USER; + } else if (!strcmp(p, "group")) { + verifyFlags |= RPMVERIFY_GROUP; + } else if (!strcmp(p, "mtime")) { + verifyFlags |= RPMVERIFY_MTIME; + } else if (!strcmp(p, "mode")) { + verifyFlags |= RPMVERIFY_MODE; + } else if (!strcmp(p, "rdev")) { + verifyFlags |= RPMVERIFY_RDEV; + } else { + rpmError(RPMERR_BADSPEC, "Invalid %s token: %s", name, p); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } + p = strtok(NULL, ", \n\t"); + } - return (0); -} + *resultVerify = not ? ~(verifyFlags) : verifyFlags; -static int glob_error(const char *foo, int bar) -{ - return 1; + return 0; } -/*************************************************************/ -/* */ -/* %attr parsing */ -/* */ -/*************************************************************/ - -static int parseForAttr(char *buf, char **currPmode, - char **currUname, char **currGname) +static int parseForLang(char *buf, struct FileList *fl) { char *p, *start, *end; char ourbuf[1024]; - int mode, x; - if (!(p = start = strstr(buf, "%attr"))) { + if (!(p = start = strstr(buf, "%lang"))) { return 0; } - *currPmode = *currUname = *currGname = NULL; - p += 5; - while (*p && (*p == ' ' || *p == '\t')) { - p++; - } + SKIPSPACE(p); if (*p != '(') { - rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } p++; @@ -837,68 +1036,66 @@ static int parseForAttr(char *buf, char **currPmode, } if (! *end) { - rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } strncpy(ourbuf, p, end-p); ourbuf[end-p] = '\0'; + while (start <= end) { + *start++ = ' '; + } - *currPmode = strtok(ourbuf, ", \n\t"); - *currUname = strtok(NULL, ", \n\t"); - *currGname = strtok(NULL, ", \n\t"); - - if (! (*currPmode && *currUname && *currGname)) { - rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf); - *currPmode = *currUname = *currGname = NULL; + p = strtok(ourbuf, ", \n\t"); + if (!p) { + rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } - - /* Do a quick test on the mode argument */ - if (strcmp(*currPmode, "-")) { - x = sscanf(*currPmode, "%o", &mode); - if ((x == 0) || (mode >> 12)) { - rpmError(RPMERR_BADSPEC, "Bad %%attr() mode spec: %s", buf); - *currPmode = *currUname = *currGname = NULL; - return RPMERR_BADSPEC; - } + if (strlen(p) != 2) { + rpmError(RPMERR_BADSPEC, "%%lang() entries are 2 characters: %s", buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } - - *currPmode = strdup(*currPmode); - *currUname = strdup(*currUname); - *currGname = strdup(*currGname); - - /* Set everything we just parsed to blank spaces */ - while (start <= end) { - *start++ = ' '; + if (strtok(NULL, ", \n\t")) { + rpmError(RPMERR_BADSPEC, "Only one entry in %%lang(): %s", buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } - + fl->currentLang = strdup(p); + return 0; } -/*************************************************************/ -/* */ -/* %verify parsing */ -/* */ -/*************************************************************/ - -static int parseForVerify(char *buf, int *verify_flags) +static int parseForAttr(char *buf, struct FileList *fl) { - char *p, *start, *end; + char *p, *s, *start, *end, *name; char ourbuf[1024]; - int not; + int x, defattr = 0; + struct AttrRec *resultAttr; - if (!(p = start = strstr(buf, "%verify"))) { - return 0; + if (!(p = start = strstr(buf, "%attr"))) { + if (!(p = start = strstr(buf, "%defattr"))) { + return 0; + } + defattr = 1; + name = "%defattr"; + resultAttr = &(fl->def); + p += 8; + } else { + name = "%attr"; + resultAttr = &(fl->current); + p += 5; } - p += 7; - while (*p && (*p == ' ' || *p == '\t')) { - p++; - } + resultAttr->PmodeString = resultAttr->Uname = resultAttr->Gname = NULL; + + SKIPSPACE(p); if (*p != '(') { - rpmError(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } p++; @@ -909,53 +1106,92 @@ static int parseForVerify(char *buf, int *verify_flags) } if (! *end) { - rpmError(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } + if (defattr) { + s = end; + s++; + SKIPSPACE(s); + if (*s) { + rpmError(RPMERR_BADSPEC, + "No files after %%defattr(): %s", buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + } + strncpy(ourbuf, p, end-p); ourbuf[end-p] = '\0'; - while (start <= end) { - *start++ = ' '; + + resultAttr->PmodeString = strtok(ourbuf, ", \n\t"); + resultAttr->Uname = strtok(NULL, ", \n\t"); + resultAttr->Gname = strtok(NULL, ", \n\t"); + resultAttr->PdirmodeString = strtok(NULL, ", \n\t"); + + if (! (resultAttr->PmodeString && + resultAttr->Uname && resultAttr->Gname)) { + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + resultAttr->PmodeString = resultAttr->Uname = resultAttr->Gname = NULL; + fl->processingFailed = 1; + return RPMERR_BADSPEC; } - p = strtok(ourbuf, ", \n\t"); - not = 0; - *verify_flags = RPMVERIFY_NONE; - while (p) { - if (!strcmp(p, "not")) { - not = 1; - } else if (!strcmp(p, "md5")) { - *verify_flags |= RPMVERIFY_MD5; - } else if (!strcmp(p, "size")) { - *verify_flags |= RPMVERIFY_FILESIZE; - } else if (!strcmp(p, "link")) { - *verify_flags |= RPMVERIFY_LINKTO; - } else if (!strcmp(p, "user")) { - *verify_flags |= RPMVERIFY_USER; - } else if (!strcmp(p, "group")) { - *verify_flags |= RPMVERIFY_GROUP; - } else if (!strcmp(p, "mtime")) { - *verify_flags |= RPMVERIFY_MTIME; - } else if (!strcmp(p, "mode")) { - *verify_flags |= RPMVERIFY_MODE; - } else if (!strcmp(p, "rdev")) { - *verify_flags |= RPMVERIFY_RDEV; - } else { - rpmError(RPMERR_BADSPEC, "Invalid %%verify token: %s", p); + /* Do a quick test on the mode argument and adjust for "-" */ + if (!strcmp(resultAttr->PmodeString, "-")) { + resultAttr->PmodeString = NULL; + } else { + x = sscanf(resultAttr->PmodeString, "%o", &(resultAttr->Pmode)); + if ((x == 0) || (resultAttr->Pmode >> 12)) { + rpmError(RPMERR_BADSPEC, "Bad %s() mode spec: %s", name, buf); + resultAttr->PmodeString = resultAttr->Uname = + resultAttr->Gname = NULL; + fl->processingFailed = 1; return RPMERR_BADSPEC; } - p = strtok(NULL, ", \n\t"); + resultAttr->PmodeString = strdup(resultAttr->PmodeString); } - - if (not) { - *verify_flags = ~(*verify_flags); + if (resultAttr->PdirmodeString) { + /* The processing here is slightly different to maintain */ + /* compatibility with old spec files. */ + if (!strcmp(resultAttr->PdirmodeString, "-")) { + resultAttr->PdirmodeString = strdup(resultAttr->PdirmodeString); + } else { + x = sscanf(resultAttr->PdirmodeString, "%o", + &(resultAttr->Pdirmode)); + if ((x == 0) || (resultAttr->Pdirmode >> 12)) { + rpmError(RPMERR_BADSPEC, + "Bad %s() dirmode spec: %s", name, buf); + resultAttr->PmodeString = resultAttr->Uname = + resultAttr->Gname = resultAttr->PdirmodeString = NULL; + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + resultAttr->PdirmodeString = strdup(resultAttr->PdirmodeString); + } + } + if (!strcmp(resultAttr->Uname, "-")) { + resultAttr->Uname = NULL; + } else { + resultAttr->Uname = strdup(resultAttr->Uname); + } + if (!strcmp(resultAttr->Gname, "-")) { + resultAttr->Gname = NULL; + } else { + resultAttr->Gname = strdup(resultAttr->Gname); + } + + /* Set everything we just parsed to blank spaces */ + while (start <= end) { + *start++ = ' '; } return 0; } -static int parseForConfig(char *buf, int *conf) +static int parseForConfig(char *buf, struct FileList *fl) { char *p, *start, *end; char ourbuf[1024]; @@ -963,12 +1199,10 @@ static int parseForConfig(char *buf, int *conf) if (!(p = start = strstr(buf, "%config"))) { return 0; } - *conf = RPMFILE_CONFIG; + fl->currentFlags = RPMFILE_CONFIG; p += 7; - while (*p && (*p == ' ' || *p == '\t')) { - p++; - } + SKIPSPACE(p); if (*p != '(') { while (start < p) { @@ -985,6 +1219,7 @@ static int parseForConfig(char *buf, int *conf) if (! *end) { rpmError(RPMERR_BADSPEC, "Bad %%config() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } @@ -997,11 +1232,12 @@ static int parseForConfig(char *buf, int *conf) p = strtok(ourbuf, ", \n\t"); while (p) { if (!strcmp(p, "missingok")) { - *conf |= RPMFILE_MISSINGOK; + fl->currentFlags |= RPMFILE_MISSINGOK; } else if (!strcmp(p, "noreplace")) { - *conf |= RPMFILE_NOREPLACE; + fl->currentFlags |= RPMFILE_NOREPLACE; } else { rpmError(RPMERR_BADSPEC, "Invalid %%config token: %s", p); + fl->processingFailed = 1; return RPMERR_BADSPEC; } p = strtok(NULL, ", \n\t"); @@ -1009,3 +1245,39 @@ static int parseForConfig(char *buf, int *conf) return 0; } + +/* glob_pattern_p() taken from bash + * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc. + * + * Return nonzero if PATTERN has any special globbing chars in it. + */ +static int myGlobPatternP (char *pattern) +{ + register char *p = pattern; + register char c; + int open = 0; + + while ((c = *p++) != '\0') + switch (c) { + case '?': + case '*': + return (1); + case '[': /* Only accept an open brace if there is a close */ + open++; /* brace to match it. Bracket expressions must be */ + continue; /* complete, according to Posix.2 */ + case ']': + if (open) + return (1); + continue; + case '\\': + if (*p++ == '\0') + return (0); + } + + return (0); +} + +static int glob_error(const char *foo, int bar) +{ + return 1; +} |