1 | /* |
2 | Copyright (c) 2014 by Elvis Angelaccio |
3 | |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | of this software and associated documentation files (the "Software"), to deal |
6 | in the Software without restriction, including without limitation the rights |
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | copies of the Software, and to permit persons to whom the Software is |
9 | furnished to do so, subject to the following conditions: |
10 | |
11 | The above copyright notice and this permission notice shall be included in |
12 | all copies or substantial portions of the Software. |
13 | |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | THE SOFTWARE. |
21 | */ |
22 | |
23 | #include "../filesystem.h" |
24 | #include "../../utils/utils.h" |
25 | |
26 | |
27 | #if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) |
28 | |
29 | /* |
30 | * Macro required by GetFileSizeEx() |
31 | * source: http://msdn.microsoft.com/en-us/library/aa383745(v=vs.85).aspx#setting_winver_or__win32_winnt |
32 | */ |
33 | #define WINVER 0x0500 |
34 | |
35 | #include <windows.h> |
36 | |
37 | #endif |
38 | |
39 | using namespace std; |
40 | |
41 | bool filesystem::existFile(const string& path) |
42 | { |
43 | DWORD attributes = GetFileAttributes(path.c_str()); |
44 | |
45 | return (attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY)); // i.e. it exists but it's not a directory |
46 | } |
47 | |
48 | bool filesystem::existDirectory(const string& path) |
49 | { |
50 | DWORD attributes = GetFileAttributes(path.c_str()); |
51 | |
52 | if (INVALID_FILE_ATTRIBUTES == attributes) |
53 | return false; |
54 | |
55 | return attributes & FILE_ATTRIBUTE_DIRECTORY; |
56 | } |
57 | |
58 | |
59 | bool filesystem::existDirectory(const string& parentDirectory, const string& name) |
60 | { |
61 | string path = parentDirectory + "/" + name; |
62 | |
63 | DWORD attributes = GetFileAttributes(path.c_str()); |
64 | |
65 | if (INVALID_FILE_ATTRIBUTES == attributes) |
66 | return false; |
67 | |
68 | return attributes & FILE_ATTRIBUTE_DIRECTORY; |
69 | } |
70 | |
71 | |
72 | void filesystem::listDirectory(const string& path, vector<string>& entries) |
73 | { |
74 | WIN32_FIND_DATA fileData; |
75 | HANDLE searchHandle; |
76 | |
77 | searchHandle = FindFirstFile((path + "/*" ).c_str(), &fileData); // Windows requires the wildcard * |
78 | |
79 | if (INVALID_HANDLE_VALUE == searchHandle) |
80 | { |
81 | DWORD error = GetLastError(); |
82 | throw FileSystemError(utils::syscallError("FindFirstFile()" , error)); |
83 | } |
84 | |
85 | string name; |
86 | |
87 | do |
88 | { |
89 | name = fileData.cFileName; |
90 | |
91 | if (name != "." && name != ".." ) |
92 | { |
93 | entries.push_back(fileData.cFileName); |
94 | } |
95 | } |
96 | while (FindNextFile(searchHandle, &fileData)); |
97 | |
98 | FindClose(searchHandle); |
99 | |
100 | } |
101 | |
102 | void filesystem::createDirectory(const string& path) |
103 | { |
104 | if (!CreateDirectory(path.c_str(), NULL)) |
105 | { |
106 | DWORD error = GetLastError(); |
107 | throw FileSystemError(utils::syscallError("CreateDirectory() on " + path, error)); |
108 | } |
109 | } |
110 | |
111 | |
112 | void filesystem::createDirectory(const string& parentDirectory, const string& name) |
113 | { |
114 | string path = parentDirectory + "/" + name; |
115 | |
116 | if (!CreateDirectory(path.c_str(), NULL)) |
117 | { |
118 | DWORD error = GetLastError(); |
119 | throw FileSystemError(utils::syscallError("CreateDirectory() on " + path, error)); |
120 | } |
121 | } |
122 | |
123 | void filesystem::removeDirectory(const string& path) |
124 | { |
125 | if (!existDirectory(path)) |
126 | throw FileSystemError(path + " is not a directory" ); |
127 | |
128 | vector<string> content; |
129 | listDirectory(path, content); |
130 | |
131 | string childPath; |
132 | for (vector<string>::iterator dirIt = content.begin(); dirIt != content.end(); dirIt++) |
133 | { |
134 | childPath = path + "/" + *dirIt; |
135 | |
136 | if (existDirectory(childPath)) // is a directory we remove it using recursion |
137 | removeDirectory(childPath); |
138 | |
139 | else if (!DeleteFile(childPath.c_str())) // is a file |
140 | { |
141 | DWORD error = GetLastError(); |
142 | throw FileSystemError(utils::syscallError("DeleteFile() on " + childPath, error)); |
143 | } |
144 | } |
145 | |
146 | /* Recursion base case: once that the directoy has been recursively emptied, we can finally remove it with the Win32 api */ |
147 | |
148 | if (!RemoveDirectory(path.c_str())) |
149 | { |
150 | DWORD error = GetLastError(); |
151 | throw FileSystemError(utils::syscallError("RemoveDirectory() on " + path, error)); |
152 | } |
153 | } |
154 | |
155 | void filesystem::renameDirectory(const string& path, const string& newPath) |
156 | { |
157 | if (!MoveFile(path.c_str(), newPath.c_str())) |
158 | { |
159 | DWORD error = GetLastError(); |
160 | throw FileSystemError(utils::syscallError("MoveFile() on " + path, error)); |
161 | } |
162 | } |
163 | |
164 | long long filesystem::getFileSize(const string& path) |
165 | { |
166 | LARGE_INTEGER size; |
167 | HANDLE file = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
168 | |
169 | if (INVALID_HANDLE_VALUE == file) |
170 | { |
171 | DWORD error = GetLastError(); |
172 | throw FileSystemError(utils::syscallError("CreateFile on opening " + path, error)); |
173 | } |
174 | |
175 | if (!GetFileSizeEx(file, &size)) |
176 | { |
177 | DWORD error = GetLastError(); |
178 | throw FileSystemError(utils::syscallError("GetFileSizeEx() on " + path, error)); |
179 | } |
180 | |
181 | CloseHandle(file); |
182 | return size.QuadPart; |
183 | } |
184 | |
185 | string filesystem::getCurrentDirectory() |
186 | { |
187 | CHAR buffer[MAX_PATH_SIZE]; |
188 | |
189 | DWORD pathSize = GetCurrentDirectory(MAX_PATH_SIZE, buffer); |
190 | |
191 | if (0 == pathSize) |
192 | { |
193 | DWORD error = GetLastError(); |
194 | throw FileSystemError(utils::syscallError("GetCurrentDirectory()" , error)); |
195 | } |
196 | |
197 | return string(buffer); |
198 | } |
199 | |
200 | bool filesystem::isAbsolutePath(const std::string& path) |
201 | { |
202 | if (path.length() < 3) // On Windows an absolute path has at least 3 characters: a "driver" letter, the ':' char and then a slash or a backslash |
203 | return false; |
204 | |
205 | if (isalpha(path[0]) && ':' == path[1] && '\\' == path[2]) // a path like "C:\foo.txt" is absolute |
206 | return true; |
207 | |
208 | if (isalpha(path[0]) && ':' == path[1] && '/' == path[2]) // a path like "C:/foo.txt" is absolute |
209 | return true; |
210 | |
211 | return false; |
212 | } |
213 | |
214 | |