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
ShellEscapeString(const BString & string)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
OpenSubDirectory(const BDirectory & baseDirectory,const RelativePath & path,bool create,BDirectory & _directory)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
CompareFileContent(const Entry & entry1,const Entry & entry2,bool & _equal)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
CompareFileContent(BPositionIO & content1,BPositionIO & content2,bool & _equal)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
CompareSymLinks(const Entry & entry1,const Entry & entry2,bool & _equal)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
CompareSymLinks(BSymLink & symLink1,BSymLink & symLink2,bool & _equal)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
ExtractPackageContent(const Entry & packageEntry,const char * contentPath,const Entry & targetDirectoryEntry)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
ExtractPackageContent(const char * packagePath,const char * contentPath,const char * targetDirectoryPath)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
_OpenFile(const Entry & entry,BFile & file)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
_OpenSymLink(const Entry & entry,BSymLink & symLink)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