aboutsummaryrefslogtreecommitdiff
path: root/src/util/disk.c
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2013-02-14 16:15:07 +0000
committerLRN <lrn1986@gmail.com>2013-02-14 16:15:07 +0000
commita2d71d8b9fa77325d466e47499d3da18c6b17a1f (patch)
tree0a5230145cfa7660ed6789a22b8541dc351f3cc8 /src/util/disk.c
parent2c3613ca587b571d45ea29da1f6ed15dace0b527 (diff)
downloadgnunet-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.c224
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 *
2378GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) 2394GNUNET_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 */
2553struct GNUNET_DISK_FileHandle *
2554GNUNET_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
2558GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p) 2587GNUNET_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