summaryrefslogtreecommitdiff
path: root/libtreefs/dir-hooks.c
blob: 5c54039aaf046c3c162328dea33c46bdac8b834a (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
/* Default hooks for directory nodes

   Copyright (C) 1995 Free Software Foundation, Inc.

   Written by Miles Bader <miles@gnu.ai.mit.edu>

   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., 675 Mass Ave, Cambridge, MA 02139, USA. */

#include <sys/fcntl.h>

#include "treefs.h"

/* ---------------------------------------------------------------- */

/* Return in CHILD a new node with one reference, presumably a possible child
   of DIR, with a mode MODE.  All attempts to create a new node go through
   this hook, so it may be overridden to easily control creation (e.g.,
   replacing it with a hook that always returns EPERM).  Note that this
   routine doesn't actually enter the child into the directory, or give the
   node a non-zero link count, that should be done by the caller.  */
error_t
_treefs_dir_create_child (struct treefs_node *dir, 
			   mode_t mode, struct treefs_auth *auth,
			   struct treefs_node **child)
{
  error_t err;

  if (!treefs_node_isdir (dir))
    return ENOTDIR;

  err = treefs_fsys_create_node (dir->fsys, dir, mode, auth, child);
  if (err)
    return err;

  return 0;
}

/* ---------------------------------------------------------------- */

/* Lookup NAME in DIR, returning the result in CHILD; AUTH should be used to
   do authentication.  FLAGS is the open flags; if FLAGS contains O_CREAT,
   and NAME is not found, then an entry should be created with a mode of
   CREATE_MODE (which includes the S_IFMT bits, e.g., S_IFREG means a normal
   file), unless O_EXCL is also set, in which case EEXIST should be returned.
   Possible special errors returned include: EAGAIN -- result would be the
   parent of our filesystem root.  */
error_t
_treefs_dir_lookup (struct treefs_node *dir, char *name,
		    struct treefs_auth *auth,
		    int flags, int create_mode,
		    struct treefs_node **child)
{
  error_t err;

  if (strcmp (name, "..") == 0 && dir == dir->fsys->root)
    /* Whoops, the result is above our heads.  */
    err = EAGAIN;
  else
    /* See if we've got an in-core entry for this file.  */
    err = treefs_mdir_get (dir, name, child);

  if (err == 0 && (flags & O_EXCL))
    return EEXIST;

  if (err == ENOENT)
    /* See if there's some other way of getting this file.  */
    err = treefs_dir_noent (dir, name, auth, flags, create_mode, child);

  if (err == ENOENT && (flags & O_CREAT))
    /* No such file, but the user wants to create it.  */
    {
      err = treefs_dir_create_child (dir, create_mode, auth, child);
      if (!err)
	{
	  err = treefs_dir_link (dir, name, *child, auth);
	  if (err)
	    treefs_node_unref (*child);
	}
    }

  return err;
}

/* ---------------------------------------------------------------- */

/* Link the node CHILD into DIR as NAME, using AUTH to check authentication.
   DIR should be locked and CHILD shouldn't be.  The default hook puts it
   into DIR's in-core directory, and uses a reference to CHILD.  */
error_t
_treefs_dir_link (struct treefs_node *dir, char *name,
		  struct treefs_node *child, struct treefs_auth *auth)
{
  struct treefs_node *old_child;
  error_t err = treefs_node_mod_link_count (child, 1);
  if (!err)
    {
      err = treefs_mdir_add (dir, name, child, &old_child);
      if (err)
	/* back out */
	treefs_node_mod_link_count (child, -1);
      else if (old_child)
	treefs_node_mod_link_count (old_child, -1);
    }
  return err;
}

/* Remove the entry NAME from DIR, using AUTH to check authentication.  DIR
   should be locked.  The default hook removes NAME from DIR's in-core
   directory.  */
error_t
_treefs_dir_unlink (struct treefs_node *dir, char *name,
		    struct treefs_auth *auth)
{
  struct treefs_node *old_child;
  error_t err = treefs_mdir_remove (dir, name, &old_child);
  if (!err && old_child)
    {
      treefs_node_mod_link_count (old_child, -1);
      treefs_node_unref (old_child);
    }
  return err;
}