llvm.org GIT mirror llvm / 8276800
[Support] Add support for getting file system permissions on Windows and implement sys::fs::set/getPermissions to work with them This change adds support for functions to set and get file permissions, in a similar manner to the C++17 permissions() function in <filesystem>. The setter uses chmod on Unix systems and SetFileAttributes on Windows, setting the permissions as passed in. The getter simply uses the existing status() function. Prior to this change, status() would always return an unknown value for the permissions on a Windows file, making it impossible to test the new function on Windows. I have therefore added support for this as well. On Linux, prior to this change, the permissions included the file type, which should actually be accessed via a different member of the file_status class. Note that on Windows, only the *_write permission bits have any affect - if any are set, the file is writable, and if not, the file is read-only. This is in common with what MSDN describes for their behaviour of std::filesystem::permissions(), and also what boost::filesystem does. The motivation behind this change is so that we can easily test behaviour on read-only files in LLVM unit tests, but I am sure that others may find it useful in some situations. Reviewers: zturner, amccarth, aaron.ballman Differential Revision: https://reviews.llvm.org/D30736 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297945 91177308-0d34-0410-b5e6-96231b3b80d8 James Henderson 3 years ago
5 changed file(s) with 253 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
9292 set_uid_on_exe = 04000,
9393 set_gid_on_exe = 02000,
9494 sticky_bit = 01000,
95 all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
9596 perms_not_known = 0xFFFF
9697 };
9798
180181
181182 file_status(file_type Type) : Type(Type) {}
182183
183 file_status(file_type Type, uint32_t LastAccessTimeHigh,
184 file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
184185 uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
185186 uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
186187 uint32_t FileSizeHigh, uint32_t FileSizeLow,
190191 LastWriteTimeLow(LastWriteTimeLow),
191192 VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
192193 FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
193 FileIndexLow(FileIndexLow), Type(Type) {}
194 FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {}
194195 #endif
195196
196197 // getters
604605 /// @brief A version for when a file descriptor is already available.
605606 std::error_code status(int FD, file_status &Result);
606607
608 /// @brief Set file permissions.
609 ///
610 /// @param Path File to set permissions on.
611 /// @param Permissions New file permissions.
612 /// @returns errc::success if the permissions were successfully set, otherwise
613 /// a platform-specific error_code.
614 /// @note On Windows, all permissions except *_write are ignored. Using any of
615 /// owner_write, group_write, or all_write will make the file writable.
616 /// Otherwise, the file will be marked as read-only.
617 std::error_code setPermissions(const Twine &Path, perms Permissions);
618
619 /// @brief Get file permissions.
620 ///
621 /// @param Path File to get permissions from.
622 /// @returns the permissions if they were successfully retrieved, otherwise a
623 /// platform-specific error_code.
624 /// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY
625 /// attribute, all_all will be returned. Otherwise, all_read | all_exe
626 /// will be returned.
627 ErrorOr getPermissions(const Twine &Path);
628
607629 /// @brief Get file size.
608630 ///
609631 /// @param Path Input path.
11911191 return fs::status(Path, result, FollowSymlinks);
11921192 }
11931193
1194 ErrorOr getPermissions(const Twine &Path) {
1195 file_status Status;
1196 if (std::error_code EC = status(Path, Status))
1197 return EC;
1198
1199 return Status.permissions();
1200 }
1201
11941202 } // end namespace fs
11951203 } // end namespace sys
11961204 } // end namespace llvm
546546 else if (S_ISLNK(Status.st_mode))
547547 Type = file_type::symlink_file;
548548
549 perms Perms = static_cast(Status.st_mode);
549 perms Perms = static_cast(Status.st_mode) & all_perms;
550550 Result =
551551 file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime,
552552 Status.st_mtime, Status.st_uid, Status.st_gid,
568568 struct stat Status;
569569 int StatRet = ::fstat(FD, &Status);
570570 return fillStatus(StatRet, Status, Result);
571 }
572
573 std::error_code setPermissions(const Twine &Path, perms Permissions) {
574 SmallString<128> PathStorage;
575 StringRef P = Path.toNullTerminatedStringRef(PathStorage);
576
577 if (::chmod(P.begin(), Permissions))
578 return std::error_code(errno, std::generic_category());
579 return std::error_code();
571580 }
572581
573582 std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
529529 file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
530530 ? file_type::directory_file
531531 : file_type::regular_file;
532 Result =
533 file_status(Type, Info.ftLastAccessTime.dwHighDateTime,
534 Info.ftLastAccessTime.dwLowDateTime,
535 Info.ftLastWriteTime.dwHighDateTime,
536 Info.ftLastWriteTime.dwLowDateTime,
537 Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
538 Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
532 perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
533 ? (all_read | all_exe)
534 : all_all;
535 Result = file_status(
536 Type, Permissions, Info.ftLastAccessTime.dwHighDateTime,
537 Info.ftLastAccessTime.dwLowDateTime,
538 Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime,
539 Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow,
540 Info.nFileIndexHigh, Info.nFileIndexLow);
539541 return std::error_code();
540542 }
541543
586588 std::error_code status(int FD, file_status &Result) {
587589 HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD));
588590 return getStatus(FileHandle, Result);
591 }
592
593 std::error_code setPermissions(const Twine &Path, perms Permissions) {
594 SmallVector PathUTF16;
595 if (std::error_code EC = widenPath(Path, PathUTF16))
596 return EC;
597
598 DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin());
599 if (Attributes == INVALID_FILE_ATTRIBUTES)
600 return mapWindowsError(GetLastError());
601
602 // There are many Windows file attributes that are not to do with the file
603 // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve
604 // them.
605 if (Permissions & all_write) {
606 Attributes &= ~FILE_ATTRIBUTE_READONLY;
607 if (Attributes == 0)
608 // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set.
609 Attributes |= FILE_ATTRIBUTE_NORMAL;
610 }
611 else {
612 Attributes |= FILE_ATTRIBUTE_READONLY;
613 // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so
614 // remove it, if it is present.
615 Attributes &= ~FILE_ATTRIBUTE_NORMAL;
616 }
617
618 if (!::SetFileAttributesW(PathUTF16.begin(), Attributes))
619 return mapWindowsError(GetLastError());
620
621 return std::error_code();
589622 }
590623
591624 std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
13341334 ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path;
13351335 }
13361336
1337 TEST_F(FileSystemTest, permissions) {
1338 int FD;
1339 SmallString<64> TempPath;
1340 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
1341 FileRemover Cleanup(TempPath);
1342
1343 // Make sure it exists.
1344 ASSERT_TRUE(fs::exists(Twine(TempPath)));
1345
1346 auto CheckPermissions = [&](fs::perms Expected) {
1347 ErrorOr Actual = fs::getPermissions(TempPath);
1348 return Actual && *Actual == Expected;
1349 };
1350
1351 std::error_code NoError;
1352 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_all), NoError);
1353 EXPECT_TRUE(CheckPermissions(fs::all_all));
1354
1355 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError);
1356 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe));
1357
1358 #if defined(LLVM_ON_WIN32)
1359 fs::perms ReadOnly = fs::all_read | fs::all_exe;
1360 EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
1361 EXPECT_TRUE(CheckPermissions(ReadOnly));
1362
1363 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
1364 EXPECT_TRUE(CheckPermissions(ReadOnly));
1365
1366 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
1367 EXPECT_TRUE(CheckPermissions(fs::all_all));
1368
1369 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
1370 EXPECT_TRUE(CheckPermissions(ReadOnly));
1371
1372 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
1373 EXPECT_TRUE(CheckPermissions(fs::all_all));
1374
1375 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
1376 EXPECT_TRUE(CheckPermissions(ReadOnly));
1377
1378 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
1379 EXPECT_TRUE(CheckPermissions(fs::all_all));
1380
1381 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
1382 EXPECT_TRUE(CheckPermissions(ReadOnly));
1383
1384 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
1385 EXPECT_TRUE(CheckPermissions(fs::all_all));
1386
1387 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
1388 EXPECT_TRUE(CheckPermissions(ReadOnly));
1389
1390 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
1391 EXPECT_TRUE(CheckPermissions(fs::all_all));
1392
1393 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
1394 EXPECT_TRUE(CheckPermissions(ReadOnly));
1395
1396 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
1397 EXPECT_TRUE(CheckPermissions(fs::all_all));
1398
1399 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
1400 EXPECT_TRUE(CheckPermissions(ReadOnly));
1401
1402 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
1403 EXPECT_TRUE(CheckPermissions(fs::all_all));
1404
1405 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
1406 EXPECT_TRUE(CheckPermissions(ReadOnly));
1407
1408 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
1409 EXPECT_TRUE(CheckPermissions(ReadOnly));
1410
1411 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
1412 EXPECT_TRUE(CheckPermissions(ReadOnly));
1413
1414 EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
1415 EXPECT_TRUE(CheckPermissions(ReadOnly));
1416
1417 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
1418 fs::set_gid_on_exe |
1419 fs::sticky_bit),
1420 NoError);
1421 EXPECT_TRUE(CheckPermissions(ReadOnly));
1422
1423 EXPECT_EQ(fs::setPermissions(TempPath, ReadOnly | fs::set_uid_on_exe |
1424 fs::set_gid_on_exe |
1425 fs::sticky_bit),
1426 NoError);
1427 EXPECT_TRUE(CheckPermissions(ReadOnly));
1428
1429 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
1430 EXPECT_TRUE(CheckPermissions(fs::all_all));
1431 #else
1432 EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
1433 EXPECT_TRUE(CheckPermissions(fs::no_perms));
1434
1435 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
1436 EXPECT_TRUE(CheckPermissions(fs::owner_read));
1437
1438 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
1439 EXPECT_TRUE(CheckPermissions(fs::owner_write));
1440
1441 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
1442 EXPECT_TRUE(CheckPermissions(fs::owner_exe));
1443
1444 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
1445 EXPECT_TRUE(CheckPermissions(fs::owner_all));
1446
1447 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
1448 EXPECT_TRUE(CheckPermissions(fs::group_read));
1449
1450 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
1451 EXPECT_TRUE(CheckPermissions(fs::group_write));
1452
1453 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
1454 EXPECT_TRUE(CheckPermissions(fs::group_exe));
1455
1456 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
1457 EXPECT_TRUE(CheckPermissions(fs::group_all));
1458
1459 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
1460 EXPECT_TRUE(CheckPermissions(fs::others_read));
1461
1462 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
1463 EXPECT_TRUE(CheckPermissions(fs::others_write));
1464
1465 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
1466 EXPECT_TRUE(CheckPermissions(fs::others_exe));
1467
1468 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
1469 EXPECT_TRUE(CheckPermissions(fs::others_all));
1470
1471 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
1472 EXPECT_TRUE(CheckPermissions(fs::all_read));
1473
1474 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
1475 EXPECT_TRUE(CheckPermissions(fs::all_write));
1476
1477 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
1478 EXPECT_TRUE(CheckPermissions(fs::all_exe));
1479
1480 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
1481 EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe));
1482
1483 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
1484 EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe));
1485
1486 EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
1487 EXPECT_TRUE(CheckPermissions(fs::sticky_bit));
1488
1489 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
1490 fs::set_gid_on_exe |
1491 fs::sticky_bit),
1492 NoError);
1493 EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe | fs::set_gid_on_exe |
1494 fs::sticky_bit));
1495
1496 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::set_uid_on_exe |
1497 fs::set_gid_on_exe |
1498 fs::sticky_bit),
1499 NoError);
1500 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe |
1501 fs::set_gid_on_exe | fs::sticky_bit));
1502
1503 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
1504 EXPECT_TRUE(CheckPermissions(fs::all_perms));
1505 #endif
1506 }
1507
13371508 } // anonymous namespace