1*ba736c79SDavid van Moolenbroek /* Created (MFS based):
2*ba736c79SDavid van Moolenbroek * June 2011 (Evgeniy Ivanov)
3*ba736c79SDavid van Moolenbroek */
4*ba736c79SDavid van Moolenbroek
5*ba736c79SDavid van Moolenbroek #include "fs.h"
6*ba736c79SDavid van Moolenbroek
7*ba736c79SDavid van Moolenbroek /*===========================================================================*
8*ba736c79SDavid van Moolenbroek * fs_create *
9*ba736c79SDavid van Moolenbroek *===========================================================================*/
fs_create(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid,struct fsdriver_node * node)10*ba736c79SDavid van Moolenbroek int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
11*ba736c79SDavid van Moolenbroek struct fsdriver_node *node)
12*ba736c79SDavid van Moolenbroek {
13*ba736c79SDavid van Moolenbroek int r;
14*ba736c79SDavid van Moolenbroek struct puffs_node *pn_dir;
15*ba736c79SDavid van Moolenbroek struct puffs_node *pn;
16*ba736c79SDavid van Moolenbroek struct puffs_newinfo pni;
17*ba736c79SDavid van Moolenbroek struct puffs_kcn pkcnp;
18*ba736c79SDavid van Moolenbroek PUFFS_MAKECRED(pcr, &global_kcred);
19*ba736c79SDavid van Moolenbroek struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
20*ba736c79SDavid van Moolenbroek struct vattr va;
21*ba736c79SDavid van Moolenbroek struct timespec cur_time;
22*ba736c79SDavid van Moolenbroek
23*ba736c79SDavid van Moolenbroek if (global_pu->pu_ops.puffs_node_create == NULL) {
24*ba736c79SDavid van Moolenbroek lpuffs_debug("No puffs_node_create");
25*ba736c79SDavid van Moolenbroek return(ENFILE);
26*ba736c79SDavid van Moolenbroek }
27*ba736c79SDavid van Moolenbroek
28*ba736c79SDavid van Moolenbroek /* Copy the last component (i.e., file name) */
29*ba736c79SDavid van Moolenbroek pcn.pcn_namelen = strlen(name);
30*ba736c79SDavid van Moolenbroek assert(pcn.pcn_namelen <= NAME_MAX);
31*ba736c79SDavid van Moolenbroek strcpy(pcn.pcn_name, name);
32*ba736c79SDavid van Moolenbroek
33*ba736c79SDavid van Moolenbroek /* Get last directory pnode (i.e., directory that will hold the new pnode) */
34*ba736c79SDavid van Moolenbroek if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
35*ba736c79SDavid van Moolenbroek return(ENOENT);
36*ba736c79SDavid van Moolenbroek
37*ba736c79SDavid van Moolenbroek memset(&pni, 0, sizeof(pni));
38*ba736c79SDavid van Moolenbroek pni.pni_cookie = (void** )&pn;
39*ba736c79SDavid van Moolenbroek
40*ba736c79SDavid van Moolenbroek (void)clock_time(&cur_time);
41*ba736c79SDavid van Moolenbroek
42*ba736c79SDavid van Moolenbroek memset(&va, 0, sizeof(va));
43*ba736c79SDavid van Moolenbroek va.va_type = VREG;
44*ba736c79SDavid van Moolenbroek va.va_mode = mode;
45*ba736c79SDavid van Moolenbroek va.va_uid = uid;
46*ba736c79SDavid van Moolenbroek va.va_gid = gid;
47*ba736c79SDavid van Moolenbroek va.va_atime = va.va_mtime = va.va_ctime = cur_time;
48*ba736c79SDavid van Moolenbroek
49*ba736c79SDavid van Moolenbroek if (buildpath) {
50*ba736c79SDavid van Moolenbroek r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
51*ba736c79SDavid van Moolenbroek if (r) {
52*ba736c79SDavid van Moolenbroek lpuffs_debug("pathbuild error\n");
53*ba736c79SDavid van Moolenbroek return(ENOENT);
54*ba736c79SDavid van Moolenbroek }
55*ba736c79SDavid van Moolenbroek }
56*ba736c79SDavid van Moolenbroek
57*ba736c79SDavid van Moolenbroek r = global_pu->pu_ops.puffs_node_create(global_pu, pn_dir, &pni, &pcn, &va);
58*ba736c79SDavid van Moolenbroek if (buildpath) {
59*ba736c79SDavid van Moolenbroek if (r) {
60*ba736c79SDavid van Moolenbroek global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
61*ba736c79SDavid van Moolenbroek } else {
62*ba736c79SDavid van Moolenbroek struct puffs_node *_pn;
63*ba736c79SDavid van Moolenbroek
64*ba736c79SDavid van Moolenbroek _pn = PU_CMAP(global_pu, pn);
65*ba736c79SDavid van Moolenbroek _pn->pn_po = pcn.pcn_po_full;
66*ba736c79SDavid van Moolenbroek }
67*ba736c79SDavid van Moolenbroek }
68*ba736c79SDavid van Moolenbroek
69*ba736c79SDavid van Moolenbroek if (r != OK) {
70*ba736c79SDavid van Moolenbroek if (r > 0) r = -r;
71*ba736c79SDavid van Moolenbroek return(r);
72*ba736c79SDavid van Moolenbroek }
73*ba736c79SDavid van Moolenbroek
74*ba736c79SDavid van Moolenbroek /* Open pnode */
75*ba736c79SDavid van Moolenbroek pn->pn_count++;
76*ba736c79SDavid van Moolenbroek
77*ba736c79SDavid van Moolenbroek update_timens(pn_dir, MTIME | CTIME, &cur_time);
78*ba736c79SDavid van Moolenbroek
79*ba736c79SDavid van Moolenbroek /* Reply message */
80*ba736c79SDavid van Moolenbroek node->fn_ino_nr = pn->pn_va.va_fileid;
81*ba736c79SDavid van Moolenbroek node->fn_mode = pn->pn_va.va_mode;
82*ba736c79SDavid van Moolenbroek node->fn_size = pn->pn_va.va_size;
83*ba736c79SDavid van Moolenbroek node->fn_uid = pn->pn_va.va_uid;
84*ba736c79SDavid van Moolenbroek node->fn_gid = pn->pn_va.va_gid;
85*ba736c79SDavid van Moolenbroek node->fn_dev = NO_DEV;
86*ba736c79SDavid van Moolenbroek
87*ba736c79SDavid van Moolenbroek return(OK);
88*ba736c79SDavid van Moolenbroek }
89*ba736c79SDavid van Moolenbroek
90*ba736c79SDavid van Moolenbroek
91*ba736c79SDavid van Moolenbroek /*===========================================================================*
92*ba736c79SDavid van Moolenbroek * fs_mknod *
93*ba736c79SDavid van Moolenbroek *===========================================================================*/
fs_mknod(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid,dev_t dev)94*ba736c79SDavid van Moolenbroek int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
95*ba736c79SDavid van Moolenbroek dev_t dev)
96*ba736c79SDavid van Moolenbroek {
97*ba736c79SDavid van Moolenbroek int r;
98*ba736c79SDavid van Moolenbroek struct puffs_node *pn_dir;
99*ba736c79SDavid van Moolenbroek struct puffs_node *pn;
100*ba736c79SDavid van Moolenbroek struct puffs_newinfo pni;
101*ba736c79SDavid van Moolenbroek struct puffs_kcn pkcnp;
102*ba736c79SDavid van Moolenbroek PUFFS_MAKECRED(pcr, &global_kcred);
103*ba736c79SDavid van Moolenbroek struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
104*ba736c79SDavid van Moolenbroek struct vattr va;
105*ba736c79SDavid van Moolenbroek struct timespec cur_time;
106*ba736c79SDavid van Moolenbroek
107*ba736c79SDavid van Moolenbroek if (global_pu->pu_ops.puffs_node_mknod == NULL) {
108*ba736c79SDavid van Moolenbroek lpuffs_debug("No puffs_node_mknod");
109*ba736c79SDavid van Moolenbroek return(ENFILE);
110*ba736c79SDavid van Moolenbroek }
111*ba736c79SDavid van Moolenbroek
112*ba736c79SDavid van Moolenbroek /* Copy the last component */
113*ba736c79SDavid van Moolenbroek pcn.pcn_namelen = strlen(name);
114*ba736c79SDavid van Moolenbroek assert(pcn.pcn_namelen <= NAME_MAX);
115*ba736c79SDavid van Moolenbroek strcpy(pcn.pcn_name, name);
116*ba736c79SDavid van Moolenbroek
117*ba736c79SDavid van Moolenbroek /* Get last directory pnode */
118*ba736c79SDavid van Moolenbroek if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
119*ba736c79SDavid van Moolenbroek return(ENOENT);
120*ba736c79SDavid van Moolenbroek
121*ba736c79SDavid van Moolenbroek memset(&pni, 0, sizeof(pni));
122*ba736c79SDavid van Moolenbroek pni.pni_cookie = (void** )&pn;
123*ba736c79SDavid van Moolenbroek
124*ba736c79SDavid van Moolenbroek (void)clock_time(&cur_time);
125*ba736c79SDavid van Moolenbroek
126*ba736c79SDavid van Moolenbroek memset(&va, 0, sizeof(va));
127*ba736c79SDavid van Moolenbroek va.va_type = VDIR;
128*ba736c79SDavid van Moolenbroek va.va_mode = mode;
129*ba736c79SDavid van Moolenbroek va.va_uid = uid;
130*ba736c79SDavid van Moolenbroek va.va_gid = gid;
131*ba736c79SDavid van Moolenbroek va.va_rdev = dev;
132*ba736c79SDavid van Moolenbroek va.va_atime = va.va_mtime = va.va_ctime = cur_time;
133*ba736c79SDavid van Moolenbroek
134*ba736c79SDavid van Moolenbroek if (buildpath) {
135*ba736c79SDavid van Moolenbroek if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0) {
136*ba736c79SDavid van Moolenbroek lpuffs_debug("pathbuild error\n");
137*ba736c79SDavid van Moolenbroek return(ENOENT);
138*ba736c79SDavid van Moolenbroek }
139*ba736c79SDavid van Moolenbroek }
140*ba736c79SDavid van Moolenbroek
141*ba736c79SDavid van Moolenbroek r = global_pu->pu_ops.puffs_node_mknod(global_pu, pn_dir, &pni, &pcn, &va);
142*ba736c79SDavid van Moolenbroek if (buildpath) {
143*ba736c79SDavid van Moolenbroek if (r) {
144*ba736c79SDavid van Moolenbroek global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
145*ba736c79SDavid van Moolenbroek } else {
146*ba736c79SDavid van Moolenbroek struct puffs_node *_pn;
147*ba736c79SDavid van Moolenbroek
148*ba736c79SDavid van Moolenbroek _pn = PU_CMAP(global_pu, pn);
149*ba736c79SDavid van Moolenbroek _pn->pn_po = pcn.pcn_po_full;
150*ba736c79SDavid van Moolenbroek }
151*ba736c79SDavid van Moolenbroek }
152*ba736c79SDavid van Moolenbroek
153*ba736c79SDavid van Moolenbroek if (r != OK) {
154*ba736c79SDavid van Moolenbroek if (r > 0) r = -r;
155*ba736c79SDavid van Moolenbroek return(r);
156*ba736c79SDavid van Moolenbroek }
157*ba736c79SDavid van Moolenbroek
158*ba736c79SDavid van Moolenbroek update_timens(pn_dir, MTIME | CTIME, &cur_time);
159*ba736c79SDavid van Moolenbroek
160*ba736c79SDavid van Moolenbroek return(OK);
161*ba736c79SDavid van Moolenbroek }
162*ba736c79SDavid van Moolenbroek
163*ba736c79SDavid van Moolenbroek
164*ba736c79SDavid van Moolenbroek /*===========================================================================*
165*ba736c79SDavid van Moolenbroek * fs_mkdir *
166*ba736c79SDavid van Moolenbroek *===========================================================================*/
fs_mkdir(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid)167*ba736c79SDavid van Moolenbroek int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
168*ba736c79SDavid van Moolenbroek {
169*ba736c79SDavid van Moolenbroek int r;
170*ba736c79SDavid van Moolenbroek struct puffs_node *pn_dir;
171*ba736c79SDavid van Moolenbroek struct puffs_node *pn;
172*ba736c79SDavid van Moolenbroek struct puffs_newinfo pni;
173*ba736c79SDavid van Moolenbroek struct puffs_kcn pkcnp;
174*ba736c79SDavid van Moolenbroek PUFFS_MAKECRED(pcr, &global_kcred);
175*ba736c79SDavid van Moolenbroek struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
176*ba736c79SDavid van Moolenbroek struct vattr va;
177*ba736c79SDavid van Moolenbroek struct timespec cur_time;
178*ba736c79SDavid van Moolenbroek
179*ba736c79SDavid van Moolenbroek if (global_pu->pu_ops.puffs_node_mkdir == NULL) {
180*ba736c79SDavid van Moolenbroek lpuffs_debug("No puffs_node_mkdir");
181*ba736c79SDavid van Moolenbroek return(ENFILE);
182*ba736c79SDavid van Moolenbroek }
183*ba736c79SDavid van Moolenbroek
184*ba736c79SDavid van Moolenbroek /* Copy the last component */
185*ba736c79SDavid van Moolenbroek pcn.pcn_namelen = strlen(name);
186*ba736c79SDavid van Moolenbroek assert(pcn.pcn_namelen <= NAME_MAX);
187*ba736c79SDavid van Moolenbroek strcpy(pcn.pcn_name, name);
188*ba736c79SDavid van Moolenbroek
189*ba736c79SDavid van Moolenbroek /* Get last directory pnode */
190*ba736c79SDavid van Moolenbroek if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
191*ba736c79SDavid van Moolenbroek return(ENOENT);
192*ba736c79SDavid van Moolenbroek
193*ba736c79SDavid van Moolenbroek (void)clock_time(&cur_time);
194*ba736c79SDavid van Moolenbroek
195*ba736c79SDavid van Moolenbroek memset(&pni, 0, sizeof(pni));
196*ba736c79SDavid van Moolenbroek pni.pni_cookie = (void** )&pn;
197*ba736c79SDavid van Moolenbroek
198*ba736c79SDavid van Moolenbroek memset(&va, 0, sizeof(va));
199*ba736c79SDavid van Moolenbroek va.va_type = VDIR;
200*ba736c79SDavid van Moolenbroek va.va_mode = mode;
201*ba736c79SDavid van Moolenbroek va.va_uid = uid;
202*ba736c79SDavid van Moolenbroek va.va_gid = gid;
203*ba736c79SDavid van Moolenbroek va.va_atime = va.va_mtime = va.va_ctime = cur_time;
204*ba736c79SDavid van Moolenbroek
205*ba736c79SDavid van Moolenbroek if (buildpath) {
206*ba736c79SDavid van Moolenbroek r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
207*ba736c79SDavid van Moolenbroek if (r) {
208*ba736c79SDavid van Moolenbroek lpuffs_debug("pathbuild error\n");
209*ba736c79SDavid van Moolenbroek return(ENOENT);
210*ba736c79SDavid van Moolenbroek }
211*ba736c79SDavid van Moolenbroek }
212*ba736c79SDavid van Moolenbroek
213*ba736c79SDavid van Moolenbroek r = global_pu->pu_ops.puffs_node_mkdir(global_pu, pn_dir, &pni, &pcn, &va);
214*ba736c79SDavid van Moolenbroek if (buildpath) {
215*ba736c79SDavid van Moolenbroek if (r) {
216*ba736c79SDavid van Moolenbroek global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
217*ba736c79SDavid van Moolenbroek } else {
218*ba736c79SDavid van Moolenbroek struct puffs_node *_pn;
219*ba736c79SDavid van Moolenbroek
220*ba736c79SDavid van Moolenbroek _pn = PU_CMAP(global_pu, pn);
221*ba736c79SDavid van Moolenbroek _pn->pn_po = pcn.pcn_po_full;
222*ba736c79SDavid van Moolenbroek }
223*ba736c79SDavid van Moolenbroek }
224*ba736c79SDavid van Moolenbroek
225*ba736c79SDavid van Moolenbroek if (r != OK) {
226*ba736c79SDavid van Moolenbroek if (r > 0) r = -r;
227*ba736c79SDavid van Moolenbroek return(r);
228*ba736c79SDavid van Moolenbroek }
229*ba736c79SDavid van Moolenbroek
230*ba736c79SDavid van Moolenbroek update_timens(pn_dir, MTIME | CTIME, &cur_time);
231*ba736c79SDavid van Moolenbroek
232*ba736c79SDavid van Moolenbroek return(OK);
233*ba736c79SDavid van Moolenbroek }
234*ba736c79SDavid van Moolenbroek
235*ba736c79SDavid van Moolenbroek
236*ba736c79SDavid van Moolenbroek /*===========================================================================*
237*ba736c79SDavid van Moolenbroek * fs_slink *
238*ba736c79SDavid van Moolenbroek *===========================================================================*/
fs_slink(ino_t dir_nr,char * name,uid_t uid,gid_t gid,struct fsdriver_data * data,size_t bytes)239*ba736c79SDavid van Moolenbroek int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
240*ba736c79SDavid van Moolenbroek struct fsdriver_data *data, size_t bytes)
241*ba736c79SDavid van Moolenbroek {
242*ba736c79SDavid van Moolenbroek int r;
243*ba736c79SDavid van Moolenbroek struct pnode *pn; /* pnode containing symbolic link */
244*ba736c79SDavid van Moolenbroek struct pnode *pn_dir; /* directory containing link */
245*ba736c79SDavid van Moolenbroek char target[PATH_MAX + 1]; /* target path */
246*ba736c79SDavid van Moolenbroek struct puffs_newinfo pni;
247*ba736c79SDavid van Moolenbroek struct puffs_kcn pkcnp;
248*ba736c79SDavid van Moolenbroek PUFFS_MAKECRED(pcr, &global_kcred);
249*ba736c79SDavid van Moolenbroek struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
250*ba736c79SDavid van Moolenbroek struct vattr va;
251*ba736c79SDavid van Moolenbroek struct timespec cur_time;
252*ba736c79SDavid van Moolenbroek
253*ba736c79SDavid van Moolenbroek /* Copy the link name's last component */
254*ba736c79SDavid van Moolenbroek pcn.pcn_namelen = strlen(name);
255*ba736c79SDavid van Moolenbroek if (pcn.pcn_namelen > NAME_MAX)
256*ba736c79SDavid van Moolenbroek return(ENAMETOOLONG);
257*ba736c79SDavid van Moolenbroek strcpy(pcn.pcn_name, name);
258*ba736c79SDavid van Moolenbroek
259*ba736c79SDavid van Moolenbroek if (bytes >= PATH_MAX)
260*ba736c79SDavid van Moolenbroek return(ENAMETOOLONG);
261*ba736c79SDavid van Moolenbroek
262*ba736c79SDavid van Moolenbroek /* Copy the target path (note that it's not null terminated) */
263*ba736c79SDavid van Moolenbroek if ((r = fsdriver_copyin(data, 0, target, bytes)) != OK)
264*ba736c79SDavid van Moolenbroek return r;
265*ba736c79SDavid van Moolenbroek
266*ba736c79SDavid van Moolenbroek target[bytes] = '\0';
267*ba736c79SDavid van Moolenbroek
268*ba736c79SDavid van Moolenbroek if (strlen(target) != bytes) {
269*ba736c79SDavid van Moolenbroek /* This can happen if the user provides a buffer
270*ba736c79SDavid van Moolenbroek * with a \0 in it. This can cause a lot of trouble
271*ba736c79SDavid van Moolenbroek * when the symlink is used later. We could just use
272*ba736c79SDavid van Moolenbroek * the strlen() value, but we want to let the user
273*ba736c79SDavid van Moolenbroek * know he did something wrong. ENAMETOOLONG doesn't
274*ba736c79SDavid van Moolenbroek * exactly describe the error, but there is no
275*ba736c79SDavid van Moolenbroek * ENAMETOOWRONG.
276*ba736c79SDavid van Moolenbroek */
277*ba736c79SDavid van Moolenbroek return(ENAMETOOLONG);
278*ba736c79SDavid van Moolenbroek }
279*ba736c79SDavid van Moolenbroek
280*ba736c79SDavid van Moolenbroek if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
281*ba736c79SDavid van Moolenbroek return(EINVAL);
282*ba736c79SDavid van Moolenbroek
283*ba736c79SDavid van Moolenbroek memset(&pni, 0, sizeof(pni));
284*ba736c79SDavid van Moolenbroek pni.pni_cookie = (void** )&pn;
285*ba736c79SDavid van Moolenbroek
286*ba736c79SDavid van Moolenbroek (void)clock_time(&cur_time);
287*ba736c79SDavid van Moolenbroek
288*ba736c79SDavid van Moolenbroek memset(&va, 0, sizeof(va));
289*ba736c79SDavid van Moolenbroek va.va_type = VLNK;
290*ba736c79SDavid van Moolenbroek va.va_mode = (I_SYMBOLIC_LINK | RWX_MODES);
291*ba736c79SDavid van Moolenbroek va.va_uid = uid;
292*ba736c79SDavid van Moolenbroek va.va_gid = gid;
293*ba736c79SDavid van Moolenbroek va.va_atime = va.va_mtime = va.va_ctime = cur_time;
294*ba736c79SDavid van Moolenbroek
295*ba736c79SDavid van Moolenbroek if (buildpath) {
296*ba736c79SDavid van Moolenbroek r = puffs_path_pcnbuild(global_pu, &pcn, pn_dir);
297*ba736c79SDavid van Moolenbroek if (r) {
298*ba736c79SDavid van Moolenbroek lpuffs_debug("pathbuild error\n");
299*ba736c79SDavid van Moolenbroek return(ENOENT);
300*ba736c79SDavid van Moolenbroek }
301*ba736c79SDavid van Moolenbroek }
302*ba736c79SDavid van Moolenbroek
303*ba736c79SDavid van Moolenbroek r = global_pu->pu_ops.puffs_node_symlink(global_pu, pn_dir, &pni, &pcn, &va, target);
304*ba736c79SDavid van Moolenbroek if (buildpath) {
305*ba736c79SDavid van Moolenbroek if (r) {
306*ba736c79SDavid van Moolenbroek global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
307*ba736c79SDavid van Moolenbroek } else {
308*ba736c79SDavid van Moolenbroek struct puffs_node *_pn;
309*ba736c79SDavid van Moolenbroek
310*ba736c79SDavid van Moolenbroek _pn = PU_CMAP(global_pu, pn);
311*ba736c79SDavid van Moolenbroek _pn->pn_po = pcn.pcn_po_full;
312*ba736c79SDavid van Moolenbroek }
313*ba736c79SDavid van Moolenbroek }
314*ba736c79SDavid van Moolenbroek
315*ba736c79SDavid van Moolenbroek if (r > 0) r = -r;
316*ba736c79SDavid van Moolenbroek
317*ba736c79SDavid van Moolenbroek return(r);
318*ba736c79SDavid van Moolenbroek }
319