1 /* 2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "FilePath.h" 27 28 #include <algorithm> 29 #include <list> 30 #include <ShellAPI.h> 31 32 bool FilePath::FileExists(const TString FileName) { 33 bool result = false; 34 WIN32_FIND_DATA FindFileData; 35 TString fileName = FixPathForPlatform(FileName); 36 HANDLE handle = FindFirstFile(fileName.data(), &FindFileData); 37 38 if (handle != INVALID_HANDLE_VALUE) { 39 if (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes) { 40 result = true; 41 } 42 else { 43 result = true; 44 } 45 46 FindClose(handle); 47 } 48 return result; 49 } 50 51 bool FilePath::DirectoryExists(const TString DirectoryName) { 52 bool result = false; 53 WIN32_FIND_DATA FindFileData; 54 TString directoryName = FixPathForPlatform(DirectoryName); 55 HANDLE handle = FindFirstFile(directoryName.data(), &FindFileData); 56 57 if (handle != INVALID_HANDLE_VALUE) { 58 if (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes) { 59 result = true; 60 } 61 62 FindClose(handle); 63 } 64 return result; 65 } 66 67 std::string GetLastErrorAsString() { 68 // Get the error message, if any. 69 DWORD errorMessageID = ::GetLastError(); 70 71 if (errorMessageID == 0) { 72 return "No error message has been recorded"; 73 } 74 75 LPSTR messageBuffer = NULL; 76 size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER 77 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 78 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, 79 SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); 80 81 std::string message(messageBuffer, size); 82 83 // Free the buffer. 84 LocalFree(messageBuffer); 85 86 return message; 87 } 88 89 bool FilePath::DeleteFile(const TString FileName) { 90 bool result = false; 91 92 if (FileExists(FileName) == true) { 93 TString lFileName = FixPathForPlatform(FileName); 94 FileAttributes attributes(lFileName); 95 96 if (attributes.Contains(faReadOnly) == true) { 97 attributes.Remove(faReadOnly); 98 } 99 100 result = ::DeleteFile(lFileName.data()) == TRUE; 101 } 102 103 return result; 104 } 105 106 bool FilePath::DeleteDirectory(const TString DirectoryName) { 107 bool result = false; 108 109 if (DirectoryExists(DirectoryName) == true) { 110 SHFILEOPSTRUCTW fos = {0}; 111 TString directoryName = FixPathForPlatform(DirectoryName); 112 DynamicBuffer<TCHAR> lDirectoryName(directoryName.size() + 2); 113 if (lDirectoryName.GetData() == NULL) { 114 return false; 115 } 116 memcpy(lDirectoryName.GetData(), directoryName.data(), (directoryName.size() + 2) * sizeof(TCHAR)); 117 lDirectoryName[directoryName.size() + 1] = NULL; 118 // Double null terminate for SHFileOperation. 119 120 // Delete the folder and everything inside. 121 fos.wFunc = FO_DELETE; 122 fos.pFrom = lDirectoryName.GetData(); 123 fos.fFlags = FOF_NO_UI; 124 result = SHFileOperation(&fos) == 0; 125 } 126 127 return result; 128 } 129 130 TString FilePath::IncludeTrailingSeparator(const TString value) { 131 TString result = value; 132 133 if (value.size() > 0) { 134 TString::iterator i = result.end(); 135 i--; 136 137 if (*i != TRAILING_PATHSEPARATOR) { 138 result += TRAILING_PATHSEPARATOR; 139 } 140 } 141 142 return result; 143 } 144 145 TString FilePath::IncludeTrailingSeparator(const char* value) { 146 TString lvalue = PlatformString(value).toString(); 147 return IncludeTrailingSeparator(lvalue); 148 } 149 150 TString FilePath::IncludeTrailingSeparator(const wchar_t* value) { 151 TString lvalue = PlatformString(value).toString(); 152 return IncludeTrailingSeparator(lvalue); 153 } 154 155 TString FilePath::ExtractFilePath(TString Path) { 156 TString result; 157 size_t slash = Path.find_last_of(TRAILING_PATHSEPARATOR); 158 if (slash != TString::npos) 159 result = Path.substr(0, slash); 160 return result; 161 } 162 163 TString FilePath::ExtractFileExt(TString Path) { 164 TString result; 165 size_t dot = Path.find_last_of('.'); 166 167 if (dot != TString::npos) { 168 result = Path.substr(dot, Path.size() - dot); 169 } 170 171 return result; 172 } 173 174 TString FilePath::ExtractFileName(TString Path) { 175 TString result; 176 177 size_t slash = Path.find_last_of(TRAILING_PATHSEPARATOR); 178 if (slash != TString::npos) 179 result = Path.substr(slash + 1, Path.size() - slash - 1); 180 181 return result; 182 } 183 184 TString FilePath::ChangeFileExt(TString Path, TString Extension) { 185 TString result; 186 size_t dot = Path.find_last_of('.'); 187 188 if (dot != TString::npos) { 189 result = Path.substr(0, dot) + Extension; 190 } 191 192 if (result.empty() == true) { 193 result = Path; 194 } 195 196 return result; 197 } 198 199 TString FilePath::FixPathForPlatform(TString Path) { 200 TString result = Path; 201 std::replace(result.begin(), result.end(), 202 BAD_TRAILING_PATHSEPARATOR, TRAILING_PATHSEPARATOR); 203 // The maximum path that does not require long path prefix. On Windows the 204 // maximum path is 260 minus 1 (NUL) but for directories it is 260 minus 205 // 12 minus 1 (to allow for the creation of a 8.3 file in the directory). 206 const int maxPath = 247; 207 if (result.length() > maxPath && 208 result.find(_T("\\\\?\\")) == TString::npos && 209 result.find(_T("\\\\?\\UNC")) == TString::npos) { 210 const TString prefix(_T("\\\\")); 211 if (!result.compare(0, prefix.size(), prefix)) { 212 // UNC path, converting to UNC path in long notation 213 result = _T("\\\\?\\UNC") + result.substr(1, result.length()); 214 } else { 215 // converting to non-UNC path in long notation 216 result = _T("\\\\?\\") + result; 217 } 218 } 219 return result; 220 } 221 222 TString FilePath::FixPathSeparatorForPlatform(TString Path) { 223 TString result = Path; 224 std::replace(result.begin(), result.end(), 225 BAD_PATH_SEPARATOR, PATH_SEPARATOR); 226 return result; 227 } 228 229 TString FilePath::PathSeparator() { 230 TString result; 231 result = PATH_SEPARATOR; 232 return result; 233 } 234 235 bool FilePath::CreateDirectory(TString Path, bool ownerOnly) { 236 bool result = false; 237 238 std::list<TString> paths; 239 TString lpath = Path; 240 241 while (lpath.empty() == false && DirectoryExists(lpath) == false) { 242 paths.push_front(lpath); 243 lpath = ExtractFilePath(lpath); 244 } 245 246 for (std::list<TString>::iterator iterator = paths.begin(); 247 iterator != paths.end(); iterator++) { 248 lpath = *iterator; 249 250 if (_wmkdir(lpath.data()) == 0) { 251 result = true; 252 } else { 253 result = false; 254 break; 255 } 256 } 257 258 return result; 259 } 260 261 void FilePath::ChangePermissions(TString FileName, bool ownerOnly) { 262 } 263 264 #include <algorithm> 265 266 FileAttributes::FileAttributes(const TString FileName, bool FollowLink) { 267 FFileName = FileName; 268 FFollowLink = FollowLink; 269 ReadAttributes(); 270 } 271 272 bool FileAttributes::WriteAttributes() { 273 bool result = false; 274 275 DWORD attributes = 0; 276 277 for (std::vector<FileAttribute>::const_iterator iterator = 278 FAttributes.begin(); 279 iterator != FAttributes.end(); iterator++) { 280 switch (*iterator) { 281 case faArchive: { 282 attributes = attributes & FILE_ATTRIBUTE_ARCHIVE; 283 break; 284 } 285 case faCompressed: { 286 attributes = attributes & FILE_ATTRIBUTE_COMPRESSED; 287 break; 288 } 289 case faDevice: { 290 attributes = attributes & FILE_ATTRIBUTE_DEVICE; 291 break; 292 } 293 case faDirectory: { 294 attributes = attributes & FILE_ATTRIBUTE_DIRECTORY; 295 break; 296 } 297 case faEncrypted: { 298 attributes = attributes & FILE_ATTRIBUTE_ENCRYPTED; 299 break; 300 } 301 case faHidden: { 302 attributes = attributes & FILE_ATTRIBUTE_HIDDEN; 303 break; 304 } 305 case faNormal: { 306 attributes = attributes & FILE_ATTRIBUTE_NORMAL; 307 break; 308 } 309 case faNotContentIndexed: { 310 attributes = attributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; 311 break; 312 } 313 case faOffline: { 314 attributes = attributes & FILE_ATTRIBUTE_OFFLINE; 315 break; 316 } 317 case faSystem: { 318 attributes = attributes & FILE_ATTRIBUTE_SYSTEM; 319 break; 320 } 321 case faSymbolicLink: { 322 attributes = attributes & FILE_ATTRIBUTE_REPARSE_POINT; 323 break; 324 } 325 case faSparceFile: { 326 attributes = attributes & FILE_ATTRIBUTE_SPARSE_FILE; 327 break; 328 } 329 case faReadOnly: { 330 attributes = attributes & FILE_ATTRIBUTE_READONLY; 331 break; 332 } 333 case faTemporary: { 334 attributes = attributes & FILE_ATTRIBUTE_TEMPORARY; 335 break; 336 } 337 case faVirtual: { 338 attributes = attributes & FILE_ATTRIBUTE_VIRTUAL; 339 break; 340 } 341 } 342 } 343 344 if (::SetFileAttributes(FFileName.data(), attributes) != 0) { 345 result = true; 346 } 347 348 return result; 349 } 350 351 #define S_ISRUSR(m) (((m) & S_IRWXU) == S_IRUSR) 352 #define S_ISWUSR(m) (((m) & S_IRWXU) == S_IWUSR) 353 #define S_ISXUSR(m) (((m) & S_IRWXU) == S_IXUSR) 354 355 #define S_ISRGRP(m) (((m) & S_IRWXG) == S_IRGRP) 356 #define S_ISWGRP(m) (((m) & S_IRWXG) == S_IWGRP) 357 #define S_ISXGRP(m) (((m) & S_IRWXG) == S_IXGRP) 358 359 #define S_ISROTH(m) (((m) & S_IRWXO) == S_IROTH) 360 #define S_ISWOTH(m) (((m) & S_IRWXO) == S_IWOTH) 361 #define S_ISXOTH(m) (((m) & S_IRWXO) == S_IXOTH) 362 363 bool FileAttributes::ReadAttributes() { 364 bool result = false; 365 366 DWORD attributes = ::GetFileAttributes(FFileName.data()); 367 368 if (attributes != INVALID_FILE_ATTRIBUTES) { 369 result = true; 370 371 if (attributes | FILE_ATTRIBUTE_ARCHIVE) { 372 FAttributes.push_back(faArchive); 373 } 374 if (attributes | FILE_ATTRIBUTE_COMPRESSED) { 375 FAttributes.push_back(faCompressed); 376 } 377 if (attributes | FILE_ATTRIBUTE_DEVICE) { 378 FAttributes.push_back(faDevice); 379 } 380 if (attributes | FILE_ATTRIBUTE_DIRECTORY) { 381 FAttributes.push_back(faDirectory); 382 } 383 if (attributes | FILE_ATTRIBUTE_ENCRYPTED) { 384 FAttributes.push_back(faEncrypted); 385 } 386 if (attributes | FILE_ATTRIBUTE_HIDDEN) { 387 FAttributes.push_back(faHidden); 388 } 389 // if (attributes | FILE_ATTRIBUTE_INTEGRITY_STREAM) { 390 // FAttributes.push_back(faIntegrityStream); 391 // } 392 if (attributes | FILE_ATTRIBUTE_NORMAL) { 393 FAttributes.push_back(faNormal); 394 } 395 if (attributes | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) { 396 FAttributes.push_back(faNotContentIndexed); 397 } 398 // if (attributes | FILE_ATTRIBUTE_NO_SCRUB_DATA) { 399 // FAttributes.push_back(faNoScrubData); 400 // } 401 if (attributes | FILE_ATTRIBUTE_SYSTEM) { 402 FAttributes.push_back(faSystem); 403 } 404 if (attributes | FILE_ATTRIBUTE_OFFLINE) { 405 FAttributes.push_back(faOffline); 406 } 407 if (attributes | FILE_ATTRIBUTE_REPARSE_POINT) { 408 FAttributes.push_back(faSymbolicLink); 409 } 410 if (attributes | FILE_ATTRIBUTE_SPARSE_FILE) { 411 FAttributes.push_back(faSparceFile); 412 } 413 if (attributes | FILE_ATTRIBUTE_READONLY ) { 414 FAttributes.push_back(faReadOnly); 415 } 416 if (attributes | FILE_ATTRIBUTE_TEMPORARY) { 417 FAttributes.push_back(faTemporary); 418 } 419 if (attributes | FILE_ATTRIBUTE_VIRTUAL) { 420 FAttributes.push_back(faVirtual); 421 } 422 } 423 424 return result; 425 } 426 427 bool FileAttributes::Valid(const FileAttribute Value) { 428 bool result = false; 429 430 switch (Value) { 431 case faHidden: 432 case faReadOnly: { 433 result = true; 434 break; 435 } 436 default: 437 break; 438 } 439 440 return result; 441 } 442 443 void FileAttributes::Append(FileAttribute Value) { 444 if (Valid(Value) == true) { 445 FAttributes.push_back(Value); 446 WriteAttributes(); 447 } 448 } 449 450 bool FileAttributes::Contains(FileAttribute Value) { 451 bool result = false; 452 453 std::vector<FileAttribute>::const_iterator iterator = 454 std::find(FAttributes.begin(), FAttributes.end(), Value); 455 456 if (iterator != FAttributes.end()) { 457 result = true; 458 } 459 460 return result; 461 } 462 463 void FileAttributes::Remove(FileAttribute Value) { 464 if (Valid(Value) == true) { 465 std::vector<FileAttribute>::iterator iterator = 466 std::find(FAttributes.begin(), FAttributes.end(), Value); 467 468 if (iterator != FAttributes.end()) { 469 FAttributes.erase(iterator); 470 WriteAttributes(); 471 } 472 } 473 }