105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Hook for making making file descriptor functions close(), ioctl() extensible.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2009-2012 Free Software Foundation, Inc.
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Written by Bruno Haible <bruno@clisp.org>, 2009.
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify it
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   under the terms of the GNU General Public License as published
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   by the Free Software Foundation; either version 3 of the License, or
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   General Public License for more details.
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "fd-hook.h"
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdlib.h>
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Currently, this entire code is only needed for the handling of sockets
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   on native Windows platforms.  */
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if WINDOWS_SOCKETS
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* The first and last link in the doubly linked list.
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Initially the list is empty.  */
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic struct fd_hook anchor = { &anchor, &anchor, NULL, NULL };
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wangexecute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary,
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     int fd)
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (remaining_list == &anchor)
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* End of list reached.  */
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return primary (fd);
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return remaining_list->private_close_fn (remaining_list->private_next,
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                             primary, fd);
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wangexecute_all_close_hooks (gl_close_fn primary, int fd)
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return execute_close_hooks (anchor.private_next, primary, fd);
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wangexecute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary,
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     int fd, int request, void *arg)
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (remaining_list == &anchor)
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    /* End of list reached.  */
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return primary (fd, request, arg);
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return remaining_list->private_ioctl_fn (remaining_list->private_next,
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                             primary, fd, request, arg);
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wangexecute_all_ioctl_hooks (gl_ioctl_fn primary,
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                         int fd, int request, void *arg)
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg);
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wangregister_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link)
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (close_hook == NULL)
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    close_hook = execute_close_hooks;
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (ioctl_hook == NULL)
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    ioctl_hook = execute_ioctl_hooks;
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (link->private_next == NULL && link->private_prev == NULL)
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Add the link to the doubly linked list.  */
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_next = anchor.private_next;
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_prev = &anchor;
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_close_fn = close_hook;
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_ioctl_fn = ioctl_hook;
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      anchor.private_next->private_prev = link;
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      anchor.private_next = link;
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* The link is already in use.  */
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (link->private_close_fn != close_hook
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          || link->private_ioctl_fn != ioctl_hook)
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        abort ();
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wangunregister_fd_hook (struct fd_hook *link)
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  struct fd_hook *next = link->private_next;
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  struct fd_hook *prev = link->private_prev;
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (next != NULL && prev != NULL)
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* The link is in use.  Remove it from the doubly linked list.  */
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      prev->private_next = next;
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      next->private_prev = prev;
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Clear the link, to mark it unused.  */
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_next = NULL;
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_prev = NULL;
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_close_fn = NULL;
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      link->private_ioctl_fn = NULL;
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
117