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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
|
/*----------------------------------------------------------------------------*/
/*lnode.c*/
/*----------------------------------------------------------------------------*/
/*Implementation of policies of management of 'light nodes'*/
/*----------------------------------------------------------------------------*/
/*Based on the code of unionfs translator.*/
/*----------------------------------------------------------------------------*/
/*Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
Written by Sergiu Ivanov <unlimitedscolobb@gmail.com>.
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 of the
License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
#define _GNU_SOURCE
/*----------------------------------------------------------------------------*/
#include "lnode.h"
#include "debug.h"
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*--------Functions-----------------------------------------------------------*/
/*Adds a reference to the `lnode` (which must be locked)*/
void
lnode_ref_add
(
lnode_t * node
)
{
/*Increment the number of references*/
++node->references;
}/*lnode_ref_add*/
/*----------------------------------------------------------------------------*/
/*Removes a reference from `node` (which must be locked). If that was the last
reference, destroy the node*/
void
lnode_ref_remove
(
lnode_t * node
)
{
/*Fail if the node is not referenced by anybody*/
assert(node->references);
/*Decrement the number of references to `node`*/
--node->references;
/*If there are no references remaining*/
if(node->references == 0)
{
/*uninstall the node from the directory it is in and destroy it*/
lnode_uninstall(node);
lnode_destroy(node);
}
else
/*simply unlock the node*/
mutex_unlock(&node->lock);
}/*lnode_ref_remove*/
/*----------------------------------------------------------------------------*/
/*Creates a new lnode with `name`; the new node is locked and contains
a single reference*/
error_t
lnode_create
(
char * name,
lnode_t ** node /*put the result here*/
)
{
/*Allocate the memory for the node*/
lnode_t * node_new = malloc(sizeof(lnode_t));
/*If the memory has not been allocated*/
if(!node_new)
{
/*stop*/
return ENOMEM;
}
/*The copy of the name*/
char * name_cp = NULL;
/*If the name exists*/
if(name)
{
/*duplicate it*/
name_cp = strdup(name);
/*If the name has not been duplicated*/
if(!name_cp)
{
/*free the node*/
free(node_new);
/*stop*/
return ENOMEM;
}
}
/*Setup the new node*/
memset(node_new, 0, sizeof(lnode_t));
node_new->name = name_cp;
node_new->name_len = (name_cp) ? (strlen(name_cp)) : (0);
/*Setup one reference to this lnode*/
node_new->references = 1;
/*Initialize the mutex and acquire a lock on this lnode*/
mutex_init(&node_new->lock);
mutex_lock(&node_new->lock);
/*Store the result in the second parameter*/
*node = node_new;
/*Return success*/
return 0;
}/*lnode_create*/
/*----------------------------------------------------------------------------*/
/*Destroys the given lnode*/
void
lnode_destroy
(
lnode_t * node /*destroy this*/
)
{
/*Destroy the name of the node*/
free(node->name);
/*Destroy the node itself*/
free(node);
}/*lnode_destroy*/
/*----------------------------------------------------------------------------*/
/*Constructs the full path for the given lnode and stores the result both in
the parameter and inside the lnode (the same string, actually)*/
error_t
lnode_path_construct
(
lnode_t * node,
char ** path /*store the path here*/
)
{
error_t err = 0;
/*The final path*/
char * p;
/*The final length of the path*/
int p_len = 0;
/*A temporary pointer to an lnode*/
lnode_t * n;
/*While the root node of the filterfs filesystem has not been reached*/
for(n = node; n && n->dir; n = n->dir)
/*add the length of the name of `n` to `p_len` make some space for
the delimiter '/', if we are not approaching the root node*/
/*p_len += n->name_len + ((n->dir->dir) ? (1) : (0));*/
/*There is some path to our root node, so we will anyway have to
add a '/'*/
p_len += n->name_len + 1;
/*Include the space for the path to the root node of the filterfs
(n is now the root of the filesystem)*/
p_len += strlen(n->path) + 1;
/*Try to allocate the space for the string*/
p = malloc(p_len * sizeof(char));
if(!p)
err = ENOMEM;
/*If memory allocation has been successful*/
else
{
/*put a terminal 0 at the end of the path*/
p[--p_len] = 0;
/*While the root node of the filterfs filesystem has not been reached*/
for(n = node; n && n->dir; n = n->dir)
{
/*compute the position where the name of `n` is to be inserted*/
p_len -= n->name_len;
/*copy the name of the node into the path (omit the terminal 0)*/
strncpy(p + p_len, n->name, n->name_len);
/*If we are not at the root node of the filterfs filesystem, add the
separator*/
/*if(n->dir->dir)
p[--p_len] = '/';*/
/*we anyway have to add the separator slash*/
p[--p_len] = '/';
}
/*put the path to the root node at the beginning of the first path
(n is at the root now)*/
strncpy(p, n->path, strlen(n->path));
/*destroy the former path in lnode, if it exists*/
if(node->path)
free(node->path);
/*store the new path inside the lnode*/
node->path = p;
/*store the path in the parameter*/
if(path)
*path = p;
}
/*Return the result of operations*/
return err;
}/*lnode_path_construct*/
/*----------------------------------------------------------------------------*/
/*Gets a light node by its name, locks it and increments its refcount*/
error_t
lnode_get
(
lnode_t * dir, /*search here*/
char * name, /*search for this name*/
lnode_t ** node /*put the result here*/
)
{
error_t err = 0;
/*The pointer to the required lnode*/
lnode_t * n;
/*Find `name` among the names of entries in `dir`*/
for(n = dir->entries; n && (strcmp(n->name, name) != 0); n = n->next);
/*If the search has been successful*/
if(n)
{
/*lock the node*/
mutex_lock(&n->lock);
/*increment the refcount of the found lnode*/
lnode_ref_add(n);
/*put a pointer to `n` into the parameter*/
*node = n;
}
else
err = ENOENT;
/*Return the result of operations*/
return err;
}/*lnode_get*/
/*----------------------------------------------------------------------------*/
/*Install the lnode into the lnode tree: add a reference to `dir` (which must
be locked)*/
void
lnode_install
(
lnode_t * dir, /*install here*/
lnode_t * node /*install this*/
)
{
/*Install `node` into the list of entries in `dir`*/
node->next = dir->entries;
node->prevp = &dir->entries; /*this node is the first on the list*/
if(dir->entries)
dir->entries->prevp = &node->next; /*here `prevp` gets the value
corresponding to its meaning*/
dir->entries = node;
/*Add a new reference to dir*/
lnode_ref_add(dir);
/*Setup the `dir` link in node*/
node->dir = dir;
}/*lnode_install*/
/*----------------------------------------------------------------------------*/
/*Unistall the node from the node tree; remove a reference from the lnode
containing `node`*/
void
lnode_uninstall
(
lnode_t * node
)
{
/*Remove a reference from the parent*/
lnode_ref_remove(node->dir);
/*Make the next pointer in the previous element point to the element,
which follows `node`*/
*node->prevp = node->next;
/*If the current node is not the last one, connect the list after removal
of the current node*/
if(node->next)
node->next->prevp = &node->next;
}/*lnode_uninstall*/
/*----------------------------------------------------------------------------*/
|