[LLVMdev] llvm/include/Support/FileSystem.h

Michael Spencer bigcheesegs at gmail.com
Mon Jun 18 19:08:07 PDT 2012


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 llvm

It also needs unit tests. Once tests are added I can do the Windows
implementation.

- Michael Spencer




More information about the llvm-dev mailing list