Michael Spencer
2012-May-18 22:22 UTC
[LLVMdev] [RFC] llvm/include/Support/FileOutputBuffer.h
On Fri, May 18, 2012 at 3:07 PM, Michael Spencer <bigcheesegs at gmail.com> wrote:> >> + error_code ec = sys::fs::status(filePathTwine, stat); > > stat is undefined if ec isn't success. ec will be success even in the case of > file_not_found.Actually I was wrong. The Windows and UNIX implementation disagree on this point. I'm going to change it to match http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3365.html#status error_code semantics.
This is a proposed patch to enhance FileSystem.h to add functionality (getting and setting permission bits and mapping an unmapping files). This implementation follows the N3365 proposal regarding permission bits. This functionality is needed for my next patch which will implement llvm/include/Support/FileOutputBuffer.h which is needed by lld. -------------- next part -------------- A non-text attachment was scrubbed... Name: FileSystem.patch Type: application/octet-stream Size: 10014 bytes Desc: not available URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120618/828a8f3e/attachment.obj> -------------- next part -------------- -Nick
On Mon, Jun 18, 2012 at 6:08 PM, Nick Kledzik <kledzik at apple.com> wrote:> This is a proposed patch to enhance FileSystem.h to add functionality (getting and setting permission bits and mapping an unmapping files). This implementation follows the N3365 proposal regarding permission bits. > > This functionality is needed for my next patch which will implement llvm/include/Support/FileOutputBuffer.h which is needed by lld. > > > > > > -Nick > > > > > Index: include/llvm/Support/FileSystem.h > ==================================================================> --- include/llvm/Support/FileSystem.h (revision 158678) > +++ include/llvm/Support/FileSystem.h (working copy) > @@ -94,6 +94,56 @@ > uint64_t available; > }; > > + > +enum perms > +{No new line before {.> + 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 +163,19 @@ > 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 +452,13 @@ > /// 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 +577,33 @@ > 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 > /// @{ > Index: lib/Support/Unix/PathV2.inc > ==================================================================> --- lib/Support/Unix/PathV2.inc (revision 158680) > +++ lib/Support/Unix/PathV2.inc (working copy) > @@ -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 @@ > 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,34 @@ > return error_code::success(); > } > > +// Modifies permissions on a file. > +error_code permissions(const Twine &path, perms prms) { > + // 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 { > + assert(0 && "neither add_perms or remove_perms is set");If neither add nor remove are set, it should set all perms. If both add and remove are set, it should llvm_unreachable.> + } > + 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 +528,36 @@ > 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 > Index: lib/Support/Windows/PathV2.inc > ==================================================================> --- lib/Support/Windows/PathV2.inc (revision 158678) > +++ lib/Support/Windows/PathV2.inc (working copy) > @@ -497,6 +497,41 @@ > 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 @@ > 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 llvmIt also needs unit tests. Once tests are added I can do the Windows implementation. - Michael Spencer
Possibly Parallel Threads
- [LLVMdev] [RFC] llvm/include/Support/FileOutputBuffer.h
- [LLVMdev] [RFC] llvm/include/Support/FileOutputBuffer.h
- [LLVMdev] [RFC] llvm/include/Support/FileOutputBuffer.h
- matrix name
- Redundant Twine->StringRef->Twine conversions in llvm::sys::fs::make_absolute?