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) { | |
30 #if !(defined(OS_MACOSX) && !defined(OS_IOS)) | 29 #if !(defined(OS_MACOSX) && !defined(OS_IOS)) |
31 // It doesn't make sense to have a open-existing private piece of shmem | 30 // It doesn't make sense to have a open-existing private piece of shmem |
32 DCHECK(!options.open_existing_deprecated); | 31 DCHECK(!options.open_existing_deprecated); |
33 #endif // !(defined(OS_MACOSX) && !defined(OS_IOS) | 32 #endif // !(defined(OS_MACOSX) && !defined(OS_IOS) |
34 // Q: Why not use the shm_open() etc. APIs? | 33 // Q: Why not use the shm_open() etc. APIs? |
35 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU | 34 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU |
36 FilePath directory; | 35 FilePath directory; |
37 ScopedPathUnlinker path_unlinker; | 36 ScopedPathUnlinker path_unlinker; |
38 if (!GetShmemTempDir(options.executable, &directory)) { | 37 if (!GetShmemTempDir(options.executable, &directory)) |
39 *error = SharedMemoryError::NO_TEMP_DIR; | |
40 return false; | 38 return false; |
41 } | |
42 | 39 |
43 fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path)); | 40 fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path)); |
44 if (!*fp) { | 41 |
45 *error = SharedMemoryError::NO_FILE; | 42 if (!*fp) |
46 return false; | 43 return false; |
47 } | |
48 | 44 |
49 // Deleting the file prevents anyone else from mapping it in (making it | 45 // Deleting the file prevents anyone else from mapping it in (making it |
50 // private), and prevents the need for cleanup (once the last fd is | 46 // private), and prevents the need for cleanup (once the last fd is |
51 // closed, it is truly freed). | 47 // closed, it is truly freed). |
52 path_unlinker.reset(path); | 48 path_unlinker.reset(path); |
53 | 49 |
54 if (options.share_read_only) { | 50 if (options.share_read_only) { |
55 // Also open as readonly so that we can GetReadOnlyHandle. | 51 // Also open as readonly so that we can GetReadOnlyHandle. |
56 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY))); | 52 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY))); |
57 if (!readonly_fd->is_valid()) { | 53 if (!readonly_fd->is_valid()) { |
58 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed"; | 54 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed"; |
59 fp->reset(); | 55 fp->reset(); |
60 *error = SharedMemoryError::MAKE_READONLY_FAILED; | |
61 return false; | 56 return false; |
62 } | 57 } |
63 } | 58 } |
64 return true; | 59 return true; |
65 } | 60 } |
66 | 61 |
67 bool PrepareMapFile(ScopedFILE fp, | 62 bool PrepareMapFile(ScopedFILE fp, |
68 ScopedFD readonly_fd, | 63 ScopedFD readonly_fd, |
69 int* mapped_file, | 64 int* mapped_file, |
70 int* readonly_mapped_file, | 65 int* readonly_mapped_file) { |
71 SharedMemoryError* error) { | |
72 DCHECK_EQ(-1, *mapped_file); | 66 DCHECK_EQ(-1, *mapped_file); |
73 DCHECK_EQ(-1, *readonly_mapped_file); | 67 DCHECK_EQ(-1, *readonly_mapped_file); |
74 if (!fp) { | 68 if (fp == NULL) |
75 *error = SharedMemoryError::NO_FILE; | |
76 return false; | 69 return false; |
77 } | |
78 | 70 |
79 // This function theoretically can block on the disk, but realistically | 71 // This function theoretically can block on the disk, but realistically |
80 // the temporary files we create will just go into the buffer cache | 72 // the temporary files we create will just go into the buffer cache |
81 // and be deleted before they ever make it out to disk. | 73 // and be deleted before they ever make it out to disk. |
82 base::ThreadRestrictions::ScopedAllowIO allow_io; | 74 base::ThreadRestrictions::ScopedAllowIO allow_io; |
83 | 75 |
84 if (readonly_fd.is_valid()) { | 76 if (readonly_fd.is_valid()) { |
85 struct stat st = {}; | 77 struct stat st = {}; |
86 if (fstat(fileno(fp.get()), &st)) | 78 if (fstat(fileno(fp.get()), &st)) |
87 NOTREACHED(); | 79 NOTREACHED(); |
88 | 80 |
89 struct stat readonly_st = {}; | 81 struct stat readonly_st = {}; |
90 if (fstat(readonly_fd.get(), &readonly_st)) | 82 if (fstat(readonly_fd.get(), &readonly_st)) |
91 NOTREACHED(); | 83 NOTREACHED(); |
92 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { | 84 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { |
93 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; | 85 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; |
94 *error = SharedMemoryError::INODE_MISMATCH; | |
95 return false; | 86 return false; |
96 } | 87 } |
97 } | 88 } |
98 | 89 |
99 *mapped_file = HANDLE_EINTR(dup(fileno(fp.get()))); | 90 *mapped_file = HANDLE_EINTR(dup(fileno(fp.get()))); |
100 if (*mapped_file == -1) { | 91 if (*mapped_file == -1) { |
101 NOTREACHED() << "Call to dup failed, errno=" << errno; | 92 NOTREACHED() << "Call to dup failed, errno=" << errno; |
102 } | 93 } |
103 *readonly_mapped_file = readonly_fd.release(); | 94 *readonly_mapped_file = readonly_fd.release(); |
104 | 95 |
105 return true; | 96 return true; |
106 } | 97 } |
107 #endif // !defined(OS_ANDROID) | 98 #endif // !defined(OS_ANDROID) |
108 | 99 |
109 } // namespace base | 100 } // namespace base |
OLD | NEW |