From 991e690a693cf3724b815c1fb358aa033af73c03 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 25 May 2013 19:47:28 +0200 Subject: initialize the whole search array with zero Git-Dch: Ignore --- cmdline/apt-cache.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmdline/apt-cache.cc') diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 0a2c28d23..de263a300 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1247,7 +1247,7 @@ bool Search(CommandLine &CmdL) } ExDescFile *DFList = new ExDescFile[Cache->HeaderP->GroupCount+1]; - memset(DFList,0,sizeof(*DFList)*Cache->HeaderP->GroupCount+1); + memset(DFList, 0, sizeof(*DFList) * (Cache->HeaderP->GroupCount + 1)); // Map versions that we want to write out onto the VerList array. for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G) -- cgit v1.2.3-70-g09d2 From 8ba17539a3ec33abc283ca382cca6e59876a0f07 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 25 May 2013 19:57:48 +0200 Subject: fix support for multiple patterns in apt-cache search Patterns can appear in the name as well as in the description, they don't have to match all in the name/description only. Closes: 691453 --- cmdline/apt-cache.cc | 79 ++++++++++++++-------- debian/changelog | 6 +- test/integration/framework | 12 +++- .../test-bug-691453-apt-cache-search-multi-pattern | 33 +++++++++ 4 files changed, 94 insertions(+), 36 deletions(-) create mode 100755 test/integration/test-bug-691453-apt-cache-search-multi-pattern (limited to 'cmdline/apt-cache.cc') diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index de263a300..bda09a5a1 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1203,7 +1203,7 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) struct ExDescFile { pkgCache::DescFile *Df; - bool NameMatch; + map_ptrloc ID; }; // Search - Perform a search /*{{{*/ @@ -1246,37 +1246,48 @@ bool Search(CommandLine &CmdL) return false; } - ExDescFile *DFList = new ExDescFile[Cache->HeaderP->GroupCount+1]; - memset(DFList, 0, sizeof(*DFList) * (Cache->HeaderP->GroupCount + 1)); + size_t const descCount = Cache->HeaderP->GroupCount + 1; + ExDescFile *DFList = new ExDescFile[descCount]; + memset(DFList,0,sizeof(*DFList) * descCount); + + bool PatternMatch[descCount * NumPatterns]; + memset(PatternMatch,false,sizeof(PatternMatch)); // Map versions that we want to write out onto the VerList array. for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G) { - if (DFList[G->ID].NameMatch == true) - continue; - - DFList[G->ID].NameMatch = true; - for (unsigned I = 0; I != NumPatterns; I++) + size_t const PatternOffset = G->ID * NumPatterns; + size_t unmatched = 0, matched = 0; + for (unsigned I = 0; I < NumPatterns; ++I) { - if (regexec(&Patterns[I],G.Name(),0,0,0) == 0) - continue; - DFList[G->ID].NameMatch = false; - break; + if (PatternMatch[PatternOffset + I] == true) + ++matched; + else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0) + PatternMatch[PatternOffset + I] = true; + else + ++unmatched; } - - // Doing names only, drop any that dont match.. - if (NamesOnly == true && DFList[G->ID].NameMatch == false) + + // already dealt with this package? + if (matched == NumPatterns) continue; - + + // Doing names only, drop any that don't match.. + if (NamesOnly == true && unmatched == NumPatterns) + continue; + // Find the proper version to use pkgCache::PkgIterator P = G.FindPreferredPkg(); if (P.end() == true) continue; pkgCache::VerIterator V = Plcy->GetCandidateVer(P); if (V.end() == false) + { DFList[G->ID].Df = V.TranslatedDescription().FileList(); + DFList[G->ID].ID = G->ID; + } - if (DFList[G->ID].NameMatch == false) + if (unmatched == NumPatterns) continue; // Include all the packages that provide matching names too @@ -1288,33 +1299,45 @@ bool Search(CommandLine &CmdL) unsigned long id = Prv.OwnerPkg().Group()->ID; DFList[id].Df = V.TranslatedDescription().FileList(); - DFList[id].NameMatch = true; + DFList[id].ID = id; + + size_t const PrvPatternOffset = id * NumPatterns; + for (unsigned I = 0; I < NumPatterns; ++I) + PatternMatch[PrvPatternOffset + I] = PatternMatch[PatternOffset + I]; } } - + LocalitySort(&DFList->Df,Cache->HeaderP->GroupCount,sizeof(*DFList)); // Create the text record parser pkgRecords Recs(*Cache); // Iterate over all the version records and check them - for (ExDescFile *J = DFList; J->Df != 0; J++) + for (ExDescFile *J = DFList; J->Df != 0; ++J) { pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache,J->Df)); + size_t const PatternOffset = J->ID * NumPatterns; - if (J->NameMatch == false && NamesOnly == false) + if (NamesOnly == false) { string const LongDesc = P.LongDesc(); - J->NameMatch = true; - for (unsigned I = 0; I != NumPatterns; I++) + for (unsigned I = 0; I < NumPatterns; ++I) { - if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0) + if (PatternMatch[PatternOffset + I] == true) continue; - J->NameMatch = false; - break; + else if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0) + PatternMatch[PatternOffset + I] = true; } } - - if (J->NameMatch == true) + + bool matchedAll = true; + for (unsigned I = 0; I < NumPatterns; ++I) + if (PatternMatch[PatternOffset + I] == false) + { + matchedAll = false; + break; + } + + if (matchedAll == true) { if (ShowFull == true) { diff --git a/debian/changelog b/debian/changelog index 8a1194b1b..9f35441f9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ apt (0.9.8.3) UNRELEASED; urgency=low * fix priority sorting by prefering higher in MarkInstall * try all providers in order if uninstallable in MarkInstall * do unpacks before configures in SmartConfigure (Closes: #707578) + * fix support for multiple patterns in apt-cache search (Closes: #691453) -- David Kalnischkies Sun, 09 Jun 2013 15:06:24 +0200 @@ -31,11 +32,6 @@ apt (0.9.8.2) unstable; urgency=low * Fix crash when the "mirror" method does not find any entry (closes: #699303) - [ Johan Kiviniemi ] - * cmdline/apt-key: - - Create new keyrings with mode 0644 instead of 0600. - - Accept a nonexistent --keyring file with the adv subcommand as well. - -- Michael Vogt Thu, 06 Jun 2013 19:15:14 +0200 apt (0.9.8.1) unstable; urgency=low diff --git a/test/integration/framework b/test/integration/framework index 31b12e8bf..e3e868d45 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -483,6 +483,7 @@ insertpackage() { local VERSION="$4" local DEPENDENCIES="$5" local PRIORITY="${6:-optional}" + local DESCRIPTION="${7}" local ARCHS="" for arch in $(echo "$ARCH" | sed -e 's#,#\n#g' | sed -e "s#^native\$#$(getarchitecture 'native')#"); do if [ "$arch" = 'all' -o "$arch" = 'none' ]; then @@ -504,11 +505,16 @@ Maintainer: Joe Sixpack " >> $FILE echo "Version: $VERSION Filename: pool/main/${NAME}/${NAME}_${VERSION}_${arch}.deb" >> $FILE test -z "$DEPENDENCIES" || echo "$DEPENDENCIES" >> $FILE - echo "Description: an autogenerated dummy ${NAME}=${VERSION}/${RELEASE} + echo -n 'Description: ' >> $FILE + if [ -z "$DESCRIPTION" ]; then + echo "an autogenerated dummy ${NAME}=${VERSION}/${RELEASE} If you find such a package installed on your system, YOU did something horribly wrong! They are autogenerated - und used only by testcases for APT and surf no other propose… -" >> $FILE + und used only by testcases for APT and surf no other propose…" >> $FILE + else + echo "$DESCRIPTION" >> $FILE + fi + echo >> $FILE done done } diff --git a/test/integration/test-bug-691453-apt-cache-search-multi-pattern b/test/integration/test-bug-691453-apt-cache-search-multi-pattern new file mode 100755 index 000000000..0367892fc --- /dev/null +++ b/test/integration/test-bug-691453-apt-cache-search-multi-pattern @@ -0,0 +1,33 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'native' + +insertpackage 'unstable' 'foobar' 'native' '1' '' '' 'funky tool' +insertpackage 'unstable' 'coolstuff' 'native' '1' '' '' 'funky tool just like foo and bar' +insertpackage 'unstable' 'foo' 'native' '1' '' '' 'tool best used with bar' +insertpackage 'unstable' 'bar' 'native' '1' '' '' 'tool best used with foo' +insertpackage 'unstable' 'baz' 'native' '1' 'Provides: bar' '' 'alternative tool best used with foo' + +setupaptarchive + +# in this special case the following queries should be equal +FOOBAR='foobar - funky tool +coolstuff - funky tool just like foo and bar +foo - tool best used with bar +bar - tool best used with foo +baz - alternative tool best used with foo' + +testequal "$FOOBAR" aptcache search foo +testequal "$FOOBAR" aptcache search bar +testequal "$FOOBAR" aptcache search foo bar + +testequal 'foobar - funky tool +foo - tool best used with bar' aptcache search -n foo +testequal 'foobar - funky tool +bar - tool best used with foo +baz - alternative tool best used with foo' aptcache search -n bar +testequal 'foobar - funky tool' aptcache search -n foo bar -- cgit v1.2.3-70-g09d2 From 99359751efb1ad84e877219639030feb47fb28f7 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 16 Jun 2013 15:42:31 +0200 Subject: handle missing "Description" in apt-cache show do not blindly assume that all packages stanzas have a "Description:" field in 'apt-cache show' as well as in the cache creation itself. We instead assume now that if the stanza has a Description, it will not be the first field as we look out for "\nDescription" to take care of MD5sum as well as (maybe ignored) translated Descriptions embedded in the package stanza. Closes: #712435 --- apt-pkg/deb/deblistparser.cc | 6 +- apt-pkg/pkgcachegen.cc | 4 +- cmdline/apt-cache.cc | 47 ++++++++---- debian/changelog | 1 + .../test-bug-712435-missing-descriptions | 89 ++++++++++++++++++++++ 5 files changed, 130 insertions(+), 17 deletions(-) create mode 100755 test/integration/test-bug-712435-missing-descriptions (limited to 'cmdline/apt-cache.cc') diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index db86bd698..28857176b 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -219,8 +219,12 @@ MD5SumValue debListParser::Description_md5() string const value = Section.FindS("Description-md5"); if (value.empty() == true) { + std::string const desc = Description() + "\n"; + if (desc == "\n") + return MD5SumValue(); + MD5Summation md5; - md5.Add((Description() + "\n").c_str()); + md5.Add(desc.c_str()); return md5.Result(); } else if (likely(value.size() == 32)) diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 3f10b6c40..7ce7aba7b 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -296,6 +296,8 @@ bool pkgCacheGenerator::MergeListPackage(ListParser &List, pkgCache::PkgIterator // Find the right version to write the description MD5SumValue CurMd5 = List.Description_md5(); + if (CurMd5.Value().empty() == true || List.Description().empty() == true) + return true; std::string CurLang = List.DescriptionLanguage(); for (Ver = Pkg.VersionList(); Ver.end() == false; ++Ver) @@ -480,7 +482,7 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator /* Record the Description (it is not translated) */ MD5SumValue CurMd5 = List.Description_md5(); - if (CurMd5.Value().empty() == true) + if (CurMd5.Value().empty() == true || List.Description().empty() == true) return true; std::string CurLang = List.DescriptionLanguage(); diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index bda09a5a1..fb4467c2c 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1161,7 +1161,11 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) } // Get a pointer to start of Description field - const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "Description:"); + const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "\nDescription"); + if (DescP != NULL) + ++DescP; + else + DescP = Buffer + V.FileList()->Size; // Write all but Description if (fwrite(Buffer,1,DescP - Buffer,stdout) < (size_t)(DescP - Buffer)) @@ -1173,25 +1177,38 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) // Show the right description pkgRecords Recs(*Cache); pkgCache::DescIterator Desc = V.TranslatedDescription(); - pkgRecords::Parser &P = Recs.Lookup(Desc.FileList()); - cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc(); - - // Find the first field after the description (if there is any) - for(DescP++;DescP != &Buffer[V.FileList()->Size];DescP++) + if (Desc.end() == false) { - if(*DescP == '\n' && *(DescP+1) != ' ') + pkgRecords::Parser &P = Recs.Lookup(Desc.FileList()); + cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc(); + cout << std::endl << "Description-md5: " << Desc.md5() << std::endl; + + // Find the first field after the description (if there is any) + while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL) { - // write the rest of the buffer - const unsigned char *end=&Buffer[V.FileList()->Size]; - if (fwrite(DescP,1,end-DescP,stdout) < (size_t)(end-DescP)) - { - delete [] Buffer; - return false; - } + if (DescP[1] == ' ') + DescP += 2; + else if (strncmp((char*)DescP, "\nDescription", strlen("\nDescription")) == 0) + DescP += strlen("\nDescription"); + else + break; + } + if (DescP != NULL) + ++DescP; + } + // if we have no translation, we found a lonely Description-md5, so don't skip it - break; + if (DescP != NULL) + { + // write the rest of the buffer + const unsigned char *end=&Buffer[V.FileList()->Size]; + if (fwrite(DescP,1,end-DescP,stdout) < (size_t)(end-DescP)) + { + delete [] Buffer; + return false; } } + // write a final newline (after the description) cout< Sun, 09 Jun 2013 15:06:24 +0200 diff --git a/test/integration/test-bug-712435-missing-descriptions b/test/integration/test-bug-712435-missing-descriptions new file mode 100755 index 000000000..9b3c2ee50 --- /dev/null +++ b/test/integration/test-bug-712435-missing-descriptions @@ -0,0 +1,89 @@ +#!/bin/sh +set -e + +TESTDIR=$(readlink -f $(dirname $0)) +. $TESTDIR/framework +setupenvironment +configarchitecture 'amd64' + +PACKAGESTANZA='Version: 0.9.7.8 +Installed-Size: 3270 +Maintainer: APT Development Team +Architecture: amd64 +Filename: pool/main/a/apt/apt_0.9.7.8_amd64.deb +MD5sum: 3a622acda41620df50aa22a9fac6f32e' + +DESCRIPTION='Description: commandline package manager + This APT has Super Cow Powers.' + +TRANSDESCRIPTION='Description-en: commandline package manager + This APT has translated Super Cow Powers.' + +echo "Package: apt-normal +$PACKAGESTANZA +$DESCRIPTION +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +Package: apt-both-below +$PACKAGESTANZA +$DESCRIPTION +$TRANSDESCRIPTION +Description-md5: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +Package: apt-both-middle +$PACKAGESTANZA +$DESCRIPTION +Description-md5: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +$TRANSDESCRIPTION + +Package: apt-both-top +$PACKAGESTANZA +Description-md5: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +$DESCRIPTION +$TRANSDESCRIPTION + +Package: apt-trans +$PACKAGESTANZA +$TRANSDESCRIPTION +Description-md5: cccccccccccccccccccccccccccccccc + +Package: apt-md5 +$PACKAGESTANZA +Description-md5: dddddddddddddddddddddddddddddddd + +Package: apt-none +$PACKAGESTANZA" > aptarchive/Packages + +setupaptarchive + +testequal "Package: apt-normal +$PACKAGESTANZA +$DESCRIPTION +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +" aptcache show apt-normal + +# displaying the translated Description would be equally valid, +# but we assume only one description is in a Packages file and +# so we prefer "Description" over "Description-*" currently. +for variant in 'below' 'middle' 'top'; do + testequal "Package: apt-both-$variant +$PACKAGESTANZA +$DESCRIPTION +Description-md5: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +" aptcache show apt-both-$variant +done + +testequal "Package: apt-trans +$PACKAGESTANZA +$TRANSDESCRIPTION +Description-md5: cccccccccccccccccccccccccccccccc +" aptcache show apt-trans + +testequal "Package: apt-md5 +$PACKAGESTANZA +Description-md5: dddddddddddddddddddddddddddddddd +" aptcache show apt-md5 + +testequal "Package: apt-none +$PACKAGESTANZA +" aptcache show apt-none -- cgit v1.2.3-70-g09d2 From 61843f539513b3e661dac55717e6d7cc0b8f9b0c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 18 Jul 2013 16:52:31 +0200 Subject: skip all Description fields in apt-cache, not just first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given a Packages file like: […] Description: foo bar baz moo moo moo Multi-Arch: foreign Description-md5: 97e204a9f4ad8c681dbd54ec7c505251 […] We have to display the Multi-Arch flag field as well as the fields after the Description-md5, but not this field itself, as we already have one printed alongside the Description we display. Closes: 717254 --- cmdline/apt-cache.cc | 52 +++++++++++++++------- .../test-bug-712435-missing-descriptions | 52 +++++++++++++++++++++- 2 files changed, 86 insertions(+), 18 deletions(-) (limited to 'cmdline/apt-cache.cc') diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index fb4467c2c..336ac544b 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1127,6 +1127,22 @@ bool Dotty(CommandLine &CmdL) // --------------------------------------------------------------------- /* This displays the package record from the proper package index file. It is not used by DumpAvail for performance reasons. */ + +static unsigned char const* skipDescriptionFields(unsigned char const * DescP) +{ + while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL) + { + if (DescP[1] == ' ') + DescP += 2; + else if (strncmp((char*)DescP, "\nDescription", strlen("\nDescription")) == 0) + DescP += strlen("\nDescription"); + else + break; + } + if (DescP != NULL) + ++DescP; + return DescP; +} bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) { pkgCache *Cache = CacheFile.GetPkgCache(); @@ -1184,32 +1200,34 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) cout << std::endl << "Description-md5: " << Desc.md5() << std::endl; // Find the first field after the description (if there is any) - while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL) - { - if (DescP[1] == ' ') - DescP += 2; - else if (strncmp((char*)DescP, "\nDescription", strlen("\nDescription")) == 0) - DescP += strlen("\nDescription"); - else - break; - } - if (DescP != NULL) - ++DescP; + DescP = skipDescriptionFields(DescP); } - // if we have no translation, we found a lonely Description-md5, so don't skip it + // else we have no translation, so we found a lonely Description-md5 -> don't skip it - if (DescP != NULL) + // write the rest of the buffer, but skip mixed in Descriptions* fields + while (DescP != NULL) { - // write the rest of the buffer - const unsigned char *end=&Buffer[V.FileList()->Size]; - if (fwrite(DescP,1,end-DescP,stdout) < (size_t)(end-DescP)) + const unsigned char * const Start = DescP; + const unsigned char *End = (unsigned char*)strstr((char*)DescP, "\nDescription"); + if (End == NULL) + { + End = &Buffer[V.FileList()->Size]; + DescP = NULL; + } + else + { + ++End; // get the newline into the output + DescP = skipDescriptionFields(End + strlen("Description")); + } + size_t const length = End - Start; + if (fwrite(Start, 1, length, stdout) < length) { delete [] Buffer; return false; } } - // write a final newline (after the description) + // write a final newline after the last field cout< aptarchive/Packages +$PACKAGESTANZA + +Package: apt-intermixed +$PACKAGESTANZA +$DESCRIPTION +X-Some-Flag: yes +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +Package: apt-intermixed2 +$PACKAGESTANZA +$DESCRIPTION +X-Some-Flag: yes +$TRANSDESCRIPTION +X-Foo-Flag: Something with a Description +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +X-Bar-Flag: no + +Package: apt-intermixed3 +$PACKAGESTANZA +$DESCRIPTION +X-Some-Flag: yes +$TRANSDESCRIPTION +X-Foo-Flag: Something with a Description +X-Bar-Flag: no +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" > aptarchive/Packages + setupaptarchive @@ -87,3 +112,28 @@ Description-md5: dddddddddddddddddddddddddddddddd testequal "Package: apt-none $PACKAGESTANZA " aptcache show apt-none + +testequal "Package: apt-intermixed +$PACKAGESTANZA +$DESCRIPTION +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +X-Some-Flag: yes +" aptcache show apt-intermixed + +testequal "Package: apt-intermixed2 +$PACKAGESTANZA +$DESCRIPTION +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +X-Some-Flag: yes +X-Foo-Flag: Something with a Description +X-Bar-Flag: no +" aptcache show apt-intermixed2 + +testequal "Package: apt-intermixed3 +$PACKAGESTANZA +$DESCRIPTION +Description-md5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +X-Some-Flag: yes +X-Foo-Flag: Something with a Description +X-Bar-Flag: no +" aptcache show apt-intermixed3 -- cgit v1.2.3-70-g09d2 From 922f07986b93ce7866f89917e3a475e6a4b3941c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Thu, 18 Jul 2013 19:22:29 +0200 Subject: fix 'apt-cache search' crash with missing description Beside the earlier fixed 'apt-cache show', 'showpkg' and 'search' deal with descriptions. 'showpkg' was fixed by fixing the cache generation for 'show', but 'search' still segfaulted. On the upside, it doesn't segfault any longer, on the downside, if a package has no description at all (aka: not in the Packages file and not in a Translation-* file) the package can't be found with 'search', even if we search only by name. That is a shortcoming in the code, but fixing it means rewriting it completely for dubious gain at best. So this commit just skips packages without a description and is done. Closes: 647590 --- cmdline/apt-cache.cc | 33 ++++++++++++++-------- .../test-bug-712435-missing-descriptions | 26 +++++++++++++++++ 2 files changed, 48 insertions(+), 11 deletions(-) (limited to 'cmdline/apt-cache.cc') diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 336ac544b..5d1ee5615 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1130,12 +1130,14 @@ bool Dotty(CommandLine &CmdL) static unsigned char const* skipDescriptionFields(unsigned char const * DescP) { + char const * const TagName = "\nDescription"; + size_t const TagLen = strlen(TagName); while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL) { if (DescP[1] == ' ') DescP += 2; - else if (strncmp((char*)DescP, "\nDescription", strlen("\nDescription")) == 0) - DescP += strlen("\nDescription"); + else if (strncmp((char*)DescP, TagName, TagLen) == 0) + DescP += TagLen; else break; } @@ -1166,11 +1168,12 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) if (PkgF.Open(I.FileName(), FileFd::ReadOnly, FileFd::Extension) == false) return false; - // Read the record - unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+1]; - Buffer[V.FileList()->Size] = '\n'; - if (PkgF.Seek(V.FileList()->Offset) == false || - PkgF.Read(Buffer,V.FileList()->Size) == false) + // Read the record (and ensure that it ends with a newline and NUL) + unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+2]; + Buffer[Vf->Size] = '\n'; + Buffer[Vf->Size+1] = '\0'; + if (PkgF.Seek(Vf->Offset) == false || + PkgF.Read(Buffer,Vf->Size) == false) { delete [] Buffer; return false; @@ -1181,7 +1184,7 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) if (DescP != NULL) ++DescP; else - DescP = Buffer + V.FileList()->Size; + DescP = Buffer + Vf->Size; // Write all but Description if (fwrite(Buffer,1,DescP - Buffer,stdout) < (size_t)(DescP - Buffer)) @@ -1211,7 +1214,7 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) const unsigned char *End = (unsigned char*)strstr((char*)DescP, "\nDescription"); if (End == NULL) { - End = &Buffer[V.FileList()->Size]; + End = &Buffer[Vf->Size]; DescP = NULL; } else @@ -1318,7 +1321,11 @@ bool Search(CommandLine &CmdL) pkgCache::VerIterator V = Plcy->GetCandidateVer(P); if (V.end() == false) { - DFList[G->ID].Df = V.TranslatedDescription().FileList(); + pkgCache::DescIterator const D = V.TranslatedDescription(); + //FIXME: packages without a description can't be found + if (D.end() == true) + continue; + DFList[G->ID].Df = D.FileList(); DFList[G->ID].ID = G->ID; } @@ -1333,7 +1340,11 @@ bool Search(CommandLine &CmdL) continue; unsigned long id = Prv.OwnerPkg().Group()->ID; - DFList[id].Df = V.TranslatedDescription().FileList(); + pkgCache::DescIterator const D = V.TranslatedDescription(); + //FIXME: packages without a description can't be found + if (D.end() == true) + continue; + DFList[id].Df = D.FileList(); DFList[id].ID = id; size_t const PrvPatternOffset = id * NumPatterns; diff --git a/test/integration/test-bug-712435-missing-descriptions b/test/integration/test-bug-712435-missing-descriptions index c61bea452..53ecbbeb3 100755 --- a/test/integration/test-bug-712435-missing-descriptions +++ b/test/integration/test-bug-712435-missing-descriptions @@ -137,3 +137,29 @@ X-Some-Flag: yes X-Foo-Flag: Something with a Description X-Bar-Flag: no " aptcache show apt-intermixed3 + +msgtest 'Test that no description does not destroy' 'showpkg' +aptcache showpkg apt-none | sed 's#/tmp/.*_aptarchive_#/tmp/aptarchive_#' >showpkg.explosion && msgpass || msgfail +testfileequal showpkg.explosion 'Package: apt-none +Versions: +0.9.7.8 (/tmp/aptarchive_Packages) + + +Reverse Depends: +Dependencies: +0.9.7.8 - +Provides: +0.9.7.8 - +Reverse Provides: ' + +testempty aptcache search nonexistentstring + +# packages without a description can't be found +testequal 'apt-normal - commandline package manager +apt-both-below - commandline package manager +apt-both-middle - commandline package manager +apt-both-top - commandline package manager +apt-trans - commandline package manager +apt-intermixed - commandline package manager +apt-intermixed2 - commandline package manager +apt-intermixed3 - commandline package manager' aptcache search apt -- cgit v1.2.3-70-g09d2 From d832304e06838275446a0b787899591061f39160 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 26 Jul 2013 11:42:02 +0200 Subject: use FileFd::Write instead of fwrite for errors Using the static FileFd::Write method gives us error messages for free so we use it here to avoid failing silently (with a fail silent error). Git-Dch: Ignore --- cmdline/apt-cache.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'cmdline/apt-cache.cc') diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 5d1ee5615..e847de875 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1187,7 +1187,8 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) DescP = Buffer + Vf->Size; // Write all but Description - if (fwrite(Buffer,1,DescP - Buffer,stdout) < (size_t)(DescP - Buffer)) + size_t const length = DescP - Buffer; + if (length != 0 && FileFd::Write(STDOUT_FILENO, Buffer, length) == false) { delete [] Buffer; return false; @@ -1223,7 +1224,7 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) DescP = skipDescriptionFields(End + strlen("Description")); } size_t const length = End - Start; - if (fwrite(Start, 1, length, stdout) < length) + if (length != 0 && FileFd::Write(STDOUT_FILENO, Start, length) == false) { delete [] Buffer; return false; @@ -1232,8 +1233,8 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) // write a final newline after the last field cout<