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
39using namespace std;
40
41bool 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
48bool 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
59bool 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
72void 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
102void 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
112void 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
123void 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
155void 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
164long 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
185string 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
200bool 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