Lines 1-10
Link Here
|
1 |
/* $Id: vboxvfs_vnops.c $ */ |
|
|
2 |
/** @file |
3 |
* Description. |
4 |
*/ |
5 |
|
6 |
/* |
1 |
/* |
7 |
* Copyright (C) 2008-2017 Oracle Corporation |
2 |
* Copyright (C) 2008-2017 Oracle Corporation |
|
|
3 |
* Copyright (C) 2017 Mahdi Mokhtari |
8 |
* |
4 |
* |
9 |
* This file is part of VirtualBox Open Source Edition (OSE), as |
5 |
* This file is part of VirtualBox Open Source Edition (OSE), as |
10 |
* available from http://www.virtualbox.org. This file is free software; |
6 |
* available from http://www.virtualbox.org. This file is free software; |
Lines 14-241
Link Here
|
14 |
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the |
10 |
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the |
15 |
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. |
11 |
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. |
16 |
*/ |
12 |
*/ |
17 |
|
|
|
18 |
#include "vboxvfs.h" |
19 |
#include <sys/param.h> |
13 |
#include <sys/param.h> |
20 |
#include <sys/systm.h> |
14 |
#include <sys/systm.h> |
21 |
#include <sys/namei.h> |
15 |
#include <sys/namei.h> |
22 |
#include <sys/kernel.h> |
16 |
#include <sys/kernel.h> |
23 |
#include <sys/proc.h> |
17 |
#include <sys/types.h> |
|
|
18 |
#include <sys/malloc.h> |
19 |
#include <sys/stat.h> |
24 |
#include <sys/bio.h> |
20 |
#include <sys/bio.h> |
|
|
21 |
#include <sys/conf.h> |
25 |
#include <sys/buf.h> |
22 |
#include <sys/buf.h> |
26 |
#include <sys/fcntl.h> |
23 |
#include <sys/iconv.h> |
27 |
#include <sys/mount.h> |
24 |
#include <sys/mount.h> |
28 |
#include <sys/unistd.h> |
|
|
29 |
#include <sys/vnode.h> |
25 |
#include <sys/vnode.h> |
30 |
#include <sys/limits.h> |
26 |
#include <sys/dirent.h> |
31 |
#include <sys/lockf.h> |
27 |
#include <sys/queue.h> |
32 |
#include <sys/stat.h> |
28 |
#include <sys/unistd.h> |
|
|
29 |
#include <sys/endian.h> |
33 |
|
30 |
|
34 |
#include <vm/vm.h> |
31 |
#include <vm/uma.h> |
35 |
#include <vm/vm_extern.h> |
|
|
36 |
|
32 |
|
|
|
33 |
#include "vboxvfs.h" |
34 |
|
35 |
#if __FreeBSD_version < 1300063 |
36 |
#define VN_IS_DOOMED(vp) (((vp)->v_iflag & VI_DOOMED) != 0) |
37 |
#endif |
38 |
|
37 |
/* |
39 |
/* |
38 |
* Prototypes for VBOXVFS vnode operations |
40 |
* Prototypes for VBOXVFS vnode operations |
39 |
*/ |
41 |
*/ |
40 |
static vop_create_t vboxvfs_create; |
42 |
static vop_create_t vboxfs_create; |
41 |
static vop_mknod_t vboxvfs_mknod; |
43 |
static vop_open_t vboxfs_open; |
42 |
static vop_open_t vboxvfs_open; |
44 |
static vop_close_t vboxfs_close; |
43 |
static vop_close_t vboxvfs_close; |
45 |
static vop_access_t vboxfs_access; |
44 |
static vop_access_t vboxvfs_access; |
46 |
static vop_getattr_t vboxfs_getattr; |
45 |
static vop_getattr_t vboxvfs_getattr; |
47 |
static vop_setattr_t vboxfs_setattr; |
46 |
static vop_setattr_t vboxvfs_setattr; |
48 |
static vop_read_t vboxfs_read; |
47 |
static vop_read_t vboxvfs_read; |
49 |
static vop_readlink_t vboxfs_readlink; |
48 |
static vop_write_t vboxvfs_write; |
50 |
static vop_write_t vboxfs_write; |
49 |
static vop_fsync_t vboxvfs_fsync; |
51 |
static vop_fsync_t vboxfs_fsync; |
50 |
static vop_remove_t vboxvfs_remove; |
52 |
static vop_remove_t vboxfs_remove; |
51 |
static vop_link_t vboxvfs_link; |
53 |
static vop_link_t vboxfs_link; |
52 |
static vop_lookup_t vboxvfs_lookup; |
54 |
static vop_cachedlookup_t vboxfs_lookup; |
53 |
static vop_rename_t vboxvfs_rename; |
55 |
static vop_rename_t vboxfs_rename; |
54 |
static vop_mkdir_t vboxvfs_mkdir; |
56 |
static vop_mkdir_t vboxfs_mkdir; |
55 |
static vop_rmdir_t vboxvfs_rmdir; |
57 |
static vop_rmdir_t vboxfs_rmdir; |
56 |
static vop_symlink_t vboxvfs_symlink; |
58 |
static vop_symlink_t vboxfs_symlink; |
57 |
static vop_readdir_t vboxvfs_readdir; |
59 |
static vop_readdir_t vboxfs_readdir; |
58 |
static vop_strategy_t vboxvfs_strategy; |
60 |
static vop_print_t vboxfs_print; |
59 |
static vop_print_t vboxvfs_print; |
61 |
static vop_pathconf_t vboxfs_pathconf; |
60 |
static vop_pathconf_t vboxvfs_pathconf; |
62 |
static vop_advlock_t vboxfs_advlock; |
61 |
static vop_advlock_t vboxvfs_advlock; |
63 |
static vop_ioctl_t vboxfs_ioctl; |
62 |
static vop_getextattr_t vboxvfs_getextattr; |
64 |
static vop_inactive_t vboxfs_inactive; |
63 |
static vop_ioctl_t vboxvfs_ioctl; |
65 |
static vop_reclaim_t vboxfs_reclaim; |
64 |
static vop_getpages_t vboxvfs_getpages; |
66 |
static vop_vptofh_t vboxfs_vptofh; |
65 |
static vop_inactive_t vboxvfs_inactive; |
|
|
66 |
static vop_putpages_t vboxvfs_putpages; |
67 |
static vop_reclaim_t vboxvfs_reclaim; |
68 |
|
67 |
|
69 |
struct vop_vector vboxvfs_vnodeops = { |
68 |
struct vop_vector vboxfs_vnodeops = { |
70 |
.vop_default = &default_vnodeops, |
69 |
.vop_default = &default_vnodeops, |
71 |
|
70 |
|
72 |
.vop_access = vboxvfs_access, |
71 |
.vop_access = vboxfs_access, |
73 |
.vop_advlock = vboxvfs_advlock, |
72 |
.vop_advlock = VOP_EOPNOTSUPP, |
74 |
.vop_close = vboxvfs_close, |
73 |
.vop_close = vboxfs_close, |
75 |
.vop_create = vboxvfs_create, |
74 |
.vop_create = vboxfs_create, |
76 |
.vop_fsync = vboxvfs_fsync, |
75 |
.vop_fsync = vboxfs_fsync, |
77 |
.vop_getattr = vboxvfs_getattr, |
76 |
.vop_getattr = vboxfs_getattr, |
78 |
.vop_getextattr = vboxvfs_getextattr, |
77 |
.vop_getextattr = VOP_EOPNOTSUPP, |
79 |
.vop_getpages = vboxvfs_getpages, |
78 |
.vop_inactive = vboxfs_inactive, |
80 |
.vop_inactive = vboxvfs_inactive, |
79 |
.vop_ioctl = vboxfs_ioctl, |
81 |
.vop_ioctl = vboxvfs_ioctl, |
80 |
.vop_link = vboxfs_link, |
82 |
.vop_link = vboxvfs_link, |
81 |
.vop_lookup = vfs_cache_lookup, |
83 |
.vop_lookup = vboxvfs_lookup, |
82 |
.vop_cachedlookup = vboxfs_lookup, |
84 |
.vop_mkdir = vboxvfs_mkdir, |
83 |
.vop_mkdir = vboxfs_mkdir, |
85 |
.vop_mknod = vboxvfs_mknod, |
84 |
.vop_mknod = VOP_EOPNOTSUPP, |
86 |
.vop_open = vboxvfs_open, |
85 |
.vop_open = vboxfs_open, |
87 |
.vop_pathconf = vboxvfs_pathconf, |
86 |
.vop_pathconf = vboxfs_pathconf, |
88 |
.vop_print = vboxvfs_print, |
87 |
.vop_print = vboxfs_print, |
89 |
.vop_putpages = vboxvfs_putpages, |
88 |
.vop_read = vboxfs_read, |
90 |
.vop_read = vboxvfs_read, |
89 |
.vop_readdir = vboxfs_readdir, |
91 |
.vop_readdir = vboxvfs_readdir, |
90 |
.vop_readlink = vboxfs_readlink, |
92 |
.vop_reclaim = vboxvfs_reclaim, |
91 |
.vop_reclaim = vboxfs_reclaim, |
93 |
.vop_remove = vboxvfs_remove, |
92 |
.vop_remove = vboxfs_remove, |
94 |
.vop_rename = vboxvfs_rename, |
93 |
.vop_rename = vboxfs_rename, |
95 |
.vop_rmdir = vboxvfs_rmdir, |
94 |
.vop_rmdir = vboxfs_rmdir, |
96 |
.vop_setattr = vboxvfs_setattr, |
95 |
.vop_setattr = vboxfs_setattr, |
97 |
.vop_strategy = vboxvfs_strategy, |
96 |
.vop_vptofh = vboxfs_vptofh, |
98 |
.vop_symlink = vboxvfs_symlink, |
97 |
.vop_symlink = vboxfs_symlink, |
99 |
.vop_write = vboxvfs_write, |
98 |
.vop_write = vboxfs_write, |
|
|
99 |
.vop_bmap = VOP_EOPNOTSUPP |
100 |
}; |
100 |
}; |
101 |
|
101 |
|
102 |
static int vboxvfs_access(struct vop_access_args *ap) |
102 |
static uint64_t |
|
|
103 |
vsfnode_cur_time_usec(void) |
103 |
{ |
104 |
{ |
104 |
return 0; |
105 |
struct timeval now; |
|
|
106 |
|
107 |
getmicrotime(&now); |
108 |
|
109 |
return (now.tv_sec*1000 + now.tv_usec); |
105 |
} |
110 |
} |
106 |
|
111 |
|
107 |
static int vboxvfs_open(struct vop_open_args *ap) |
112 |
static int |
|
|
113 |
vsfnode_stat_cached(struct vboxfs_node *np) |
108 |
{ |
114 |
{ |
109 |
return 0; |
115 |
return (vsfnode_cur_time_usec() - np->sf_stat_time) < |
|
|
116 |
np->vboxfsmp->sf_stat_ttl * 1000UL; |
110 |
} |
117 |
} |
111 |
|
118 |
|
112 |
static int vboxvfs_close(struct vop_close_args *ap) |
119 |
static int |
|
|
120 |
vsfnode_update_stat_cache(struct vboxfs_node *np) |
113 |
{ |
121 |
{ |
114 |
return 0; |
122 |
int error; |
|
|
123 |
|
124 |
error = sfprov_get_attr(np->vboxfsmp->sf_handle, np->sf_path, |
125 |
&np->sf_stat); |
126 |
#if 0 |
127 |
if (error == ENOENT) |
128 |
sfnode_make_stale(node); |
129 |
#endif |
130 |
if (error == 0) |
131 |
np->sf_stat_time = vsfnode_cur_time_usec(); |
132 |
|
133 |
return (error); |
115 |
} |
134 |
} |
116 |
|
135 |
|
117 |
static int vboxvfs_getattr(struct vop_getattr_args *ap) |
136 |
/* |
|
|
137 |
* Need to clear v_object for insmntque failure. |
138 |
*/ |
139 |
static void |
140 |
vboxfs_insmntque_dtr(struct vnode *vp, void *dtr_arg) |
118 |
{ |
141 |
{ |
119 |
return 0; |
142 |
|
|
|
143 |
// XXX: vboxfs_destroy_vobject(vp, vp->v_object); |
144 |
vp->v_object = NULL; |
145 |
vp->v_data = NULL; |
146 |
vp->v_op = &dead_vnodeops; |
147 |
vgone(vp); |
148 |
vput(vp); |
120 |
} |
149 |
} |
121 |
|
150 |
|
122 |
static int vboxvfs_setattr(struct vop_setattr_args *ap) |
151 |
/* |
|
|
152 |
* Allocates a new vnode for the node node or returns a new reference to |
153 |
* an existing one if the node had already a vnode referencing it. The |
154 |
* resulting locked vnode is returned in *vpp. |
155 |
* |
156 |
* Returns zero on success or an appropriate error code on failure. |
157 |
*/ |
158 |
int |
159 |
vboxfs_alloc_vp(struct mount *mp, struct vboxfs_node *node, int lkflag, |
160 |
struct vnode **vpp) |
123 |
{ |
161 |
{ |
124 |
return 0; |
162 |
struct vnode *vp; |
|
|
163 |
int error; |
164 |
|
165 |
error = 0; |
166 |
loop: |
167 |
VBOXFS_NODE_LOCK(node); |
168 |
loop1: |
169 |
if ((vp = node->sf_vnode) != NULL) { |
170 |
MPASS((node->sf_vpstate & VBOXFS_VNODE_DOOMED) == 0); |
171 |
VI_LOCK(vp); |
172 |
if ((node->sf_type == VDIR && node->sf_parent == NULL) || |
173 |
(VN_IS_DOOMED(vp) && |
174 |
(lkflag & LK_NOWAIT) != 0)) { |
175 |
VI_UNLOCK(vp); |
176 |
VBOXFS_NODE_UNLOCK(node); |
177 |
error = ENOENT; |
178 |
vp = NULL; |
179 |
goto out; |
180 |
} |
181 |
if (VN_IS_DOOMED(vp)) { |
182 |
VI_UNLOCK(vp); |
183 |
node->sf_vpstate |= VBOXFS_VNODE_WRECLAIM; |
184 |
while ((node->sf_vpstate & VBOXFS_VNODE_WRECLAIM) != 0) { |
185 |
msleep(&node->sf_vnode, VBOXFS_NODE_MTX(node), |
186 |
0, "vsfE", 0); |
187 |
} |
188 |
goto loop1; |
189 |
} |
190 |
VBOXFS_NODE_UNLOCK(node); |
191 |
error = vget(vp, lkflag | LK_INTERLOCK, curthread); |
192 |
if (error == ENOENT) |
193 |
goto loop; |
194 |
if (error != 0) { |
195 |
vp = NULL; |
196 |
goto out; |
197 |
} |
198 |
|
199 |
/* |
200 |
* Make sure the vnode is still there after |
201 |
* getting the interlock to avoid racing a free. |
202 |
*/ |
203 |
if (node->sf_vnode == NULL || node->sf_vnode != vp) { |
204 |
vput(vp); |
205 |
goto loop; |
206 |
} |
207 |
|
208 |
goto out; |
209 |
} |
210 |
|
211 |
if ((node->sf_vpstate & VBOXFS_VNODE_DOOMED) || |
212 |
(node->sf_type == VDIR && node->sf_parent == NULL)) { |
213 |
VBOXFS_NODE_UNLOCK(node); |
214 |
error = ENOENT; |
215 |
vp = NULL; |
216 |
goto out; |
217 |
} |
218 |
|
219 |
/* |
220 |
* otherwise lock the vp list while we call getnewvnode |
221 |
* since that can block. |
222 |
*/ |
223 |
if (node->sf_vpstate & VBOXFS_VNODE_ALLOCATING) { |
224 |
node->sf_vpstate |= VBOXFS_VNODE_WANT; |
225 |
error = msleep((caddr_t) &node->sf_vpstate, |
226 |
VBOXFS_NODE_MTX(node), PDROP | PCATCH, |
227 |
"vboxfs_alloc_vp", 0); |
228 |
if (error) |
229 |
return error; |
230 |
|
231 |
goto loop; |
232 |
} else |
233 |
node->sf_vpstate |= VBOXFS_VNODE_ALLOCATING; |
234 |
|
235 |
VBOXFS_NODE_UNLOCK(node); |
236 |
|
237 |
/* Get a new vnode and associate it with our node. */ |
238 |
error = getnewvnode("vboxfs", mp, &vboxfs_vnodeops, &vp); |
239 |
if (error != 0) |
240 |
goto unlock; |
241 |
MPASS(vp != NULL); |
242 |
|
243 |
/* lkflag is ignored, the lock is exclusive */ |
244 |
(void) vn_lock(vp, lkflag | LK_RETRY); |
245 |
|
246 |
vp->v_data = node; |
247 |
vp->v_type = node->sf_type; |
248 |
|
249 |
/* Type-specific initialization. */ |
250 |
switch (node->sf_type) { |
251 |
case VBLK: |
252 |
/* FALLTHROUGH */ |
253 |
case VCHR: |
254 |
/* FALLTHROUGH */ |
255 |
case VLNK: |
256 |
/* FALLTHROUGH */ |
257 |
case VSOCK: |
258 |
/* FALLTHROUGH */ |
259 |
case VFIFO: |
260 |
/* FALLTHROUGH */ |
261 |
case VREG: |
262 |
break; |
263 |
case VDIR: |
264 |
MPASS(node->sf_parent != NULL); |
265 |
if (node->sf_parent == node) |
266 |
vp->v_vflag |= VV_ROOT; |
267 |
break; |
268 |
|
269 |
default: |
270 |
panic("vboxfs_alloc_vp: type %p %d", node, (int)node->sf_type); |
271 |
} |
272 |
|
273 |
if (vp->v_type != VFIFO) |
274 |
VN_LOCK_ASHARE(vp); |
275 |
|
276 |
error = insmntque1(vp, mp, vboxfs_insmntque_dtr, NULL); |
277 |
if (error) |
278 |
vp = NULL; |
279 |
|
280 |
unlock: |
281 |
VBOXFS_NODE_LOCK(node); |
282 |
|
283 |
MPASS(node->sf_vpstate & VBOXFS_VNODE_ALLOCATING); |
284 |
node->sf_vpstate &= ~VBOXFS_VNODE_ALLOCATING; |
285 |
node->sf_vnode = vp; |
286 |
|
287 |
if (node->sf_vpstate & VBOXFS_VNODE_WANT) { |
288 |
node->sf_vpstate &= ~VBOXFS_VNODE_WANT; |
289 |
VBOXFS_NODE_UNLOCK(node); |
290 |
wakeup((caddr_t) &node->sf_vpstate); |
291 |
} else |
292 |
VBOXFS_NODE_UNLOCK(node); |
293 |
|
294 |
out: |
295 |
*vpp = vp; |
296 |
|
297 |
#ifdef INVARIANTS |
298 |
if (error == 0) { |
299 |
MPASS(*vpp != NULL && VOP_ISLOCKED(*vpp)); |
300 |
VBOXFS_NODE_LOCK(node); |
301 |
MPASS(*vpp == node->sf_vnode); |
302 |
VBOXFS_NODE_UNLOCK(node); |
303 |
} |
304 |
#endif |
305 |
|
306 |
return error; |
125 |
} |
307 |
} |
126 |
|
308 |
|
127 |
static int vboxvfs_read(struct vop_read_args *ap) |
309 |
/* |
|
|
310 |
* Destroys the association between the vnode vp and the node it |
311 |
* references. |
312 |
*/ |
313 |
void |
314 |
vboxfs_free_vp(struct vnode *vp) |
128 |
{ |
315 |
{ |
129 |
return 0; |
316 |
struct vboxfs_node *node; |
|
|
317 |
|
318 |
node = VP_TO_VBOXFS_NODE(vp); |
319 |
|
320 |
VBOXFS_NODE_ASSERT_LOCKED(node); |
321 |
node->sf_vnode = NULL; |
322 |
if ((node->sf_vpstate & VBOXFS_VNODE_WRECLAIM) != 0) |
323 |
wakeup(&node->sf_vnode); |
324 |
node->sf_vpstate &= ~VBOXFS_VNODE_WRECLAIM; |
325 |
vp->v_data = NULL; |
130 |
} |
326 |
} |
131 |
|
327 |
|
132 |
static int vboxvfs_write(struct vop_write_args *ap) |
328 |
/* |
|
|
329 |
* Allocate new vboxfs_node and vnode for given file |
330 |
*/ |
331 |
static int |
332 |
vboxfs_alloc_file(struct vboxfs_mnt *vboxfsmp, const char *fullpath, |
333 |
enum vtype type, mode_t mode, struct vboxfs_node *parent, |
334 |
int lkflag, struct vnode **vpp) |
133 |
{ |
335 |
{ |
134 |
return 0; |
336 |
int error; |
|
|
337 |
struct vboxfs_node *unode; |
338 |
|
339 |
error = vboxfs_alloc_node(vboxfsmp->sf_vfsp, vboxfsmp, fullpath, type, |
340 |
vboxfsmp->sf_uid, vboxfsmp->sf_gid, mode, parent, &unode); |
341 |
|
342 |
if (error) |
343 |
goto out; |
344 |
|
345 |
error = vboxfs_alloc_vp(vboxfsmp->sf_vfsp, unode, lkflag, vpp); |
346 |
if (error) |
347 |
vboxfs_free_node(vboxfsmp, unode); |
348 |
|
349 |
out: |
350 |
return (error); |
135 |
} |
351 |
} |
136 |
|
352 |
|
137 |
static int vboxvfs_create(struct vop_create_args *ap) |
353 |
static int |
|
|
354 |
vboxfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags, |
355 |
struct vnode **rvp) |
138 |
{ |
356 |
{ |
139 |
return 0; |
357 |
|
|
|
358 |
return (vboxfs_alloc_vp(mp, arg, lkflags, rvp)); |
140 |
} |
359 |
} |
141 |
|
360 |
|
142 |
static int vboxvfs_remove(struct vop_remove_args *ap) |
361 |
/* |
|
|
362 |
* Construct a new pathname given an sfnode plus an optional tail |
363 |
* component of length len |
364 |
* This handles ".." and "." |
365 |
*/ |
366 |
static char * |
367 |
sfnode_construct_path(struct vboxfs_node *node, char *tail, int len) |
143 |
{ |
368 |
{ |
144 |
return 0; |
369 |
char *p; |
|
|
370 |
|
371 |
if (len <= 2 && tail[0] == '.' && (len == 1 || tail[1] == '.')) |
372 |
panic("construct path for %s", tail); |
373 |
p = malloc(strlen(node->sf_path) + 1 + len + 1, M_VBOXVFS, M_WAITOK); |
374 |
strcpy(p, node->sf_path); |
375 |
strcat(p, "/"); |
376 |
strcat(p, tail); |
377 |
return (p); |
145 |
} |
378 |
} |
146 |
|
379 |
|
147 |
static int vboxvfs_rename(struct vop_rename_args *ap) |
380 |
static int |
|
|
381 |
vboxfs_access(struct vop_access_args *ap) |
148 |
{ |
382 |
{ |
149 |
return 0; |
383 |
struct vnode *vp = ap->a_vp; |
|
|
384 |
accmode_t accmode = ap->a_accmode; |
385 |
struct vboxfs_node *node; |
386 |
int error; |
387 |
mode_t m; |
388 |
|
389 |
MPASS(VOP_ISLOCKED(vp)); |
390 |
|
391 |
node = VP_TO_VBOXFS_NODE(vp); |
392 |
|
393 |
if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { |
394 |
switch (vp->v_type) { |
395 |
case VDIR: |
396 |
case VLNK: |
397 |
case VREG: |
398 |
return (EROFS); |
399 |
/* NOT REACHED */ |
400 |
default: |
401 |
break; |
402 |
} |
403 |
} |
404 |
|
405 |
if (vsfnode_stat_cached(node)) |
406 |
error = 0; |
407 |
else |
408 |
error = vsfnode_update_stat_cache(node); |
409 |
m = (error == 0) ? node->sf_stat.sf_mode : 0; |
410 |
|
411 |
return (vaccess(vp->v_type, m, node->vboxfsmp->sf_uid, |
412 |
node->vboxfsmp->sf_gid, accmode, ap->a_cred)); |
150 |
} |
413 |
} |
151 |
|
414 |
|
152 |
static int vboxvfs_link(struct vop_link_args *ap) |
415 |
/* |
|
|
416 |
* Clears the (cached) directory listing for the node. |
417 |
*/ |
418 |
static void |
419 |
vfsnode_clear_dir_list(struct vboxfs_node *np) |
153 |
{ |
420 |
{ |
154 |
return EOPNOTSUPP; |
421 |
while (np->sf_dir_list != NULL) { |
|
|
422 |
sffs_dirents_t *next = np->sf_dir_list->sf_next; |
423 |
free(np->sf_dir_list, M_VBOXVFS); |
424 |
np->sf_dir_list = next; |
425 |
} |
155 |
} |
426 |
} |
156 |
|
427 |
|
157 |
static int vboxvfs_symlink(struct vop_symlink_args *ap) |
428 |
static int |
|
|
429 |
vboxfs_open(struct vop_open_args *ap) |
158 |
{ |
430 |
{ |
159 |
return EOPNOTSUPP; |
431 |
struct vboxfs_node *np; |
|
|
432 |
sfp_file_t *fp; |
433 |
int error; |
434 |
|
435 |
MPASS(VOP_ISLOCKED(vp)); |
436 |
|
437 |
np = VP_TO_VBOXFS_NODE(ap->a_vp); |
438 |
error = sfprov_open(np->vboxfsmp->sf_handle, np->sf_path, &fp); |
439 |
if (error != 0) |
440 |
goto out; |
441 |
|
442 |
np->sf_file = fp; |
443 |
vnode_create_vobject(ap->a_vp, 0, ap->a_td); |
444 |
|
445 |
out: |
446 |
MPASS(VOP_ISLOCKED(vp)); |
447 |
|
448 |
return (error); |
160 |
} |
449 |
} |
161 |
|
450 |
|
162 |
static int vboxvfs_mknod(struct vop_mknod_args *ap) |
451 |
static void |
|
|
452 |
vfsnode_invalidate_stat_cache(struct vboxfs_node *np) |
163 |
{ |
453 |
{ |
164 |
return EOPNOTSUPP; |
454 |
np->sf_stat_time = 0; |
165 |
} |
455 |
} |
166 |
|
456 |
|
167 |
static int vboxvfs_mkdir(struct vop_mkdir_args *ap) |
457 |
static int |
|
|
458 |
vboxfs_close(struct vop_close_args *ap) |
168 |
{ |
459 |
{ |
169 |
return 0; |
460 |
struct vnode *vp = ap->a_vp; |
|
|
461 |
struct vboxfs_node *np; |
462 |
|
463 |
np = VP_TO_VBOXFS_NODE(vp); |
464 |
|
465 |
/* |
466 |
* Free the directory entries for the node. We do this on this call |
467 |
* here because the directory node may not become inactive for a long |
468 |
* time after the readdir is over. Case in point, if somebody cd's into |
469 |
* the directory then it won't become inactive until they cd away again. |
470 |
* In such a case we would end up with the directory listing not getting |
471 |
* updated (i.e. the result of 'ls' always being the same) until they |
472 |
* change the working directory. |
473 |
*/ |
474 |
vfsnode_clear_dir_list(np); |
475 |
|
476 |
vfsnode_invalidate_stat_cache(np); |
477 |
|
478 |
if (np->sf_file != NULL && vp->v_usecount <= 1) { |
479 |
(void) sfprov_close(np->sf_file); |
480 |
np->sf_file = NULL; |
481 |
} |
482 |
|
483 |
return (0); |
170 |
} |
484 |
} |
171 |
|
485 |
|
172 |
static int vboxvfs_rmdir(struct vop_rmdir_args *ap) |
486 |
static int |
|
|
487 |
vboxfs_getattr(struct vop_getattr_args *ap) |
173 |
{ |
488 |
{ |
174 |
return 0; |
489 |
struct vnode *vp = ap->a_vp; |
|
|
490 |
struct vattr *vap = ap->a_vap; |
491 |
struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); |
492 |
struct vboxfs_mnt *mp = np->vboxfsmp; |
493 |
mode_t mode; |
494 |
int error = 0; |
495 |
|
496 |
mode = 0; |
497 |
vap->va_type = vp->v_type; |
498 |
|
499 |
vap->va_nlink = 1; /* number of references to file */ |
500 |
vap->va_uid = mp->sf_uid; /* owner user id */ |
501 |
vap->va_gid = mp->sf_gid; /* owner group id */ |
502 |
vap->va_rdev = NODEV; /* device the special file represents */ |
503 |
vap->va_gen = VNOVAL; /* generation number of file */ |
504 |
vap->va_flags = 0; /* flags defined for file */ |
505 |
vap->va_filerev = 0; /* file modification number */ |
506 |
vap->va_vaflags = 0; /* operations flags */ |
507 |
vap->va_fileid = np->sf_ino; /* file id */ |
508 |
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; |
509 |
if (vap->va_fileid == 0) |
510 |
vap->va_fileid = 2; |
511 |
|
512 |
vap->va_atime.tv_sec = VNOVAL; |
513 |
vap->va_atime.tv_nsec = VNOVAL; |
514 |
vap->va_mtime.tv_sec = VNOVAL; |
515 |
vap->va_mtime.tv_nsec = VNOVAL; |
516 |
vap->va_ctime.tv_sec = VNOVAL; |
517 |
vap->va_ctime.tv_nsec = VNOVAL; |
518 |
|
519 |
if (!vsfnode_stat_cached(np)) { |
520 |
error = vsfnode_update_stat_cache(np); |
521 |
if (error != 0) |
522 |
goto done; |
523 |
} |
524 |
|
525 |
vap->va_atime = np->sf_stat.sf_atime; |
526 |
vap->va_mtime = np->sf_stat.sf_mtime; |
527 |
vap->va_ctime = np->sf_stat.sf_ctime; |
528 |
|
529 |
mode = np->sf_stat.sf_mode; |
530 |
|
531 |
vap->va_mode = mode; |
532 |
if (S_ISDIR(mode)) { |
533 |
vap->va_type = VDIR; /* vnode type (for create) */ |
534 |
vap->va_mode = mp->sf_dmode != 0 ? (mp->sf_dmode & 0777) : vap->va_mode; |
535 |
vap->va_mode &= ~mp->sf_dmask; |
536 |
vap->va_mode |= S_IFDIR; |
537 |
} else if (S_ISREG(mode)) { |
538 |
vap->va_type = VREG; |
539 |
vap->va_mode = mp->sf_fmode != 0 ? (mp->sf_fmode & 0777) : vap->va_mode; |
540 |
vap->va_mode &= ~mp->sf_fmask; |
541 |
vap->va_mode |= S_IFREG; |
542 |
} else if (S_ISFIFO(mode)) |
543 |
vap->va_type = VFIFO; |
544 |
else if (S_ISCHR(mode)) |
545 |
vap->va_type = VCHR; |
546 |
else if (S_ISBLK(mode)) |
547 |
vap->va_type = VBLK; |
548 |
else if (S_ISLNK(mode)) { |
549 |
vap->va_type = VLNK; |
550 |
vap->va_mode = mp->sf_fmode != 0 ? (mp->sf_fmode & 0777) : vap->va_mode; |
551 |
vap->va_mode &= ~mp->sf_fmask; |
552 |
vap->va_mode |= S_IFLNK; |
553 |
} else if (S_ISSOCK(mode)) |
554 |
vap->va_type = VSOCK; |
555 |
|
556 |
vap->va_size = np->sf_stat.sf_size; |
557 |
vap->va_blocksize = 512; |
558 |
/* bytes of disk space held by file */ |
559 |
vap->va_bytes = (np->sf_stat.sf_alloc + 511) / 512; |
560 |
|
561 |
done: |
562 |
return (error); |
175 |
} |
563 |
} |
176 |
|
564 |
|
177 |
static int vboxvfs_readdir(struct vop_readdir_args *ap) |
565 |
static int |
|
|
566 |
vboxfs_setattr(struct vop_setattr_args *ap) |
178 |
{ |
567 |
{ |
179 |
return 0; |
568 |
struct vnode *vp = ap->a_vp; |
|
|
569 |
struct vattr *vap = ap->a_vap; |
570 |
struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); |
571 |
int error; |
572 |
mode_t mode; |
573 |
|
574 |
mode = vap->va_mode; |
575 |
if (vp->v_type == VREG) |
576 |
mode |= S_IFREG; |
577 |
else if (vp->v_type == VDIR) |
578 |
mode |= S_IFDIR; |
579 |
else if (vp->v_type == VBLK) |
580 |
mode |= S_IFBLK; |
581 |
else if (vp->v_type == VCHR) |
582 |
mode |= S_IFCHR; |
583 |
else if (vp->v_type == VLNK) |
584 |
mode |= S_IFLNK; |
585 |
else if (vp->v_type == VFIFO) |
586 |
mode |= S_IFIFO; |
587 |
else if (vp->v_type == VSOCK) |
588 |
mode |= S_IFSOCK; |
589 |
|
590 |
vfsnode_invalidate_stat_cache(np); |
591 |
|
592 |
error = sfprov_set_attr(np->vboxfsmp->sf_handle, np->sf_path, |
593 |
mode, vap->va_atime, vap->va_mtime, vap->va_ctime); |
594 |
#if 0 |
595 |
if (error == ENOENT) |
596 |
sfnode_make_stale(np); |
597 |
#endif |
598 |
if (vap->va_size != (u_quad_t)VNOVAL) { |
599 |
switch (vp->v_type) { |
600 |
case VDIR: |
601 |
return (EISDIR); |
602 |
case VLNK: |
603 |
/* FALLTHROUGH */ |
604 |
case VREG: |
605 |
error = sfprov_set_size(np->vboxfsmp->sf_handle, np->sf_path, vap->va_size); |
606 |
break; |
607 |
case VCHR: |
608 |
/* FALLTHROUGH */ |
609 |
case VBLK: |
610 |
/* FALLTHROUGH */ |
611 |
case VSOCK: |
612 |
/* FALLTHROUGH */ |
613 |
case VFIFO: |
614 |
/* FALLTHROUGH */ |
615 |
case VNON: |
616 |
/* FALLTHROUGH */ |
617 |
case VBAD: |
618 |
/* FALLTHROUGH */ |
619 |
case VMARKER: |
620 |
return (0); |
621 |
} |
622 |
} |
623 |
|
624 |
return (error); |
180 |
} |
625 |
} |
181 |
|
626 |
|
182 |
static int vboxvfs_fsync(struct vop_fsync_args *ap) |
627 |
#define blkoff(vboxfsmp, loc) ((loc) & (vboxfsmp)->bmask) |
|
|
628 |
|
629 |
static int |
630 |
vboxfs_read(struct vop_read_args *ap) |
183 |
{ |
631 |
{ |
184 |
return 0; |
632 |
struct vnode *vp = ap->a_vp; |
|
|
633 |
struct uio *uio = ap->a_uio; |
634 |
struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); |
635 |
int error = 0; |
636 |
uint32_t bytes; |
637 |
uint32_t done; |
638 |
unsigned long offset; |
639 |
ssize_t total; |
640 |
void *tmpbuf; |
641 |
|
642 |
if (vp->v_type == VDIR) |
643 |
return (EISDIR); |
644 |
|
645 |
if (vp->v_type != VREG) |
646 |
return (EINVAL); |
647 |
|
648 |
if (uio->uio_offset < 0) |
649 |
return (EINVAL); |
650 |
|
651 |
total = uio->uio_resid; |
652 |
if (total == 0) |
653 |
return (0); |
654 |
|
655 |
/* |
656 |
* XXXGONZO: this is just to get things working |
657 |
* should be optimized |
658 |
*/ |
659 |
tmpbuf = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK, 0, ~0, PAGE_SIZE, 0); |
660 |
if (tmpbuf == 0) |
661 |
return (ENOMEM); |
662 |
|
663 |
do { |
664 |
offset = uio->uio_offset; |
665 |
done = bytes = min(PAGE_SIZE, uio->uio_resid); |
666 |
error = sfprov_read(np->sf_file, tmpbuf, |
667 |
offset, &done, 0); |
668 |
if (error == 0 && done > 0) |
669 |
error = uiomove(tmpbuf, done, uio); |
670 |
} while (error == 0 && uio->uio_resid > 0 && done > 0); |
671 |
|
672 |
contigfree(tmpbuf, PAGE_SIZE, M_DEVBUF); |
673 |
|
674 |
/* a partial read is never an error */ |
675 |
if (total != uio->uio_resid) |
676 |
error = 0; |
677 |
|
678 |
return (error); |
185 |
} |
679 |
} |
186 |
|
680 |
|
187 |
static int vboxvfs_print (struct vop_print_args *ap) |
681 |
static int |
|
|
682 |
vboxfs_write(struct vop_write_args *ap) |
188 |
{ |
683 |
{ |
189 |
return 0; |
684 |
struct vnode *vp = ap->a_vp; |
|
|
685 |
struct uio *uio = ap->a_uio; |
686 |
struct vboxfs_node *np = VP_TO_VBOXFS_NODE(vp); |
687 |
int error = 0; |
688 |
uint32_t bytes; |
689 |
uint32_t done; |
690 |
unsigned long offset; |
691 |
ssize_t total; |
692 |
void *tmpbuf; |
693 |
|
694 |
if (vp->v_type == VDIR) |
695 |
return (EISDIR); |
696 |
|
697 |
if (vp->v_type != VREG) |
698 |
return (EINVAL); |
699 |
|
700 |
if (uio->uio_offset < 0) |
701 |
return (EINVAL); |
702 |
|
703 |
total = uio->uio_resid; |
704 |
if (total == 0) |
705 |
return (0); |
706 |
|
707 |
/* |
708 |
* XXXGONZO: this is just to get things working |
709 |
* should be optimized |
710 |
*/ |
711 |
tmpbuf = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK, 0, ~0, PAGE_SIZE, 0); |
712 |
if (tmpbuf == 0) |
713 |
return (ENOMEM); |
714 |
|
715 |
do { |
716 |
offset = uio->uio_offset; |
717 |
bytes = min(PAGE_SIZE, uio->uio_resid); |
718 |
error = uiomove(tmpbuf, bytes, uio); |
719 |
if (error != 0) |
720 |
break; |
721 |
done = bytes; |
722 |
error = sfprov_write(np->sf_file, tmpbuf, |
723 |
offset, &done, 0); |
724 |
if (error != 0) |
725 |
break; |
726 |
total -= done; |
727 |
if (done != bytes) |
728 |
uio->uio_resid += bytes - done; |
729 |
} while (error == 0 && uio->uio_resid > 0 && done > 0); |
730 |
|
731 |
contigfree(tmpbuf, PAGE_SIZE, M_DEVBUF); |
732 |
|
733 |
/* a partial write is never an error */ |
734 |
if (total != uio->uio_resid) |
735 |
error = 0; |
736 |
|
737 |
return (error); |
190 |
} |
738 |
} |
191 |
|
739 |
|
192 |
static int vboxvfs_pathconf (struct vop_pathconf_args *ap) |
740 |
static int |
|
|
741 |
vboxfs_create(struct vop_create_args *ap) |
193 |
{ |
742 |
{ |
194 |
return 0; |
743 |
struct vnode *dvp = ap->a_dvp; |
|
|
744 |
struct vnode **vpp = ap->a_vpp; |
745 |
struct componentname *cnp = ap->a_cnp; |
746 |
struct vattr *vap = ap->a_vap; |
747 |
sffs_stat_t stat; |
748 |
char *fullpath = NULL; |
749 |
struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(dvp); |
750 |
sfp_file_t *fp; |
751 |
int error; |
752 |
struct vboxfs_mnt *vboxfsmp = dir->vboxfsmp; |
753 |
|
754 |
MPASS(vap->va_type == VREG); |
755 |
|
756 |
fullpath = sfnode_construct_path(dir, cnp->cn_nameptr, cnp->cn_namelen); |
757 |
error = sfprov_create(dir->vboxfsmp->sf_handle, fullpath, vap->va_mode, |
758 |
&fp, &stat); |
759 |
|
760 |
if (error) |
761 |
goto out; |
762 |
|
763 |
error = vboxfs_alloc_file(vboxfsmp, fullpath, VREG, vap->va_mode, dir, cnp->cn_lkflags, vpp); |
764 |
|
765 |
out: |
766 |
if (fullpath) |
767 |
free(fullpath, M_VBOXVFS); |
768 |
|
769 |
if (error == 0) { |
770 |
vfsnode_clear_dir_list(dir); |
771 |
if ((cnp->cn_flags & MAKEENTRY) != 0) |
772 |
cache_enter(dvp, *vpp, cnp); |
773 |
} |
774 |
|
775 |
return (error); |
195 |
} |
776 |
} |
196 |
|
777 |
|
197 |
static int vboxvfs_strategy (struct vop_strategy_args *ap) |
778 |
static int |
|
|
779 |
vboxfs_remove(struct vop_remove_args *ap) |
198 |
{ |
780 |
{ |
199 |
return 0; |
781 |
struct vnode *dvp = ap->a_dvp; |
|
|
782 |
struct vnode *vp = ap->a_vp; |
783 |
struct vboxfs_node *np, *dir; |
784 |
|
785 |
int error; |
786 |
|
787 |
MPASS(VOP_ISLOCKED(dvp)); |
788 |
MPASS(VOP_ISLOCKED(vp)); |
789 |
|
790 |
error = 0; |
791 |
|
792 |
np = VP_TO_VBOXFS_NODE(vp); |
793 |
dir = VP_TO_VBOXFS_NODE(vp); |
794 |
|
795 |
/* |
796 |
* If anything else is using this vnode, then fail the remove. |
797 |
* Why? Windows hosts can't sfprov_remove() a file that is open, |
798 |
* so we have to sfprov_close() it first. |
799 |
* There is no errno for this - since it's not a problem on UNIX, |
800 |
* but ETXTBSY is the closest. |
801 |
*/ |
802 |
if (np->sf_file != NULL) { |
803 |
if (vp->v_usecount > 1) { |
804 |
error = ETXTBSY; |
805 |
goto out; |
806 |
} |
807 |
sfprov_close(np->sf_file); |
808 |
np->sf_file = NULL; |
809 |
} |
810 |
|
811 |
error = sfprov_remove(np->vboxfsmp->sf_handle, np->sf_path, |
812 |
np->sf_type == VLNK); |
813 |
|
814 |
#if 0 |
815 |
if (error == ENOENT || error == 0) |
816 |
sfnode_make_stale(np); |
817 |
#endif |
818 |
|
819 |
if (error == 0) |
820 |
vfsnode_clear_dir_list(dir); |
821 |
|
822 |
out: |
823 |
return (error); |
200 |
} |
824 |
} |
201 |
|
825 |
|
202 |
static int vboxvfs_ioctl(struct vop_ioctl_args *ap) |
826 |
static int |
|
|
827 |
vboxfs_rename(struct vop_rename_args *ap) |
203 |
{ |
828 |
{ |
204 |
return ENOTTY; |
829 |
struct vnode *fvp; |
|
|
830 |
struct vnode *fdvp; |
831 |
struct vnode *tvp; |
832 |
struct vnode *tdvp; |
833 |
struct componentname *fcnp; |
834 |
struct componentname *tcnp; |
835 |
struct vboxfs_node *np; |
836 |
int ret; |
837 |
|
838 |
fvp = ap->a_fvp; |
839 |
fdvp = ap->a_fdvp; |
840 |
tvp = ap->a_tvp; |
841 |
tdvp = ap->a_tdvp; |
842 |
fcnp = ap->a_fcnp; |
843 |
tcnp = ap->a_tcnp; |
844 |
|
845 |
/* Check for cross-device rename */ |
846 |
if ((fvp->v_mount != tdvp->v_mount) || |
847 |
(tvp && (fvp->v_mount != tvp->v_mount))) { |
848 |
ret = EXDEV; |
849 |
goto out; |
850 |
} |
851 |
np = VP_TO_VBOXFS_NODE(fvp); |
852 |
if (np == NULL) |
853 |
return (0); |
854 |
ret = sfprov_rename(np->vboxfsmp->sf_handle, |
855 |
fcnp->cn_nameptr, tcnp->cn_nameptr, fvp->v_type == VDIR); |
856 |
out: |
857 |
if (tdvp == tvp) |
858 |
vrele(tdvp); |
859 |
else |
860 |
vput(tdvp); |
861 |
if (tvp) |
862 |
vput(tvp); |
863 |
vrele(fdvp); |
864 |
vrele(fvp); |
865 |
return (ret); |
205 |
} |
866 |
} |
206 |
|
867 |
|
207 |
static int vboxvfs_getextattr(struct vop_getextattr_args *ap) |
868 |
static int |
|
|
869 |
vboxfs_link(struct vop_link_args *ap) |
208 |
{ |
870 |
{ |
209 |
return 0; |
871 |
return (EOPNOTSUPP); |
210 |
} |
872 |
} |
211 |
|
873 |
|
212 |
static int vboxvfs_advlock(struct vop_advlock_args *ap) |
874 |
static int |
|
|
875 |
vboxfs_symlink(struct vop_symlink_args *ap) |
213 |
{ |
876 |
{ |
214 |
return 0; |
877 |
struct vnode *dvp = ap->a_dvp; |
|
|
878 |
struct vnode **vpp = ap->a_vpp; |
879 |
struct componentname *cnp = ap->a_cnp; |
880 |
struct vattr *vap = ap->a_vap; |
881 |
sffs_stat_t stat; |
882 |
char *fullpath = NULL; |
883 |
struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(dvp); |
884 |
int error; |
885 |
struct vboxfs_mnt *vboxfsmp = dir->vboxfsmp; |
886 |
|
887 |
MPASS(vap->va_type == VLNK); |
888 |
|
889 |
fullpath = sfnode_construct_path(dir, cnp->cn_nameptr, cnp->cn_namelen); |
890 |
error = sfprov_symlink(dir->vboxfsmp->sf_handle, fullpath, ap->a_target, &stat); |
891 |
|
892 |
if (error) |
893 |
goto out; |
894 |
|
895 |
error = vboxfs_alloc_file(vboxfsmp, fullpath, VLNK, vap->va_mode, dir, cnp->cn_lkflags, vpp); |
896 |
|
897 |
out: |
898 |
if (fullpath) |
899 |
free(fullpath, M_VBOXVFS); |
900 |
|
901 |
if (error == 0) |
902 |
vfsnode_clear_dir_list(dir); |
903 |
|
904 |
return (error); |
215 |
} |
905 |
} |
216 |
|
906 |
|
217 |
static int vboxvfs_lookup(struct vop_lookup_args *ap) |
907 |
static int |
|
|
908 |
vboxfs_mkdir(struct vop_mkdir_args *ap) |
218 |
{ |
909 |
{ |
219 |
return 0; |
910 |
struct vnode *dvp = ap->a_dvp; |
|
|
911 |
struct vnode **vpp = ap->a_vpp; |
912 |
struct componentname *cnp = ap->a_cnp; |
913 |
struct vattr *vap = ap->a_vap; |
914 |
sffs_stat_t stat; |
915 |
char *fullpath = NULL; |
916 |
struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(dvp); |
917 |
sfp_file_t *fp; |
918 |
int error; |
919 |
struct vboxfs_mnt *vboxfsmp = dir->vboxfsmp; |
920 |
|
921 |
MPASS(vap->va_type == VDIR); |
922 |
|
923 |
fullpath = sfnode_construct_path(dir, cnp->cn_nameptr, cnp->cn_namelen); |
924 |
error = sfprov_mkdir(dir->vboxfsmp->sf_handle, fullpath, vap->va_mode, |
925 |
&fp, &stat); |
926 |
|
927 |
if (error) |
928 |
goto out; |
929 |
|
930 |
error = vboxfs_alloc_file(vboxfsmp, fullpath, VDIR, vap->va_mode, dir, cnp->cn_lkflags, vpp); |
931 |
|
932 |
out: |
933 |
if (fullpath) |
934 |
free(fullpath, M_VBOXVFS); |
935 |
|
936 |
if (error == 0) |
937 |
vfsnode_clear_dir_list(dir); |
938 |
|
939 |
return (error); |
220 |
} |
940 |
} |
221 |
|
941 |
|
222 |
static int vboxvfs_inactive(struct vop_inactive_args *ap) |
942 |
static int |
|
|
943 |
vboxfs_rmdir(struct vop_rmdir_args *ap) |
223 |
{ |
944 |
{ |
224 |
return 0; |
945 |
struct vnode *dvp = ap->a_dvp; |
|
|
946 |
struct vnode *vp = ap->a_vp; |
947 |
struct vboxfs_node *np, *dir; |
948 |
|
949 |
int error; |
950 |
|
951 |
MPASS(VOP_ISLOCKED(dvp)); |
952 |
MPASS(VOP_ISLOCKED(vp)); |
953 |
|
954 |
error = 0; |
955 |
|
956 |
np = VP_TO_VBOXFS_NODE(vp); |
957 |
dir = VP_TO_VBOXFS_NODE(vp); |
958 |
|
959 |
/* |
960 |
* If anything else is using this vnode, then fail the remove. |
961 |
* Why? Windows hosts can't sfprov_remove() a file that is open, |
962 |
* so we have to sfprov_close() it first. |
963 |
* There is no errno for this - since it's not a problem on UNIX, |
964 |
* but ETXTBSY is the closest. |
965 |
*/ |
966 |
if (np->sf_file != NULL) { |
967 |
if (vp->v_usecount > 1) { |
968 |
error = ETXTBSY; |
969 |
goto out; |
970 |
} |
971 |
sfprov_close(np->sf_file); |
972 |
np->sf_file = NULL; |
973 |
} |
974 |
|
975 |
error = sfprov_rmdir(np->vboxfsmp->sf_handle, np->sf_path); |
976 |
|
977 |
#if 0 |
978 |
if (error == ENOENT || error == 0) |
979 |
sfnode_make_stale(np); |
980 |
#endif |
981 |
|
982 |
if (error == 0) |
983 |
vfsnode_clear_dir_list(dir); |
984 |
|
985 |
out: |
986 |
return (error); |
225 |
} |
987 |
} |
226 |
|
988 |
|
227 |
static int vboxvfs_reclaim(struct vop_reclaim_args *ap) |
989 |
static int |
|
|
990 |
vboxfs_readdir(struct vop_readdir_args *ap) |
228 |
{ |
991 |
{ |
229 |
return 0; |
992 |
int *eofp = ap->a_eofflag; |
|
|
993 |
struct vnode *vp = ap->a_vp; |
994 |
struct uio *uio = ap->a_uio; |
995 |
struct vboxfs_node *dir = VP_TO_VBOXFS_NODE(vp); |
996 |
struct vboxfs_node *node; |
997 |
struct sffs_dirent *dirent = NULL; |
998 |
sffs_dirents_t *cur_buf; |
999 |
off_t offset = 0; |
1000 |
off_t orig_off = uio->uio_offset; |
1001 |
int error = 0; |
1002 |
int dummy_eof; |
1003 |
|
1004 |
if (vp->v_type != VDIR) |
1005 |
return (ENOTDIR); |
1006 |
|
1007 |
if (eofp == NULL) |
1008 |
eofp = &dummy_eof; |
1009 |
*eofp = 0; |
1010 |
|
1011 |
/* |
1012 |
* Get the directory entry names from the host. This gets all |
1013 |
* entries. These are stored in a linked list of sffs_dirents_t |
1014 |
* buffers, each of which contains a list of dirent64_t's. |
1015 |
*/ |
1016 |
if (dir->sf_dir_list == NULL) { |
1017 |
error = sfprov_readdir(dir->vboxfsmp->sf_handle, dir->sf_path, |
1018 |
&dir->sf_dir_list); |
1019 |
if (error != 0) |
1020 |
goto done; |
1021 |
} |
1022 |
|
1023 |
/* |
1024 |
* Validate and skip to the desired offset. |
1025 |
*/ |
1026 |
cur_buf = dir->sf_dir_list; |
1027 |
offset = 0; |
1028 |
|
1029 |
while (cur_buf != NULL && offset + cur_buf->sf_len <= uio->uio_offset) { |
1030 |
offset += cur_buf->sf_len; |
1031 |
cur_buf = cur_buf->sf_next; |
1032 |
} |
1033 |
|
1034 |
if (cur_buf == NULL && offset != uio->uio_offset) { |
1035 |
error = EINVAL; |
1036 |
goto done; |
1037 |
} |
1038 |
|
1039 |
if (cur_buf != NULL && offset != uio->uio_offset) { |
1040 |
off_t off = offset; |
1041 |
int step; |
1042 |
dirent = &cur_buf->sf_entries[0]; |
1043 |
|
1044 |
while (off < uio->uio_offset) { |
1045 |
if (dirent->sf_off == uio->uio_offset) |
1046 |
break; |
1047 |
step = sizeof(struct sffs_dirent) + dirent->sf_entry.d_reclen; |
1048 |
dirent = (struct sffs_dirent *) (((char *) dirent) + step); |
1049 |
off += step; |
1050 |
} |
1051 |
|
1052 |
if (off >= uio->uio_offset) { |
1053 |
error = EINVAL; |
1054 |
goto done; |
1055 |
} |
1056 |
} |
1057 |
|
1058 |
offset = uio->uio_offset - offset; |
1059 |
|
1060 |
/* |
1061 |
* Lookup each of the names, so that we have ino's, and copy to |
1062 |
* result buffer. |
1063 |
*/ |
1064 |
while (cur_buf != NULL) { |
1065 |
if (offset >= cur_buf->sf_len) { |
1066 |
cur_buf = cur_buf->sf_next; |
1067 |
offset = 0; |
1068 |
continue; |
1069 |
} |
1070 |
|
1071 |
dirent = (struct sffs_dirent *) |
1072 |
(((char *) &cur_buf->sf_entries[0]) + offset); |
1073 |
if (dirent->sf_entry.d_reclen > uio->uio_resid) |
1074 |
break; |
1075 |
|
1076 |
if (strcmp(dirent->sf_entry.d_name, ".") == 0) { |
1077 |
node = dir; |
1078 |
} else if (strcmp(dirent->sf_entry.d_name, "..") == 0) { |
1079 |
node = dir->sf_parent; |
1080 |
if (node == NULL) |
1081 |
node = dir; |
1082 |
} else { |
1083 |
#if 0 |
1084 |
node = vsfnode_lookup(dir, dirent->sf_entry.d_name, VNON, |
1085 |
0, &dirent->sf_stat, vsfnode_cur_time_usec(), NULL); |
1086 |
if (node == NULL) |
1087 |
panic("sffs_readdir() lookup failed"); |
1088 |
#endif |
1089 |
} |
1090 |
|
1091 |
if (node) |
1092 |
dirent->sf_entry.d_fileno = node->sf_ino; |
1093 |
else |
1094 |
dirent->sf_entry.d_fileno = 0xdeadbeef; |
1095 |
|
1096 |
error = uiomove(&dirent->sf_entry, dirent->sf_entry.d_reclen, uio); |
1097 |
if (error != 0) |
1098 |
break; |
1099 |
|
1100 |
uio->uio_offset = dirent->sf_off; |
1101 |
offset += sizeof(struct sffs_dirent) + dirent->sf_entry.d_reclen; |
1102 |
} |
1103 |
|
1104 |
if (error == 0 && cur_buf == NULL) |
1105 |
*eofp = 1; |
1106 |
done: |
1107 |
if (error != 0) |
1108 |
uio->uio_offset = orig_off; |
1109 |
return (error); |
230 |
} |
1110 |
} |
231 |
|
1111 |
|
232 |
static int vboxvfs_getpages(struct vop_getpages_args *ap) |
1112 |
static int |
|
|
1113 |
vboxfs_readlink(struct vop_readlink_args *v) |
233 |
{ |
1114 |
{ |
234 |
return 0; |
1115 |
struct vnode *vp = v->a_vp; |
|
|
1116 |
struct uio *uio = v->a_uio; |
1117 |
|
1118 |
int error; |
1119 |
struct vboxfs_node *np; |
1120 |
void *tmpbuf; |
1121 |
|
1122 |
MPASS(uio->uio_offset == 0); |
1123 |
MPASS(vp->v_type == VLNK); |
1124 |
|
1125 |
np = VP_TO_VBOXFS_NODE(vp); |
1126 |
|
1127 |
tmpbuf = contigmalloc(MAXPATHLEN, M_DEVBUF, M_WAITOK, 0, ~0, 1, 0); |
1128 |
if (tmpbuf == NULL) |
1129 |
return (ENOMEM); |
1130 |
|
1131 |
error = sfprov_readlink(np->vboxfsmp->sf_handle, np->sf_path, tmpbuf, |
1132 |
MAXPATHLEN); |
1133 |
if (error) |
1134 |
goto done; |
1135 |
|
1136 |
error = uiomove(tmpbuf, strlen(tmpbuf), uio); |
1137 |
|
1138 |
done: |
1139 |
if (tmpbuf) |
1140 |
contigfree(tmpbuf, MAXPATHLEN, M_DEVBUF); |
1141 |
return (error); |
235 |
} |
1142 |
} |
236 |
|
1143 |
|
237 |
static int vboxvfs_putpages(struct vop_putpages_args *ap) |
1144 |
static int |
|
|
1145 |
vboxfs_fsync(struct vop_fsync_args *ap) |
238 |
{ |
1146 |
{ |
239 |
return 0; |
1147 |
struct vnode *vp; |
|
|
1148 |
struct vboxfs_node *np; |
1149 |
int ret; |
1150 |
|
1151 |
vp = ap->a_vp; |
1152 |
np = VP_TO_VBOXFS_NODE(vp); |
1153 |
if (np == NULL) |
1154 |
return (0); |
1155 |
ret = sfprov_fsync(np->sf_file); |
1156 |
return (ret); |
240 |
} |
1157 |
} |
241 |
|
1158 |
|
|
|
1159 |
static int |
1160 |
vboxfs_print(struct vop_print_args *ap) |
1161 |
{ |
1162 |
struct vnode *vp = ap->a_vp; |
1163 |
struct vboxfs_node *np; |
1164 |
|
1165 |
np = VP_TO_VBOXFS_NODE(vp); |
1166 |
|
1167 |
if (np == NULL) { |
1168 |
printf("No vboxfs_node data\n"); |
1169 |
return (0); |
1170 |
} |
1171 |
|
1172 |
printf("\tpath = %s, parent = %p", np->sf_path, |
1173 |
np->sf_parent ? np->sf_parent : NULL); |
1174 |
printf("\n"); |
1175 |
return (0); |
1176 |
} |
1177 |
|
1178 |
static int |
1179 |
vboxfs_pathconf(struct vop_pathconf_args *ap) |
1180 |
{ |
1181 |
register_t *retval = ap->a_retval; |
1182 |
int error = 0; |
1183 |
|
1184 |
switch (ap->a_name) { |
1185 |
case _PC_LINK_MAX: |
1186 |
*retval = 65535; |
1187 |
break; |
1188 |
case _PC_NAME_MAX: |
1189 |
*retval = NAME_MAX; |
1190 |
break; |
1191 |
case _PC_PATH_MAX: |
1192 |
*retval = PATH_MAX; |
1193 |
break; |
1194 |
default: |
1195 |
error = EINVAL; |
1196 |
break; |
1197 |
} |
1198 |
return (error); |
1199 |
} |
1200 |
|
1201 |
/* |
1202 |
* File specific ioctls. |
1203 |
*/ |
1204 |
static int |
1205 |
vboxfs_ioctl(struct vop_ioctl_args *ap) |
1206 |
{ |
1207 |
return (ENOTTY); |
1208 |
} |
1209 |
|
1210 |
/* |
1211 |
* Lookup an entry in a directory and create a new vnode if found. |
1212 |
*/ |
1213 |
static int |
1214 |
vboxfs_lookup(struct vop_cachedlookup_args /* { |
1215 |
struct vnodeop_desc *a_desc; |
1216 |
struct vnode *a_dvp; |
1217 |
struct vnode **a_vpp; |
1218 |
struct componentname *a_cnp; |
1219 |
} */ *ap) |
1220 |
{ |
1221 |
struct componentname *cnp = ap->a_cnp; |
1222 |
struct vnode *dvp = ap->a_dvp; /* the directory vnode */ |
1223 |
char *nameptr = cnp->cn_nameptr; /* the name of the file or directory */ |
1224 |
struct vnode **vpp = ap->a_vpp; /* the vnode we found or NULL */ |
1225 |
struct vnode *tdp = NULL; |
1226 |
struct vboxfs_node *node = VP_TO_VBOXFS_NODE(dvp); |
1227 |
struct vboxfs_mnt *vboxfsmp = node->vboxfsmp; |
1228 |
u_long nameiop = cnp->cn_nameiop; |
1229 |
u_long flags = cnp->cn_flags; |
1230 |
sffs_stat_t stat; |
1231 |
//long namelen; |
1232 |
ino_t id = 0; |
1233 |
int ltype, type, error = 0; |
1234 |
int lkflags = cnp->cn_lkflags; |
1235 |
char *fullpath = NULL; |
1236 |
|
1237 |
error = ENOENT; |
1238 |
if (cnp->cn_flags & ISDOTDOT) { |
1239 |
error = vn_vget_ino_gen(dvp, vboxfs_vn_get_ino_alloc, |
1240 |
node->sf_parent, cnp->cn_lkflags, vpp); |
1241 |
error = ENOENT; |
1242 |
if (error != 0) |
1243 |
goto out; |
1244 |
|
1245 |
} else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { |
1246 |
VREF(dvp); |
1247 |
*vpp = dvp; |
1248 |
error = 0; |
1249 |
} else { |
1250 |
mode_t m; |
1251 |
type = VNON; |
1252 |
fullpath = sfnode_construct_path(node, cnp->cn_nameptr, cnp->cn_namelen); |
1253 |
error = sfprov_get_attr(node->vboxfsmp->sf_handle, |
1254 |
fullpath, &stat); |
1255 |
// stat_time = vsfnode_cur_time_usec(); |
1256 |
|
1257 |
m = stat.sf_mode; |
1258 |
if (error != 0) { |
1259 |
/* The entry was not found in the directory. |
1260 |
* This is OK if we are creating or renaming an |
1261 |
* entry and are working on the last component of |
1262 |
* the path name. */ |
1263 |
if ((cnp->cn_flags & ISLASTCN) && |
1264 |
(cnp->cn_nameiop == CREATE || \ |
1265 |
cnp->cn_nameiop == RENAME || |
1266 |
(cnp->cn_nameiop == DELETE && |
1267 |
cnp->cn_flags & DOWHITEOUT && |
1268 |
cnp->cn_flags & ISWHITEOUT))) { |
1269 |
error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, |
1270 |
cnp->cn_thread); |
1271 |
if (error != 0) |
1272 |
goto out; |
1273 |
|
1274 |
/* Keep the component name in the buffer for |
1275 |
* future uses. */ |
1276 |
cnp->cn_flags |= SAVENAME; |
1277 |
|
1278 |
error = EJUSTRETURN; |
1279 |
} else |
1280 |
error = ENOENT; |
1281 |
} |
1282 |
else { |
1283 |
if (S_ISDIR(m)) |
1284 |
type = VDIR; |
1285 |
else if (S_ISREG(m)) |
1286 |
type = VREG; |
1287 |
else if (S_ISLNK(m)) |
1288 |
type = VLNK; |
1289 |
error = vboxfs_alloc_file(vboxfsmp, fullpath, type, 0755, node, cnp->cn_lkflags, vpp); |
1290 |
} |
1291 |
} |
1292 |
|
1293 |
if ((cnp->cn_flags & MAKEENTRY) != 0) |
1294 |
cache_enter(dvp, *vpp, cnp); |
1295 |
out: |
1296 |
if (fullpath) |
1297 |
free(fullpath, M_VBOXVFS); |
1298 |
|
1299 |
return (error); |
1300 |
} |
1301 |
|
1302 |
static int |
1303 |
vboxfs_inactive(struct vop_inactive_args *ap) |
1304 |
{ |
1305 |
return (0); |
1306 |
} |
1307 |
|
1308 |
static int |
1309 |
vboxfs_reclaim(struct vop_reclaim_args *ap) |
1310 |
{ |
1311 |
struct vnode *vp; |
1312 |
struct vboxfs_node *node; |
1313 |
struct vboxfs_mnt *vboxfsmp; |
1314 |
|
1315 |
vp = ap->a_vp; |
1316 |
node = VP_TO_VBOXFS_NODE(vp); |
1317 |
vboxfsmp = node->vboxfsmp; |
1318 |
|
1319 |
vnode_destroy_vobject(vp); |
1320 |
vp->v_object = NULL; |
1321 |
cache_purge(vp); |
1322 |
|
1323 |
VBOXFS_NODE_LOCK(node); |
1324 |
VBOXFS_ASSERT_ELOCKED(node); |
1325 |
vboxfs_free_vp(vp); |
1326 |
|
1327 |
/* If the node referenced by this vnode was deleted by the user, |
1328 |
* we must free its associated data structures (now that the vnode |
1329 |
* is being reclaimed). */ |
1330 |
if ((node->sf_vpstate & VBOXFS_VNODE_ALLOCATING) == 0) { |
1331 |
node->sf_vpstate = VBOXFS_VNODE_DOOMED; |
1332 |
VBOXFS_NODE_UNLOCK(node); |
1333 |
vboxfs_free_node(vboxfsmp, node); |
1334 |
} else |
1335 |
VBOXFS_NODE_UNLOCK(node); |
1336 |
|
1337 |
MPASS(vp->v_data == NULL); |
1338 |
|
1339 |
return (0); |
1340 |
} |
1341 |
|
1342 |
static int |
1343 |
vboxfs_vptofh(struct vop_vptofh_args *ap) |
1344 |
{ |
1345 |
|
1346 |
return (EOPNOTSUPP); |
1347 |
} |