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