summaryrefslogtreecommitdiff
path: root/libnetfs/dir-lookup.c
blob: ddd08e1c9535b4f497c77d3ae33b76b2060fd34b (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* 
   Copyright (C) 1995 Free Software Foundation, Inc.
   Written by Michael I. Bushnell, p/BSG.

   This file is part of the GNU Hurd.

   The GNU Hurd 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.

   The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */

#include <fcntl.h>
#include "netfs.h"
#include "fs_S.h"


error_t
netfs_S_dir_lookup (struct protid *diruser,
		    char *filename,
		    int flags,
		    mode_t mode,
		    retry_type *do_retry,
		    char *retry_name,
		    mach_port_t *retry_port,
		    mach_msg_type_name_t *retry_port_type)
{
  int create;			/* true if O_CREAT flag set */
  int excl;			/* true if O_EXCL flag set */
  int mustbedir;		/* true if the result must be S_IFDIR */
  int lastcomp;			/* true if we are at the last component */
  int newnode;			/* true if this node is newly created */
  struct node *dnp, *np;
  char *nextname;

  if (!diruser)
    return EOPNOTSUPP;
  
  create = (flags & O_CREAT);
  excl = (flags & O_EXCL);
  
  /* Skip leading slashes */
  while (*filename == '/')
    filename++;
  
  *retry_poly = MACH_MSG_TYPE_MAKE_SEND;
  *retry = FS_RETRY_NORMAL;
  *retry_name = '\0';
  
  if (*filename == '\0')
    {
      mustbedir = 1;
      
      /* Set things up in the state expected by the code from gotit: on. */
      dnp = 0;
      np = diruser->po->np;
      mutex_lock (&np->lock);
      netfs_nref (np);
      goto gotit;
    }
  
  dnp = diruser->po->np;
  mutex_lock (&dnp->lock);
  np = 0;
  
  netfs_nref (dnp);		/* acquire a reference for later netfs_nput */
  
  do
    {
      assert (!lastcomp);
      
      /* Find the name of the next pathname component */
      nextname = index (filename, '/');
      
      if (nextname)
	{
	  *nextname++ = '\0';
	  while (*nextname == '/')
	    nextname++;
	  if (*nextname == '\0')
	    {
	      /* These are the rules for filenames ending in /. */
	      nextname = 0;
	      lastcomp = 1;
	      mustbedir = 1;
	      create = 0;
	    }
	  else
	    lastcomp = 1;
	  
	  np = 0;
	  
	  /* Attempt a lookup on the next pathname component. */
	  error = netfs_attempt_lookup (user, dnp, nextname, &np);

	  /* Implement O_EXCL flag here */
	  if (lastcomp && create && excl && (!error || error == EAGAIN))
	    error = EEXIST;
	  
	  /* If we get an error, we're done */
	  if (error == EAGAIN)
	    {
	      /* This really means .. from root */
	      if (diruser->po->dotdotport != MACH_PORT_NULL)
		{
		  *retry = FS_RETRY_REAUTH;
		  *retry_port = dircred->po->dotdotport;
		  *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
		  if (!lastcomp)
		    strcpy (retry_name, nextname);
		  error = 0;
		  goto out;
		}
	      else
		{
		  /* We are the global root; .. from our root is
		     just our root again. */
		  error = 0;
		  np = dnp;
		  netfs_nref (np);
		}
	    }
	  
	  /* Create the new node if necessary */
	  if (lastcomp && create)
	    {
	      if (error == ENOENT)
		{
		  mode &= ~(S_IFMT | S_ISPARE | S_ISVTX);
		  mode |= S_IFREG;
		  error = netfs_attempt_create_file (diruser, dnp, 
						     filename, mode, &np);
		  newnode = 1;
		}