1 /* 2 * Copyright 2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Oliver Tappe <zooey@hirschkaefer.de> 7 */ 8 9 10 #include <package/PackageRoster.h> 11 12 #include <errno.h> 13 #include <sys/stat.h> 14 15 #include <Directory.h> 16 #include <Entry.h> 17 #include <Path.h> 18 #include <String.h> 19 #include <StringList.h> 20 21 #include <package/PackageInfo.h> 22 #include <package/PackageInfoContentHandler.h> 23 #include <package/PackageInfoSet.h> 24 #include <package/RepositoryCache.h> 25 #include <package/RepositoryConfig.h> 26 27 #include <package/hpkg/PackageReader.h> 28 29 30 namespace BPackageKit { 31 32 33 using namespace BHPKG; 34 35 36 BPackageRoster::BPackageRoster() 37 { 38 } 39 40 41 BPackageRoster::~BPackageRoster() 42 { 43 } 44 45 46 status_t 47 BPackageRoster::GetCommonRepositoryConfigPath(BPath* path, bool create) const 48 { 49 return _GetRepositoryPath(path, create, B_COMMON_SETTINGS_DIRECTORY); 50 } 51 52 53 status_t 54 BPackageRoster::GetUserRepositoryConfigPath(BPath* path, bool create) const 55 { 56 return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY); 57 } 58 59 60 status_t 61 BPackageRoster::GetCommonRepositoryCachePath(BPath* path, bool create) const 62 { 63 return _GetRepositoryPath(path, create, B_COMMON_CACHE_DIRECTORY); 64 } 65 66 67 status_t 68 BPackageRoster::GetUserRepositoryCachePath(BPath* path, bool create) const 69 { 70 return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY); 71 } 72 73 74 status_t 75 BPackageRoster::VisitCommonRepositoryConfigs(BRepositoryConfigVisitor& visitor) 76 { 77 BPath commonRepositoryConfigPath; 78 status_t result 79 = GetCommonRepositoryConfigPath(&commonRepositoryConfigPath); 80 if (result != B_OK) 81 return result; 82 83 return _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor); 84 } 85 86 87 status_t 88 BPackageRoster::VisitUserRepositoryConfigs(BRepositoryConfigVisitor& visitor) 89 { 90 BPath userRepositoryConfigPath; 91 status_t result = GetUserRepositoryConfigPath(&userRepositoryConfigPath); 92 if (result != B_OK) 93 return result; 94 95 return _VisitRepositoryConfigs(userRepositoryConfigPath, visitor); 96 } 97 98 99 status_t 100 BPackageRoster::GetRepositoryNames(BStringList& names) 101 { 102 struct RepositoryNameCollector : public BRepositoryConfigVisitor { 103 RepositoryNameCollector(BStringList& _names) 104 : names(_names) 105 { 106 } 107 status_t operator()(const BEntry& entry) 108 { 109 char name[B_FILE_NAME_LENGTH]; 110 status_t result = entry.GetName(name); 111 if (result != B_OK) 112 return result; 113 int32 count = names.CountStrings(); 114 for (int i = 0; i < count; ++i) { 115 if (names.StringAt(i).Compare(name) == 0) 116 return B_OK; 117 } 118 names.Add(name); 119 return B_OK; 120 } 121 BStringList& names; 122 }; 123 RepositoryNameCollector repositoryNameCollector(names); 124 status_t result = VisitUserRepositoryConfigs(repositoryNameCollector); 125 if (result != B_OK) 126 return result; 127 128 return VisitCommonRepositoryConfigs(repositoryNameCollector); 129 } 130 131 132 status_t 133 BPackageRoster::GetRepositoryCache(const BString& name, 134 BRepositoryCache* repositoryCache) 135 { 136 if (repositoryCache == NULL) 137 return B_BAD_VALUE; 138 139 // user path has higher precedence than common path 140 BPath path; 141 status_t result = GetUserRepositoryCachePath(&path); 142 if (result != B_OK) 143 return result; 144 path.Append(name.String()); 145 146 BEntry repoCacheEntry(path.Path()); 147 if (repoCacheEntry.Exists()) 148 return repositoryCache->SetTo(repoCacheEntry); 149 150 if ((result = GetCommonRepositoryCachePath(&path, true)) != B_OK) 151 return result; 152 path.Append(name.String()); 153 154 repoCacheEntry.SetTo(path.Path()); 155 return repositoryCache->SetTo(repoCacheEntry); 156 } 157 158 159 status_t 160 BPackageRoster::GetRepositoryConfig(const BString& name, 161 BRepositoryConfig* repositoryConfig) 162 { 163 if (repositoryConfig == NULL) 164 return B_BAD_VALUE; 165 166 // user path has higher precedence than common path 167 BPath path; 168 status_t result = GetUserRepositoryConfigPath(&path); 169 if (result != B_OK) 170 return result; 171 path.Append(name.String()); 172 173 BEntry repoConfigEntry(path.Path()); 174 if (repoConfigEntry.Exists()) 175 return repositoryConfig->SetTo(repoConfigEntry); 176 177 if ((result = GetCommonRepositoryConfigPath(&path, true)) != B_OK) 178 return result; 179 path.Append(name.String()); 180 181 repoConfigEntry.SetTo(path.Path()); 182 return repositoryConfig->SetTo(repoConfigEntry); 183 } 184 185 186 status_t 187 BPackageRoster::GetActivePackages(BPackageInstallationLocation location, 188 BPackageInfoSet& packageInfos) 189 { 190 // This method makes sense only on an installed Haiku, but not for the build 191 // tools. 192 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 193 // check the given location 194 directory_which packagesDirectory; 195 switch (location) { 196 case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM: 197 packagesDirectory = B_SYSTEM_PACKAGES_DIRECTORY; 198 break; 199 case B_PACKAGE_INSTALLATION_LOCATION_COMMON: 200 packagesDirectory = B_COMMON_PACKAGES_DIRECTORY; 201 break; 202 case B_PACKAGE_INSTALLATION_LOCATION_HOME: 203 packagesDirectory = B_USER_PACKAGES_DIRECTORY; 204 break; 205 default: 206 return B_BAD_VALUE; 207 } 208 209 // find the package links directory 210 BPath packageLinksPath; 211 status_t error = find_directory(B_PACKAGE_LINKS_DIRECTORY, 212 &packageLinksPath); 213 if (error != B_OK) 214 return error; 215 216 // find and open the packages directory 217 BPath packagesDirPath; 218 error = find_directory(packagesDirectory, &packagesDirPath); 219 if (error != B_OK) 220 return error; 221 222 BDirectory directory; 223 error = directory.SetTo(packagesDirPath.Path()); 224 if (error != B_OK) 225 return error; 226 227 // TODO: Implement that correctly be reading the activation files/directory! 228 229 // iterate through the packages 230 char buffer[sizeof(dirent) + B_FILE_NAME_LENGTH]; 231 dirent* entry = (dirent*)&buffer; 232 while (directory.GetNextDirents(entry, sizeof(buffer), 1) == 1) { 233 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) 234 continue; 235 236 // get the full package file path 237 BPath packagePath; 238 error = packagePath.SetTo(packagesDirPath.Path(), entry->d_name); 239 if (error != B_OK) 240 continue; 241 242 // read the package info from the file 243 BPackageReader packageReader(NULL); 244 error = packageReader.Init(packagePath.Path()); 245 if (error != B_OK) 246 continue; 247 248 BPackageInfo info; 249 BPackageInfoContentHandler handler(info); 250 error = packageReader.ParseContent(&handler); 251 if (error != B_OK || info.InitCheck() != B_OK) 252 continue; 253 254 // check whether the package is really active by verifying that a 255 // package link exists for it 256 BString packageLinkName(info.Name()); 257 packageLinkName << '-' << info.Version().ToString(); 258 BPath packageLinkPath; 259 struct stat st; 260 if (packageLinkPath.SetTo(packageLinksPath.Path(), packageLinkName) 261 != B_OK 262 || lstat(packageLinkPath.Path(), &st) != 0) { 263 continue; 264 } 265 266 // add the info 267 error = packageInfos.AddInfo(info); 268 if (error != B_OK) 269 return error; 270 } 271 272 return B_OK; 273 #else 274 return B_NOT_SUPPORTED; 275 #endif 276 } 277 278 279 status_t 280 BPackageRoster::_GetRepositoryPath(BPath* path, bool create, 281 directory_which whichDir) const 282 { 283 if (path == NULL) 284 return B_BAD_VALUE; 285 286 status_t result = find_directory(whichDir, path); 287 if (result != B_OK) 288 return result; 289 if ((result = path->Append("package-repositories")) != B_OK) 290 return result; 291 292 if (create) { 293 BEntry entry(path->Path(), true); 294 if (!entry.Exists()) { 295 if (mkdir(path->Path(), 0755) != 0) 296 return errno; 297 } 298 } 299 300 return B_OK; 301 } 302 303 304 status_t 305 BPackageRoster::_VisitRepositoryConfigs(const BPath& path, 306 BRepositoryConfigVisitor& visitor) 307 { 308 BDirectory directory(path.Path()); 309 status_t result = directory.InitCheck(); 310 if (result == B_ENTRY_NOT_FOUND) 311 return B_OK; 312 if (result != B_OK) 313 return result; 314 315 BEntry entry; 316 while (directory.GetNextEntry(&entry, true) == B_OK) { 317 if ((result = visitor(entry)) != B_OK) 318 return result; 319 } 320 321 return B_OK; 322 } 323 324 325 } // namespace BPackageKit 326