@@ -18,28 +18,6 @@ static void XCWCloseFD(int *fd) {
1818 }
1919}
2020
21- static NSData *XCWReadAllAndCloseFD (int fd) {
22- if (fd < 0 ) {
23- return [NSData data ];
24- }
25-
26- NSMutableData *data = [NSMutableData data ];
27- uint8_t buffer[16384 ];
28- for (;;) {
29- ssize_t count = read (fd, buffer, sizeof (buffer));
30- if (count > 0 ) {
31- [data appendBytes: buffer length: (NSUInteger )count];
32- continue ;
33- }
34- if (count < 0 && errno == EINTR) {
35- continue ;
36- }
37- break ;
38- }
39- close (fd);
40- return data;
41- }
42-
4321static void XCWWriteAllAndCloseFD (int fd, NSData *data) {
4422 if (fd < 0 ) {
4523 return ;
@@ -68,6 +46,33 @@ static void XCWWriteAllAndCloseFD(int fd, NSData *data) {
6846 userInfo: @{ NSLocalizedDescriptionKey : description ?: @" Process failed." }];
6947}
7048
49+ static int XCWCreateTemporaryOutputFile (NSString **path, NSError * _Nullable __autoreleasing *error) {
50+ NSString *templatePath = [NSTemporaryDirectory () stringByAppendingPathComponent: @" simdeck-process-XXXXXX" ];
51+ char *fileTemplate = strdup (templatePath.fileSystemRepresentation );
52+ if (fileTemplate == NULL ) {
53+ if (error != NULL ) {
54+ *error = XCWProcessRunnerError (6 , @" Failed to allocate temporary output path." );
55+ }
56+ return -1 ;
57+ }
58+
59+ int fd = mkstemp (fileTemplate);
60+ if (fd < 0 ) {
61+ if (error != NULL ) {
62+ *error = XCWProcessRunnerError (7 , [NSString stringWithFormat: @" Failed to create temporary output file: %s " , strerror (errno)]);
63+ }
64+ free (fileTemplate);
65+ return -1 ;
66+ }
67+
68+ if (path != NULL ) {
69+ *path = [[NSFileManager defaultManager ] stringWithFileSystemRepresentation: fileTemplate
70+ length: strlen (fileTemplate)];
71+ }
72+ free (fileTemplate);
73+ return fd;
74+ }
75+
7176@implementation XCWProcessResult
7277
7378- (instancetype )initWithTerminationStatus : (int )terminationStatus
@@ -94,51 +99,58 @@ + (XCWProcessResult *)runLaunchPath:(NSString *)launchPath
9499 arguments : (NSArray <NSString *> *)arguments
95100 inputData : (NSData *)inputData
96101 error : (NSError * _Nullable __autoreleasing *)error {
97- int stdoutPipe[ 2 ] = { - 1 , - 1 } ;
98- int stderrPipe[ 2 ] = { - 1 , - 1 } ;
102+ int stdoutFD = - 1 ;
103+ int stderrFD = - 1 ;
99104 int stdinPipe[2 ] = { -1 , -1 };
105+ NSString *stdoutPath = nil ;
106+ NSString *stderrPath = nil ;
100107 posix_spawn_file_actions_t fileActions;
101108 BOOL fileActionsInitialized = NO ;
102109 char **argv = NULL ;
103110
104- if (pipe (stdoutPipe) != 0 || pipe (stderrPipe) != 0 || (inputData != nil && pipe (stdinPipe) != 0 )) {
111+ NSError *creationError = nil ;
112+ stdoutFD = XCWCreateTemporaryOutputFile (&stdoutPath, &creationError);
113+ stderrFD = XCWCreateTemporaryOutputFile (&stderrPath, &creationError);
114+ if (stdoutFD < 0 || stderrFD < 0 || (inputData != nil && pipe (stdinPipe) != 0 )) {
105115 if (error != NULL ) {
106- *error = XCWProcessRunnerError (1 , [NSString stringWithFormat: @" Failed to create process pipes: %s " , strerror (errno)]);
116+ *error = creationError ?: XCWProcessRunnerError (1 , [NSString stringWithFormat: @" Failed to create process pipes: %s " , strerror (errno)]);
107117 }
108- XCWCloseFD (&stdoutPipe[0 ]);
109- XCWCloseFD (&stdoutPipe[1 ]);
110- XCWCloseFD (&stderrPipe[0 ]);
111- XCWCloseFD (&stderrPipe[1 ]);
118+ XCWCloseFD (&stdoutFD);
119+ XCWCloseFD (&stderrFD);
112120 XCWCloseFD (&stdinPipe[0 ]);
113121 XCWCloseFD (&stdinPipe[1 ]);
122+ if (stdoutPath != nil ) {
123+ [[NSFileManager defaultManager ] removeItemAtPath: stdoutPath error: nil ];
124+ }
125+ if (stderrPath != nil ) {
126+ [[NSFileManager defaultManager ] removeItemAtPath: stderrPath error: nil ];
127+ }
114128 return nil ;
115129 }
116130
117131 if (posix_spawn_file_actions_init (&fileActions) != 0 ) {
118132 if (error != NULL ) {
119133 *error = XCWProcessRunnerError (2 , [NSString stringWithFormat: @" Failed to initialize spawn actions: %s " , strerror (errno)]);
120134 }
121- XCWCloseFD (&stdoutPipe[0 ]);
122- XCWCloseFD (&stdoutPipe[1 ]);
123- XCWCloseFD (&stderrPipe[0 ]);
124- XCWCloseFD (&stderrPipe[1 ]);
135+ XCWCloseFD (&stdoutFD);
136+ XCWCloseFD (&stderrFD);
125137 XCWCloseFD (&stdinPipe[0 ]);
126138 XCWCloseFD (&stdinPipe[1 ]);
139+ [[NSFileManager defaultManager ] removeItemAtPath: stdoutPath error: nil ];
140+ [[NSFileManager defaultManager ] removeItemAtPath: stderrPath error: nil ];
127141 return nil ;
128142 }
129143 fileActionsInitialized = YES ;
130144
131- posix_spawn_file_actions_adddup2 (&fileActions, stdoutPipe[ 1 ] , STDOUT_FILENO);
132- posix_spawn_file_actions_adddup2 (&fileActions, stderrPipe[ 1 ] , STDERR_FILENO);
145+ posix_spawn_file_actions_adddup2 (&fileActions, stdoutFD , STDOUT_FILENO);
146+ posix_spawn_file_actions_adddup2 (&fileActions, stderrFD , STDERR_FILENO);
133147 if (inputData != nil ) {
134148 posix_spawn_file_actions_adddup2 (&fileActions, stdinPipe[0 ], STDIN_FILENO);
135149 } else {
136150 posix_spawn_file_actions_addopen (&fileActions, STDIN_FILENO, " /dev/null" , O_RDONLY, 0 );
137151 }
138- posix_spawn_file_actions_addclose (&fileActions, stdoutPipe[0 ]);
139- posix_spawn_file_actions_addclose (&fileActions, stdoutPipe[1 ]);
140- posix_spawn_file_actions_addclose (&fileActions, stderrPipe[0 ]);
141- posix_spawn_file_actions_addclose (&fileActions, stderrPipe[1 ]);
152+ posix_spawn_file_actions_addclose (&fileActions, stdoutFD);
153+ posix_spawn_file_actions_addclose (&fileActions, stderrFD);
142154 if (inputData != nil ) {
143155 posix_spawn_file_actions_addclose (&fileActions, stdinPipe[0 ]);
144156 posix_spawn_file_actions_addclose (&fileActions, stdinPipe[1 ]);
@@ -151,12 +163,12 @@ + (XCWProcessResult *)runLaunchPath:(NSString *)launchPath
151163 *error = XCWProcessRunnerError (3 , @" Failed to allocate process arguments." );
152164 }
153165 posix_spawn_file_actions_destroy (&fileActions);
154- XCWCloseFD (&stdoutPipe[0 ]);
155- XCWCloseFD (&stdoutPipe[1 ]);
156- XCWCloseFD (&stderrPipe[0 ]);
157- XCWCloseFD (&stderrPipe[1 ]);
166+ XCWCloseFD (&stdoutFD);
167+ XCWCloseFD (&stderrFD);
158168 XCWCloseFD (&stdinPipe[0 ]);
159169 XCWCloseFD (&stdinPipe[1 ]);
170+ [[NSFileManager defaultManager ] removeItemAtPath: stdoutPath error: nil ];
171+ [[NSFileManager defaultManager ] removeItemAtPath: stderrPath error: nil ];
160172 return nil ;
161173 }
162174 argv[0 ] = (char *)launchPath.fileSystemRepresentation ;
@@ -173,39 +185,23 @@ + (XCWProcessResult *)runLaunchPath:(NSString *)launchPath
173185 }
174186 posix_spawn_file_actions_destroy (&fileActions);
175187 free (argv);
176- XCWCloseFD (&stdoutPipe[0 ]);
177- XCWCloseFD (&stdoutPipe[1 ]);
178- XCWCloseFD (&stderrPipe[0 ]);
179- XCWCloseFD (&stderrPipe[1 ]);
188+ XCWCloseFD (&stdoutFD);
189+ XCWCloseFD (&stderrFD);
180190 XCWCloseFD (&stdinPipe[0 ]);
181191 XCWCloseFD (&stdinPipe[1 ]);
192+ [[NSFileManager defaultManager ] removeItemAtPath: stdoutPath error: nil ];
193+ [[NSFileManager defaultManager ] removeItemAtPath: stderrPath error: nil ];
182194 return nil ;
183195 }
184196
185- __block NSData *stdoutData = [NSData data ];
186- __block NSData *stderrData = [NSData data ];
187- dispatch_group_t readGroup = dispatch_group_create ();
188- dispatch_queue_t readQueue = dispatch_get_global_queue (QOS_CLASS_UTILITY, 0 );
189- int stdoutReadFD = stdoutPipe[0 ];
190- int stderrReadFD = stderrPipe[0 ];
191- stdoutPipe[0 ] = -1 ;
192- stderrPipe[0 ] = -1 ;
193-
194- dispatch_group_async (readGroup, readQueue, ^{
195- stdoutData = XCWReadAllAndCloseFD (stdoutReadFD);
196- });
197-
198- dispatch_group_async (readGroup, readQueue, ^{
199- stderrData = XCWReadAllAndCloseFD (stderrReadFD);
200- });
201-
202- XCWCloseFD (&stdoutPipe[1 ]);
203- XCWCloseFD (&stderrPipe[1 ]);
197+ XCWCloseFD (&stdoutFD);
198+ XCWCloseFD (&stderrFD);
199+ dispatch_group_t writeGroup = inputData != nil ? dispatch_group_create () : nil ;
204200 if (inputData != nil ) {
205201 XCWCloseFD (&stdinPipe[0 ]);
206202 int stdinWriteFD = stdinPipe[1 ];
207203 stdinPipe[1 ] = -1 ;
208- dispatch_group_async (readGroup, readQueue , ^{
204+ dispatch_group_async (writeGroup, dispatch_get_global_queue (QOS_CLASS_UTILITY, 0 ) , ^{
209205 XCWWriteAllAndCloseFD (stdinWriteFD, inputData);
210206 });
211207 }
@@ -215,7 +211,9 @@ + (XCWProcessResult *)runLaunchPath:(NSString *)launchPath
215211 do {
216212 waitResult = waitpid (pid, &waitStatus, 0 );
217213 } while (waitResult < 0 && errno == EINTR);
218- dispatch_group_wait (readGroup, DISPATCH_TIME_FOREVER);
214+ if (writeGroup != nil ) {
215+ dispatch_group_wait (writeGroup, DISPATCH_TIME_FOREVER);
216+ }
219217 int terminationStatus = 1 ;
220218 if (waitResult < 0 ) {
221219 if (error != NULL ) {
@@ -232,6 +230,11 @@ + (XCWProcessResult *)runLaunchPath:(NSString *)launchPath
232230 }
233231 free (argv);
234232
233+ NSData *stdoutData = [NSData dataWithContentsOfFile: stdoutPath] ?: [NSData data ];
234+ NSData *stderrData = [NSData dataWithContentsOfFile: stderrPath] ?: [NSData data ];
235+ [[NSFileManager defaultManager ] removeItemAtPath: stdoutPath error: nil ];
236+ [[NSFileManager defaultManager ] removeItemAtPath: stderrPath error: nil ];
237+
235238 return [[XCWProcessResult alloc ] initWithTerminationStatus: terminationStatus
236239 stdoutData: stdoutData
237240 stderrData: stderrData];
0 commit comments