|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 #include "base/file_descriptor_shuffle.h" |
|
6 |
|
7 #include <errno.h> |
|
8 #include <unistd.h> |
|
9 |
|
10 #include "base/eintr_wrapper.h" |
|
11 #include "base/logging.h" |
|
12 |
|
13 namespace base { |
|
14 |
|
15 bool PerformInjectiveMultimapDestructive( |
|
16 InjectiveMultimap* m, InjectionDelegate* delegate) { |
|
17 static const size_t kMaxExtraFDs = 16; |
|
18 int extra_fds[kMaxExtraFDs]; |
|
19 unsigned next_extra_fd = 0; |
|
20 |
|
21 // DANGER: this function may not allocate. |
|
22 |
|
23 for (InjectiveMultimap::iterator i = m->begin(); i != m->end(); ++i) { |
|
24 int temp_fd = -1; |
|
25 |
|
26 // We DCHECK the injectiveness of the mapping. |
|
27 for (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) { |
|
28 DCHECK(i->dest != j->dest) << "Both fd " << i->source |
|
29 << " and " << j->source << " map to " << i->dest; |
|
30 } |
|
31 |
|
32 const bool is_identity = i->source == i->dest; |
|
33 |
|
34 for (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) { |
|
35 if (!is_identity && i->dest == j->source) { |
|
36 if (temp_fd == -1) { |
|
37 if (!delegate->Duplicate(&temp_fd, i->dest)) |
|
38 return false; |
|
39 if (next_extra_fd < kMaxExtraFDs) { |
|
40 extra_fds[next_extra_fd++] = temp_fd; |
|
41 } else { |
|
42 DLOG(ERROR) << "PerformInjectiveMultimapDestructive overflowed " |
|
43 << "extra_fds. Leaking file descriptors!"; |
|
44 } |
|
45 } |
|
46 |
|
47 j->source = temp_fd; |
|
48 j->close = false; |
|
49 } |
|
50 |
|
51 if (i->close && i->source == j->dest) |
|
52 i->close = false; |
|
53 |
|
54 if (i->close && i->source == j->source) { |
|
55 i->close = false; |
|
56 j->close = true; |
|
57 } |
|
58 } |
|
59 |
|
60 if (!is_identity) { |
|
61 if (!delegate->Move(i->source, i->dest)) |
|
62 return false; |
|
63 } |
|
64 |
|
65 if (!is_identity && i->close) |
|
66 delegate->Close(i->source); |
|
67 } |
|
68 |
|
69 for (unsigned i = 0; i < next_extra_fd; i++) |
|
70 delegate->Close(extra_fds[i]); |
|
71 |
|
72 return true; |
|
73 } |
|
74 |
|
75 bool PerformInjectiveMultimap(const InjectiveMultimap& m_in, |
|
76 InjectionDelegate* delegate) { |
|
77 InjectiveMultimap m(m_in); |
|
78 return PerformInjectiveMultimapDestructive(&m, delegate); |
|
79 } |
|
80 |
|
81 bool FileDescriptorTableInjection::Duplicate(int* result, int fd) { |
|
82 *result = HANDLE_EINTR(dup(fd)); |
|
83 return *result >= 0; |
|
84 } |
|
85 |
|
86 bool FileDescriptorTableInjection::Move(int src, int dest) { |
|
87 return HANDLE_EINTR(dup2(src, dest)) != -1; |
|
88 } |
|
89 |
|
90 void FileDescriptorTableInjection::Close(int fd) { |
|
91 HANDLE_EINTR(close(fd)); |
|
92 } |
|
93 |
|
94 } // namespace base |