1 1.111 christos /* $NetBSD: ntfs_vfsops.c,v 1.111 2024/02/04 00:16:59 christos Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /*- 4 1.1 jdolecek * Copyright (c) 1998, 1999 Semen Ustimenko 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 8 1.1 jdolecek * modification, are permitted provided that the following conditions 9 1.1 jdolecek * are met: 10 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 11 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 12 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 14 1.1 jdolecek * documentation and/or other materials provided with the distribution. 15 1.1 jdolecek * 16 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jdolecek * SUCH DAMAGE. 27 1.1 jdolecek * 28 1.1 jdolecek * Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp 29 1.1 jdolecek */ 30 1.1 jdolecek 31 1.1 jdolecek #include <sys/cdefs.h> 32 1.111 christos __KERNEL_RCSID(0, "$NetBSD: ntfs_vfsops.c,v 1.111 2024/02/04 00:16:59 christos Exp $"); 33 1.1 jdolecek 34 1.1 jdolecek #include <sys/param.h> 35 1.1 jdolecek #include <sys/systm.h> 36 1.1 jdolecek #include <sys/namei.h> 37 1.1 jdolecek #include <sys/proc.h> 38 1.1 jdolecek #include <sys/kernel.h> 39 1.1 jdolecek #include <sys/vnode.h> 40 1.1 jdolecek #include <sys/mount.h> 41 1.1 jdolecek #include <sys/buf.h> 42 1.1 jdolecek #include <sys/fcntl.h> 43 1.1 jdolecek #include <sys/malloc.h> 44 1.15 atatat #include <sys/sysctl.h> 45 1.1 jdolecek #include <sys/device.h> 46 1.1 jdolecek #include <sys/conf.h> 47 1.41 elad #include <sys/kauth.h> 48 1.70 rumble #include <sys/module.h> 49 1.1 jdolecek 50 1.1 jdolecek #include <uvm/uvm_extern.h> 51 1.1 jdolecek 52 1.62 dholland #include <miscfs/genfs/genfs.h> 53 1.1 jdolecek #include <miscfs/specfs/specdev.h> 54 1.1 jdolecek 55 1.1 jdolecek #include <fs/ntfs/ntfs.h> 56 1.1 jdolecek #include <fs/ntfs/ntfs_inode.h> 57 1.1 jdolecek #include <fs/ntfs/ntfs_subr.h> 58 1.1 jdolecek #include <fs/ntfs/ntfs_vfsops.h> 59 1.1 jdolecek #include <fs/ntfs/ntfs_ihash.h> 60 1.1 jdolecek #include <fs/ntfs/ntfsmount.h> 61 1.1 jdolecek 62 1.70 rumble MODULE(MODULE_CLASS_VFS, ntfs, NULL); 63 1.70 rumble 64 1.50 pooka MALLOC_JUSTDEFINE(M_NTFSMNT, "NTFS mount", "NTFS mount structure"); 65 1.50 pooka MALLOC_JUSTDEFINE(M_NTFSNTNODE,"NTFS ntnode", "NTFS ntnode information"); 66 1.50 pooka MALLOC_JUSTDEFINE(M_NTFSDIR,"NTFS dir", "NTFS dir buffer"); 67 1.1 jdolecek 68 1.103 maxv static int ntfs_superblock_validate(struct ntfsmount *); 69 1.59 pooka static int ntfs_mount(struct mount *, const char *, void *, size_t *); 70 1.109 ad static int ntfs_root(struct mount *, int, struct vnode **); 71 1.59 pooka static int ntfs_start(struct mount *, int); 72 1.59 pooka static int ntfs_statvfs(struct mount *, struct statvfs *); 73 1.59 pooka static int ntfs_sync(struct mount *, int, kauth_cred_t); 74 1.59 pooka static int ntfs_unmount(struct mount *, int); 75 1.109 ad static int ntfs_vget(struct mount *mp, ino_t ino, int, 76 1.33 xtraeme struct vnode **vpp); 77 1.97 hannken static int ntfs_loadvnode(struct mount *, struct vnode *, 78 1.97 hannken const void *, size_t, const void **); 79 1.33 xtraeme static int ntfs_mountfs(struct vnode *, struct mount *, 80 1.36 christos struct ntfs_args *, struct lwp *); 81 1.42 martin static int ntfs_vptofh(struct vnode *, struct fid *, size_t *); 82 1.1 jdolecek 83 1.98 maxv static void ntfs_init(void); 84 1.98 maxv static void ntfs_reinit(void); 85 1.98 maxv static void ntfs_done(void); 86 1.109 ad static int ntfs_fhtovp(struct mount *, struct fid *, int, 87 1.56 pooka struct vnode **); 88 1.98 maxv static int ntfs_mountroot(void); 89 1.1 jdolecek 90 1.31 yamt static const struct genfs_ops ntfs_genfsops = { 91 1.31 yamt .gop_write = genfs_compat_gop_write, 92 1.1 jdolecek }; 93 1.1 jdolecek 94 1.72 rumble static struct sysctllog *ntfs_sysctl_log; 95 1.1 jdolecek 96 1.1 jdolecek static int 97 1.76 cegger ntfs_mountroot(void) 98 1.1 jdolecek { 99 1.1 jdolecek struct mount *mp; 100 1.36 christos struct lwp *l = curlwp; /* XXX */ 101 1.1 jdolecek int error; 102 1.1 jdolecek struct ntfs_args args; 103 1.1 jdolecek 104 1.37 thorpej if (device_class(root_device) != DV_DISK) 105 1.1 jdolecek return (ENODEV); 106 1.1 jdolecek 107 1.1 jdolecek if ((error = vfs_rootmountalloc(MOUNT_NTFS, "root_device", &mp))) { 108 1.1 jdolecek vrele(rootvp); 109 1.1 jdolecek return (error); 110 1.1 jdolecek } 111 1.1 jdolecek 112 1.1 jdolecek args.flag = 0; 113 1.1 jdolecek args.uid = 0; 114 1.1 jdolecek args.gid = 0; 115 1.111 christos args.mode = S_IRWXU|S_IRWXG|S_IRWXO; 116 1.1 jdolecek 117 1.36 christos if ((error = ntfs_mountfs(rootvp, mp, &args, l)) != 0) { 118 1.107 hannken vfs_unbusy(mp); 119 1.106 hannken vfs_rele(mp); 120 1.1 jdolecek return (error); 121 1.1 jdolecek } 122 1.1 jdolecek 123 1.90 christos mountlist_append(mp); 124 1.59 pooka (void)ntfs_statvfs(mp, &mp->mnt_stat); 125 1.107 hannken vfs_unbusy(mp); 126 1.1 jdolecek return (0); 127 1.1 jdolecek } 128 1.1 jdolecek 129 1.1 jdolecek static void 130 1.76 cegger ntfs_init(void) 131 1.1 jdolecek { 132 1.50 pooka 133 1.5 christos malloc_type_attach(M_NTFSMNT); 134 1.5 christos malloc_type_attach(M_NTFSNTNODE); 135 1.5 christos malloc_type_attach(M_NTFSDIR); 136 1.6 christos malloc_type_attach(M_NTFSNTVATTR); 137 1.7 christos malloc_type_attach(M_NTFSRDATA); 138 1.7 christos malloc_type_attach(M_NTFSDECOMP); 139 1.7 christos malloc_type_attach(M_NTFSRUN); 140 1.1 jdolecek ntfs_nthashinit(); 141 1.1 jdolecek ntfs_toupper_init(); 142 1.1 jdolecek } 143 1.1 jdolecek 144 1.1 jdolecek static void 145 1.76 cegger ntfs_reinit(void) 146 1.1 jdolecek { 147 1.1 jdolecek ntfs_nthashreinit(); 148 1.1 jdolecek } 149 1.1 jdolecek 150 1.1 jdolecek static void 151 1.76 cegger ntfs_done(void) 152 1.1 jdolecek { 153 1.1 jdolecek ntfs_nthashdone(); 154 1.5 christos malloc_type_detach(M_NTFSMNT); 155 1.5 christos malloc_type_detach(M_NTFSNTNODE); 156 1.5 christos malloc_type_detach(M_NTFSDIR); 157 1.6 christos malloc_type_detach(M_NTFSNTVATTR); 158 1.7 christos malloc_type_detach(M_NTFSRDATA); 159 1.7 christos malloc_type_detach(M_NTFSDECOMP); 160 1.7 christos malloc_type_detach(M_NTFSRUN); 161 1.1 jdolecek } 162 1.1 jdolecek 163 1.1 jdolecek static int 164 1.98 maxv ntfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 165 1.1 jdolecek { 166 1.59 pooka struct lwp *l = curlwp; 167 1.28 mycroft int err = 0, flags; 168 1.1 jdolecek struct vnode *devvp; 169 1.51 dsl struct ntfs_args *args = data; 170 1.51 dsl 171 1.94 maxv if (args == NULL) 172 1.94 maxv return EINVAL; 173 1.51 dsl if (*data_len < sizeof *args) 174 1.51 dsl return EINVAL; 175 1.1 jdolecek 176 1.1 jdolecek if (mp->mnt_flag & MNT_GETARGS) { 177 1.1 jdolecek struct ntfsmount *ntmp = VFSTONTFS(mp); 178 1.1 jdolecek if (ntmp == NULL) 179 1.1 jdolecek return EIO; 180 1.51 dsl args->fspec = NULL; 181 1.51 dsl args->uid = ntmp->ntm_uid; 182 1.51 dsl args->gid = ntmp->ntm_gid; 183 1.51 dsl args->mode = ntmp->ntm_mode; 184 1.51 dsl args->flag = ntmp->ntm_flag; 185 1.51 dsl *data_len = sizeof *args; 186 1.51 dsl return 0; 187 1.1 jdolecek } 188 1.1 jdolecek /* 189 1.1 jdolecek *** 190 1.1 jdolecek * Mounting non-root file system or updating a file system 191 1.1 jdolecek *** 192 1.1 jdolecek */ 193 1.1 jdolecek 194 1.1 jdolecek /* 195 1.1 jdolecek * If updating, check whether changing from read-only to 196 1.1 jdolecek * read/write; if there is no device name, that's all we do. 197 1.1 jdolecek */ 198 1.1 jdolecek if (mp->mnt_flag & MNT_UPDATE) { 199 1.1 jdolecek printf("ntfs_mount(): MNT_UPDATE not supported\n"); 200 1.28 mycroft return (EINVAL); 201 1.1 jdolecek } 202 1.1 jdolecek 203 1.1 jdolecek /* 204 1.1 jdolecek * Not an update, or updating the name: look up the name 205 1.1 jdolecek * and verify that it refers to a sensible block device. 206 1.1 jdolecek */ 207 1.78 dholland err = namei_simple_user(args->fspec, 208 1.78 dholland NSM_FOLLOW_NOEMULROOT, &devvp); 209 1.98 maxv if (err) 210 1.28 mycroft return (err); 211 1.1 jdolecek 212 1.1 jdolecek if (devvp->v_type != VBLK) { 213 1.1 jdolecek err = ENOTBLK; 214 1.28 mycroft goto fail; 215 1.1 jdolecek } 216 1.1 jdolecek if (bdevsw_lookup(devvp->v_rdev) == NULL) { 217 1.1 jdolecek err = ENXIO; 218 1.28 mycroft goto fail; 219 1.1 jdolecek } 220 1.1 jdolecek if (mp->mnt_flag & MNT_UPDATE) { 221 1.1 jdolecek #if 0 222 1.1 jdolecek /* 223 1.1 jdolecek ******************** 224 1.1 jdolecek * UPDATE 225 1.1 jdolecek ******************** 226 1.1 jdolecek */ 227 1.1 jdolecek 228 1.28 mycroft if (devvp != ntmp->um_devvp) { 229 1.1 jdolecek err = EINVAL; /* needs translation */ 230 1.28 mycroft goto fail; 231 1.28 mycroft } 232 1.28 mycroft 233 1.1 jdolecek /* 234 1.1 jdolecek * Update device name only on success 235 1.1 jdolecek */ 236 1.51 dsl err = set_statvfs_info(NULL, UIO_USERSPACE, args->fspec, 237 1.52 pooka UIO_USERSPACE, mp->mnt_op->vfs_name, mp, p); 238 1.28 mycroft if (err) 239 1.28 mycroft goto fail; 240 1.28 mycroft 241 1.28 mycroft vrele(devvp); 242 1.1 jdolecek #endif 243 1.1 jdolecek } else { 244 1.1 jdolecek /* 245 1.1 jdolecek ******************** 246 1.1 jdolecek * NEW MOUNT 247 1.1 jdolecek ******************** 248 1.1 jdolecek */ 249 1.1 jdolecek 250 1.1 jdolecek /* 251 1.1 jdolecek * Since this is a new mount, we want the names for 252 1.1 jdolecek * the device and the mount point copied in. If an 253 1.1 jdolecek * error occurs, the mountpoint is discarded by the 254 1.1 jdolecek * upper level code. 255 1.1 jdolecek */ 256 1.28 mycroft 257 1.1 jdolecek /* Save "last mounted on" info for mount point (NULL pad)*/ 258 1.51 dsl err = set_statvfs_info(path, UIO_USERSPACE, args->fspec, 259 1.52 pooka UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); 260 1.28 mycroft if (err) 261 1.28 mycroft goto fail; 262 1.28 mycroft 263 1.28 mycroft if (mp->mnt_flag & MNT_RDONLY) 264 1.28 mycroft flags = FREAD; 265 1.28 mycroft else 266 1.28 mycroft flags = FREAD|FWRITE; 267 1.87 hannken vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 268 1.59 pooka err = VOP_OPEN(devvp, flags, FSCRED); 269 1.87 hannken VOP_UNLOCK(devvp); 270 1.28 mycroft if (err) 271 1.28 mycroft goto fail; 272 1.51 dsl err = ntfs_mountfs(devvp, mp, args, l); 273 1.28 mycroft if (err) { 274 1.28 mycroft vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 275 1.59 pooka (void)VOP_CLOSE(devvp, flags, NOCRED); 276 1.81 hannken VOP_UNLOCK(devvp); 277 1.28 mycroft goto fail; 278 1.4 christos } 279 1.1 jdolecek } 280 1.1 jdolecek 281 1.1 jdolecek /* 282 1.1 jdolecek * Initialize FS stat information in mount struct; uses both 283 1.1 jdolecek * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 284 1.1 jdolecek * 285 1.1 jdolecek * This code is common to root and non-root mounts 286 1.1 jdolecek */ 287 1.59 pooka (void)VFS_STATVFS(mp, &mp->mnt_stat); 288 1.28 mycroft return (err); 289 1.1 jdolecek 290 1.28 mycroft fail: 291 1.1 jdolecek vrele(devvp); 292 1.28 mycroft return (err); 293 1.1 jdolecek } 294 1.1 jdolecek 295 1.103 maxv static int 296 1.103 maxv ntfs_superblock_validate(struct ntfsmount *ntmp) 297 1.103 maxv { 298 1.103 maxv /* Sanity checks. XXX: More checks are probably needed. */ 299 1.103 maxv if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { 300 1.103 maxv dprintf(("ntfs_superblock_validate: invalid boot block\n")); 301 1.103 maxv return EINVAL; 302 1.103 maxv } 303 1.103 maxv if (ntmp->ntm_bps == 0) { 304 1.103 maxv dprintf(("ntfs_superblock_validate: invalid bytes per sector\n")); 305 1.103 maxv return EINVAL; 306 1.103 maxv } 307 1.103 maxv if (ntmp->ntm_spc == 0) { 308 1.103 maxv dprintf(("ntfs_superblock_validate: invalid sectors per cluster\n")); 309 1.103 maxv return EINVAL; 310 1.103 maxv } 311 1.103 maxv return 0; 312 1.103 maxv } 313 1.103 maxv 314 1.1 jdolecek /* 315 1.1 jdolecek * Common code for mount and mountroot 316 1.1 jdolecek */ 317 1.1 jdolecek int 318 1.75 dsl ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, struct lwp *l) 319 1.1 jdolecek { 320 1.1 jdolecek struct buf *bp; 321 1.1 jdolecek struct ntfsmount *ntmp; 322 1.1 jdolecek dev_t dev = devvp->v_rdev; 323 1.89 christos int error, i; 324 1.1 jdolecek struct vnode *vp; 325 1.108 hannken struct vnode_iterator *marker; 326 1.1 jdolecek 327 1.39 xtraeme ntmp = NULL; 328 1.39 xtraeme 329 1.1 jdolecek /* 330 1.1 jdolecek * Flush out any old buffers remaining from a previous use. 331 1.1 jdolecek */ 332 1.28 mycroft vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 333 1.43 ad error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0); 334 1.81 hannken VOP_UNLOCK(devvp); 335 1.1 jdolecek if (error) 336 1.1 jdolecek return (error); 337 1.1 jdolecek 338 1.1 jdolecek bp = NULL; 339 1.1 jdolecek 340 1.104 maxv error = bread(devvp, BBLOCK, BBSIZE, 0, &bp); 341 1.1 jdolecek if (error) 342 1.1 jdolecek goto out; 343 1.98 maxv ntmp = malloc(sizeof(*ntmp), M_NTFSMNT, M_WAITOK|M_ZERO); 344 1.98 maxv memcpy(&ntmp->ntm_bootfile, bp->b_data, sizeof(struct bootfile)); 345 1.98 maxv brelse(bp, 0); 346 1.1 jdolecek bp = NULL; 347 1.1 jdolecek 348 1.103 maxv if ((error = ntfs_superblock_validate(ntmp))) 349 1.1 jdolecek goto out; 350 1.1 jdolecek 351 1.1 jdolecek { 352 1.1 jdolecek int8_t cpr = ntmp->ntm_mftrecsz; 353 1.98 maxv if (cpr > 0) 354 1.1 jdolecek ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; 355 1.1 jdolecek else 356 1.1 jdolecek ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; 357 1.1 jdolecek } 358 1.1 jdolecek dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", 359 1.103 maxv ntmp->ntm_bps, ntmp->ntm_spc, ntmp->ntm_bootfile.bf_media, 360 1.103 maxv ntmp->ntm_mftrecsz, ntmp->ntm_bpmftrec)); 361 1.1 jdolecek dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", 362 1.103 maxv (u_int32_t)ntmp->ntm_mftcn, (u_int32_t)ntmp->ntm_mftmirrcn)); 363 1.1 jdolecek 364 1.1 jdolecek ntmp->ntm_mountp = mp; 365 1.1 jdolecek ntmp->ntm_dev = dev; 366 1.1 jdolecek ntmp->ntm_devvp = devvp; 367 1.1 jdolecek ntmp->ntm_uid = argsp->uid; 368 1.1 jdolecek ntmp->ntm_gid = argsp->gid; 369 1.111 christos ntmp->ntm_mode = argsp->mode & (S_IRWXU|S_IRWXG|S_IRWXO); 370 1.1 jdolecek ntmp->ntm_flag = argsp->flag; 371 1.1 jdolecek mp->mnt_data = ntmp; 372 1.1 jdolecek 373 1.1 jdolecek /* set file name encode/decode hooks XXX utf-8 only for now */ 374 1.1 jdolecek ntmp->ntm_wget = ntfs_utf8_wget; 375 1.1 jdolecek ntmp->ntm_wput = ntfs_utf8_wput; 376 1.1 jdolecek ntmp->ntm_wcmp = ntfs_utf8_wcmp; 377 1.1 jdolecek 378 1.1 jdolecek dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", 379 1.1 jdolecek (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", 380 1.1 jdolecek (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", 381 1.1 jdolecek ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); 382 1.1 jdolecek 383 1.1 jdolecek /* 384 1.29 perry * We read in some system nodes to do not allow 385 1.1 jdolecek * reclaim them and to have everytime access to them. 386 1.29 perry */ 387 1.1 jdolecek { 388 1.1 jdolecek int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; 389 1.98 maxv for (i = 0; i < 3; i++) { 390 1.109 ad error = VFS_VGET(mp, pi[i], LK_EXCLUSIVE, 391 1.109 ad &(ntmp->ntm_sysvn[pi[i]])); 392 1.98 maxv if (error) 393 1.1 jdolecek goto out1; 394 1.58 ad ntmp->ntm_sysvn[pi[i]]->v_vflag |= VV_SYSTEM; 395 1.80 pooka vref(ntmp->ntm_sysvn[pi[i]]); 396 1.1 jdolecek vput(ntmp->ntm_sysvn[pi[i]]); 397 1.1 jdolecek } 398 1.1 jdolecek } 399 1.1 jdolecek 400 1.1 jdolecek /* read the Unicode lowercase --> uppercase translation table, 401 1.1 jdolecek * if necessary */ 402 1.1 jdolecek if ((error = ntfs_toupper_use(mp, ntmp))) 403 1.1 jdolecek goto out1; 404 1.1 jdolecek 405 1.1 jdolecek /* 406 1.1 jdolecek * Scan $BitMap and count free clusters 407 1.1 jdolecek */ 408 1.1 jdolecek error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); 409 1.98 maxv if (error) 410 1.1 jdolecek goto out1; 411 1.1 jdolecek 412 1.1 jdolecek /* 413 1.1 jdolecek * Read and translate to internal format attribute 414 1.29 perry * definition file. 415 1.1 jdolecek */ 416 1.1 jdolecek { 417 1.1 jdolecek int num,j; 418 1.1 jdolecek struct attrdef ad; 419 1.1 jdolecek 420 1.1 jdolecek /* Open $AttrDef */ 421 1.109 ad error = VFS_VGET(mp, NTFS_ATTRDEFINO, LK_EXCLUSIVE, &vp); 422 1.98 maxv if (error) 423 1.1 jdolecek goto out1; 424 1.1 jdolecek 425 1.1 jdolecek /* Count valid entries */ 426 1.98 maxv for (num = 0; ; num++) { 427 1.1 jdolecek error = ntfs_readattr(ntmp, VTONT(vp), 428 1.1 jdolecek NTFS_A_DATA, NULL, 429 1.1 jdolecek num * sizeof(ad), sizeof(ad), 430 1.1 jdolecek &ad, NULL); 431 1.1 jdolecek if (error) 432 1.1 jdolecek goto out1; 433 1.1 jdolecek if (ad.ad_name[0] == 0) 434 1.1 jdolecek break; 435 1.1 jdolecek } 436 1.1 jdolecek 437 1.1 jdolecek /* Alloc memory for attribute definitions */ 438 1.1 jdolecek ntmp->ntm_ad = (struct ntvattrdef *) malloc( 439 1.1 jdolecek num * sizeof(struct ntvattrdef), 440 1.1 jdolecek M_NTFSMNT, M_WAITOK); 441 1.1 jdolecek 442 1.1 jdolecek ntmp->ntm_adnum = num; 443 1.1 jdolecek 444 1.1 jdolecek /* Read them and translate */ 445 1.98 maxv for (i = 0; i < num; i++) { 446 1.1 jdolecek error = ntfs_readattr(ntmp, VTONT(vp), 447 1.1 jdolecek NTFS_A_DATA, NULL, 448 1.1 jdolecek i * sizeof(ad), sizeof(ad), 449 1.1 jdolecek &ad, NULL); 450 1.1 jdolecek if (error) 451 1.1 jdolecek goto out1; 452 1.1 jdolecek j = 0; 453 1.1 jdolecek do { 454 1.1 jdolecek ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; 455 1.1 jdolecek } while(ad.ad_name[j++]); 456 1.1 jdolecek ntmp->ntm_ad[i].ad_namelen = j - 1; 457 1.1 jdolecek ntmp->ntm_ad[i].ad_type = ad.ad_type; 458 1.1 jdolecek } 459 1.1 jdolecek 460 1.1 jdolecek vput(vp); 461 1.1 jdolecek } 462 1.1 jdolecek 463 1.18 christos mp->mnt_stat.f_fsidx.__fsid_val[0] = dev; 464 1.18 christos mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_NTFS); 465 1.18 christos mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; 466 1.25 jdolecek mp->mnt_stat.f_namemax = NTFS_MAXFILENAME; 467 1.1 jdolecek mp->mnt_flag |= MNT_LOCAL; 468 1.88 hannken spec_node_setmountedfs(devvp, mp); 469 1.1 jdolecek return (0); 470 1.1 jdolecek 471 1.1 jdolecek out1: 472 1.98 maxv for (i = 0; i < NTFS_SYSNODESNUM; i++) 473 1.98 maxv if (ntmp->ntm_sysvn[i]) 474 1.98 maxv vrele(ntmp->ntm_sysvn[i]); 475 1.1 jdolecek 476 1.108 hannken vfs_vnode_iterator_init(mp, &marker); 477 1.108 hannken while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { 478 1.108 hannken if (vrecycle(vp)) 479 1.108 hannken continue; 480 1.108 hannken panic("%s: cannot recycle vnode %p", __func__, vp); 481 1.45 christos } 482 1.108 hannken vfs_vnode_iterator_destroy(marker); 483 1.1 jdolecek out: 484 1.88 hannken spec_node_setmountedfs(devvp, NULL); 485 1.1 jdolecek if (bp) 486 1.57 ad brelse(bp, 0); 487 1.1 jdolecek 488 1.38 christos if (error) { 489 1.40 christos if (ntmp) { 490 1.40 christos if (ntmp->ntm_ad) 491 1.40 christos free(ntmp->ntm_ad, M_NTFSMNT); 492 1.40 christos free(ntmp, M_NTFSMNT); 493 1.40 christos } 494 1.38 christos } 495 1.38 christos 496 1.1 jdolecek return (error); 497 1.1 jdolecek } 498 1.1 jdolecek 499 1.1 jdolecek static int 500 1.98 maxv ntfs_start(struct mount *mp, int flags) 501 1.1 jdolecek { 502 1.1 jdolecek return (0); 503 1.1 jdolecek } 504 1.1 jdolecek 505 1.1 jdolecek static int 506 1.98 maxv ntfs_unmount(struct mount *mp, int mntflags) 507 1.1 jdolecek { 508 1.59 pooka struct lwp *l = curlwp; 509 1.1 jdolecek struct ntfsmount *ntmp; 510 1.1 jdolecek int error, ronly = 0, flags, i; 511 1.1 jdolecek 512 1.1 jdolecek dprintf(("ntfs_unmount: unmounting...\n")); 513 1.1 jdolecek ntmp = VFSTONTFS(mp); 514 1.1 jdolecek 515 1.1 jdolecek flags = 0; 516 1.98 maxv if (mntflags & MNT_FORCE) 517 1.1 jdolecek flags |= FORCECLOSE; 518 1.1 jdolecek 519 1.1 jdolecek dprintf(("ntfs_unmount: vflushing...\n")); 520 1.98 maxv error = vflush(mp, NULLVP, flags | SKIPSYSTEM); 521 1.1 jdolecek if (error) { 522 1.1 jdolecek dprintf(("ntfs_unmount: vflush failed: %d\n",error)); 523 1.1 jdolecek return (error); 524 1.1 jdolecek } 525 1.1 jdolecek 526 1.1 jdolecek /* Check if only system vnodes are rest */ 527 1.98 maxv for (i = 0; i < NTFS_SYSNODESNUM; i++) 528 1.98 maxv if ((ntmp->ntm_sysvn[i]) && 529 1.110 ad (vrefcnt(ntmp->ntm_sysvn[i]) > 1)) 530 1.98 maxv return (EBUSY); 531 1.1 jdolecek 532 1.1 jdolecek /* Dereference all system vnodes */ 533 1.98 maxv for (i = 0; i < NTFS_SYSNODESNUM; i++) 534 1.98 maxv if (ntmp->ntm_sysvn[i]) 535 1.98 maxv vrele(ntmp->ntm_sysvn[i]); 536 1.1 jdolecek 537 1.1 jdolecek /* vflush system vnodes */ 538 1.98 maxv error = vflush(mp, NULLVP, flags); 539 1.1 jdolecek if (error) { 540 1.54 pooka panic("ntfs_unmount: vflush failed(sysnodes): %d\n",error); 541 1.1 jdolecek } 542 1.1 jdolecek 543 1.1 jdolecek /* Check if the type of device node isn't VBAD before 544 1.1 jdolecek * touching v_specinfo. If the device vnode is revoked, the 545 1.1 jdolecek * field is NULL and touching it causes null pointer derefercence. 546 1.1 jdolecek */ 547 1.1 jdolecek if (ntmp->ntm_devvp->v_type != VBAD) 548 1.88 hannken spec_node_setmountedfs(ntmp->ntm_devvp, NULL); 549 1.1 jdolecek 550 1.91 christos error = vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, l, 0, 0); 551 1.91 christos KASSERT(error == 0); 552 1.1 jdolecek 553 1.1 jdolecek /* lock the device vnode before calling VOP_CLOSE() */ 554 1.23 yamt vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY); 555 1.1 jdolecek error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, 556 1.59 pooka NOCRED); 557 1.54 pooka KASSERT(error == 0); 558 1.81 hannken VOP_UNLOCK(ntmp->ntm_devvp); 559 1.1 jdolecek 560 1.1 jdolecek vrele(ntmp->ntm_devvp); 561 1.1 jdolecek 562 1.1 jdolecek /* free the toupper table, if this has been last mounted ntfs volume */ 563 1.1 jdolecek ntfs_toupper_unuse(); 564 1.1 jdolecek 565 1.1 jdolecek dprintf(("ntfs_umount: freeing memory...\n")); 566 1.1 jdolecek mp->mnt_data = NULL; 567 1.1 jdolecek mp->mnt_flag &= ~MNT_LOCAL; 568 1.1 jdolecek free(ntmp->ntm_ad, M_NTFSMNT); 569 1.73 cegger free(ntmp, M_NTFSMNT); 570 1.54 pooka return (0); 571 1.1 jdolecek } 572 1.1 jdolecek 573 1.1 jdolecek static int 574 1.109 ad ntfs_root(struct mount *mp, int lktype, struct vnode **vpp) 575 1.1 jdolecek { 576 1.1 jdolecek struct vnode *nvp; 577 1.1 jdolecek int error = 0; 578 1.1 jdolecek 579 1.1 jdolecek dprintf(("ntfs_root(): sysvn: %p\n", 580 1.1 jdolecek VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO])); 581 1.109 ad error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, lktype, &nvp); 582 1.98 maxv if (error) { 583 1.98 maxv printf("ntfs_root: VFS_VGET failed: %d\n", error); 584 1.1 jdolecek return (error); 585 1.1 jdolecek } 586 1.1 jdolecek 587 1.1 jdolecek *vpp = nvp; 588 1.1 jdolecek return (0); 589 1.1 jdolecek } 590 1.1 jdolecek 591 1.1 jdolecek int 592 1.98 maxv ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep) 593 1.1 jdolecek { 594 1.1 jdolecek struct vnode *vp; 595 1.1 jdolecek u_int8_t *tmp; 596 1.1 jdolecek int j, error; 597 1.16 jdolecek cn_t cfree = 0; 598 1.1 jdolecek size_t bmsize, i; 599 1.1 jdolecek 600 1.1 jdolecek vp = ntmp->ntm_sysvn[NTFS_BITMAPINO]; 601 1.1 jdolecek bmsize = VTOF(vp)->f_size; 602 1.1 jdolecek tmp = (u_int8_t *) malloc(bmsize, M_TEMP, M_WAITOK); 603 1.1 jdolecek 604 1.1 jdolecek error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 605 1.98 maxv 0, bmsize, tmp, NULL); 606 1.1 jdolecek if (error) 607 1.1 jdolecek goto out; 608 1.1 jdolecek 609 1.98 maxv for (i = 0; i < bmsize; i++) 610 1.98 maxv for (j = 0; j < 8; j++) 611 1.98 maxv if (~tmp[i] & (1 << j)) 612 1.98 maxv cfree++; 613 1.1 jdolecek *cfreep = cfree; 614 1.1 jdolecek 615 1.98 maxv out: 616 1.1 jdolecek free(tmp, M_TEMP); 617 1.1 jdolecek return(error); 618 1.1 jdolecek } 619 1.1 jdolecek 620 1.1 jdolecek static int 621 1.98 maxv ntfs_statvfs(struct mount *mp, struct statvfs *sbp) 622 1.1 jdolecek { 623 1.1 jdolecek struct ntfsmount *ntmp = VFSTONTFS(mp); 624 1.1 jdolecek u_int64_t mftallocated; 625 1.1 jdolecek 626 1.18 christos dprintf(("ntfs_statvfs():\n")); 627 1.1 jdolecek 628 1.1 jdolecek mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated; 629 1.1 jdolecek 630 1.1 jdolecek sbp->f_bsize = ntmp->ntm_bps; 631 1.18 christos sbp->f_frsize = sbp->f_bsize; /* XXX */ 632 1.1 jdolecek sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc; 633 1.1 jdolecek sbp->f_blocks = ntmp->ntm_bootfile.bf_spv; 634 1.1 jdolecek sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree); 635 1.18 christos sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec; 636 1.1 jdolecek sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) + 637 1.18 christos sbp->f_ffree; 638 1.18 christos sbp->f_fresvd = sbp->f_bresvd = 0; /* XXX */ 639 1.18 christos sbp->f_flag = mp->mnt_flag; 640 1.18 christos copy_statvfs_info(sbp, mp); 641 1.1 jdolecek return (0); 642 1.1 jdolecek } 643 1.1 jdolecek 644 1.1 jdolecek static int 645 1.98 maxv ntfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) 646 1.1 jdolecek { 647 1.1 jdolecek /*dprintf(("ntfs_sync():\n"));*/ 648 1.1 jdolecek return (0); 649 1.1 jdolecek } 650 1.1 jdolecek 651 1.1 jdolecek /*ARGSUSED*/ 652 1.1 jdolecek static int 653 1.109 ad ntfs_fhtovp(struct mount *mp, struct fid *fhp, int lktype, struct vnode **vpp) 654 1.1 jdolecek { 655 1.42 martin struct ntfid ntfh; 656 1.1 jdolecek int error; 657 1.1 jdolecek 658 1.42 martin if (fhp->fid_len != sizeof(struct ntfid)) 659 1.42 martin return EINVAL; 660 1.42 martin memcpy(&ntfh, fhp, sizeof(ntfh)); 661 1.35 christos ddprintf(("ntfs_fhtovp(): %s: %llu\n", mp->mnt_stat.f_mntonname, 662 1.42 martin (unsigned long long)ntfh.ntfid_ino)); 663 1.1 jdolecek 664 1.95 hannken error = ntfs_vgetex(mp, ntfh.ntfid_ino, ntfh.ntfid_attr, "", 665 1.109 ad lktype, vpp); 666 1.1 jdolecek if (error != 0) { 667 1.1 jdolecek *vpp = NULLVP; 668 1.1 jdolecek return (error); 669 1.1 jdolecek } 670 1.1 jdolecek 671 1.1 jdolecek /* XXX as unlink/rmdir/mkdir/creat are not currently possible 672 1.1 jdolecek * with NTFS, we don't need to check anything else for now */ 673 1.1 jdolecek return (0); 674 1.1 jdolecek } 675 1.1 jdolecek 676 1.1 jdolecek static int 677 1.98 maxv ntfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) 678 1.1 jdolecek { 679 1.1 jdolecek struct ntnode *ntp; 680 1.42 martin struct ntfid ntfh; 681 1.1 jdolecek struct fnode *fn; 682 1.1 jdolecek 683 1.42 martin if (*fh_size < sizeof(struct ntfid)) { 684 1.42 martin *fh_size = sizeof(struct ntfid); 685 1.42 martin return E2BIG; 686 1.42 martin } 687 1.42 martin *fh_size = sizeof(struct ntfid); 688 1.42 martin 689 1.1 jdolecek ddprintf(("ntfs_fhtovp(): %s: %p\n", vp->v_mount->mnt_stat.f_mntonname, 690 1.1 jdolecek vp)); 691 1.1 jdolecek 692 1.1 jdolecek fn = VTOF(vp); 693 1.1 jdolecek ntp = VTONT(vp); 694 1.42 martin memset(&ntfh, 0, sizeof(ntfh)); 695 1.42 martin ntfh.ntfid_len = sizeof(struct ntfid); 696 1.42 martin ntfh.ntfid_ino = ntp->i_number; 697 1.42 martin ntfh.ntfid_attr = fn->f_attrtype; 698 1.1 jdolecek #ifdef notyet 699 1.42 martin ntfh.ntfid_gen = ntp->i_gen; 700 1.1 jdolecek #endif 701 1.42 martin memcpy(fhp, &ntfh, sizeof(ntfh)); 702 1.1 jdolecek return (0); 703 1.1 jdolecek } 704 1.1 jdolecek 705 1.97 hannken static int 706 1.97 hannken ntfs_loadvnode(struct mount *mp, struct vnode *vp, 707 1.97 hannken const void *key, size_t key_len, const void **new_key) 708 1.1 jdolecek { 709 1.1 jdolecek int error; 710 1.97 hannken struct ntvattr *vap; 711 1.97 hannken struct ntkey small_key, *ntkey; 712 1.1 jdolecek struct ntfsmount *ntmp; 713 1.1 jdolecek struct ntnode *ip; 714 1.97 hannken struct fnode *fp = NULL; 715 1.13 christos enum vtype f_type = VBAD; 716 1.1 jdolecek 717 1.97 hannken if (key_len <= sizeof(small_key)) 718 1.97 hannken ntkey = &small_key; 719 1.97 hannken else 720 1.97 hannken ntkey = kmem_alloc(key_len, KM_SLEEP); 721 1.97 hannken memcpy(ntkey, key, key_len); 722 1.97 hannken 723 1.97 hannken dprintf(("ntfs_loadvnode: ino: %llu, attr: 0x%x:%s", 724 1.97 hannken (unsigned long long)ntkey->k_ino, 725 1.97 hannken ntkey->k_attrtype, ntkey->k_attrname)); 726 1.1 jdolecek 727 1.1 jdolecek ntmp = VFSTONTFS(mp); 728 1.1 jdolecek 729 1.1 jdolecek /* Get ntnode */ 730 1.97 hannken error = ntfs_ntlookup(ntmp, ntkey->k_ino, &ip); 731 1.1 jdolecek if (error) { 732 1.97 hannken printf("ntfs_loadvnode: ntfs_ntget failed\n"); 733 1.97 hannken goto out; 734 1.1 jdolecek } 735 1.1 jdolecek /* It may be not initialized fully, so force load it */ 736 1.96 hannken if (!(ip->i_flag & IN_LOADED)) { 737 1.98 maxv error = ntfs_loadntnode(ntmp, ip); 738 1.98 maxv if (error) { 739 1.98 maxv printf("ntfs_loadvnode: CAN'T LOAD ATTRIBUTES FOR INO:" 740 1.98 maxv " %llu\n", (unsigned long long)ip->i_number); 741 1.98 maxv ntfs_ntput(ip); 742 1.98 maxv goto out; 743 1.98 maxv } 744 1.1 jdolecek } 745 1.1 jdolecek 746 1.97 hannken /* Setup fnode */ 747 1.97 hannken fp = kmem_zalloc(sizeof(*fp), KM_SLEEP); 748 1.97 hannken dprintf(("%s: allocating fnode: %p\n", __func__, fp)); 749 1.96 hannken 750 1.97 hannken error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap); 751 1.83 hannken if (error) { 752 1.102 hannken printf("%s: attr %x for ino %" PRId64 ": error %d\n", 753 1.102 hannken __func__, NTFS_A_NAME, ip->i_number, error); 754 1.83 hannken ntfs_ntput(ip); 755 1.97 hannken goto out; 756 1.83 hannken } 757 1.97 hannken fp->f_fflag = vap->va_a_name->n_flag; 758 1.97 hannken fp->f_pnumber = vap->va_a_name->n_pnumber; 759 1.97 hannken fp->f_times = vap->va_a_name->n_times; 760 1.97 hannken ntfs_ntvattrrele(vap); 761 1.97 hannken 762 1.97 hannken if ((ip->i_frflag & NTFS_FRFLAG_DIR) && 763 1.97 hannken (ntkey->k_attrtype == NTFS_A_DATA && 764 1.97 hannken strcmp(ntkey->k_attrname, "") == 0)) { 765 1.98 maxv f_type = VDIR; 766 1.97 hannken } else { 767 1.97 hannken f_type = VREG; 768 1.97 hannken error = ntfs_ntvattrget(ntmp, ip, 769 1.97 hannken ntkey->k_attrtype, ntkey->k_attrname, 0, &vap); 770 1.97 hannken if (error == 0) { 771 1.97 hannken fp->f_size = vap->va_datalen; 772 1.97 hannken fp->f_allocated = vap->va_allocated; 773 1.97 hannken ntfs_ntvattrrele(vap); 774 1.97 hannken } else if (ntkey->k_attrtype == NTFS_A_DATA && 775 1.97 hannken strcmp(ntkey->k_attrname, "") == 0 && 776 1.97 hannken error == ENOENT) { 777 1.97 hannken fp->f_size = 0; 778 1.97 hannken fp->f_allocated = 0; 779 1.97 hannken error = 0; 780 1.101 christos } else { 781 1.102 hannken printf("%s: attr %x for ino %" PRId64 ": error %d\n", 782 1.102 hannken __func__, ntkey->k_attrtype, ip->i_number, error); 783 1.102 hannken ntfs_ntput(ip); 784 1.97 hannken goto out; 785 1.101 christos } 786 1.97 hannken } 787 1.97 hannken 788 1.97 hannken if (key_len <= sizeof(fp->f_smallkey)) 789 1.97 hannken fp->f_key = &fp->f_smallkey; 790 1.97 hannken else 791 1.97 hannken fp->f_key = kmem_alloc(key_len, KM_SLEEP); 792 1.97 hannken fp->f_ip = ip; 793 1.97 hannken fp->f_ino = ip->i_number; 794 1.97 hannken strcpy(fp->f_attrname, ntkey->k_attrname); 795 1.97 hannken fp->f_attrtype = ntkey->k_attrtype; 796 1.1 jdolecek fp->f_vp = vp; 797 1.1 jdolecek vp->v_data = fp; 798 1.97 hannken 799 1.97 hannken vp->v_tag = VT_NTFS; 800 1.97 hannken vp->v_type = f_type; 801 1.97 hannken vp->v_op = ntfs_vnodeop_p; 802 1.97 hannken ntfs_ntref(ip); 803 1.97 hannken vref(ip->i_devvp); 804 1.64 pooka genfs_node_init(vp, &ntfs_genfsops); 805 1.1 jdolecek 806 1.97 hannken if (ip->i_number == NTFS_ROOTINO) 807 1.58 ad vp->v_vflag |= VV_ROOT; 808 1.1 jdolecek 809 1.97 hannken uvm_vnp_setsize(vp, fp->f_size); 810 1.83 hannken ntfs_ntput(ip); 811 1.83 hannken 812 1.97 hannken *new_key = fp->f_key; 813 1.97 hannken 814 1.97 hannken fp = NULL; 815 1.97 hannken 816 1.97 hannken out: 817 1.97 hannken if (ntkey != &small_key) 818 1.97 hannken kmem_free(ntkey, key_len); 819 1.97 hannken if (fp) 820 1.97 hannken kmem_free(fp, sizeof(*fp)); 821 1.1 jdolecek 822 1.97 hannken return error; 823 1.1 jdolecek } 824 1.1 jdolecek 825 1.1 jdolecek static int 826 1.109 ad ntfs_vget(struct mount *mp, ino_t ino, int lktype, struct vnode **vpp) 827 1.1 jdolecek { 828 1.109 ad return ntfs_vgetex(mp, ino, NTFS_A_DATA, "", lktype, vpp); 829 1.1 jdolecek } 830 1.1 jdolecek 831 1.97 hannken int 832 1.98 maxv ntfs_vgetex(struct mount *mp, ino_t ino, u_int32_t attrtype, 833 1.98 maxv const char *attrname, u_long lkflags, struct vnode **vpp) 834 1.97 hannken { 835 1.97 hannken const int attrlen = strlen(attrname); 836 1.97 hannken int error; 837 1.97 hannken struct ntkey small_key, *ntkey; 838 1.97 hannken 839 1.97 hannken if (NTKEY_SIZE(attrlen) <= sizeof(small_key)) 840 1.97 hannken ntkey = &small_key; 841 1.97 hannken else 842 1.97 hannken ntkey = malloc(NTKEY_SIZE(attrlen), M_TEMP, M_WAITOK); 843 1.97 hannken ntkey->k_ino = ino; 844 1.97 hannken ntkey->k_attrtype = attrtype; 845 1.97 hannken strcpy(ntkey->k_attrname, attrname); 846 1.97 hannken 847 1.97 hannken error = vcache_get(mp, ntkey, NTKEY_SIZE(attrlen), vpp); 848 1.97 hannken if (error) 849 1.97 hannken goto out; 850 1.97 hannken 851 1.97 hannken if ((lkflags & (LK_SHARED | LK_EXCLUSIVE)) != 0) { 852 1.97 hannken error = vn_lock(*vpp, lkflags); 853 1.97 hannken if (error) { 854 1.97 hannken vrele(*vpp); 855 1.97 hannken *vpp = NULL; 856 1.97 hannken } 857 1.97 hannken } 858 1.97 hannken 859 1.97 hannken out: 860 1.97 hannken if (ntkey != &small_key) 861 1.97 hannken free(ntkey, M_TEMP); 862 1.97 hannken return error; 863 1.97 hannken } 864 1.97 hannken 865 1.1 jdolecek extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc; 866 1.1 jdolecek 867 1.1 jdolecek const struct vnodeopv_desc * const ntfs_vnodeopv_descs[] = { 868 1.1 jdolecek &ntfs_vnodeop_opv_desc, 869 1.1 jdolecek NULL, 870 1.1 jdolecek }; 871 1.1 jdolecek 872 1.1 jdolecek struct vfsops ntfs_vfsops = { 873 1.93 hannken .vfs_name = MOUNT_NTFS, 874 1.93 hannken .vfs_min_mount_data = sizeof (struct ntfs_args), 875 1.93 hannken .vfs_mount = ntfs_mount, 876 1.93 hannken .vfs_start = ntfs_start, 877 1.93 hannken .vfs_unmount = ntfs_unmount, 878 1.93 hannken .vfs_root = ntfs_root, 879 1.93 hannken .vfs_quotactl = (void *)eopnotsupp, 880 1.93 hannken .vfs_statvfs = ntfs_statvfs, 881 1.93 hannken .vfs_sync = ntfs_sync, 882 1.93 hannken .vfs_vget = ntfs_vget, 883 1.97 hannken .vfs_loadvnode = ntfs_loadvnode, 884 1.93 hannken .vfs_fhtovp = ntfs_fhtovp, 885 1.93 hannken .vfs_vptofh = ntfs_vptofh, 886 1.93 hannken .vfs_init = ntfs_init, 887 1.93 hannken .vfs_reinit = ntfs_reinit, 888 1.93 hannken .vfs_done = ntfs_done, 889 1.93 hannken .vfs_mountroot = ntfs_mountroot, 890 1.93 hannken .vfs_snapshot = (void *)eopnotsupp, 891 1.93 hannken .vfs_extattrctl = vfs_stdextattrctl, 892 1.105 hannken .vfs_suspendctl = genfs_suspendctl, 893 1.93 hannken .vfs_renamelock_enter = genfs_renamelock_enter, 894 1.93 hannken .vfs_renamelock_exit = genfs_renamelock_exit, 895 1.93 hannken .vfs_fsync = (void *)eopnotsupp, 896 1.93 hannken .vfs_opv_descs = ntfs_vnodeopv_descs 897 1.1 jdolecek }; 898 1.70 rumble 899 1.70 rumble static int 900 1.70 rumble ntfs_modcmd(modcmd_t cmd, void *arg) 901 1.70 rumble { 902 1.72 rumble int error; 903 1.70 rumble 904 1.70 rumble switch (cmd) { 905 1.70 rumble case MODULE_CMD_INIT: 906 1.72 rumble error = vfs_attach(&ntfs_vfsops); 907 1.72 rumble if (error != 0) 908 1.72 rumble break; 909 1.72 rumble sysctl_createv(&ntfs_sysctl_log, 0, NULL, NULL, 910 1.72 rumble CTLFLAG_PERMANENT, 911 1.72 rumble CTLTYPE_NODE, "ntfs", 912 1.72 rumble SYSCTL_DESCR("NTFS file system"), 913 1.72 rumble NULL, 0, NULL, 0, 914 1.72 rumble CTL_VFS, 20, CTL_EOL); 915 1.72 rumble /* 916 1.72 rumble * XXX the "20" above could be dynamic, thereby eliminating 917 1.72 rumble * one more instance of the "number to vfs" mapping problem, 918 1.72 rumble * but "20" is the order as taken from sys/mount.h 919 1.72 rumble */ 920 1.72 rumble break; 921 1.70 rumble case MODULE_CMD_FINI: 922 1.72 rumble error = vfs_detach(&ntfs_vfsops); 923 1.72 rumble if (error != 0) 924 1.72 rumble break; 925 1.72 rumble sysctl_teardown(&ntfs_sysctl_log); 926 1.72 rumble break; 927 1.70 rumble default: 928 1.72 rumble error = ENOTTY; 929 1.72 rumble break; 930 1.70 rumble } 931 1.72 rumble 932 1.72 rumble return (error); 933 1.70 rumble } 934