fd-hook.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /* Hook for making file descriptor functions close(), ioctl() extensible.
  2. Copyright (C) 2009-2024 Free Software Foundation, Inc.
  3. Written by Bruno Haible <bruno@clisp.org>, 2009.
  4. This file is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation; either version 2.1 of the
  7. License, or (at your option) any later version.
  8. This file is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  14. #include <config.h>
  15. /* Specification. */
  16. #include "fd-hook.h"
  17. #include <stdlib.h>
  18. /* Currently, this entire code is only needed for the handling of sockets
  19. on native Windows platforms. */
  20. #if WINDOWS_SOCKETS
  21. /* The first and last link in the doubly linked list.
  22. Initially the list is empty. */
  23. static struct fd_hook anchor = { &anchor, &anchor, NULL, NULL };
  24. int
  25. execute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary,
  26. int fd)
  27. {
  28. if (remaining_list == &anchor)
  29. /* End of list reached. */
  30. return primary (fd);
  31. else
  32. return remaining_list->private_close_fn (remaining_list->private_next,
  33. primary, fd);
  34. }
  35. int
  36. execute_all_close_hooks (gl_close_fn primary, int fd)
  37. {
  38. return execute_close_hooks (anchor.private_next, primary, fd);
  39. }
  40. int
  41. execute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary,
  42. int fd, int request, void *arg)
  43. {
  44. if (remaining_list == &anchor)
  45. /* End of list reached. */
  46. return primary (fd, request, arg);
  47. else
  48. return remaining_list->private_ioctl_fn (remaining_list->private_next,
  49. primary, fd, request, arg);
  50. }
  51. int
  52. execute_all_ioctl_hooks (gl_ioctl_fn primary,
  53. int fd, int request, void *arg)
  54. {
  55. return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg);
  56. }
  57. void
  58. register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link)
  59. {
  60. if (close_hook == NULL)
  61. close_hook = execute_close_hooks;
  62. if (ioctl_hook == NULL)
  63. ioctl_hook = execute_ioctl_hooks;
  64. if (link->private_next == NULL && link->private_prev == NULL)
  65. {
  66. /* Add the link to the doubly linked list. */
  67. link->private_next = anchor.private_next;
  68. link->private_prev = &anchor;
  69. link->private_close_fn = close_hook;
  70. link->private_ioctl_fn = ioctl_hook;
  71. anchor.private_next->private_prev = link;
  72. anchor.private_next = link;
  73. }
  74. else
  75. {
  76. /* The link is already in use. */
  77. if (link->private_close_fn != close_hook
  78. || link->private_ioctl_fn != ioctl_hook)
  79. abort ();
  80. }
  81. }
  82. void
  83. unregister_fd_hook (struct fd_hook *link)
  84. {
  85. struct fd_hook *next = link->private_next;
  86. struct fd_hook *prev = link->private_prev;
  87. if (next != NULL && prev != NULL)
  88. {
  89. /* The link is in use. Remove it from the doubly linked list. */
  90. prev->private_next = next;
  91. next->private_prev = prev;
  92. /* Clear the link, to mark it unused. */
  93. link->private_next = NULL;
  94. link->private_prev = NULL;
  95. link->private_close_fn = NULL;
  96. link->private_ioctl_fn = NULL;
  97. }
  98. }
  99. #endif