diff options
author | LRN <lrn1986@gmail.com> | 2013-02-14 16:15:07 +0000 |
---|---|---|
committer | LRN <lrn1986@gmail.com> | 2013-02-14 16:15:07 +0000 |
commit | a2d71d8b9fa77325d466e47499d3da18c6b17a1f (patch) | |
tree | 0a5230145cfa7660ed6789a22b8541dc351f3cc8 /src/util/disk.c | |
parent | 2c3613ca587b571d45ea29da1f6ed15dace0b527 (diff) | |
download | gnunet-a2d71d8b9fa77325d466e47499d3da18c6b17a1f.tar.gz gnunet-a2d71d8b9fa77325d466e47499d3da18c6b17a1f.zip |
Make pipe ends detachable, fix W32 corner-cases
Now pipe ends are fully-functional FileHandles. You can detach
them from the pipe, and closing pipe will not affect them afterwards.
Tightened W32 implementation (make it close events!)
Diffstat (limited to 'src/util/disk.c')
-rw-r--r-- | src/util/disk.c | 224 |
1 files changed, 115 insertions, 109 deletions
diff --git a/src/util/disk.c b/src/util/disk.c index 5cd85b67b..01a3cc214 100644 --- a/src/util/disk.c +++ b/src/util/disk.c | |||
@@ -88,6 +88,7 @@ struct GNUNET_DISK_PipeHandle | |||
88 | { | 88 | { |
89 | /** | 89 | /** |
90 | * File descriptors for the pipe. | 90 | * File descriptors for the pipe. |
91 | * One or both of them could be NULL. | ||
91 | */ | 92 | */ |
92 | struct GNUNET_DISK_FileHandle *fd[2]; | 93 | struct GNUNET_DISK_FileHandle *fd[2]; |
93 | }; | 94 | }; |
@@ -2295,19 +2296,22 @@ GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int i | |||
2295 | fd); | 2296 | fd); |
2296 | #else | 2297 | #else |
2297 | struct GNUNET_DISK_PipeHandle *p; | 2298 | struct GNUNET_DISK_PipeHandle *p; |
2298 | struct GNUNET_DISK_FileHandle *fds; | ||
2299 | BOOL ret; | 2299 | BOOL ret; |
2300 | HANDLE tmp_handle; | 2300 | HANDLE tmp_handle; |
2301 | 2301 | int save_errno; | |
2302 | 2302 | ||
2303 | p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) + | 2303 | p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle)); |
2304 | 2 * sizeof (struct GNUNET_DISK_FileHandle)); | 2304 | p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); |
2305 | fds = (struct GNUNET_DISK_FileHandle *) &p[1]; | 2305 | p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); |
2306 | p->fd[0] = &fds[0]; | ||
2307 | p->fd[1] = &fds[1]; | ||
2308 | 2306 | ||
2309 | /* All pipes are overlapped. If you want them to block - just | 2307 | /* All pipes are overlapped. If you want them to block - just |
2310 | * call WriteFile() and ReadFile() with NULL overlapped pointer. | 2308 | * call WriteFile() and ReadFile() with NULL overlapped pointer. |
2309 | * NOTE: calling with NULL overlapped pointer works only | ||
2310 | * for pipes, and doesn't seem to be a documented feature. | ||
2311 | * It will NOT work for files, because overlapped files need | ||
2312 | * to read offsets from the overlapped structure, regardless. | ||
2313 | * Pipes are not seekable, and need no offsets, which is | ||
2314 | * probably why it works for them. | ||
2311 | */ | 2315 | */ |
2312 | ret = | 2316 | ret = |
2313 | create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0, | 2317 | create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0, |
@@ -2315,8 +2319,12 @@ GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int i | |||
2315 | FILE_FLAG_OVERLAPPED); | 2319 | FILE_FLAG_OVERLAPPED); |
2316 | if (!ret) | 2320 | if (!ret) |
2317 | { | 2321 | { |
2318 | GNUNET_free (p); | ||
2319 | SetErrnoFromWinError (GetLastError ()); | 2322 | SetErrnoFromWinError (GetLastError ()); |
2323 | save_errno = errno; | ||
2324 | GNUNET_free (p->fd[0]); | ||
2325 | GNUNET_free (p->fd[1]); | ||
2326 | GNUNET_free (p); | ||
2327 | errno = save_errno; | ||
2320 | return NULL; | 2328 | return NULL; |
2321 | } | 2329 | } |
2322 | if (!DuplicateHandle | 2330 | if (!DuplicateHandle |
@@ -2324,9 +2332,13 @@ GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int i | |||
2324 | inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) | 2332 | inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) |
2325 | { | 2333 | { |
2326 | SetErrnoFromWinError (GetLastError ()); | 2334 | SetErrnoFromWinError (GetLastError ()); |
2335 | save_errno = errno; | ||
2327 | CloseHandle (p->fd[0]->h); | 2336 | CloseHandle (p->fd[0]->h); |
2328 | CloseHandle (p->fd[1]->h); | 2337 | CloseHandle (p->fd[1]->h); |
2338 | GNUNET_free (p->fd[0]); | ||
2339 | GNUNET_free (p->fd[1]); | ||
2329 | GNUNET_free (p); | 2340 | GNUNET_free (p); |
2341 | errno = save_errno; | ||
2330 | return NULL; | 2342 | return NULL; |
2331 | } | 2343 | } |
2332 | CloseHandle (p->fd[0]->h); | 2344 | CloseHandle (p->fd[0]->h); |
@@ -2337,9 +2349,13 @@ GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int i | |||
2337 | inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) | 2349 | inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) |
2338 | { | 2350 | { |
2339 | SetErrnoFromWinError (GetLastError ()); | 2351 | SetErrnoFromWinError (GetLastError ()); |
2352 | save_errno = errno; | ||
2340 | CloseHandle (p->fd[0]->h); | 2353 | CloseHandle (p->fd[0]->h); |
2341 | CloseHandle (p->fd[1]->h); | 2354 | CloseHandle (p->fd[1]->h); |
2355 | GNUNET_free (p->fd[0]); | ||
2356 | GNUNET_free (p->fd[1]); | ||
2342 | GNUNET_free (p); | 2357 | GNUNET_free (p); |
2358 | errno = save_errno; | ||
2343 | return NULL; | 2359 | return NULL; |
2344 | } | 2360 | } |
2345 | CloseHandle (p->fd[1]->h); | 2361 | CloseHandle (p->fd[1]->h); |
@@ -2378,23 +2394,19 @@ struct GNUNET_DISK_PipeHandle * | |||
2378 | GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) | 2394 | GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) |
2379 | { | 2395 | { |
2380 | struct GNUNET_DISK_PipeHandle *p; | 2396 | struct GNUNET_DISK_PipeHandle *p; |
2381 | struct GNUNET_DISK_FileHandle *fds; | ||
2382 | 2397 | ||
2383 | p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) + | 2398 | p = GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle)); |
2384 | 2 * sizeof (struct GNUNET_DISK_FileHandle)); | 2399 | |
2385 | fds = (struct GNUNET_DISK_FileHandle *) &p[1]; | ||
2386 | p->fd[0] = &fds[0]; | ||
2387 | p->fd[1] = &fds[1]; | ||
2388 | #ifndef MINGW | 2400 | #ifndef MINGW |
2389 | int ret; | 2401 | int ret; |
2390 | int flags; | 2402 | int flags; |
2391 | int eno = 0; /* make gcc happy */ | 2403 | int eno = 0; /* make gcc happy */ |
2392 | 2404 | ||
2393 | p->fd[0]->fd = fd[0]; | ||
2394 | p->fd[1]->fd = fd[1]; | ||
2395 | ret = 0; | 2405 | ret = 0; |
2396 | if (fd[0] >= 0) | 2406 | if (fd[0] >= 0) |
2397 | { | 2407 | { |
2408 | p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); | ||
2409 | p->fd[0]->fd = fd[0]; | ||
2398 | if (!blocking_read) | 2410 | if (!blocking_read) |
2399 | { | 2411 | { |
2400 | flags = fcntl (fd[0], F_GETFL); | 2412 | flags = fcntl (fd[0], F_GETFL); |
@@ -2416,6 +2428,8 @@ GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) | |||
2416 | 2428 | ||
2417 | if (fd[1] >= 0) | 2429 | if (fd[1] >= 0) |
2418 | { | 2430 | { |
2431 | p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); | ||
2432 | p->fd[1]->fd = fd[1]; | ||
2419 | if (!blocking_write) | 2433 | if (!blocking_write) |
2420 | { | 2434 | { |
2421 | flags = fcntl (fd[1], F_GETFL); | 2435 | flags = fcntl (fd[1], F_GETFL); |
@@ -2442,37 +2456,50 @@ GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) | |||
2442 | GNUNET_break (0 == close (p->fd[0]->fd)); | 2456 | GNUNET_break (0 == close (p->fd[0]->fd)); |
2443 | if (p->fd[1]->fd >= 0) | 2457 | if (p->fd[1]->fd >= 0) |
2444 | GNUNET_break (0 == close (p->fd[1]->fd)); | 2458 | GNUNET_break (0 == close (p->fd[1]->fd)); |
2459 | GNUNET_free_non_null (p->fd[0]); | ||
2460 | GNUNET_free_non_null (p->fd[1]); | ||
2445 | GNUNET_free (p); | 2461 | GNUNET_free (p); |
2446 | errno = eno; | 2462 | errno = eno; |
2447 | return NULL; | 2463 | return NULL; |
2448 | } | 2464 | } |
2449 | #else | 2465 | #else |
2450 | if (fd[0] >= 0) | 2466 | if (fd[0] >= 0) |
2467 | { | ||
2468 | p->fd[0] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); | ||
2451 | p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]); | 2469 | p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]); |
2452 | else | 2470 | if (p->fd[0]->h != INVALID_HANDLE_VALUE) |
2453 | p->fd[0]->h = INVALID_HANDLE_VALUE; | 2471 | { |
2472 | p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE; | ||
2473 | p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); | ||
2474 | p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); | ||
2475 | p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
2476 | p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
2477 | } | ||
2478 | else | ||
2479 | { | ||
2480 | GNUNET_free (p->fd[0]); | ||
2481 | p->fd[0] = NULL; | ||
2482 | } | ||
2483 | } | ||
2454 | if (fd[1] >= 0) | 2484 | if (fd[1] >= 0) |
2455 | p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]); | ||
2456 | else | ||
2457 | p->fd[1]->h = INVALID_HANDLE_VALUE; | ||
2458 | |||
2459 | if (p->fd[0]->h != INVALID_HANDLE_VALUE) | ||
2460 | { | 2485 | { |
2461 | p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE; | 2486 | p->fd[1] = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); |
2462 | p->fd[0]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); | 2487 | p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]); |
2463 | p->fd[0]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); | 2488 | if (p->fd[1]->h != INVALID_HANDLE_VALUE) |
2464 | p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | 2489 | { |
2465 | p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | 2490 | p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE; |
2491 | p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); | ||
2492 | p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); | ||
2493 | p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
2494 | p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
2495 | } | ||
2496 | else | ||
2497 | { | ||
2498 | GNUNET_free (p->fd[1]); | ||
2499 | p->fd[1] = NULL; | ||
2500 | } | ||
2466 | } | 2501 | } |
2467 | 2502 | ||
2468 | if (p->fd[1]->h != INVALID_HANDLE_VALUE) | ||
2469 | { | ||
2470 | p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE; | ||
2471 | p->fd[1]->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); | ||
2472 | p->fd[1]->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); | ||
2473 | p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
2474 | p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
2475 | } | ||
2476 | #endif | 2503 | #endif |
2477 | return p; | 2504 | return p; |
2478 | } | 2505 | } |
@@ -2490,60 +2517,62 @@ GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p, | |||
2490 | enum GNUNET_DISK_PipeEnd end) | 2517 | enum GNUNET_DISK_PipeEnd end) |
2491 | { | 2518 | { |
2492 | int ret = GNUNET_OK; | 2519 | int ret = GNUNET_OK; |
2493 | int save; | ||
2494 | 2520 | ||
2495 | #ifdef MINGW | ||
2496 | if (end == GNUNET_DISK_PIPE_END_READ) | 2521 | if (end == GNUNET_DISK_PIPE_END_READ) |
2497 | { | 2522 | { |
2498 | if (p->fd[0]->h != INVALID_HANDLE_VALUE) | 2523 | if (p->fd[0]) |
2499 | { | 2524 | { |
2500 | if (!CloseHandle (p->fd[0]->h)) | 2525 | ret = GNUNET_DISK_file_close (p->fd[0]); |
2501 | { | 2526 | p->fd[0] = NULL; |
2502 | SetErrnoFromWinError (GetLastError ()); | ||
2503 | ret = GNUNET_SYSERR; | ||
2504 | } | ||
2505 | GNUNET_free (p->fd[0]->oOverlapRead); | ||
2506 | GNUNET_free (p->fd[0]->oOverlapWrite); | ||
2507 | p->fd[0]->h = INVALID_HANDLE_VALUE; | ||
2508 | } | 2527 | } |
2509 | } | 2528 | } |
2510 | else if (end == GNUNET_DISK_PIPE_END_WRITE) | 2529 | else if (end == GNUNET_DISK_PIPE_END_WRITE) |
2511 | { | 2530 | { |
2512 | if (p->fd[0]->h != INVALID_HANDLE_VALUE) | 2531 | if (p->fd[1]) |
2513 | { | 2532 | { |
2514 | if (!CloseHandle (p->fd[1]->h)) | 2533 | ret = GNUNET_DISK_file_close (p->fd[1]); |
2515 | { | 2534 | p->fd[1] = NULL; |
2516 | SetErrnoFromWinError (GetLastError ()); | ||
2517 | ret = GNUNET_SYSERR; | ||
2518 | } | ||
2519 | GNUNET_free (p->fd[1]->oOverlapRead); | ||
2520 | GNUNET_free (p->fd[1]->oOverlapWrite); | ||
2521 | p->fd[1]->h = INVALID_HANDLE_VALUE; | ||
2522 | } | 2535 | } |
2523 | } | 2536 | } |
2524 | save = errno; | 2537 | |
2525 | #else | 2538 | return ret; |
2526 | save = 0; | 2539 | } |
2540 | |||
2541 | /** | ||
2542 | * Detaches one of the ends from the pipe. | ||
2543 | * Detached end is a fully-functional FileHandle, it will | ||
2544 | * not be affected by anything you do with the pipe afterwards. | ||
2545 | * Each end of a pipe can only be detched from it once (i.e. | ||
2546 | * it is not duplicated). | ||
2547 | * | ||
2548 | * @param p pipe to detach an end from | ||
2549 | * @param end which end of the pipe to detach | ||
2550 | * @return Detached end on success, NULL on failure | ||
2551 | * (or if that end is not present or is closed). | ||
2552 | */ | ||
2553 | struct GNUNET_DISK_FileHandle * | ||
2554 | GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p, | ||
2555 | enum GNUNET_DISK_PipeEnd end) | ||
2556 | { | ||
2557 | struct GNUNET_DISK_FileHandle *ret = NULL; | ||
2558 | |||
2527 | if (end == GNUNET_DISK_PIPE_END_READ) | 2559 | if (end == GNUNET_DISK_PIPE_END_READ) |
2528 | { | 2560 | { |
2529 | if (0 != close (p->fd[0]->fd)) | 2561 | if (p->fd[0]) |
2530 | { | 2562 | { |
2531 | ret = GNUNET_SYSERR; | 2563 | ret = p->fd[0]; |
2532 | save = errno; | 2564 | p->fd[0] = NULL; |
2533 | } | 2565 | } |
2534 | p->fd[0]->fd = -1; | ||
2535 | } | 2566 | } |
2536 | else if (end == GNUNET_DISK_PIPE_END_WRITE) | 2567 | else if (end == GNUNET_DISK_PIPE_END_WRITE) |
2537 | { | 2568 | { |
2538 | if (0 != close (p->fd[1]->fd)) | 2569 | if (p->fd[1]) |
2539 | { | 2570 | { |
2540 | ret = GNUNET_SYSERR; | 2571 | ret = p->fd[1]; |
2541 | save = errno; | 2572 | p->fd[1] = NULL; |
2542 | } | 2573 | } |
2543 | p->fd[1]->fd = -1; | ||
2544 | } | 2574 | } |
2545 | #endif | 2575 | |
2546 | errno = save; | ||
2547 | return ret; | 2576 | return ret; |
2548 | } | 2577 | } |
2549 | 2578 | ||
@@ -2558,52 +2587,29 @@ int | |||
2558 | GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p) | 2587 | GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p) |
2559 | { | 2588 | { |
2560 | int ret = GNUNET_OK; | 2589 | int ret = GNUNET_OK; |
2561 | int save; | ||
2562 | 2590 | ||
2563 | #ifdef MINGW | 2591 | int read_end_close; |
2564 | if (p->fd[0]->h != INVALID_HANDLE_VALUE) | 2592 | int write_end_close; |
2565 | { | 2593 | int read_end_close_errno; |
2566 | if (!CloseHandle (p->fd[0]->h)) | 2594 | int write_end_close_errno; |
2567 | { | 2595 | |
2568 | SetErrnoFromWinError (GetLastError ()); | 2596 | read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ); |
2569 | ret = GNUNET_SYSERR; | 2597 | read_end_close_errno = errno; |
2570 | } | 2598 | write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE); |
2571 | GNUNET_free (p->fd[0]->oOverlapRead); | 2599 | write_end_close_errno = errno; |
2572 | GNUNET_free (p->fd[0]->oOverlapWrite); | 2600 | GNUNET_free (p); |
2573 | } | 2601 | |
2574 | if (p->fd[1]->h != INVALID_HANDLE_VALUE) | 2602 | if (GNUNET_OK != read_end_close) |
2575 | { | 2603 | { |
2576 | if (!CloseHandle (p->fd[1]->h)) | 2604 | errno = read_end_close_errno; |
2577 | { | 2605 | ret = read_end_close; |
2578 | SetErrnoFromWinError (GetLastError ()); | ||
2579 | ret = GNUNET_SYSERR; | ||
2580 | } | ||
2581 | GNUNET_free (p->fd[1]->oOverlapRead); | ||
2582 | GNUNET_free (p->fd[1]->oOverlapWrite); | ||
2583 | } | 2606 | } |
2584 | save = errno; | 2607 | else if (GNUNET_OK != write_end_close) |
2585 | #else | ||
2586 | save = 0; | ||
2587 | if (p->fd[0]->fd != -1) | ||
2588 | { | 2608 | { |
2589 | if (0 != close (p->fd[0]->fd)) | 2609 | errno = write_end_close_errno; |
2590 | { | 2610 | ret = write_end_close; |
2591 | ret = GNUNET_SYSERR; | ||
2592 | save = errno; | ||
2593 | } | ||
2594 | } | 2611 | } |
2595 | 2612 | ||
2596 | if (p->fd[1]->fd != -1) | ||
2597 | { | ||
2598 | if (0 != close (p->fd[1]->fd)) | ||
2599 | { | ||
2600 | ret = GNUNET_SYSERR; | ||
2601 | save = errno; | ||
2602 | } | ||
2603 | } | ||
2604 | #endif | ||
2605 | GNUNET_free (p); | ||
2606 | errno = save; | ||
2607 | return ret; | 2613 | return ret; |
2608 | } | 2614 | } |
2609 | 2615 | ||