mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-01 15:11:24 +00:00
Add permissions(), map_file_pages(), and unmap_file_pages() to llvm::sys::fs and add unit test. Unix is implemented. Windows side needs to be implemented.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@158770 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
44b2c82871
commit
ca077ec5ea
@ -94,6 +94,55 @@ struct space_info {
|
||||
uint64_t available;
|
||||
};
|
||||
|
||||
|
||||
enum perms {
|
||||
no_perms = 0,
|
||||
owner_read = 0400,
|
||||
owner_write = 0200,
|
||||
owner_exe = 0100,
|
||||
owner_all = owner_read | owner_write | owner_exe,
|
||||
group_read = 040,
|
||||
group_write = 020,
|
||||
group_exe = 010,
|
||||
group_all = group_read | group_write | group_exe,
|
||||
others_read = 04,
|
||||
others_write = 02,
|
||||
others_exe = 01,
|
||||
others_all = others_read | others_write | others_exe,
|
||||
all_all = owner_all | group_all | others_all,
|
||||
set_uid_on_exe = 04000,
|
||||
set_gid_on_exe = 02000,
|
||||
sticky_bit = 01000,
|
||||
perms_mask = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
|
||||
perms_not_known = 0xFFFF,
|
||||
add_perms = 0x1000,
|
||||
remove_perms = 0x2000,
|
||||
symlink_perms = 0x4000
|
||||
};
|
||||
|
||||
// Helper functions so that you can use & and | to manipulate perms bits:
|
||||
inline perms operator|(perms l , perms r) {
|
||||
return static_cast<perms>(
|
||||
static_cast<unsigned short>(l) | static_cast<unsigned short>(r));
|
||||
}
|
||||
inline perms operator&(perms l , perms r) {
|
||||
return static_cast<perms>(
|
||||
static_cast<unsigned short>(l) & static_cast<unsigned short>(r));
|
||||
}
|
||||
inline perms &operator|=(perms &l, perms r) {
|
||||
l = l | r;
|
||||
return l;
|
||||
}
|
||||
inline perms &operator&=(perms &l, perms r) {
|
||||
l = l & r;
|
||||
return l;
|
||||
}
|
||||
inline perms operator~(perms x) {
|
||||
return static_cast<perms>(~static_cast<unsigned short>(x));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// file_status - Represents the result of a call to stat and friends. It has
|
||||
/// a platform specific member to store the result.
|
||||
class file_status
|
||||
@ -113,12 +162,19 @@ class file_status
|
||||
friend bool equivalent(file_status A, file_status B);
|
||||
friend error_code status(const Twine &path, file_status &result);
|
||||
file_type Type;
|
||||
perms Perms;
|
||||
public:
|
||||
explicit file_status(file_type v=file_type::status_error)
|
||||
: Type(v) {}
|
||||
explicit file_status(file_type v=file_type::status_error,
|
||||
perms prms=perms_not_known)
|
||||
: Type(v), Perms(prms) {}
|
||||
|
||||
// getters
|
||||
file_type type() const { return Type; }
|
||||
perms permissions() const { return Perms; }
|
||||
|
||||
// setters
|
||||
void type(file_type v) { Type = v; }
|
||||
void permissions(perms p) { Perms = p; }
|
||||
};
|
||||
|
||||
/// file_magic - An "enum class" enumeration of file types based on magic (the first
|
||||
@ -395,6 +451,13 @@ error_code is_symlink(const Twine &path, bool &result);
|
||||
/// platform specific error_code.
|
||||
error_code status(const Twine &path, file_status &result);
|
||||
|
||||
/// @brief Modifies permission bits on a file
|
||||
///
|
||||
/// @param path Input path.
|
||||
/// @results errc::success if permissions have been changed, otherwise a
|
||||
/// platform specific error_code.
|
||||
error_code permissions(const Twine &path, perms prms);
|
||||
|
||||
/// @brief Is status available?
|
||||
///
|
||||
/// @param path Input path.
|
||||
@ -513,6 +576,33 @@ error_code FindLibrary(const Twine &short_name, SmallVectorImpl<char> &result);
|
||||
error_code GetMainExecutable(const char *argv0, void *MainAddr,
|
||||
SmallVectorImpl<char> &result);
|
||||
|
||||
|
||||
/// @brief Memory maps the contents of a file
|
||||
///
|
||||
/// @param path Path to file to map.
|
||||
/// @param file_offset Byte offset in file where mapping should begin.
|
||||
/// @param size_t Byte length of range of the file to map.
|
||||
/// @param map_writable If true, the file will be mapped in r/w such
|
||||
/// that changes to the the mapped buffer will be flushed back
|
||||
/// to the file. If false, the file will be mapped read-only
|
||||
/// and the buffer will be read-only.
|
||||
/// @param result Set to the start address of the mapped buffer.
|
||||
/// @results errc::success if result has been successfully set, otherwise a
|
||||
/// platform specific error_code.
|
||||
error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
|
||||
bool map_writable, void *&result);
|
||||
|
||||
|
||||
/// @brief Memory unmaps the contents of a file
|
||||
///
|
||||
/// @param base Pointer to the start of the buffer.
|
||||
/// @param size Byte length of the range to unmmap.
|
||||
/// @results errc::success if result has been successfully set, otherwise a
|
||||
/// platform specific error_code.
|
||||
error_code unmap_file_pages(void *base, size_t size);
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
/// @name Iterators
|
||||
/// @{
|
||||
|
@ -24,6 +24,9 @@
|
||||
#if HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#if HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
@ -325,20 +328,22 @@ error_code status(const Twine &path, file_status &result) {
|
||||
return ec;
|
||||
}
|
||||
|
||||
perms prms = static_cast<perms>(status.st_mode & perms_mask);
|
||||
|
||||
if (S_ISDIR(status.st_mode))
|
||||
result = file_status(file_type::directory_file);
|
||||
result = file_status(file_type::directory_file, prms);
|
||||
else if (S_ISREG(status.st_mode))
|
||||
result = file_status(file_type::regular_file);
|
||||
result = file_status(file_type::regular_file, prms);
|
||||
else if (S_ISBLK(status.st_mode))
|
||||
result = file_status(file_type::block_file);
|
||||
result = file_status(file_type::block_file, prms);
|
||||
else if (S_ISCHR(status.st_mode))
|
||||
result = file_status(file_type::character_file);
|
||||
result = file_status(file_type::character_file, prms);
|
||||
else if (S_ISFIFO(status.st_mode))
|
||||
result = file_status(file_type::fifo_file);
|
||||
result = file_status(file_type::fifo_file, prms);
|
||||
else if (S_ISSOCK(status.st_mode))
|
||||
result = file_status(file_type::socket_file);
|
||||
result = file_status(file_type::socket_file, prms);
|
||||
else
|
||||
result = file_status(file_type::type_unknown);
|
||||
result = file_status(file_type::type_unknown, prms);
|
||||
|
||||
result.fs_st_dev = status.st_dev;
|
||||
result.fs_st_ino = status.st_ino;
|
||||
@ -346,6 +351,35 @@ error_code status(const Twine &path, file_status &result) {
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
// Modifies permissions on a file.
|
||||
error_code permissions(const Twine &path, perms prms) {
|
||||
if ((prms & add_perms) && (prms & remove_perms))
|
||||
llvm_unreachable("add_perms and remove_perms are mutually exclusive");
|
||||
|
||||
// Get current permissions
|
||||
file_status info;
|
||||
if (error_code ec = status(path, info)) {
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Set updated permissions.
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toNullTerminatedStringRef(path_storage);
|
||||
perms permsToSet;
|
||||
if (prms & add_perms) {
|
||||
permsToSet = (info.permissions() | prms) & perms_mask;
|
||||
} else if (prms & remove_perms) {
|
||||
permsToSet = (info.permissions() & ~prms) & perms_mask;
|
||||
} else {
|
||||
permsToSet = prms & perms_mask;
|
||||
}
|
||||
if (::chmod(p.begin(), static_cast<mode_t>(permsToSet))) {
|
||||
return error_code(errno, system_category());
|
||||
}
|
||||
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
// Since this is most often used for temporary files, mode defaults to 0600.
|
||||
error_code unique_file(const Twine &model, int &result_fd,
|
||||
SmallVectorImpl<char> &result_path,
|
||||
@ -495,6 +529,36 @@ error_code get_magic(const Twine &path, uint32_t len,
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
|
||||
bool map_writable, void *&result) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef name = path.toNullTerminatedStringRef(path_storage);
|
||||
int oflags = map_writable ? O_RDWR : O_RDONLY;
|
||||
int ofd = ::open(name.begin(), oflags);
|
||||
if ( ofd == -1 )
|
||||
return error_code(errno, system_category());
|
||||
AutoFD fd(ofd);
|
||||
int flags = map_writable ? MAP_SHARED : MAP_PRIVATE;
|
||||
int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ;
|
||||
#ifdef MAP_FILE
|
||||
flags |= MAP_FILE;
|
||||
#endif
|
||||
result = ::mmap(0, size, prot, flags, fd, file_offset);
|
||||
if (result == MAP_FAILED) {
|
||||
return error_code(errno, system_category());
|
||||
}
|
||||
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
error_code unmap_file_pages(void *base, size_t size) {
|
||||
if ( ::munmap(base, size) == -1 )
|
||||
return error_code(errno, system_category());
|
||||
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace fs
|
||||
} // end namespace sys
|
||||
} // end namespace llvm
|
||||
|
@ -497,6 +497,41 @@ handle_status_error:
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
|
||||
// Modifies permissions on a file.
|
||||
error_code permissions(const Twine &path, perms prms) {
|
||||
#if 0 // verify code below before enabling:
|
||||
// If the permissions bits are not trying to modify
|
||||
// "write" permissions, there is nothing to do.
|
||||
if (!(prms & (owner_write|group_write|others_write)))
|
||||
return error_code::success();
|
||||
|
||||
SmallString<128> path_storage;
|
||||
SmallVector<wchar_t, 128> path_utf16;
|
||||
|
||||
if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
|
||||
path_utf16))
|
||||
return ec;
|
||||
|
||||
DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
|
||||
|
||||
if (prms & add_perms) {
|
||||
attributes &= ~FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
else if (prms & remove_perms) {
|
||||
attributes |= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
else {
|
||||
assert(0 && "neither add_perms or remove_perms is set");
|
||||
}
|
||||
|
||||
if ( ! ::SetFileAttributesW(path_utf16.begin(), attributes))
|
||||
return windows_error(::GetLastError());
|
||||
#endif
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
|
||||
// FIXME: mode should be used here and default to user r/w only,
|
||||
// it currently comes in as a UNIX mode.
|
||||
error_code unique_file(const Twine &model, int &result_fd,
|
||||
@ -755,6 +790,17 @@ error_code detail::directory_iterator_increment(detail::DirIterState &it) {
|
||||
return error_code::success();
|
||||
}
|
||||
|
||||
error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
|
||||
bool map_writable, void *&result) {
|
||||
assert(0 && "NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
error_code unmap_file_pages(void *base, size_t size) {
|
||||
assert(0 && "NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace fs
|
||||
} // end namespace sys
|
||||
} // end namespace llvm
|
||||
|
@ -312,4 +312,69 @@ TEST_F(FileSystemTest, Magic) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(FileSystemTest, Permissions) {
|
||||
// Create a temp file.
|
||||
int FileDescriptor;
|
||||
SmallString<64> TempPath;
|
||||
ASSERT_NO_ERROR(
|
||||
fs::unique_file("%%-%%-%%-%%.temp", FileDescriptor, TempPath));
|
||||
|
||||
// Mark file as read-only
|
||||
const fs::perms AllWrite = fs::owner_write|fs::group_write|fs::others_write;
|
||||
ASSERT_NO_ERROR(fs::permissions(Twine(TempPath), fs::remove_perms|AllWrite));
|
||||
|
||||
// Verify file is read-only
|
||||
fs::file_status Status;
|
||||
ASSERT_NO_ERROR(fs::status(Twine(TempPath), Status));
|
||||
bool AnyWriteBits = (Status.permissions() & AllWrite);
|
||||
EXPECT_FALSE(AnyWriteBits);
|
||||
|
||||
// Mark file as read-write
|
||||
ASSERT_NO_ERROR(fs::permissions(Twine(TempPath), fs::add_perms|AllWrite));
|
||||
|
||||
// Verify file is read-write
|
||||
ASSERT_NO_ERROR(fs::status(Twine(TempPath), Status));
|
||||
AnyWriteBits = (Status.permissions() & AllWrite);
|
||||
EXPECT_TRUE(AnyWriteBits);
|
||||
}
|
||||
|
||||
TEST_F(FileSystemTest, FileMapping) {
|
||||
// Create a temp file.
|
||||
int FileDescriptor;
|
||||
SmallString<64> TempPath;
|
||||
ASSERT_NO_ERROR(
|
||||
fs::unique_file("%%-%%-%%-%%.temp", FileDescriptor, TempPath));
|
||||
|
||||
// Grow temp file to be 4096 bytes
|
||||
ASSERT_NO_ERROR(sys::fs::resize_file(Twine(TempPath), 4096));
|
||||
|
||||
// Map in temp file and add some content
|
||||
void* MappedMemory;
|
||||
ASSERT_NO_ERROR(fs::map_file_pages(Twine(TempPath), 0, 4096,
|
||||
true /*writable*/, MappedMemory));
|
||||
char* Memory = reinterpret_cast<char*>(MappedMemory);
|
||||
strcpy(Memory, "hello there");
|
||||
|
||||
// Unmap temp file
|
||||
ASSERT_NO_ERROR(fs::unmap_file_pages(MappedMemory, 4096));
|
||||
MappedMemory = NULL;
|
||||
Memory = NULL;
|
||||
|
||||
// Map it back in read-only
|
||||
ASSERT_NO_ERROR(fs::map_file_pages(Twine(TempPath), 0, 4096,
|
||||
false /*read-only*/, MappedMemory));
|
||||
|
||||
// Verify content
|
||||
Memory = reinterpret_cast<char*>(MappedMemory);
|
||||
bool SAME = (strcmp(Memory, "hello there") == 0);
|
||||
EXPECT_TRUE(SAME);
|
||||
|
||||
// Unmap temp file
|
||||
ASSERT_NO_ERROR(fs::unmap_file_pages(MappedMemory, 4096));
|
||||
MappedMemory = NULL;
|
||||
Memory = NULL;
|
||||
}
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user