vfs: check userland buffers before reading them.
[haiku.git] / src / servers / package / FSUtils.cpp
blob65f909eac65bc974c8963713141e81c9e3950d84
1 /*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "FSUtils.h"
9 #include <string.h>
11 #include <algorithm>
12 #include <string>
14 #include <Directory.h>
15 #include <File.h>
16 #include <Path.h>
17 #include <SymLink.h>
19 #include <AutoDeleter.h>
21 #include "DebugSupport.h"
24 static const size_t kCompareDataBufferSize = 64 * 1024;
25 const char* const kShellEscapeCharacters = " ~`#$&*()\\|[]{};'\"<>?!";
28 /*static*/ BString
29 FSUtils::ShellEscapeString(const BString& string)
31 BString result(string);
32 result.CharacterEscape(kShellEscapeCharacters, '\\');
33 if (result.IsEmpty())
34 throw std::bad_alloc();
35 return result;
39 /*static*/ status_t
40 FSUtils::OpenSubDirectory(const BDirectory& baseDirectory,
41 const RelativePath& path, bool create, BDirectory& _directory)
43 // get a string for the path
44 BString pathString = path.ToString();
45 if (pathString.IsEmpty())
46 RETURN_ERROR(B_NO_MEMORY);
48 // If creating is not allowed, just try to open it.
49 if (!create)
50 RETURN_ERROR(_directory.SetTo(&baseDirectory, pathString));
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);
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);
71 RETURN_ERROR(_directory.SetTo(&baseDirectory, pathString));
75 /*static*/ status_t
76 FSUtils::CompareFileContent(const Entry& entry1, const Entry& entry2,
77 bool& _equal)
79 BFile file1;
80 status_t error = _OpenFile(entry1, file1);
81 if (error != B_OK)
82 return error;
84 BFile file2;
85 error = _OpenFile(entry2, file2);
86 if (error != B_OK)
87 return error;
89 return CompareFileContent(file1, file2, _equal);
93 /*static*/ status_t
94 FSUtils::CompareFileContent(BPositionIO& content1, BPositionIO& content2,
95 bool& _equal)
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;
103 off_t size2;
104 error = content2.GetSize(&size2);
105 if (error != B_OK)
106 return error;
108 if (size1 != size2) {
109 _equal = false;
110 return B_OK;
113 if (size1 == 0) {
114 _equal = true;
115 return B_OK;
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;
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;
136 bytesRead = content2.ReadAt(offset, buffer2, toCompare);
137 if (bytesRead < 0)
138 return bytesRead;
139 if ((size_t)bytesRead != toCompare)
140 return B_ERROR;
142 if (memcmp(buffer1, buffer2, toCompare) != 0) {
143 _equal = false;
144 return B_OK;
147 offset += bytesRead;
150 _equal = true;
151 return B_OK;
155 /*static*/ status_t
156 FSUtils::CompareSymLinks(const Entry& entry1, const Entry& entry2, bool& _equal)
158 BSymLink symLink1;
159 status_t error = _OpenSymLink(entry1, symLink1);
160 if (error != B_OK)
161 return error;
163 BSymLink symLink2;
164 error = _OpenSymLink(entry2, symLink2);
165 if (error != B_OK)
166 return error;
168 return CompareSymLinks(symLink1, symLink2, _equal);
172 /*static*/ status_t
173 FSUtils::CompareSymLinks(BSymLink& symLink1, BSymLink& symLink2, bool& _equal)
175 char buffer1[B_PATH_NAME_LENGTH];
176 ssize_t bytesRead1 = symLink1.ReadLink(buffer1, sizeof(buffer1));
177 if (bytesRead1 < 0)
178 return bytesRead1;
180 char buffer2[B_PATH_NAME_LENGTH];
181 ssize_t bytesRead2 = symLink2.ReadLink(buffer2, sizeof(buffer2));
182 if (bytesRead2 < 0)
183 return bytesRead2;
185 _equal = bytesRead1 == bytesRead2
186 && memcmp(buffer1, buffer2, bytesRead1) == 0;
187 return B_OK;
191 /*static*/ status_t
192 FSUtils::ExtractPackageContent(const Entry& packageEntry,
193 const char* contentPath, const Entry& targetDirectoryEntry)
195 BPath packagePathBuffer;
196 const char* packagePath;
197 status_t error = packageEntry.GetPath(packagePathBuffer, packagePath);
198 if (error != B_OK)
199 return error;
201 BPath targetPathBuffer;
202 const char* targetPath;
203 error = targetDirectoryEntry.GetPath(targetPathBuffer, targetPath);
204 if (error != B_OK)
205 return error;
207 return ExtractPackageContent(packagePath, contentPath, targetPath);
211 /*static*/ status_t
212 FSUtils::ExtractPackageContent(const char* packagePath, const char* contentPath,
213 const char* targetDirectoryPath)
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;
227 /*static*/ status_t
228 FSUtils::_OpenFile(const Entry& entry, BFile& file)
230 BPath pathBuffer;
231 const char* path;
232 status_t error = entry.GetPath(pathBuffer, path);
233 if (error != B_OK)
234 return error;
236 return file.SetTo(path, B_READ_ONLY);
240 /*static*/ status_t
241 FSUtils::_OpenSymLink(const Entry& entry, BSymLink& symLink)
243 BPath pathBuffer;
244 const char* path;
245 status_t error = entry.GetPath(pathBuffer, path);
246 if (error != B_OK)
247 return error;
249 return symLink.SetTo(path);