/* * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include "FSUtils.h" #include #include #include #include #include #include #include #include #include "DebugSupport.h" static const size_t kCompareDataBufferSize = 64 * 1024; const char* const kShellEscapeCharacters = " ~`#$&*()\\|[]{};'\"<>?!"; /*static*/ BString FSUtils::ShellEscapeString(const BString& string) { BString result(string); result.CharacterEscape(kShellEscapeCharacters, '\\'); if (result.IsEmpty()) throw std::bad_alloc(); return result; } /*static*/ status_t FSUtils::OpenSubDirectory(const BDirectory& baseDirectory, const RelativePath& path, bool create, BDirectory& _directory) { // get a string for the path BString pathString = path.ToString(); if (pathString.IsEmpty()) RETURN_ERROR(B_NO_MEMORY); // If creating is not allowed, just try to open it. if (!create) RETURN_ERROR(_directory.SetTo(&baseDirectory, pathString)); // get an absolute path and create the subdirectory BPath absolutePath; status_t error = absolutePath.SetTo(&baseDirectory, pathString); if (error != B_OK) { ERROR("Volume::OpenSubDirectory(): failed to get absolute path " "for subdirectory \"%s\": %s\n", pathString.String(), strerror(error)); RETURN_ERROR(error); } error = create_directory(absolutePath.Path(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); if (error != B_OK) { ERROR("Volume::OpenSubDirectory(): failed to create " "subdirectory \"%s\": %s\n", pathString.String(), strerror(error)); RETURN_ERROR(error); } RETURN_ERROR(_directory.SetTo(&baseDirectory, pathString)); } /*static*/ status_t FSUtils::CompareFileContent(const Entry& entry1, const Entry& entry2, bool& _equal) { BFile file1; status_t error = _OpenFile(entry1, file1); if (error != B_OK) return error; BFile file2; error = _OpenFile(entry2, file2); if (error != B_OK) return error; return CompareFileContent(file1, file2, _equal); } /*static*/ status_t FSUtils::CompareFileContent(BPositionIO& content1, BPositionIO& content2, bool& _equal) { // get and compare content size off_t size1; status_t error = content1.GetSize(&size1); if (error != B_OK) return error; off_t size2; error = content2.GetSize(&size2); if (error != B_OK) return error; if (size1 != size2) { _equal = false; return B_OK; } if (size1 == 0) { _equal = true; return B_OK; } // allocate a data buffer uint8* buffer1 = new(std::nothrow) uint8[2 * kCompareDataBufferSize]; if (buffer1 == NULL) return B_NO_MEMORY; ArrayDeleter bufferDeleter(buffer1); uint8* buffer2 = buffer1 + kCompareDataBufferSize; // compare the data off_t offset = 0; while (offset < size1) { size_t toCompare = std::min(size_t(size1 - offset), kCompareDataBufferSize); ssize_t bytesRead = content1.ReadAt(offset, buffer1, toCompare); if (bytesRead < 0) return bytesRead; if ((size_t)bytesRead != toCompare) return B_ERROR; bytesRead = content2.ReadAt(offset, buffer2, toCompare); if (bytesRead < 0) return bytesRead; if ((size_t)bytesRead != toCompare) return B_ERROR; if (memcmp(buffer1, buffer2, toCompare) != 0) { _equal = false; return B_OK; } offset += bytesRead; } _equal = true; return B_OK; } /*static*/ status_t FSUtils::CompareSymLinks(const Entry& entry1, const Entry& entry2, bool& _equal) { BSymLink symLink1; status_t error = _OpenSymLink(entry1, symLink1); if (error != B_OK) return error; BSymLink symLink2; error = _OpenSymLink(entry2, symLink2); if (error != B_OK) return error; return CompareSymLinks(symLink1, symLink2, _equal); } /*static*/ status_t FSUtils::CompareSymLinks(BSymLink& symLink1, BSymLink& symLink2, bool& _equal) { char buffer1[B_PATH_NAME_LENGTH]; ssize_t bytesRead1 = symLink1.ReadLink(buffer1, sizeof(buffer1)); if (bytesRead1 < 0) return bytesRead1; char buffer2[B_PATH_NAME_LENGTH]; ssize_t bytesRead2 = symLink2.ReadLink(buffer2, sizeof(buffer2)); if (bytesRead2 < 0) return bytesRead2; _equal = bytesRead1 == bytesRead2 && memcmp(buffer1, buffer2, bytesRead1) == 0; return B_OK; } /*static*/ status_t FSUtils::ExtractPackageContent(const Entry& packageEntry, const char* contentPath, const Entry& targetDirectoryEntry) { BPath packagePathBuffer; const char* packagePath; status_t error = packageEntry.GetPath(packagePathBuffer, packagePath); if (error != B_OK) return error; BPath targetPathBuffer; const char* targetPath; error = targetDirectoryEntry.GetPath(targetPathBuffer, targetPath); if (error != B_OK) return error; return ExtractPackageContent(packagePath, contentPath, targetPath); } /*static*/ status_t FSUtils::ExtractPackageContent(const char* packagePath, const char* contentPath, const char* targetDirectoryPath) { std::string commandLine = std::string("package extract -C ") + ShellEscapeString(targetDirectoryPath).String() + " " + ShellEscapeString(packagePath).String() + " " + ShellEscapeString(contentPath).String(); if (system(commandLine.c_str()) != 0) return B_ERROR; return B_OK; } /*static*/ status_t FSUtils::_OpenFile(const Entry& entry, BFile& file) { BPath pathBuffer; const char* path; status_t error = entry.GetPath(pathBuffer, path); if (error != B_OK) return error; return file.SetTo(path, B_READ_ONLY); } /*static*/ status_t FSUtils::_OpenSymLink(const Entry& entry, BSymLink& symLink) { BPath pathBuffer; const char* path; status_t error = entry.GetPath(pathBuffer, path); if (error != B_OK) return error; return symLink.SetTo(path); }