1 /* 2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <package/hpkg/RepositoryReaderImpl.h> 8 9 #include <errno.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <sys/stat.h> 14 15 #include <algorithm> 16 #include <new> 17 18 #include <ByteOrder.h> 19 #include <Message.h> 20 21 #include <package/hpkg/HPKGDefsPrivate.h> 22 #include <package/hpkg/RepositoryContentHandler.h> 23 24 25 namespace BPackageKit { 26 27 namespace BHPKG { 28 29 namespace BPrivate { 30 31 32 //#define TRACE(format...) printf(format) 33 #define TRACE(format...) do {} while (false) 34 35 36 // maximum repository info size we support reading 37 static const size_t kMaxRepositoryInfoSize = 1 * 1024 * 1024; 38 39 // maximum package attributes size we support reading 40 static const size_t kMaxPackageAttributesSize = 64 * 1024 * 1024; 41 42 43 // #pragma mark - PackagesAttributeHandler 44 45 46 class RepositoryReaderImpl::PackagesAttributeHandler 47 : public AttributeHandler { 48 public: 49 PackagesAttributeHandler(BRepositoryContentHandler* contentHandler) 50 : 51 fContentHandler(contentHandler), 52 fPackageName(NULL) 53 { 54 } 55 56 virtual status_t HandleAttribute(AttributeHandlerContext* context, uint8 id, 57 const AttributeValue& value, AttributeHandler** _handler) 58 { 59 switch (id) { 60 case B_HPKG_ATTRIBUTE_ID_PACKAGE: 61 { 62 status_t error = _NotifyPackageDone(); 63 if (error != B_OK) 64 return error; 65 66 if (_handler != NULL) { 67 if (fContentHandler != NULL) { 68 error = fContentHandler->HandlePackage(value.string); 69 if (error != B_OK) 70 return error; 71 } 72 73 *_handler = new(std::nothrow) PackageAttributeHandler; 74 if (*_handler == NULL) 75 return B_NO_MEMORY; 76 77 fPackageName = value.string; 78 } 79 break; 80 } 81 82 default: 83 if (context->ignoreUnknownAttributes) 84 break; 85 86 context->errorOutput->PrintError( 87 "Error: Invalid package attribute section: unexpected " 88 "top level attribute id %d encountered\n", id); 89 return B_BAD_DATA; 90 } 91 92 return B_OK; 93 } 94 95 virtual status_t Delete(AttributeHandlerContext* context) 96 { 97 return _NotifyPackageDone(); 98 } 99 100 private: 101 status_t _NotifyPackageDone() 102 { 103 if (fPackageName == NULL || fContentHandler == NULL) 104 return B_OK; 105 106 status_t error = fContentHandler->HandlePackageDone(fPackageName); 107 fPackageName = NULL; 108 return error; 109 } 110 111 private: 112 BRepositoryContentHandler* fContentHandler; 113 const char* fPackageName; 114 }; 115 116 117 // #pragma mark - PackageContentHandlerAdapter 118 119 120 class RepositoryReaderImpl::PackageContentHandlerAdapter 121 : public BPackageContentHandler { 122 public: 123 PackageContentHandlerAdapter(BRepositoryContentHandler* contentHandler) 124 : 125 fContentHandler(contentHandler) 126 { 127 } 128 129 virtual status_t HandleEntry(BPackageEntry* entry) 130 { 131 return B_OK; 132 } 133 134 virtual status_t HandleEntryAttribute(BPackageEntry* entry, 135 BPackageEntryAttribute* attribute) 136 { 137 return B_OK; 138 } 139 140 virtual status_t HandleEntryDone(BPackageEntry* entry) 141 { 142 return B_OK; 143 } 144 145 virtual status_t HandlePackageAttribute( 146 const BPackageInfoAttributeValue& value) 147 { 148 return fContentHandler->HandlePackageAttribute(value); 149 } 150 151 virtual void HandleErrorOccurred() 152 { 153 return fContentHandler->HandleErrorOccurred(); 154 } 155 156 private: 157 BRepositoryContentHandler* fContentHandler; 158 }; 159 160 161 // #pragma mark - RepositoryReaderImpl 162 163 164 RepositoryReaderImpl::RepositoryReaderImpl(BErrorOutput* errorOutput) 165 : 166 inherited("repository", errorOutput) 167 { 168 } 169 170 171 RepositoryReaderImpl::~RepositoryReaderImpl() 172 { 173 } 174 175 176 status_t 177 RepositoryReaderImpl::Init(const char* fileName) 178 { 179 // open file 180 int fd = open(fileName, O_RDONLY); 181 if (fd < 0) { 182 ErrorOutput()->PrintError( 183 "Error: Failed to open repository file \"%s\": %s\n", fileName, 184 strerror(errno)); 185 return errno; 186 } 187 188 return Init(fd, true); 189 } 190 191 192 status_t 193 RepositoryReaderImpl::Init(int fd, bool keepFD) 194 { 195 hpkg_repo_header header; 196 status_t error = inherited::Init<hpkg_repo_header, B_HPKG_REPO_MAGIC, 197 B_HPKG_REPO_VERSION, B_HPKG_REPO_MINOR_VERSION>(fd, keepFD, header, 0); 198 if (error != B_OK) 199 return error; 200 201 // init package attributes section 202 error = InitSection(fPackageAttributesSection, 203 UncompressedHeapSize(), 204 B_BENDIAN_TO_HOST_INT64(header.packages_length), 205 kMaxPackageAttributesSize, 206 B_BENDIAN_TO_HOST_INT64(header.packages_strings_length), 207 B_BENDIAN_TO_HOST_INT64(header.packages_strings_count)); 208 if (error != B_OK) 209 return error; 210 211 // init repository info section 212 PackageFileSection repositoryInfoSection("repository info"); 213 error = InitSection(repositoryInfoSection, 214 fPackageAttributesSection.offset, 215 B_BENDIAN_TO_HOST_INT32(header.info_length), kMaxRepositoryInfoSize, 0, 216 0); 217 if (error != B_OK) 218 return error; 219 220 // prepare the sections for use 221 error = PrepareSection(repositoryInfoSection); 222 if (error != B_OK) 223 return error; 224 225 error = PrepareSection(fPackageAttributesSection); 226 if (error != B_OK) 227 return error; 228 229 // unarchive repository info 230 BMessage repositoryInfoArchive; 231 error = repositoryInfoArchive.Unflatten((char*)repositoryInfoSection.data); 232 if (error != B_OK) { 233 ErrorOutput()->PrintError( 234 "Error: Unable to unflatten repository info archive!\n"); 235 return error; 236 } 237 error = fRepositoryInfo.SetTo(&repositoryInfoArchive); 238 if (error != B_OK) { 239 ErrorOutput()->PrintError( 240 "Error: Unable to unarchive repository info!\n"); 241 return error; 242 } 243 244 return B_OK; 245 } 246 247 248 status_t 249 RepositoryReaderImpl::GetRepositoryInfo(BRepositoryInfo* _repositoryInfo) const 250 { 251 if (_repositoryInfo == NULL) 252 return B_BAD_VALUE; 253 254 *_repositoryInfo = fRepositoryInfo; 255 return B_OK; 256 } 257 258 259 status_t 260 RepositoryReaderImpl::ParseContent(BRepositoryContentHandler* contentHandler) 261 { 262 status_t result = contentHandler->HandleRepositoryInfo(fRepositoryInfo); 263 if (result == B_OK) { 264 PackageContentHandlerAdapter contentHandlerAdapter(contentHandler); 265 AttributeHandlerContext context(ErrorOutput(), 266 contentHandler != NULL ? &contentHandlerAdapter : NULL, 267 B_HPKG_SECTION_PACKAGE_ATTRIBUTES, 268 MinorFormatVersion() > B_HPKG_REPO_MINOR_VERSION); 269 PackagesAttributeHandler rootAttributeHandler(contentHandler); 270 result = ParsePackageAttributesSection(&context, &rootAttributeHandler); 271 } 272 return result; 273 } 274 275 276 } // namespace BPrivate 277 278 } // namespace BHPKG 279 280 } // namespace BPackageKit 281