summaryrefslogtreecommitdiff
path: root/libdiskfs/file-inv-trans.c
blob: 6838a4a68f71942244caa4cbe474496a405662d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/* 
   Copyright (C) 1994 Free Software Foundation

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "priv.h"
#include "fs_S.h"

/* Implement fs.defs:file_invoke_translator as described in <hurd/fs.defs>. */
kern_return_t
diskfs_S_file_invoke_translator (struct protid *cred,
				 int flags,
				 retry_type *retry,
				 char *retry_name,
				 mach_port_t *retrypt,
				 mach_msg_type_name_t *retrypttype)
{
  error_t error = 0;
  mode_t type;
  struct node *np;
  
  /* This code is very similar (but subtly different) from
     dir-pathtrans.c and fsys-getroot.c.  A way should be found to
     combine them. */

  if (!cred)
    return EOPNOTSUPP;
  
  flags &= O_HURD;

  np = cred->po->np;
  
  mutex_lock (&np->lock);
  
  type = np->dn_stat.st_mode & S_IFMT;
  
 repeat_transcheck:
  /* Ignore O_NOTRANS in the following check */
  if (diskfs_node_translated (np) || np->translator.control != MACH_PORT_NULL)
    {
      mach_port_t control = np->translator.control;

      if (control == MACH_PORT_NULL)
	{
	  /* This use of _diskfs_dotdot_file is completely and utterly
	     bogus. XXX */
	  if (error = diskfs_start_translator (np, _diskfs_dotdot_file))
	    {
	      mutex_unlock (&np->lock);
	      return error;
	    }
	  control = np->translator.control;
	}

      mach_port_mod_refs (mach_task_self (), control, MACH_PORT_RIGHT_SEND, 1);
      mutex_unlock (&np->lock);
      error = fsys_getroot (childcontrol, cred->uids, cred->nuids, 
			    cred->gids, cred->ngids, flags, retry,
			    retryname, retrypt);
      if (error == MACH_SEND_INVALID_DEST)
	{
	  mutex_lock (&np->lock);
	  if (np->translator.control == control)
	    fshelp_translator_drop (&np->translator);
	  mach_port_deallocate (mach_task_self (), control);
	  error = 0;
	  goto repeat_transcheck;
	}
      
      if (!error && *retrypt != MACH_PORT_NULL)
	*retrypttype = MACH_MSG_TYPE_MOVE_SEND;
      else
	*retrypttype = MACH_MSG_TYPE_COPY_SEND;
      
      return error;
    }
  
  /* Ignore O_NOTRANS here. */
  if (type == S_IFLNK && !(flags & O_NOLINK))