llvm.org GIT mirror llvm / d45fbe6
Support/FileSystem: Implement bool equivalent(file_status A, file_status B); git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@146364 91177308-0d34-0410-b5e6-96231b3b80d8 Michael J. Spencer 8 years ago
4 changed file(s) with 79 addition(s) and 84 deletion(s). Raw diff Collapse all Expand all
3838 #include
3939 #include
4040
41 #if HAVE_SYS_STAT_H
42 #include
43 #endif
44
4145 namespace llvm {
4246 namespace sys {
4347 namespace fs {
9397 /// a platform specific member to store the result.
9498 class file_status
9599 {
96 // implementation defined status field.
100 #if defined(LLVM_ON_UNIX)
101 dev_t st_dev;
102 ino_t st_ino;
103 #elif defined (LLVM_ON_WIN32)
104 uint32_t LastWriteTimeHigh;
105 uint32_t LastWriteTimeLow;
106 uint32_t VolumeSerialNumber;
107 uint32_t FileSizeHigh;
108 uint32_t FileSizeLow;
109 uint32_t FileIndexHigh;
110 uint32_t FileIndexLow;
111 #endif
112 friend bool equivalent(file_status A, file_status B);
113 friend error_code status(const Twine &path, file_status &result);
97114 file_type Type;
98115 public:
99116 explicit file_status(file_type v=file_type::status_error)
242259 bool equivalent(file_status A, file_status B);
243260
244261 /// @brief Do paths represent the same thing?
262 ///
263 /// assert(status_known(A) || status_known(B));
245264 ///
246265 /// @param A Input path A.
247266 /// @param B Input path B.
272272 return success;
273273 }
274274
275 bool equivalent(file_status A, file_status B) {
276 assert(status_known(A) && status_known(B));
277 return A.st_dev == B.st_dev &&
278 A.st_ino == B.st_ino;
279 }
280
275281 error_code equivalent(const Twine &A, const Twine &B, bool &result) {
276 // Get arguments.
277 SmallString<128> a_storage;
278 SmallString<128> b_storage;
279 StringRef a = A.toNullTerminatedStringRef(a_storage);
280 StringRef b = B.toNullTerminatedStringRef(b_storage);
281
282 struct stat stat_a, stat_b;
283 int error_b = ::stat(b.begin(), &stat_b);
284 int error_a = ::stat(a.begin(), &stat_a);
285
286 // If both are invalid, it's an error. If only one is, the result is false.
287 if (error_a != 0 || error_b != 0) {
288 if (error_a == error_b)
289 return error_code(errno, system_category());
290 result = false;
291 } else {
292 result =
293 stat_a.st_dev == stat_b.st_dev &&
294 stat_a.st_ino == stat_b.st_ino;
295 }
296
282 file_status fsA, fsB;
283 if (error_code ec = status(A, fsA)) return ec;
284 if (error_code ec = status(B, fsB)) return ec;
285 result = equivalent(fsA, fsB);
297286 return success;
298287 }
299288
339328 result = file_status(file_type::socket_file);
340329 else
341330 result = file_status(file_type::type_unknown);
331
332 result.st_dev = status.st_dev;
333 result.st_ino = status.st_ino;
342334
343335 return success;
344336 }
349349 return success;
350350 }
351351
352 bool equivalent(file_status A, file_status B) {
353 assert(status_known(A) && status_known(B));
354 return A.FileIndexHigh == B.FileIndexHigh &&
355 A.FileIndexLow == B.FileIndexLow &&
356 A.FileSizeHigh == B.FileSizeHigh &&
357 A.FileSizeLow == B.FileSizeLow &&
358 A.LastWriteTimeHigh == B.LastWriteTimeHigh &&
359 A.LastWriteTimeLow == B.LastWriteTimeLow &&
360 A.VolumeSerialNumber == B.VolumeSerialNumber;
361 }
362
352363 error_code equivalent(const Twine &A, const Twine &B, bool &result) {
353 // Get arguments.
354 SmallString<128> a_storage;
355 SmallString<128> b_storage;
356 StringRef a = A.toStringRef(a_storage);
357 StringRef b = B.toStringRef(b_storage);
358
359 // Convert to utf-16.
360 SmallVector wide_a;
361 SmallVector wide_b;
362 if (error_code ec = UTF8ToUTF16(a, wide_a)) return ec;
363 if (error_code ec = UTF8ToUTF16(b, wide_b)) return ec;
364
365 ScopedFileHandle HandleB(
366 ::CreateFileW(wide_b.begin(),
367 0,
368 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
369 0,
370 OPEN_EXISTING,
371 FILE_FLAG_BACKUP_SEMANTICS,
372 0));
373
374 ScopedFileHandle HandleA(
375 ::CreateFileW(wide_a.begin(),
376 0,
377 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
378 0,
379 OPEN_EXISTING,
380 FILE_FLAG_BACKUP_SEMANTICS,
381 0));
382
383 // If both handles are invalid, it's an error.
384 if (!HandleA && !HandleB)
385 return windows_error(::GetLastError());
386
387 // If only one is invalid, it's false.
388 if (!HandleA || !HandleB) {
389 result = false;
390 return success;
391 }
392
393 // Get file information.
394 BY_HANDLE_FILE_INFORMATION InfoA, InfoB;
395 if (!::GetFileInformationByHandle(HandleA, &InfoA))
396 return windows_error(::GetLastError());
397 if (!::GetFileInformationByHandle(HandleB, &InfoB))
398 return windows_error(::GetLastError());
399
400 // See if it's all the same.
401 result =
402 InfoA.dwVolumeSerialNumber == InfoB.dwVolumeSerialNumber &&
403 InfoA.nFileIndexHigh == InfoB.nFileIndexHigh &&
404 InfoA.nFileIndexLow == InfoB.nFileIndexLow &&
405 InfoA.nFileSizeHigh == InfoB.nFileSizeHigh &&
406 InfoA.nFileSizeLow == InfoB.nFileSizeLow &&
407 InfoA.ftLastWriteTime.dwLowDateTime ==
408 InfoB.ftLastWriteTime.dwLowDateTime &&
409 InfoA.ftLastWriteTime.dwHighDateTime ==
410 InfoB.ftLastWriteTime.dwHighDateTime;
411
364 file_status fsA, fsB;
365 if (error_code ec = status(A, fsA)) return ec;
366 if (error_code ec = status(B, fsB)) return ec;
367 result = equivalent(fsA, fsB);
412368 return success;
413369 }
414370
466422 return success;
467423 }
468424
469 if (error_code ec = UTF8ToUTF16(path8,
470 path_utf16))
425 if (error_code ec = UTF8ToUTF16(path8, path_utf16))
471426 return ec;
472427
473428 DWORD attr = ::GetFileAttributesW(path_utf16.begin());
490445
491446 if (attr & FILE_ATTRIBUTE_DIRECTORY)
492447 result = file_status(file_type::directory_file);
493 else
448 else {
494449 result = file_status(file_type::regular_file);
450 ScopedFileHandle h(
451 ::CreateFileW(path_utf16.begin(),
452 0, // Attributes only.
453 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
454 NULL,
455 OPEN_EXISTING,
456 FILE_FLAG_BACKUP_SEMANTICS,
457 0));
458 if (!h)
459 goto handle_status_error;
460 BY_HANDLE_FILE_INFORMATION Info;
461 if (!::GetFileInformationByHandle(h, &Info))
462 goto handle_status_error;
463 result.FileIndexHigh = Info.nFileIndexHigh;
464 result.FileIndexLow = Info.nFileIndexLow;
465 result.FileSizeHigh = Info.nFileSizeHigh;
466 result.FileSizeLow = Info.nFileSizeLow;
467 result.LastWriteTimeHigh = Info.ftLastWriteTime.dwHighDateTime;
468 result.LastWriteTimeLow = Info.ftLastWriteTime.dwLowDateTime;
469 result.VolumeSerialNumber = Info.dwVolumeSerialNumber;
470 }
495471
496472 return success;
497473
182182 ASSERT_NO_ERROR(fs::unique_file("%%-%%-%%-%%.temp", FD2, TempPath2));
183183 ASSERT_NE(TempPath.str(), TempPath2.str());
184184
185 fs::file_status A, B;
186 ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));
187 ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));
188 EXPECT_FALSE(fs::equivalent(A, B));
189
185190 // Try to copy the first to the second.
186191 EXPECT_EQ(
187192 fs::copy_file(Twine(TempPath), Twine(TempPath2)), errc::file_exists);
203208 bool equal;
204209 ASSERT_NO_ERROR(fs::equivalent(Twine(TempPath), Twine(TempPath2), equal));
205210 EXPECT_TRUE(equal);
211 ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));
212 ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));
213 EXPECT_TRUE(fs::equivalent(A, B));
206214
207215 // Remove Temp1.
208216 ::close(FileDescriptor);