[email protected] | 91d91fa | 2011-04-29 20:45:22 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BASE_FILE_DESCRIPTOR_SHUFFLE_H_ |
| 6 | #define BASE_FILE_DESCRIPTOR_SHUFFLE_H_ |
[email protected] | 32b76ef | 2010-07-26 23:08:24 | [diff] [blame] | 7 | #pragma once |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 8 | |
| 9 | // This code exists to perform the shuffling of file descriptors which is |
| 10 | // commonly needed when forking subprocesses. The naive approve is very simple, |
| 11 | // just call dup2 to setup the desired descriptors, but wrong. It's tough to |
| 12 | // handle the edge cases (like mapping 0 -> 1, 1 -> 0) correctly. |
| 13 | // |
| 14 | // In order to unittest this code, it's broken into the abstract action (an |
| 15 | // injective multimap) and the concrete code for dealing with file descriptors. |
| 16 | // Users should use the code like this: |
| 17 | // base::InjectiveMultimap file_descriptor_map; |
| 18 | // file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true)); |
| 19 | // file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true)); |
| 20 | // file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true)); |
| 21 | // base::ShuffleFileDescriptors(file_descriptor_map); |
| 22 | // |
| 23 | // and trust the the Right Thing will get done. |
| 24 | |
| 25 | #include <vector> |
| 26 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 27 | #include "base/base_export.h" |
[email protected] | 91d91fa | 2011-04-29 20:45:22 | [diff] [blame] | 28 | |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 29 | namespace base { |
| 30 | |
| 31 | // A Delegate which performs the actions required to perform an injective |
| 32 | // multimapping in place. |
| 33 | class InjectionDelegate { |
| 34 | public: |
| 35 | // Duplicate |fd|, an element of the domain, and write a fresh element of the |
| 36 | // domain into |result|. Returns true iff successful. |
| 37 | virtual bool Duplicate(int* result, int fd) = 0; |
| 38 | // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff |
| 39 | // successful. |
| 40 | virtual bool Move(int src, int dest) = 0; |
| 41 | // Delete an element of the domain. |
| 42 | virtual void Close(int fd) = 0; |
[email protected] | 20cb5f48 | 2009-12-16 01:01:25 | [diff] [blame] | 43 | |
| 44 | protected: |
| 45 | virtual ~InjectionDelegate() {} |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 46 | }; |
| 47 | |
| 48 | // An implementation of the InjectionDelegate interface using the file |
| 49 | // descriptor table of the current process as the domain. |
| 50 | class FileDescriptorTableInjection : public InjectionDelegate { |
[email protected] | 78994ab0 | 2010-12-08 18:06:44 | [diff] [blame] | 51 | virtual bool Duplicate(int* result, int fd); |
| 52 | virtual bool Move(int src, int dest); |
| 53 | virtual void Close(int fd); |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 54 | }; |
| 55 | |
| 56 | // A single arc of the directed graph which describes an injective multimapping. |
| 57 | struct InjectionArc { |
| 58 | InjectionArc(int in_source, int in_dest, bool in_close) |
| 59 | : source(in_source), |
| 60 | dest(in_dest), |
| 61 | close(in_close) { |
| 62 | } |
| 63 | |
| 64 | int source; |
| 65 | int dest; |
| 66 | bool close; // if true, delete the source element after performing the |
| 67 | // mapping. |
| 68 | }; |
| 69 | |
| 70 | typedef std::vector<InjectionArc> InjectiveMultimap; |
| 71 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 72 | BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map, |
| 73 | InjectionDelegate* delegate); |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 74 | |
[email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 75 | BASE_EXPORT bool PerformInjectiveMultimapDestructive( |
| 76 | InjectiveMultimap* map, |
| 77 | InjectionDelegate* delegate); |
[email protected] | ef73044e | 2010-03-11 15:25:54 | [diff] [blame] | 78 | |
| 79 | // This function will not call malloc but will mutate |map| |
| 80 | static inline bool ShuffleFileDescriptors(InjectiveMultimap* map) { |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 81 | FileDescriptorTableInjection delegate; |
[email protected] | ef73044e | 2010-03-11 15:25:54 | [diff] [blame] | 82 | return PerformInjectiveMultimapDestructive(map, &delegate); |
[email protected] | 3f04f2b | 2009-04-30 19:40:03 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | } // namespace base |
| 86 | |
[email protected] | 2fdc86a | 2010-01-26 23:08:02 | [diff] [blame] | 87 | #endif // BASE_FILE_DESCRIPTOR_SHUFFLE_H_ |