llvm.org GIT mirror llvm / ca077ec
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 Nick Kledzik 8 years ago
4 changed file(s) with 275 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
9393 uint64_t available;
9494 };
9595
96
97 enum perms {
98 no_perms = 0,
99 owner_read = 0400,
100 owner_write = 0200,
101 owner_exe = 0100,
102 owner_all = owner_read | owner_write | owner_exe,
103 group_read = 040,
104 group_write = 020,
105 group_exe = 010,
106 group_all = group_read | group_write | group_exe,
107 others_read = 04,
108 others_write = 02,
109 others_exe = 01,
110 others_all = others_read | others_write | others_exe,
111 all_all = owner_all | group_all | others_all,
112 set_uid_on_exe = 04000,
113 set_gid_on_exe = 02000,
114 sticky_bit = 01000,
115 perms_mask = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
116 perms_not_known = 0xFFFF,
117 add_perms = 0x1000,
118 remove_perms = 0x2000,
119 symlink_perms = 0x4000
120 };
121
122 // Helper functions so that you can use & and | to manipulate perms bits:
123 inline perms operator|(perms l , perms r) {
124 return static_cast(
125 static_cast(l) | static_cast(r));
126 }
127 inline perms operator&(perms l , perms r) {
128 return static_cast(
129 static_cast(l) & static_cast(r));
130 }
131 inline perms &operator|=(perms &l, perms r) {
132 l = l | r;
133 return l;
134 }
135 inline perms &operator&=(perms &l, perms r) {
136 l = l & r;
137 return l;
138 }
139 inline perms operator~(perms x) {
140 return static_cast(~static_cast(x));
141 }
142
143
144
96145 /// file_status - Represents the result of a call to stat and friends. It has
97146 /// a platform specific member to store the result.
98147 class file_status
112161 friend bool equivalent(file_status A, file_status B);
113162 friend error_code status(const Twine &path, file_status &result);
114163 file_type Type;
164 perms Perms;
115165 public:
116 explicit file_status(file_type v=file_type::status_error)
117 : Type(v) {}
118
166 explicit file_status(file_type v=file_type::status_error,
167 perms prms=perms_not_known)
168 : Type(v), Perms(prms) {}
169
170 // getters
119171 file_type type() const { return Type; }
172 perms permissions() const { return Perms; }
173
174 // setters
120175 void type(file_type v) { Type = v; }
176 void permissions(perms p) { Perms = p; }
121177 };
122178
123179 /// file_magic - An "enum class" enumeration of file types based on magic (the first
394450 /// platform specific error_code.
395451 error_code status(const Twine &path, file_status &result);
396452
453 /// @brief Modifies permission bits on a file
454 ///
455 /// @param path Input path.
456 /// @results errc::success if permissions have been changed, otherwise a
457 /// platform specific error_code.
458 error_code permissions(const Twine &path, perms prms);
459
397460 /// @brief Is status available?
398461 ///
399462 /// @param path Input path.
511574 /// platform specific error_code.
512575 error_code GetMainExecutable(const char *argv0, void *MainAddr,
513576 SmallVectorImpl &result);
577
578
579 /// @brief Memory maps the contents of a file
580 ///
581 /// @param path Path to file to map.
582 /// @param file_offset Byte offset in file where mapping should begin.
583 /// @param size_t Byte length of range of the file to map.
584 /// @param map_writable If true, the file will be mapped in r/w such
585 /// that changes to the the mapped buffer will be flushed back
586 /// to the file. If false, the file will be mapped read-only
587 /// and the buffer will be read-only.
588 /// @param result Set to the start address of the mapped buffer.
589 /// @results errc::success if result has been successfully set, otherwise a
590 /// platform specific error_code.
591 error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
592 bool map_writable, void *&result);
593
594
595 /// @brief Memory unmaps the contents of a file
596 ///
597 /// @param base Pointer to the start of the buffer.
598 /// @param size Byte length of the range to unmmap.
599 /// @results errc::success if result has been successfully set, otherwise a
600 /// platform specific error_code.
601 error_code unmap_file_pages(void *base, size_t size);
602
603
514604
515605 /// @}
516606 /// @name Iterators
2222 #endif
2323 #if HAVE_FCNTL_H
2424 #include
25 #endif
26 #ifdef HAVE_SYS_MMAN_H
27 #include
2528 #endif
2629 #if HAVE_DIRENT_H
2730 # include
324327 return ec;
325328 }
326329
330 perms prms = static_cast(status.st_mode & perms_mask);
331
327332 if (S_ISDIR(status.st_mode))
328 result = file_status(file_type::directory_file);
333 result = file_status(file_type::directory_file, prms);
329334 else if (S_ISREG(status.st_mode))
330 result = file_status(file_type::regular_file);
335 result = file_status(file_type::regular_file, prms);
331336 else if (S_ISBLK(status.st_mode))
332 result = file_status(file_type::block_file);
337 result = file_status(file_type::block_file, prms);
333338 else if (S_ISCHR(status.st_mode))
334 result = file_status(file_type::character_file);
339 result = file_status(file_type::character_file, prms);
335340 else if (S_ISFIFO(status.st_mode))
336 result = file_status(file_type::fifo_file);
341 result = file_status(file_type::fifo_file, prms);
337342 else if (S_ISSOCK(status.st_mode))
338 result = file_status(file_type::socket_file);
343 result = file_status(file_type::socket_file, prms);
339344 else
340 result = file_status(file_type::type_unknown);
345 result = file_status(file_type::type_unknown, prms);
341346
342347 result.fs_st_dev = status.st_dev;
343348 result.fs_st_ino = status.st_ino;
349
350 return error_code::success();
351 }
352
353 // Modifies permissions on a file.
354 error_code permissions(const Twine &path, perms prms) {
355 if ((prms & add_perms) && (prms & remove_perms))
356 llvm_unreachable("add_perms and remove_perms are mutually exclusive");
357
358 // Get current permissions
359 file_status info;
360 if (error_code ec = status(path, info)) {
361 return ec;
362 }
363
364 // Set updated permissions.
365 SmallString<128> path_storage;
366 StringRef p = path.toNullTerminatedStringRef(path_storage);
367 perms permsToSet;
368 if (prms & add_perms) {
369 permsToSet = (info.permissions() | prms) & perms_mask;
370 } else if (prms & remove_perms) {
371 permsToSet = (info.permissions() & ~prms) & perms_mask;
372 } else {
373 permsToSet = prms & perms_mask;
374 }
375 if (::chmod(p.begin(), static_cast(permsToSet))) {
376 return error_code(errno, system_category());
377 }
344378
345379 return error_code::success();
346380 }
494528 return error_code::success();
495529 }
496530
531 error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
532 bool map_writable, void *&result) {
533 SmallString<128> path_storage;
534 StringRef name = path.toNullTerminatedStringRef(path_storage);
535 int oflags = map_writable ? O_RDWR : O_RDONLY;
536 int ofd = ::open(name.begin(), oflags);
537 if ( ofd == -1 )
538 return error_code(errno, system_category());
539 AutoFD fd(ofd);
540 int flags = map_writable ? MAP_SHARED : MAP_PRIVATE;
541 int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ;
542 #ifdef MAP_FILE
543 flags |= MAP_FILE;
544 #endif
545 result = ::mmap(0, size, prot, flags, fd, file_offset);
546 if (result == MAP_FAILED) {
547 return error_code(errno, system_category());
548 }
549
550 return error_code::success();
551 }
552
553 error_code unmap_file_pages(void *base, size_t size) {
554 if ( ::munmap(base, size) == -1 )
555 return error_code(errno, system_category());
556
557 return error_code::success();
558 }
559
560
497561 } // end namespace fs
498562 } // end namespace sys
499563 } // end namespace llvm
495495
496496 return error_code::success();
497497 }
498
499
500 // Modifies permissions on a file.
501 error_code permissions(const Twine &path, perms prms) {
502 #if 0 // verify code below before enabling:
503 // If the permissions bits are not trying to modify
504 // "write" permissions, there is nothing to do.
505 if (!(prms & (owner_write|group_write|others_write)))
506 return error_code::success();
507
508 SmallString<128> path_storage;
509 SmallVector path_utf16;
510
511 if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
512 path_utf16))
513 return ec;
514
515 DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
516
517 if (prms & add_perms) {
518 attributes &= ~FILE_ATTRIBUTE_READONLY;
519 }
520 else if (prms & remove_perms) {
521 attributes |= FILE_ATTRIBUTE_READONLY;
522 }
523 else {
524 assert(0 && "neither add_perms or remove_perms is set");
525 }
526
527 if ( ! ::SetFileAttributesW(path_utf16.begin(), attributes))
528 return windows_error(::GetLastError());
529 #endif
530 return error_code::success();
531 }
532
498533
499534 // FIXME: mode should be used here and default to user r/w only,
500535 // it currently comes in as a UNIX mode.
754789 return error_code::success();
755790 }
756791
792 error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
793 bool map_writable, void *&result) {
794 assert(0 && "NOT IMPLEMENTED");
795 }
796
797 error_code unmap_file_pages(void *base, size_t size) {
798 assert(0 && "NOT IMPLEMENTED");
799 }
800
801
802
757803 } // end namespace fs
758804 } // end namespace sys
759805 } // end namespace llvm
311311 }
312312 }
313313
314
315 TEST_F(FileSystemTest, Permissions) {
316 // Create a temp file.
317 int FileDescriptor;
318 SmallString<64> TempPath;
319 ASSERT_NO_ERROR(
320 fs::unique_file("%%-%%-%%-%%.temp", FileDescriptor, TempPath));
321
322 // Mark file as read-only
323 const fs::perms AllWrite = fs::owner_write|fs::group_write|fs::others_write;
324 ASSERT_NO_ERROR(fs::permissions(Twine(TempPath), fs::remove_perms|AllWrite));
325
326 // Verify file is read-only
327 fs::file_status Status;
328 ASSERT_NO_ERROR(fs::status(Twine(TempPath), Status));
329 bool AnyWriteBits = (Status.permissions() & AllWrite);
330 EXPECT_FALSE(AnyWriteBits);
331
332 // Mark file as read-write
333 ASSERT_NO_ERROR(fs::permissions(Twine(TempPath), fs::add_perms|AllWrite));
334
335 // Verify file is read-write
336 ASSERT_NO_ERROR(fs::status(Twine(TempPath), Status));
337 AnyWriteBits = (Status.permissions() & AllWrite);
338 EXPECT_TRUE(AnyWriteBits);
339 }
340
341 TEST_F(FileSystemTest, FileMapping) {
342 // Create a temp file.
343 int FileDescriptor;
344 SmallString<64> TempPath;
345 ASSERT_NO_ERROR(
346 fs::unique_file("%%-%%-%%-%%.temp", FileDescriptor, TempPath));
347
348 // Grow temp file to be 4096 bytes
349 ASSERT_NO_ERROR(sys::fs::resize_file(Twine(TempPath), 4096));
350
351 // Map in temp file and add some content
352 void* MappedMemory;
353 ASSERT_NO_ERROR(fs::map_file_pages(Twine(TempPath), 0, 4096,
354 true /*writable*/, MappedMemory));
355 char* Memory = reinterpret_cast(MappedMemory);
356 strcpy(Memory, "hello there");
357
358 // Unmap temp file
359 ASSERT_NO_ERROR(fs::unmap_file_pages(MappedMemory, 4096));
360 MappedMemory = NULL;
361 Memory = NULL;
362
363 // Map it back in read-only
364 ASSERT_NO_ERROR(fs::map_file_pages(Twine(TempPath), 0, 4096,
365 false /*read-only*/, MappedMemory));
366
367 // Verify content
368 Memory = reinterpret_cast(MappedMemory);
369 bool SAME = (strcmp(Memory, "hello there") == 0);
370 EXPECT_TRUE(SAME);
371
372 // Unmap temp file
373 ASSERT_NO_ERROR(fs::unmap_file_pages(MappedMemory, 4096));
374 MappedMemory = NULL;
375 Memory = NULL;
376 }
377
378
314379 } // anonymous namespace