Line data Source code
1 : /* $OpenBSD: ntfs_vnops.c,v 1.44 2018/05/02 02:24:56 visa Exp $ */
2 : /* $NetBSD: ntfs_vnops.c,v 1.6 2003/04/10 21:57:26 jdolecek Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1992, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : *
8 : * This code is derived from software contributed to Berkeley by
9 : * John Heidemann of the UCLA Ficus project.
10 : *
11 : * Redistribution and use in source and binary forms, with or without
12 : * modification, are permitted provided that the following conditions
13 : * are met:
14 : * 1. Redistributions of source code must retain the above copyright
15 : * notice, this list of conditions and the following disclaimer.
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in the
18 : * documentation and/or other materials provided with the distribution.
19 : * 3. Neither the name of the University nor the names of its contributors
20 : * may be used to endorse or promote products derived from this software
21 : * without specific prior written permission.
22 : *
23 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 : * SUCH DAMAGE.
34 : *
35 : * Id: ntfs_vnops.c,v 1.5 1999/05/12 09:43:06 semenu Exp
36 : *
37 : */
38 :
39 : #include <sys/param.h>
40 : #include <sys/systm.h>
41 : #include <sys/time.h>
42 : #include <sys/stat.h>
43 : #include <sys/vnode.h>
44 : #include <sys/lock.h>
45 : #include <sys/mount.h>
46 : #include <sys/namei.h>
47 : #include <sys/malloc.h>
48 : #include <sys/buf.h>
49 : #include <sys/dirent.h>
50 : #include <sys/specdev.h>
51 :
52 : /*#define NTFS_DEBUG 1*/
53 : #include <ntfs/ntfs.h>
54 : #include <ntfs/ntfs_inode.h>
55 : #include <ntfs/ntfs_subr.h>
56 :
57 : #include <sys/unistd.h> /* for pathconf(2) constants */
58 :
59 : int ntfs_read(void *);
60 : int ntfs_getattr(void *);
61 : int ntfs_inactive(void *);
62 : int ntfs_print(void *);
63 : int ntfs_reclaim(void *);
64 : int ntfs_strategy(void *);
65 : int ntfs_access(void *v);
66 : int ntfs_open(void *v);
67 : int ntfs_close(void *);
68 : int ntfs_readdir(void *);
69 : int ntfs_lookup(void *);
70 : int ntfs_bmap(void *);
71 : int ntfs_fsync(void *);
72 : int ntfs_pathconf(void *);
73 :
74 : int ntfs_prtactive = 0; /* 1 => print out reclaim of active vnodes */
75 :
76 : /*
77 : * This is a noop, simply returning what one has been given.
78 : */
79 : int
80 0 : ntfs_bmap(void *v)
81 : {
82 0 : struct vop_bmap_args *ap = v;
83 : DPRINTF("ntfs_bmap: vn: %p, blk: %lld\n",
84 : ap->a_vp, (long long)ap->a_bn);
85 0 : if (ap->a_vpp != NULL)
86 0 : *ap->a_vpp = ap->a_vp;
87 0 : if (ap->a_bnp != NULL)
88 0 : *ap->a_bnp = ap->a_bn;
89 0 : if (ap->a_runp != NULL)
90 0 : *ap->a_runp = 0;
91 0 : return (0);
92 : }
93 :
94 : int
95 0 : ntfs_read(void *v)
96 : {
97 0 : struct vop_read_args *ap = v;
98 0 : struct vnode *vp = ap->a_vp;
99 0 : struct fnode *fp = VTOF(vp);
100 0 : struct ntnode *ip = FTONT(fp);
101 0 : struct uio *uio = ap->a_uio;
102 0 : struct ntfsmount *ntmp = ip->i_mp;
103 : u_int64_t toread;
104 : int error;
105 :
106 : DPRINTF("ntfs_read: ino: %u, off: %lld resid: %zu, segflg: %d\n",
107 : ip->i_number, uio->uio_offset, uio->uio_resid, uio->uio_segflg);
108 :
109 : DPRINTF("ntfs_read: filesize: %llu", fp->f_size);
110 :
111 : /* don't allow reading after end of file */
112 0 : if (uio->uio_offset > fp->f_size)
113 0 : toread = 0;
114 : else
115 0 : toread = MIN(uio->uio_resid, fp->f_size - uio->uio_offset);
116 :
117 : DPRINTF(", toread: %llu\n", toread);
118 :
119 0 : if (toread == 0)
120 0 : return (0);
121 :
122 0 : error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
123 0 : fp->f_attrname, uio->uio_offset, toread, NULL, uio);
124 0 : if (error) {
125 0 : printf("ntfs_read: ntfs_readattr failed: %d\n",error);
126 0 : return (error);
127 : }
128 :
129 0 : return (0);
130 0 : }
131 :
132 : int
133 0 : ntfs_getattr(void *v)
134 : {
135 0 : struct vop_getattr_args *ap = v;
136 0 : struct vnode *vp = ap->a_vp;
137 0 : struct fnode *fp = VTOF(vp);
138 0 : struct ntnode *ip = FTONT(fp);
139 0 : struct vattr *vap = ap->a_vap;
140 :
141 : DPRINTF("ntfs_getattr: %u, flags: %u\n", ip->i_number, ip->i_flag);
142 :
143 0 : vap->va_fsid = ip->i_dev;
144 0 : vap->va_fileid = ip->i_number;
145 0 : vap->va_mode = ip->i_mp->ntm_mode;
146 0 : vap->va_nlink = ip->i_nlink;
147 0 : vap->va_uid = ip->i_mp->ntm_uid;
148 0 : vap->va_gid = ip->i_mp->ntm_gid;
149 0 : vap->va_rdev = 0; /* XXX UNODEV ? */
150 0 : vap->va_size = fp->f_size;
151 0 : vap->va_bytes = fp->f_allocated;
152 0 : vap->va_atime = ntfs_nttimetounix(fp->f_times.t_access);
153 0 : vap->va_mtime = ntfs_nttimetounix(fp->f_times.t_write);
154 0 : vap->va_ctime = ntfs_nttimetounix(fp->f_times.t_create);
155 0 : vap->va_flags = ip->i_flag;
156 0 : vap->va_gen = 0;
157 0 : vap->va_blocksize = ip->i_mp->ntm_spc * ip->i_mp->ntm_bps;
158 0 : vap->va_type = vp->v_type;
159 0 : vap->va_filerev = 0;
160 :
161 : /*
162 : * Ensure that a directory link count is always 1 so that things
163 : * like fts_read() do not try to be smart and end up skipping over
164 : * directories. Additionally, ip->i_nlink will not be initialised
165 : * until the ntnode has been loaded for the file.
166 : */
167 0 : if (vp->v_type == VDIR || ip->i_nlink < 1)
168 0 : vap->va_nlink = 1;
169 :
170 0 : return (0);
171 : }
172 :
173 :
174 : /*
175 : * Last reference to an ntnode. If necessary, write or delete it.
176 : */
177 : int
178 0 : ntfs_inactive(void *v)
179 : {
180 0 : struct vop_inactive_args *ap = v;
181 0 : struct vnode *vp = ap->a_vp;
182 : #ifdef NTFS_DEBUG
183 : struct ntnode *ip = VTONT(vp);
184 : #endif
185 :
186 : DPRINTF("ntfs_inactive: vnode: %p, ntnode: %u\n", vp, ip->i_number);
187 :
188 : #ifdef DIAGNOSTIC
189 0 : if (ntfs_prtactive && vp->v_usecount != 0)
190 0 : vprint("ntfs_inactive: pushing active", vp);
191 : #endif
192 :
193 0 : VOP_UNLOCK(vp);
194 :
195 : /* XXX since we don't support any filesystem changes
196 : * right now, nothing more needs to be done
197 : */
198 0 : return (0);
199 : }
200 :
201 : /*
202 : * Reclaim an fnode/ntnode so that it can be used for other purposes.
203 : */
204 : int
205 0 : ntfs_reclaim(void *v)
206 : {
207 0 : struct vop_reclaim_args *ap = v;
208 0 : struct vnode *vp = ap->a_vp;
209 0 : struct fnode *fp = VTOF(vp);
210 0 : struct ntnode *ip = FTONT(fp);
211 0 : struct proc *p = ap->a_p;
212 : int error;
213 :
214 : DPRINTF("ntfs_reclaim: vnode: %p, ntnode: %u\n", vp, ip->i_number);
215 :
216 : #ifdef DIAGNOSTIC
217 0 : if (ntfs_prtactive && vp->v_usecount != 0)
218 0 : vprint("ntfs_reclaim: pushing active", vp);
219 : #endif
220 :
221 0 : if ((error = ntfs_ntget(ip, p)) != 0)
222 0 : return (error);
223 :
224 : /* Purge old data structures associated with the inode. */
225 0 : cache_purge(vp);
226 :
227 0 : ntfs_frele(fp);
228 0 : ntfs_ntput(ip, p);
229 :
230 0 : vp->v_data = NULL;
231 :
232 0 : return (0);
233 0 : }
234 :
235 : int
236 0 : ntfs_print(void *v)
237 : {
238 0 : struct vop_print_args *ap = v;
239 0 : struct ntnode *ip = VTONT(ap->a_vp);
240 :
241 0 : printf("tag VT_NTFS, ino %u, flag %#x, usecount %d, nlink %ld\n",
242 0 : ip->i_number, ip->i_flag, ip->i_usecount, ip->i_nlink);
243 :
244 0 : return (0);
245 : }
246 :
247 : /*
248 : * Calculate the logical to physical mapping if not done already,
249 : * then call the device strategy routine.
250 : */
251 : int
252 0 : ntfs_strategy(void *v)
253 : {
254 0 : struct vop_strategy_args *ap = v;
255 0 : struct buf *bp = ap->a_bp;
256 0 : struct vnode *vp = bp->b_vp;
257 0 : struct fnode *fp = VTOF(vp);
258 0 : struct ntnode *ip = FTONT(fp);
259 0 : struct ntfsmount *ntmp = ip->i_mp;
260 : int error, s;
261 :
262 : DPRINTF("ntfs_strategy: blkno: %lld, lblkno: %lld\n",
263 : (long long)bp->b_blkno, (long long)bp->b_lblkno);
264 :
265 : DPRINTF("strategy: bcount: %ld flags: 0x%lx\n",
266 : bp->b_bcount, bp->b_flags);
267 :
268 0 : if (bp->b_flags & B_READ) {
269 : u_int32_t toread;
270 :
271 0 : if (ntfs_cntob(bp->b_blkno) >= fp->f_size) {
272 0 : clrbuf(bp);
273 : error = 0;
274 0 : } else {
275 0 : toread = MIN(bp->b_bcount,
276 : fp->f_size - ntfs_cntob(bp->b_blkno));
277 : DPRINTF("ntfs_strategy: toread: %u, fsize: %llu\n",
278 : toread, fp->f_size);
279 :
280 0 : error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
281 0 : fp->f_attrname, ntfs_cntob(bp->b_blkno),
282 0 : toread, bp->b_data, NULL);
283 :
284 0 : if (error) {
285 0 : printf("ntfs_strategy: ntfs_readattr failed\n");
286 0 : bp->b_error = error;
287 0 : bp->b_flags |= B_ERROR;
288 0 : }
289 :
290 0 : bzero(bp->b_data + toread, bp->b_bcount - toread);
291 : }
292 0 : } else {
293 0 : bp->b_error = error = EROFS;
294 0 : bp->b_flags |= B_ERROR;
295 : }
296 0 : s = splbio();
297 0 : biodone(bp);
298 0 : splx(s);
299 0 : return (error);
300 : }
301 :
302 : int
303 0 : ntfs_access(void *v)
304 : {
305 0 : struct vop_access_args *ap = v;
306 0 : struct vnode *vp = ap->a_vp;
307 0 : struct ntnode *ip = VTONT(vp);
308 0 : struct ucred *cred = ap->a_cred;
309 0 : mode_t mask, mode = ap->a_mode;
310 : gid_t *gp;
311 : int i;
312 :
313 : DPRINTF("ntfs_access: %u\n", ip->i_number);
314 :
315 : /*
316 : * Disallow write attempts unless the file is a socket, fifo, or
317 : * a block or character device resident on the file system.
318 : */
319 0 : if (mode & VWRITE) {
320 0 : switch ((int)vp->v_type) {
321 : case VDIR:
322 : case VLNK:
323 : case VREG:
324 0 : return (EROFS);
325 : }
326 : }
327 :
328 : /* Otherwise, user id 0 always gets access. */
329 0 : if (cred->cr_uid == 0)
330 0 : return (0);
331 :
332 : mask = 0;
333 :
334 : /* Otherwise, check the owner. */
335 0 : if (cred->cr_uid == ip->i_mp->ntm_uid) {
336 0 : if (mode & VEXEC)
337 0 : mask |= S_IXUSR;
338 0 : if (mode & VREAD)
339 0 : mask |= S_IRUSR;
340 0 : if (mode & VWRITE)
341 0 : mask |= S_IWUSR;
342 0 : return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES);
343 : }
344 :
345 : /* Otherwise, check the groups. */
346 0 : for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
347 0 : if (ip->i_mp->ntm_gid == *gp) {
348 0 : if (mode & VEXEC)
349 0 : mask |= S_IXGRP;
350 0 : if (mode & VREAD)
351 0 : mask |= S_IRGRP;
352 0 : if (mode & VWRITE)
353 0 : mask |= S_IWGRP;
354 0 : return ((ip->i_mp->ntm_mode&mask) == mask ? 0 : EACCES);
355 : }
356 :
357 : /* Otherwise, check everyone else. */
358 0 : if (mode & VEXEC)
359 0 : mask |= S_IXOTH;
360 0 : if (mode & VREAD)
361 0 : mask |= S_IROTH;
362 0 : if (mode & VWRITE)
363 0 : mask |= S_IWOTH;
364 0 : return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES);
365 0 : }
366 :
367 : /*
368 : * Open called.
369 : *
370 : * Nothing to do.
371 : */
372 : int
373 0 : ntfs_open(void *v)
374 : {
375 : #if NTFS_DEBUG
376 : struct vop_open_args *ap = v;
377 : struct vnode *vp = ap->a_vp;
378 : struct ntnode *ip = VTONT(vp);
379 :
380 : printf("ntfs_open: %d\n",ip->i_number);
381 : #endif
382 :
383 : /*
384 : * Files marked append-only must be opened for appending.
385 : */
386 :
387 0 : return (0);
388 : }
389 :
390 : /*
391 : * Close called.
392 : *
393 : * Update the times on the inode.
394 : */
395 : int
396 0 : ntfs_close(void *v)
397 : {
398 : #if NTFS_DEBUG
399 : struct vop_close_args *ap = v;
400 : struct vnode *vp = ap->a_vp;
401 : struct ntnode *ip = VTONT(vp);
402 :
403 : printf("ntfs_close: %d\n",ip->i_number);
404 : #endif
405 :
406 0 : return (0);
407 : }
408 :
409 : int
410 0 : ntfs_readdir(void *v)
411 : {
412 0 : struct vop_readdir_args *ap = v;
413 0 : struct vnode *vp = ap->a_vp;
414 0 : struct fnode *fp = VTOF(vp);
415 0 : struct ntnode *ip = FTONT(fp);
416 0 : struct uio *uio = ap->a_uio;
417 0 : struct ntfsmount *ntmp = ip->i_mp;
418 : int i, error = 0;
419 : u_int32_t faked = 0, num;
420 0 : struct dirent cde;
421 : off_t off;
422 :
423 : DPRINTF("ntfs_readdir %u off: %lld resid: %zu\n", ip->i_number,
424 : uio->uio_offset, uio->uio_resid);
425 :
426 0 : off = uio->uio_offset;
427 0 : memset(&cde, 0, sizeof(cde));
428 :
429 : /* Simulate . in every dir except ROOT */
430 0 : if (ip->i_number != NTFS_ROOTINO && uio->uio_offset == 0) {
431 0 : cde.d_fileno = ip->i_number;
432 0 : cde.d_reclen = sizeof(struct dirent);
433 0 : cde.d_type = DT_DIR;
434 0 : cde.d_namlen = 1;
435 0 : cde.d_off = sizeof(struct dirent);
436 0 : cde.d_name[0] = '.';
437 0 : cde.d_name[1] = '\0';
438 0 : error = uiomove(&cde, sizeof(struct dirent), uio);
439 0 : if (error)
440 : goto out;
441 : }
442 :
443 : /* Simulate .. in every dir including ROOT */
444 0 : if (uio->uio_offset < 2 * sizeof(struct dirent)) {
445 0 : cde.d_fileno = NTFS_ROOTINO; /* XXX */
446 0 : cde.d_reclen = sizeof(struct dirent);
447 0 : cde.d_type = DT_DIR;
448 0 : cde.d_namlen = 2;
449 0 : cde.d_off = 2 * sizeof(struct dirent);
450 0 : cde.d_name[0] = '.';
451 0 : cde.d_name[1] = '.';
452 0 : cde.d_name[2] = '\0';
453 0 : error = uiomove(&cde, sizeof(struct dirent), uio);
454 0 : if (error)
455 : goto out;
456 : }
457 :
458 0 : faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
459 0 : num = uio->uio_offset / sizeof(struct dirent) - faked;
460 :
461 0 : while (uio->uio_resid >= sizeof(struct dirent)) {
462 0 : struct attr_indexentry *iep;
463 : char *fname;
464 : size_t remains;
465 : int sz;
466 :
467 0 : error = ntfs_ntreaddir(ntmp, fp, num, &iep, uio->uio_procp);
468 0 : if (error)
469 0 : goto out;
470 :
471 0 : if (NULL == iep)
472 0 : break;
473 :
474 0 : for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent));
475 0 : iep = NTFS_NEXTREC(iep, struct attr_indexentry *))
476 : {
477 0 : if(!ntfs_isnamepermitted(ntmp,iep))
478 : continue;
479 :
480 : remains = sizeof(cde.d_name) - 1;
481 0 : fname = cde.d_name;
482 0 : for(i=0; i<iep->ie_fnamelen; i++) {
483 0 : sz = (*ntmp->ntm_wput)(fname, remains,
484 0 : iep->ie_fname[i]);
485 0 : fname += sz;
486 0 : remains -= sz;
487 : }
488 0 : *fname = '\0';
489 : DPRINTF("ntfs_readdir: elem: %u, fname:[%s] type: %u, "
490 : "flag: %u, ",
491 : num, cde.d_name, iep->ie_fnametype, iep->ie_flag);
492 0 : cde.d_namlen = fname - (char *) cde.d_name;
493 0 : cde.d_fileno = iep->ie_number;
494 0 : cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
495 0 : cde.d_reclen = sizeof(struct dirent);
496 0 : cde.d_off = uio->uio_offset + sizeof(struct dirent);
497 : DPRINTF("%s\n", cde.d_type == DT_DIR ? "dir" : "reg");
498 :
499 0 : error = uiomove(&cde, sizeof(struct dirent), uio);
500 0 : if (error)
501 0 : goto out;
502 0 : num++;
503 0 : }
504 0 : }
505 :
506 : DPRINTF("ntfs_readdir: %u entries (%lld bytes) read\n",
507 : num, uio->uio_offset - off);
508 : DPRINTF("ntfs_readdir: off: %lld resid: %zu\n",
509 : uio->uio_offset, uio->uio_resid);
510 :
511 : /*
512 : if (ap->a_eofflag)
513 : *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset;
514 : */
515 : out:
516 0 : if (fp->f_dirblbuf != NULL) {
517 0 : free(fp->f_dirblbuf, M_NTFSDIR, 0);
518 0 : fp->f_dirblbuf = NULL;
519 0 : }
520 0 : return (error);
521 0 : }
522 :
523 : int
524 0 : ntfs_lookup(void *v)
525 : {
526 0 : struct vop_lookup_args *ap = v;
527 0 : struct vnode *dvp = ap->a_dvp;
528 0 : struct ntnode *dip = VTONT(dvp);
529 0 : struct ntfsmount *ntmp = dip->i_mp;
530 0 : struct componentname *cnp = ap->a_cnp;
531 0 : struct ucred *cred = cnp->cn_cred;
532 : int error;
533 0 : int lockparent = cnp->cn_flags & LOCKPARENT;
534 0 : struct proc *p = cnp->cn_proc;
535 : #if NTFS_DEBUG
536 : int wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
537 : #endif
538 : DPRINTF("ntfs_lookup: \"%.*s\" (%ld bytes) in %u, lp: %d, wp: %d \n",
539 : (unsigned int)cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_namelen,
540 : dip->i_number, lockparent, wantparent);
541 :
542 0 : error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc);
543 0 : if(error)
544 0 : return (error);
545 :
546 0 : if ((cnp->cn_flags & ISLASTCN) &&
547 0 : (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
548 0 : return (EROFS);
549 :
550 : /*
551 : * We now have a segment name to search for, and a directory
552 : * to search.
553 : *
554 : * Before tediously performing a linear scan of the directory,
555 : * check the name cache to see if the directory/name pair
556 : * we are looking for is known already.
557 : */
558 0 : if ((error = cache_lookup(ap->a_dvp, ap->a_vpp, cnp)) >= 0)
559 0 : return (error);
560 :
561 0 : if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
562 : DPRINTF("ntfs_lookup: faking . directory in %u\n",
563 : dip->i_number);
564 :
565 0 : vref(dvp);
566 0 : *ap->a_vpp = dvp;
567 : error = 0;
568 0 : } else if (cnp->cn_flags & ISDOTDOT) {
569 0 : struct ntvattr *vap;
570 :
571 : DPRINTF("ntfs_lookup: faking .. directory in %u\n",
572 : dip->i_number);
573 :
574 0 : VOP_UNLOCK(dvp);
575 0 : cnp->cn_flags |= PDIRUNLOCK;
576 :
577 0 : error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap);
578 0 : if(error)
579 0 : return (error);
580 :
581 : DPRINTF("ntfs_lookup: parentdir: %u\n",
582 : vap->va_a_name->n_pnumber);
583 0 : error = VFS_VGET(ntmp->ntm_mountp,
584 : vap->va_a_name->n_pnumber,ap->a_vpp);
585 0 : ntfs_ntvattrrele(vap);
586 0 : if (error) {
587 0 : if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) == 0)
588 0 : cnp->cn_flags &= ~PDIRUNLOCK;
589 0 : return (error);
590 : }
591 :
592 0 : if (lockparent && (cnp->cn_flags & ISLASTCN)) {
593 0 : error = vn_lock(dvp, LK_EXCLUSIVE);
594 0 : if (error) {
595 0 : vput( *(ap->a_vpp) );
596 0 : return (error);
597 : }
598 0 : cnp->cn_flags &= ~PDIRUNLOCK;
599 0 : }
600 0 : } else {
601 0 : error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp, p);
602 0 : if (error) {
603 : DPRINTF("ntfs_ntlookupfile: returned %d\n", error);
604 0 : return (error);
605 : }
606 :
607 : DPRINTF("ntfs_lookup: found ino: %u\n",
608 : VTONT(*ap->a_vpp)->i_number);
609 :
610 0 : if(!lockparent || (cnp->cn_flags & ISLASTCN) == 0) {
611 0 : VOP_UNLOCK(dvp);
612 0 : cnp->cn_flags |= PDIRUNLOCK;
613 0 : }
614 : }
615 :
616 0 : if (cnp->cn_flags & MAKEENTRY)
617 0 : cache_enter(dvp, *ap->a_vpp, cnp);
618 :
619 0 : return (error);
620 0 : }
621 :
622 : /*
623 : * Flush the blocks of a file to disk.
624 : *
625 : * This function is worthless for vnodes that represent directories. Maybe we
626 : * could just do a sync if they try an fsync on a directory file.
627 : */
628 : int
629 0 : ntfs_fsync(void *v)
630 : {
631 0 : return (0);
632 : }
633 :
634 : /*
635 : * Return POSIX pathconf information applicable to NTFS filesystem
636 : */
637 : int
638 0 : ntfs_pathconf(void *v)
639 : {
640 0 : struct vop_pathconf_args *ap = v;
641 : int error = 0;
642 :
643 0 : switch (ap->a_name) {
644 : case _PC_LINK_MAX:
645 0 : *ap->a_retval = 1;
646 0 : break;
647 : case _PC_NAME_MAX:
648 0 : *ap->a_retval = NTFS_MAXFILENAME;
649 0 : break;
650 : case _PC_CHOWN_RESTRICTED:
651 0 : *ap->a_retval = 1;
652 0 : break;
653 : case _PC_NO_TRUNC:
654 0 : *ap->a_retval = 0;
655 0 : break;
656 : default:
657 : error = EINVAL;
658 0 : break;
659 : }
660 :
661 0 : return (error);
662 : }
663 :
664 : /*
665 : * Global vfs data structures
666 : */
667 : struct vops ntfs_vops = {
668 : .vop_getattr = ntfs_getattr,
669 : .vop_inactive = ntfs_inactive,
670 : .vop_reclaim = ntfs_reclaim,
671 : .vop_print = ntfs_print,
672 : .vop_pathconf = ntfs_pathconf,
673 : .vop_islocked = vop_generic_islocked,
674 : .vop_unlock = vop_generic_unlock,
675 : .vop_lock = vop_generic_lock,
676 : .vop_lookup = ntfs_lookup,
677 : .vop_access = ntfs_access,
678 : .vop_close = ntfs_close,
679 : .vop_open = ntfs_open,
680 : .vop_readdir = ntfs_readdir,
681 : .vop_fsync = ntfs_fsync,
682 : .vop_bmap = ntfs_bmap,
683 : .vop_strategy = ntfs_strategy,
684 : .vop_bwrite = vop_generic_bwrite,
685 : .vop_read = ntfs_read,
686 : };
|