1 // Copyright (c) 2011 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.
5 #include "base/posix/file_descriptor_shuffle.h"
11 #include "base/posix/eintr_wrapper.h"
12 #include "base/logging.h"
16 bool PerformInjectiveMultimapDestructive(
17 InjectiveMultimap
* m
, InjectionDelegate
* delegate
) {
18 static const size_t kMaxExtraFDs
= 16;
19 int extra_fds
[kMaxExtraFDs
];
20 unsigned next_extra_fd
= 0;
22 // DANGER: this function must not allocate or lock.
23 // Cannot use STL iterators here, since debug iterators use locks.
25 for (size_t i_index
= 0; i_index
< m
->size(); ++i_index
) {
26 InjectiveMultimap::value_type
* i
= &(*m
)[i_index
];
29 // We DCHECK the injectiveness of the mapping.
30 for (size_t j_index
= i_index
+ 1; j_index
< m
->size(); ++j_index
) {
31 InjectiveMultimap::value_type
* j
= &(*m
)[j_index
];
32 DCHECK(i
->dest
!= j
->dest
) << "Both fd " << i
->source
33 << " and " << j
->source
<< " map to " << i
->dest
;
36 const bool is_identity
= i
->source
== i
->dest
;
38 for (size_t j_index
= i_index
+ 1; j_index
< m
->size(); ++j_index
) {
39 InjectiveMultimap::value_type
* j
= &(*m
)[j_index
];
40 if (!is_identity
&& i
->dest
== j
->source
) {
42 if (!delegate
->Duplicate(&temp_fd
, i
->dest
))
44 if (next_extra_fd
< kMaxExtraFDs
) {
45 extra_fds
[next_extra_fd
++] = temp_fd
;
47 RAW_LOG(ERROR
, "PerformInjectiveMultimapDestructive overflowed "
48 "extra_fds. Leaking file descriptors!");
56 if (i
->close
&& i
->source
== j
->dest
)
59 if (i
->close
&& i
->source
== j
->source
) {
66 if (!delegate
->Move(i
->source
, i
->dest
))
70 if (!is_identity
&& i
->close
)
71 delegate
->Close(i
->source
);
74 for (unsigned i
= 0; i
< next_extra_fd
; i
++)
75 delegate
->Close(extra_fds
[i
]);
80 bool PerformInjectiveMultimap(const InjectiveMultimap
& m_in
,
81 InjectionDelegate
* delegate
) {
82 InjectiveMultimap
m(m_in
);
83 return PerformInjectiveMultimapDestructive(&m
, delegate
);
86 bool FileDescriptorTableInjection::Duplicate(int* result
, int fd
) {
87 *result
= HANDLE_EINTR(dup(fd
));
91 bool FileDescriptorTableInjection::Move(int src
, int dest
) {
92 return HANDLE_EINTR(dup2(src
, dest
)) != -1;
95 void FileDescriptorTableInjection::Close(int fd
) {
96 int ret
= IGNORE_EINTR(close(fd
));