[llvm-commits] [llvm] r158770 - in /llvm/trunk: include/llvm/Support/FileSystem.h lib/Support/Unix/PathV2.inc lib/Support/Windows/PathV2.inc unittests/Support/Path.cpp

Nick Kledzik kledzik at apple.com
Tue Jun 19 17:28:55 PDT 2012


Author: kledzik
Date: Tue Jun 19 19:28:54 2012
New Revision: 158770

URL: http://llvm.org/viewvc/llvm-project?rev=158770&view=rev
Log:
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.

Modified:
    llvm/trunk/include/llvm/Support/FileSystem.h
    llvm/trunk/lib/Support/Unix/PathV2.inc
    llvm/trunk/lib/Support/Windows/PathV2.inc
    llvm/trunk/unittests/Support/Path.cpp

Modified: llvm/trunk/include/llvm/Support/FileSystem.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileSystem.h?rev=158770&r1=158769&r2=158770&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileSystem.h (original)
+++ llvm/trunk/include/llvm/Support/FileSystem.h Tue Jun 19 19:28:54 2012
@@ -94,6 +94,55 @@
   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 @@
   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 @@
 ///          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 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
 /// @{

Modified: llvm/trunk/lib/Support/Unix/PathV2.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/PathV2.inc?rev=158770&r1=158769&r2=158770&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Unix/PathV2.inc (original)
+++ llvm/trunk/lib/Support/Unix/PathV2.inc Tue Jun 19 19:28:54 2012
@@ -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,35 @@
   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 @@
   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

Modified: llvm/trunk/lib/Support/Windows/PathV2.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/PathV2.inc?rev=158770&r1=158769&r2=158770&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/PathV2.inc (original)
+++ llvm/trunk/lib/Support/Windows/PathV2.inc Tue Jun 19 19:28:54 2012
@@ -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

Modified: llvm/trunk/unittests/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Path.cpp?rev=158770&r1=158769&r2=158770&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/Path.cpp (original)
+++ llvm/trunk/unittests/Support/Path.cpp Tue Jun 19 19:28:54 2012
@@ -312,4 +312,69 @@
   }
 }
 
+
+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





More information about the llvm-commits mailing list