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