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 may not allocate.
24 for (InjectiveMultimap::iterator i
= m
->begin(); i
!= m
->end(); ++i
) {
27 // We DCHECK the injectiveness of the mapping.
28 for (InjectiveMultimap::iterator j
= i
+ 1; j
!= m
->end(); ++j
) {
29 DCHECK(i
->dest
!= j
->dest
) << "Both fd " << i
->source
30 << " and " << j
->source
<< " map to " << i
->dest
;
33 const bool is_identity
= i
->source
== i
->dest
;
35 for (InjectiveMultimap::iterator j
= i
+ 1; j
!= m
->end(); ++j
) {
36 if (!is_identity
&& i
->dest
== j
->source
) {
38 if (!delegate
->Duplicate(&temp_fd
, i
->dest
))
40 if (next_extra_fd
< kMaxExtraFDs
) {
41 extra_fds
[next_extra_fd
++] = temp_fd
;
43 RAW_LOG(ERROR
, "PerformInjectiveMultimapDestructive overflowed "
44 "extra_fds. Leaking file descriptors!");
52 if (i
->close
&& i
->source
== j
->dest
)
55 if (i
->close
&& i
->source
== j
->source
) {
62 if (!delegate
->Move(i
->source
, i
->dest
))
66 if (!is_identity
&& i
->close
)
67 delegate
->Close(i
->source
);
70 for (unsigned i
= 0; i
< next_extra_fd
; i
++)
71 delegate
->Close(extra_fds
[i
]);
76 bool PerformInjectiveMultimap(const InjectiveMultimap
& m_in
,
77 InjectionDelegate
* delegate
) {
78 InjectiveMultimap
m(m_in
);
79 return PerformInjectiveMultimapDestructive(&m
, delegate
);
82 bool FileDescriptorTableInjection::Duplicate(int* result
, int fd
) {
83 *result
= HANDLE_EINTR(dup(fd
));
87 bool FileDescriptorTableInjection::Move(int src
, int dest
) {
88 return HANDLE_EINTR(dup2(src
, dest
)) != -1;
91 void FileDescriptorTableInjection::Close(int fd
) {
92 int ret
= HANDLE_EINTR(close(fd
));