1 /* 2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "FSUtils.h" 8 9 #include <string.h> 10 11 #include <algorithm> 12 #include <string> 13 14 #include <Directory.h> 15 #include <File.h> 16 #include <Path.h> 17 #include <SymLink.h> 18 19 #include <AutoDeleter.h> 20 21 #include "DebugSupport.h" 22 23 24 static const size_t kCompareDataBufferSize = 64 * 1024; 25 const char* const kShellEscapeCharacters = " ~`#$&*()\\|[]{};'\"<>?!"; 26 27 28 /*static*/ BString 29 FSUtils::ShellEscapeString(const BString& string) 30 { 31 BString result(string); 32 result.CharacterEscape(kShellEscapeCharacters, '\\'); 33 if (result.IsEmpty()) 34 throw std::bad_alloc(); 35 return result; 36 } 37 38 39 /*static*/ status_t 40 FSUtils::OpenSubDirectory(const BDirectory& baseDirectory, 41 const RelativePath& path, bool create, BDirectory& _directory) 42 { 43 // get a string for the path 44 BString pathString = path.ToString(); 45 if (pathString.IsEmpty()) 46 RETURN_ERROR(B_NO_MEMORY); 47 48 // If creating is not allowed, just try to open it. 49 if (!create) 50 RETURN_ERROR(_directory.SetTo(&baseDirectory, pathString)); 51 52 // get an absolute path and create the subdirectory 53 BPath absolutePath; 54 status_t error = absolutePath.SetTo(&baseDirectory, pathString); 55 if (error != B_OK) { 56 ERROR("Volume::OpenSubDirectory(): failed to get absolute path " 57 "for subdirectory \"%s\": %s\n", pathString.String(), 58 strerror(error)); 59 RETURN_ERROR(error); 60 } 61 62 error = create_directory(absolutePath.Path(), 63 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 64 if (error != B_OK) { 65 ERROR("Volume::OpenSubDirectory(): failed to create " 66 "subdirectory \"%s\": %s\n", pathString.String(), 67 strerror(error)); 68 RETURN_ERROR(error); 69 } 70 71 RETURN_ERROR(_directory.SetTo(&baseDirectory, pathString)); 72 } 73 74 75 /*static*/ status_t 76 FSUtils::CompareFileContent(const Entry& entry1, const Entry& entry2, 77 bool& _equal) 78 { 79 BFile file1; 80 status_t error = _OpenFile(entry1, file1); 81 if (error != B_OK) 82 return error; 83 84 BFile file2; 85 error = _OpenFile(entry2, file2); 86 if (error != B_OK) 87 return error; 88 89 return CompareFileContent(file1, file2, _equal); 90 } 91 92 93 /*static*/ status_t 94 FSUtils::CompareFileContent(BPositionIO& content1, BPositionIO& content2, 95 bool& _equal) 96 { 97 // get and compare content size 98 off_t size1; 99 status_t error = content1.GetSize(&size1); 100 if (error != B_OK) 101 return error; 102 103 off_t size2; 104 error = content2.GetSize(&size2); 105 if (error != B_OK) 106 return error; 107 108 if (size1 != size2) { 109 _equal = false; 110 return B_OK; 111 } 112 113 if (size1 == 0) { 114 _equal = true; 115 return B_OK; 116 } 117 118 // allocate a data buffer 119 uint8* buffer1 = new(std::nothrow) uint8[2 * kCompareDataBufferSize]; 120 if (buffer1 == NULL) 121 return B_NO_MEMORY; 122 ArrayDeleter<uint8> bufferDeleter(buffer1); 123 uint8* buffer2 = buffer1 + kCompareDataBufferSize; 124 125 // compare the data 126 off_t offset = 0; 127 while (offset < size1) { 128 size_t toCompare = std::min(size_t(size1 - offset), 129 kCompareDataBufferSize); 130 ssize_t bytesRead = content1.ReadAt(offset, buffer1, toCompare); 131 if (bytesRead < 0) 132 return bytesRead; 133 if ((size_t)bytesRead != toCompare) 134 return B_ERROR; 135 136 bytesRead = content2.ReadAt(offset, buffer2, toCompare); 137 if (bytesRead < 0) 138 return bytesRead; 139 if ((size_t)bytesRead != toCompare) 140 return B_ERROR; 141 142 if (memcmp(buffer1, buffer2, toCompare) != 0) { 143 _equal = false; 144 return B_OK; 145 } 146 147 offset += bytesRead; 148 } 149 150 _equal = true; 151 return B_OK; 152 } 153 154 155 /*static*/ status_t 156 FSUtils::CompareSymLinks(const Entry& entry1, const Entry& entry2, bool& _equal) 157 { 158 BSymLink symLink1; 159 status_t error = _OpenSymLink(entry1, symLink1); 160 if (error != B_OK) 161 return error; 162 163 BSymLink symLink2; 164 error = _OpenSymLink(entry2, symLink2); 165 if (error != B_OK) 166 return error; 167 168 return CompareSymLinks(symLink1, symLink2, _equal); 169 } 170 171 172 /*static*/ status_t 173 FSUtils::CompareSymLinks(BSymLink& symLink1, BSymLink& symLink2, bool& _equal) 174 { 175 char buffer1[B_PATH_NAME_LENGTH]; 176 ssize_t bytesRead1 = symLink1.ReadLink(buffer1, sizeof(buffer1)); 177 if (bytesRead1 < 0) 178 return bytesRead1; 179 180 char buffer2[B_PATH_NAME_LENGTH]; 181 ssize_t bytesRead2 = symLink2.ReadLink(buffer2, sizeof(buffer2)); 182 if (bytesRead2 < 0) 183 return bytesRead2; 184 185 _equal = bytesRead1 == bytesRead2 186 && memcmp(buffer1, buffer2, bytesRead1) == 0; 187 return B_OK; 188 } 189 190 191 /*static*/ status_t 192 FSUtils::ExtractPackageContent(const Entry& packageEntry, 193 const char* contentPath, const Entry& targetDirectoryEntry) 194 { 195 BPath packagePathBuffer; 196 const char* packagePath; 197 status_t error = packageEntry.GetPath(packagePathBuffer, packagePath); 198 if (error != B_OK) 199 return error; 200 201 BPath targetPathBuffer; 202 const char* targetPath; 203 error = targetDirectoryEntry.GetPath(targetPathBuffer, targetPath); 204 if (error != B_OK) 205 return error; 206 207 return ExtractPackageContent(packagePath, contentPath, targetPath); 208 } 209 210 211 /*static*/ status_t 212 FSUtils::ExtractPackageContent(const char* packagePath, const char* contentPath, 213 const char* targetDirectoryPath) 214 { 215 std::string commandLine = std::string("package extract -C ") 216 + ShellEscapeString(targetDirectoryPath).String() 217 + " " 218 + ShellEscapeString(packagePath).String() 219 + " " 220 + ShellEscapeString(contentPath).String(); 221 if (system(commandLine.c_str()) != 0) 222 return B_ERROR; 223 return B_OK; 224 } 225 226 227 /*static*/ status_t 228 FSUtils::_OpenFile(const Entry& entry, BFile& file) 229 { 230 BPath pathBuffer; 231 const char* path; 232 status_t error = entry.GetPath(pathBuffer, path); 233 if (error != B_OK) 234 return error; 235 236 return file.SetTo(path, B_READ_ONLY); 237 } 238 239 240 /*static*/ status_t 241 FSUtils::_OpenSymLink(const Entry& entry, BSymLink& symLink) 242 { 243 BPath pathBuffer; 244 const char* path; 245 status_t error = entry.GetPath(pathBuffer, path); 246 if (error != B_OK) 247 return error; 248 249 return symLink.SetTo(path); 250 } 251