| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/memory/shared_memory_helper.h" | 5 #include "base/memory/shared_memory_helper.h" |
| 6 | 6 |
| 7 #include "base/threading/thread_restrictions.h" | 7 #include "base/threading/thread_restrictions.h" |
| 8 | 8 |
| 9 namespace base { | 9 namespace base { |
| 10 | 10 |
| 11 struct ScopedPathUnlinkerTraits { | 11 struct ScopedPathUnlinkerTraits { |
| 12 static const FilePath* InvalidValue() { return nullptr; } | 12 static const FilePath* InvalidValue() { return nullptr; } |
| 13 | 13 |
| 14 static void Free(const FilePath* path) { | 14 static void Free(const FilePath* path) { |
| 15 if (unlink(path->value().c_str())) | 15 if (unlink(path->value().c_str())) |
| 16 PLOG(WARNING) << "unlink"; | 16 PLOG(WARNING) << "unlink"; |
| 17 } | 17 } |
| 18 }; | 18 }; |
| 19 | 19 |
| 20 // Unlinks the FilePath when the object is destroyed. | 20 // Unlinks the FilePath when the object is destroyed. |
| 21 using ScopedPathUnlinker = | 21 using ScopedPathUnlinker = |
| 22 ScopedGeneric<const FilePath*, ScopedPathUnlinkerTraits>; | 22 ScopedGeneric<const FilePath*, ScopedPathUnlinkerTraits>; |
| 23 | 23 |
| 24 #if !defined(OS_ANDROID) | 24 #if !defined(OS_ANDROID) |
| 25 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options, | 25 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options, |
| 26 ScopedFILE* fp, | 26 ScopedFILE* fp, |
| 27 ScopedFD* readonly_fd, | 27 ScopedFD* readonly_fd, |
| 28 FilePath* path) { | 28 FilePath* path, |
| 29 SharedMemoryError* error) { |
| 29 #if !(defined(OS_MACOSX) && !defined(OS_IOS)) | 30 #if !(defined(OS_MACOSX) && !defined(OS_IOS)) |
| 30 // It doesn't make sense to have a open-existing private piece of shmem | 31 // It doesn't make sense to have a open-existing private piece of shmem |
| 31 DCHECK(!options.open_existing_deprecated); | 32 DCHECK(!options.open_existing_deprecated); |
| 32 #endif // !(defined(OS_MACOSX) && !defined(OS_IOS) | 33 #endif // !(defined(OS_MACOSX) && !defined(OS_IOS) |
| 33 // Q: Why not use the shm_open() etc. APIs? | 34 // Q: Why not use the shm_open() etc. APIs? |
| 34 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU | 35 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU |
| 35 FilePath directory; | 36 FilePath directory; |
| 36 ScopedPathUnlinker path_unlinker; | 37 ScopedPathUnlinker path_unlinker; |
| 37 if (!GetShmemTempDir(options.executable, &directory)) | 38 if (!GetShmemTempDir(options.executable, &directory)) { |
| 39 *error = SharedMemoryError::NO_TEMP_DIR; |
| 38 return false; | 40 return false; |
| 41 } |
| 39 | 42 |
| 40 fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path)); | 43 fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path)); |
| 41 | 44 if (!*fp) { |
| 42 if (!*fp) | 45 *error = SharedMemoryError::NO_FILE; |
| 43 return false; | 46 return false; |
| 47 } |
| 44 | 48 |
| 45 // Deleting the file prevents anyone else from mapping it in (making it | 49 // Deleting the file prevents anyone else from mapping it in (making it |
| 46 // private), and prevents the need for cleanup (once the last fd is | 50 // private), and prevents the need for cleanup (once the last fd is |
| 47 // closed, it is truly freed). | 51 // closed, it is truly freed). |
| 48 path_unlinker.reset(path); | 52 path_unlinker.reset(path); |
| 49 | 53 |
| 50 if (options.share_read_only) { | 54 if (options.share_read_only) { |
| 51 // Also open as readonly so that we can GetReadOnlyHandle. | 55 // Also open as readonly so that we can GetReadOnlyHandle. |
| 52 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY))); | 56 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY))); |
| 53 if (!readonly_fd->is_valid()) { | 57 if (!readonly_fd->is_valid()) { |
| 54 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed"; | 58 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed"; |
| 55 fp->reset(); | 59 fp->reset(); |
| 60 *error = SharedMemoryError::MAKE_READONLY_FAILED; |
| 56 return false; | 61 return false; |
| 57 } | 62 } |
| 58 } | 63 } |
| 59 return true; | 64 return true; |
| 60 } | 65 } |
| 61 | 66 |
| 62 bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd, int* mapped_file, | 67 bool PrepareMapFile(ScopedFILE fp, |
| 63 int* readonly_mapped_file) { | 68 ScopedFD readonly_fd, |
| 69 int* mapped_file, |
| 70 int* readonly_mapped_file, |
| 71 SharedMemoryError* error) { |
| 64 DCHECK_EQ(-1, *mapped_file); | 72 DCHECK_EQ(-1, *mapped_file); |
| 65 DCHECK_EQ(-1, *readonly_mapped_file); | 73 DCHECK_EQ(-1, *readonly_mapped_file); |
| 66 if (fp == NULL) | 74 if (!fp) { |
| 75 *error = SharedMemoryError::NO_FILE; |
| 67 return false; | 76 return false; |
| 77 } |
| 68 | 78 |
| 69 // This function theoretically can block on the disk, but realistically | 79 // This function theoretically can block on the disk, but realistically |
| 70 // the temporary files we create will just go into the buffer cache | 80 // the temporary files we create will just go into the buffer cache |
| 71 // and be deleted before they ever make it out to disk. | 81 // and be deleted before they ever make it out to disk. |
| 72 base::ThreadRestrictions::ScopedAllowIO allow_io; | 82 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 73 | 83 |
| 74 if (readonly_fd.is_valid()) { | 84 if (readonly_fd.is_valid()) { |
| 75 struct stat st = {}; | 85 struct stat st = {}; |
| 76 if (fstat(fileno(fp.get()), &st)) | 86 if (fstat(fileno(fp.get()), &st)) |
| 77 NOTREACHED(); | 87 NOTREACHED(); |
| 78 | 88 |
| 79 struct stat readonly_st = {}; | 89 struct stat readonly_st = {}; |
| 80 if (fstat(readonly_fd.get(), &readonly_st)) | 90 if (fstat(readonly_fd.get(), &readonly_st)) |
| 81 NOTREACHED(); | 91 NOTREACHED(); |
| 82 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { | 92 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { |
| 83 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; | 93 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; |
| 94 *error = SharedMemoryError::INODE_MISMATCH; |
| 84 return false; | 95 return false; |
| 85 } | 96 } |
| 86 } | 97 } |
| 87 | 98 |
| 88 *mapped_file = HANDLE_EINTR(dup(fileno(fp.get()))); | 99 *mapped_file = HANDLE_EINTR(dup(fileno(fp.get()))); |
| 89 if (*mapped_file == -1) { | 100 if (*mapped_file == -1) { |
| 90 NOTREACHED() << "Call to dup failed, errno=" << errno; | 101 NOTREACHED() << "Call to dup failed, errno=" << errno; |
| 91 } | 102 } |
| 92 *readonly_mapped_file = readonly_fd.release(); | 103 *readonly_mapped_file = readonly_fd.release(); |
| 93 | 104 |
| 94 return true; | 105 return true; |
| 95 } | 106 } |
| 96 #endif // !defined(OS_ANDROID) | 107 #endif // !defined(OS_ANDROID) |
| 97 | 108 |
| 98 } // namespace base | 109 } // namespace base |
| OLD | NEW |