1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/param.h> 30*0Sstevel@tonic-gate #include <sys/errno.h> 31*0Sstevel@tonic-gate #include <sys/systm.h> 32*0Sstevel@tonic-gate #include <sys/sysmacros.h> 33*0Sstevel@tonic-gate #include <sys/buf.h> 34*0Sstevel@tonic-gate #include <sys/vfs.h> 35*0Sstevel@tonic-gate #include <sys/kmem.h> 36*0Sstevel@tonic-gate #include <sys/vnode.h> 37*0Sstevel@tonic-gate #include <sys/debug.h> 38*0Sstevel@tonic-gate #include <sys/cmn_err.h> 39*0Sstevel@tonic-gate #include <sys/fs/pc_label.h> 40*0Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 41*0Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 42*0Sstevel@tonic-gate #include <sys/fs/pc_node.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate static int pc_makedirentry(struct pcnode *dp, struct pcdir *direntries, 45*0Sstevel@tonic-gate int ndirentries, struct vattr *vap, offset_t offset); 46*0Sstevel@tonic-gate static int pc_dirempty(struct pcnode *); 47*0Sstevel@tonic-gate static int pc_findentry(struct pcnode *, char *, struct slot *, offset_t *); 48*0Sstevel@tonic-gate static int pc_parsename(char *, char *, char *); 49*0Sstevel@tonic-gate static int pc_remove_long_fn(struct pcnode *pcp, 50*0Sstevel@tonic-gate offset_t lfn_offset); 51*0Sstevel@tonic-gate static int generate_short_name(struct pcnode *dp, char *namep, 52*0Sstevel@tonic-gate struct pcdir *ep); 53*0Sstevel@tonic-gate static struct pcdir *pc_name_to_pcdir(struct pcnode *dp, char *namep, 54*0Sstevel@tonic-gate int ndirentries, int *errret); 55*0Sstevel@tonic-gate static offset_t pc_find_free_space(struct pcnode *pcp, int ndirentries); 56*0Sstevel@tonic-gate static int direntries_needed(struct pcnode *dp, char *namep); 57*0Sstevel@tonic-gate static int pc_is_short_file_name(char *namep, int foldcase); 58*0Sstevel@tonic-gate static int shortname_exists(struct pcnode *dp, char *fname, char *fext); 59*0Sstevel@tonic-gate static int pc_dirfixdotdot(struct pcnode *cdp, struct pcnode *opdp, 60*0Sstevel@tonic-gate struct pcnode *npdp); 61*0Sstevel@tonic-gate /* 62*0Sstevel@tonic-gate * Tunables 63*0Sstevel@tonic-gate */ 64*0Sstevel@tonic-gate int enable_long_filenames = 1; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* 67*0Sstevel@tonic-gate * Lookup a name in a directory. Return a pointer to the pc_node 68*0Sstevel@tonic-gate * which represents the entry. 69*0Sstevel@tonic-gate */ 70*0Sstevel@tonic-gate int 71*0Sstevel@tonic-gate pc_dirlook( 72*0Sstevel@tonic-gate struct pcnode *dp, /* parent directory */ 73*0Sstevel@tonic-gate char *namep, /* name to lookup */ 74*0Sstevel@tonic-gate struct pcnode **pcpp) /* result */ 75*0Sstevel@tonic-gate { 76*0Sstevel@tonic-gate struct vnode *vp; 77*0Sstevel@tonic-gate struct slot slot; 78*0Sstevel@tonic-gate int error; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate PC_DPRINTF2(4, "pc_dirlook (dp %p name %s)\n", (void *)dp, namep); 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate if (!(dp->pc_entry.pcd_attr & PCA_DIR)) { 83*0Sstevel@tonic-gate return (ENOTDIR); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate vp = PCTOV(dp); 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * check now for changed disk, before any return(0) 88*0Sstevel@tonic-gate */ 89*0Sstevel@tonic-gate if (error = pc_verify(VFSTOPCFS(vp->v_vfsp))) 90*0Sstevel@tonic-gate return (error); 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate /* 93*0Sstevel@tonic-gate * Null component name is synonym for directory being searched. 94*0Sstevel@tonic-gate */ 95*0Sstevel@tonic-gate if (*namep == '\0') { 96*0Sstevel@tonic-gate VN_HOLD(vp); 97*0Sstevel@tonic-gate *pcpp = dp; 98*0Sstevel@tonic-gate return (0); 99*0Sstevel@tonic-gate } 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * The root directory does not have "." and ".." entries, 102*0Sstevel@tonic-gate * so they are faked here. 103*0Sstevel@tonic-gate */ 104*0Sstevel@tonic-gate if (vp->v_flag & VROOT) { 105*0Sstevel@tonic-gate if (bcmp(namep, ".", 2) == 0 || bcmp(namep, "..", 3) == 0) { 106*0Sstevel@tonic-gate VN_HOLD(vp); 107*0Sstevel@tonic-gate *pcpp = dp; 108*0Sstevel@tonic-gate return (0); 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate error = pc_findentry(dp, namep, &slot, NULL); 112*0Sstevel@tonic-gate if (error == 0) { 113*0Sstevel@tonic-gate *pcpp = pc_getnode(VFSTOPCFS(vp->v_vfsp), 114*0Sstevel@tonic-gate slot.sl_blkno, slot.sl_offset, slot.sl_ep); 115*0Sstevel@tonic-gate brelse(slot.sl_bp); 116*0Sstevel@tonic-gate PC_DPRINTF1(4, "pc_dirlook: FOUND pcp=%p\n", (void *)*pcpp); 117*0Sstevel@tonic-gate } else if (error == EINVAL) { 118*0Sstevel@tonic-gate error = ENOENT; 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate return (error); 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate /* 124*0Sstevel@tonic-gate * Enter a name in a directory. 125*0Sstevel@tonic-gate */ 126*0Sstevel@tonic-gate int 127*0Sstevel@tonic-gate pc_direnter( 128*0Sstevel@tonic-gate struct pcnode *dp, /* directory to make entry in */ 129*0Sstevel@tonic-gate char *namep, /* name of entry */ 130*0Sstevel@tonic-gate struct vattr *vap, /* attributes of new entry */ 131*0Sstevel@tonic-gate struct pcnode **pcpp) 132*0Sstevel@tonic-gate { 133*0Sstevel@tonic-gate int error; 134*0Sstevel@tonic-gate struct slot slot; 135*0Sstevel@tonic-gate struct vnode *vp = PCTOV(dp); 136*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 137*0Sstevel@tonic-gate offset_t offset; 138*0Sstevel@tonic-gate int blkno; 139*0Sstevel@tonic-gate int boff; 140*0Sstevel@tonic-gate struct buf *bp = NULL; 141*0Sstevel@tonic-gate struct pcdir *ep; 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate PC_DPRINTF4(4, "pc_dirent(dp %p, name %s, vap %p, pcpp %p\n", 144*0Sstevel@tonic-gate (void *)dp, namep, (void *)vap, (void *)pcpp); 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate if (pcpp != NULL) 147*0Sstevel@tonic-gate *pcpp = NULL; 148*0Sstevel@tonic-gate /* 149*0Sstevel@tonic-gate * Leading spaces are not allowed in DOS. 150*0Sstevel@tonic-gate */ 151*0Sstevel@tonic-gate if (*namep == ' ') 152*0Sstevel@tonic-gate return (EINVAL); 153*0Sstevel@tonic-gate /* 154*0Sstevel@tonic-gate * If name is "." or "..", just look it up. 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate if (PC_NAME_IS_DOT(namep) || PC_NAME_IS_DOTDOT(namep)) { 157*0Sstevel@tonic-gate if (pcpp) { 158*0Sstevel@tonic-gate error = pc_dirlook(dp, namep, pcpp); 159*0Sstevel@tonic-gate if (error) 160*0Sstevel@tonic-gate return (error); 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate return (EEXIST); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, dp->pc_entry.pcd_attr)) { 165*0Sstevel@tonic-gate return (EPERM); 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate /* 168*0Sstevel@tonic-gate * Make sure directory has not been removed while fs was unlocked. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate if (dp->pc_entry.pcd_filename[0] == PCD_ERASED) { 171*0Sstevel@tonic-gate return (ENOENT); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate error = pc_findentry(dp, namep, &slot, NULL); 174*0Sstevel@tonic-gate if (error == 0) { 175*0Sstevel@tonic-gate if (pcpp) { 176*0Sstevel@tonic-gate *pcpp = 177*0Sstevel@tonic-gate pc_getnode(fsp, slot.sl_blkno, slot.sl_offset, 178*0Sstevel@tonic-gate slot.sl_ep); 179*0Sstevel@tonic-gate error = EEXIST; 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate brelse(slot.sl_bp); 182*0Sstevel@tonic-gate } else if (error == ENOENT) { 183*0Sstevel@tonic-gate struct pcdir *direntries; 184*0Sstevel@tonic-gate int ndirentries; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* 187*0Sstevel@tonic-gate * The entry does not exist. Check write permission in 188*0Sstevel@tonic-gate * directory to see if entry can be created. 189*0Sstevel@tonic-gate */ 190*0Sstevel@tonic-gate if (dp->pc_entry.pcd_attr & PCA_RDONLY) { 191*0Sstevel@tonic-gate return (EPERM); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate error = 0; 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate * Make sure there is a slot. 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate if (slot.sl_status == SL_NONE) 198*0Sstevel@tonic-gate panic("pc_direnter: no slot\n"); 199*0Sstevel@tonic-gate ndirentries = direntries_needed(dp, namep); 200*0Sstevel@tonic-gate if (ndirentries == -1) { 201*0Sstevel@tonic-gate return (EINVAL); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate offset = pc_find_free_space(dp, ndirentries); 205*0Sstevel@tonic-gate if (offset == -1) { 206*0Sstevel@tonic-gate return (ENOSPC); 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * Make an entry from the supplied attributes. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate direntries = pc_name_to_pcdir(dp, namep, ndirentries, &error); 213*0Sstevel@tonic-gate if (direntries == NULL) { 214*0Sstevel@tonic-gate return (error); 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate error = pc_makedirentry(dp, direntries, ndirentries, vap, 217*0Sstevel@tonic-gate offset); 218*0Sstevel@tonic-gate kmem_free(direntries, ndirentries * sizeof (struct pcdir)); 219*0Sstevel@tonic-gate if (error) { 220*0Sstevel@tonic-gate return (error); 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate offset += (ndirentries - 1) * sizeof (struct pcdir); 223*0Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 224*0Sstevel@tonic-gate error = pc_blkatoff(dp, offset, &bp, &ep); 225*0Sstevel@tonic-gate if (error) { 226*0Sstevel@tonic-gate return (error); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate blkno = pc_daddrdb(fsp, bp->b_blkno); 229*0Sstevel@tonic-gate /* 230*0Sstevel@tonic-gate * Get a pcnode for the new entry. 231*0Sstevel@tonic-gate */ 232*0Sstevel@tonic-gate *pcpp = pc_getnode(fsp, blkno, boff, ep); 233*0Sstevel@tonic-gate brelse(bp); 234*0Sstevel@tonic-gate if (vap->va_type == VDIR) 235*0Sstevel@tonic-gate (*pcpp)->pc_size = fsp->pcfs_clsize; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* 238*0Sstevel@tonic-gate * Write out the new entry in the parent directory. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate error = pc_syncfat(fsp); 241*0Sstevel@tonic-gate if (!error) { 242*0Sstevel@tonic-gate error = pc_nodeupdate(*pcpp); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate return (error); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate /* 249*0Sstevel@tonic-gate * Template for "." and ".." directory entries. 250*0Sstevel@tonic-gate */ 251*0Sstevel@tonic-gate static struct { 252*0Sstevel@tonic-gate struct pcdir t_dot; /* dot entry */ 253*0Sstevel@tonic-gate struct pcdir t_dotdot; /* dotdot entry */ 254*0Sstevel@tonic-gate } dirtemplate = { 255*0Sstevel@tonic-gate { 256*0Sstevel@tonic-gate ". ", 257*0Sstevel@tonic-gate " ", 258*0Sstevel@tonic-gate PCA_DIR 259*0Sstevel@tonic-gate }, 260*0Sstevel@tonic-gate { 261*0Sstevel@tonic-gate ".. ", 262*0Sstevel@tonic-gate " ", 263*0Sstevel@tonic-gate PCA_DIR 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate }; 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * Convert an attributes structure into the short filename entry 269*0Sstevel@tonic-gate * and write out the whole entry. 270*0Sstevel@tonic-gate */ 271*0Sstevel@tonic-gate static int 272*0Sstevel@tonic-gate pc_makedirentry(struct pcnode *dp, struct pcdir *direntries, 273*0Sstevel@tonic-gate int ndirentries, struct vattr *vap, offset_t offset) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate struct vnode *vp = PCTOV(dp); 276*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 277*0Sstevel@tonic-gate int error; 278*0Sstevel@tonic-gate struct pcdir *ep; 279*0Sstevel@tonic-gate int boff; 280*0Sstevel@tonic-gate int i; 281*0Sstevel@tonic-gate struct buf *bp = NULL; 282*0Sstevel@tonic-gate timestruc_t now; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate if (vap != NULL && vap->va_mask & (AT_ATIME|AT_MTIME)) 285*0Sstevel@tonic-gate return (EOPNOTSUPP); 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate ep = &direntries[ndirentries - 1]; 288*0Sstevel@tonic-gate gethrestime(&now); 289*0Sstevel@tonic-gate pc_tvtopct(&now, &ep->pcd_mtime); 290*0Sstevel@tonic-gate ep->pcd_crtime = ep->pcd_mtime; 291*0Sstevel@tonic-gate ep->pcd_ladate = ep->pcd_mtime.pct_date; 292*0Sstevel@tonic-gate ep->pcd_crtime_msec = 0; 293*0Sstevel@tonic-gate ep->pcd_size = 0; 294*0Sstevel@tonic-gate ep->pcd_attr = 0; 295*0Sstevel@tonic-gate /* 296*0Sstevel@tonic-gate * Fields we don't use. 297*0Sstevel@tonic-gate */ 298*0Sstevel@tonic-gate ep->pcd_ntattr = 0; 299*0Sstevel@tonic-gate if (!IS_FAT32(fsp)) 300*0Sstevel@tonic-gate ep->un.pcd_eattr = 0; 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate if (vap && ((vap->va_mode & 0222) == 0)) 303*0Sstevel@tonic-gate ep->pcd_attr |= PCA_RDONLY; 304*0Sstevel@tonic-gate if (vap && (vap->va_type == VDIR)) { 305*0Sstevel@tonic-gate pc_cluster32_t cn; 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate ep->pcd_attr |= PCA_DIR; 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * Make dot and dotdot entries for a new directory. 310*0Sstevel@tonic-gate */ 311*0Sstevel@tonic-gate cn = pc_alloccluster(fsp, 0); 312*0Sstevel@tonic-gate switch (cn) { 313*0Sstevel@tonic-gate case PCF_FREECLUSTER: 314*0Sstevel@tonic-gate return (ENOSPC); 315*0Sstevel@tonic-gate case PCF_ERRORCLUSTER: 316*0Sstevel@tonic-gate return (EIO); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate bp = ngeteblk(fsp->pcfs_clsize); 319*0Sstevel@tonic-gate bp->b_edev = fsp->pcfs_xdev; 320*0Sstevel@tonic-gate bp->b_dev = cmpdev(bp->b_edev); 321*0Sstevel@tonic-gate bp->b_blkno = pc_cldaddr(fsp, cn); 322*0Sstevel@tonic-gate clrbuf(bp); 323*0Sstevel@tonic-gate pc_setstartcluster(fsp, ep, cn); 324*0Sstevel@tonic-gate pc_setstartcluster(fsp, &dirtemplate.t_dot, cn); 325*0Sstevel@tonic-gate cn = pc_getstartcluster(fsp, &dp->pc_entry); 326*0Sstevel@tonic-gate pc_setstartcluster(fsp, &dirtemplate.t_dotdot, cn); 327*0Sstevel@tonic-gate dirtemplate.t_dot.pcd_mtime = 328*0Sstevel@tonic-gate dirtemplate.t_dotdot.pcd_mtime = ep->pcd_mtime; 329*0Sstevel@tonic-gate dirtemplate.t_dot.pcd_crtime = 330*0Sstevel@tonic-gate dirtemplate.t_dotdot.pcd_crtime = ep->pcd_crtime; 331*0Sstevel@tonic-gate dirtemplate.t_dot.pcd_ladate = 332*0Sstevel@tonic-gate dirtemplate.t_dotdot.pcd_ladate = ep->pcd_ladate; 333*0Sstevel@tonic-gate dirtemplate.t_dot.pcd_crtime_msec = 334*0Sstevel@tonic-gate dirtemplate.t_dotdot.pcd_crtime_msec = 0; 335*0Sstevel@tonic-gate bcopy(&dirtemplate, 336*0Sstevel@tonic-gate bp->b_un.b_addr, sizeof (dirtemplate)); 337*0Sstevel@tonic-gate bwrite2(bp); 338*0Sstevel@tonic-gate error = geterror(bp); 339*0Sstevel@tonic-gate brelse(bp); 340*0Sstevel@tonic-gate if (error) { 341*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_makedirentry error"); 342*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 343*0Sstevel@tonic-gate return (EIO); 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate } else { 346*0Sstevel@tonic-gate pc_setstartcluster(fsp, ep, 0); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate bp = NULL; 349*0Sstevel@tonic-gate for (i = 0, ep = NULL; i < ndirentries; i++, ep++) { 350*0Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 351*0Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 352*0Sstevel@tonic-gate if (bp != NULL) { 353*0Sstevel@tonic-gate /* always modified */ 354*0Sstevel@tonic-gate bwrite2(bp); 355*0Sstevel@tonic-gate error = geterror(bp); 356*0Sstevel@tonic-gate brelse(bp); 357*0Sstevel@tonic-gate if (error) 358*0Sstevel@tonic-gate return (error); 359*0Sstevel@tonic-gate bp = NULL; 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate error = pc_blkatoff(dp, offset, &bp, &ep); 362*0Sstevel@tonic-gate if (error) 363*0Sstevel@tonic-gate return (error); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate *ep = direntries[i]; 367*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate if (bp != NULL) { 370*0Sstevel@tonic-gate /* always modified */ 371*0Sstevel@tonic-gate bwrite2(bp); 372*0Sstevel@tonic-gate error = geterror(bp); 373*0Sstevel@tonic-gate brelse(bp); 374*0Sstevel@tonic-gate if (error) 375*0Sstevel@tonic-gate return (error); 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate return (0); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* 381*0Sstevel@tonic-gate * Remove a name from a directory. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate int 384*0Sstevel@tonic-gate pc_dirremove( 385*0Sstevel@tonic-gate struct pcnode *dp, 386*0Sstevel@tonic-gate char *namep, 387*0Sstevel@tonic-gate struct vnode *cdir, 388*0Sstevel@tonic-gate enum vtype type) 389*0Sstevel@tonic-gate { 390*0Sstevel@tonic-gate struct slot slot; 391*0Sstevel@tonic-gate struct pcnode *pcp; 392*0Sstevel@tonic-gate int error; 393*0Sstevel@tonic-gate struct vnode *vp = PCTOV(dp); 394*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 395*0Sstevel@tonic-gate offset_t lfn_offset = -1; 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate PC_DPRINTF2(4, "pc_dirremove (dp %p name %s)\n", (void *)dp, namep); 398*0Sstevel@tonic-gate if ((dp->pc_entry.pcd_attr & PCA_RDONLY) || 399*0Sstevel@tonic-gate PCA_IS_HIDDEN(fsp, dp->pc_entry.pcd_attr)) { 400*0Sstevel@tonic-gate return (EPERM); 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate error = pc_findentry(dp, namep, &slot, &lfn_offset); 403*0Sstevel@tonic-gate if (error) 404*0Sstevel@tonic-gate return (error); 405*0Sstevel@tonic-gate if (slot.sl_flags == SL_DOT) { 406*0Sstevel@tonic-gate error = EINVAL; 407*0Sstevel@tonic-gate } else if (slot.sl_flags == SL_DOTDOT) { 408*0Sstevel@tonic-gate error = ENOTEMPTY; 409*0Sstevel@tonic-gate } else { 410*0Sstevel@tonic-gate pcp = 411*0Sstevel@tonic-gate pc_getnode(VFSTOPCFS(vp->v_vfsp), 412*0Sstevel@tonic-gate slot.sl_blkno, slot.sl_offset, slot.sl_ep); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate if (error) { 415*0Sstevel@tonic-gate brelse(slot.sl_bp); 416*0Sstevel@tonic-gate return (error); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate if (type == VDIR) { 419*0Sstevel@tonic-gate if (pcp->pc_entry.pcd_attr & PCA_DIR) { 420*0Sstevel@tonic-gate if (PCTOV(pcp) == cdir) 421*0Sstevel@tonic-gate error = EINVAL; 422*0Sstevel@tonic-gate else if (!pc_dirempty(pcp)) 423*0Sstevel@tonic-gate error = ENOTEMPTY; 424*0Sstevel@tonic-gate } else { 425*0Sstevel@tonic-gate error = ENOTDIR; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate } else { 428*0Sstevel@tonic-gate if (pcp->pc_entry.pcd_attr & PCA_DIR) 429*0Sstevel@tonic-gate error = EISDIR; 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate if (error == 0) { 432*0Sstevel@tonic-gate /* 433*0Sstevel@tonic-gate * Mark the in core node and on disk entry 434*0Sstevel@tonic-gate * as removed. The slot may then be reused. 435*0Sstevel@tonic-gate * The files clusters will be deallocated 436*0Sstevel@tonic-gate * when the last reference goes away. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate pcp->pc_eblkno = -1; 439*0Sstevel@tonic-gate pcp->pc_entry.pcd_filename[0] = PCD_ERASED; 440*0Sstevel@tonic-gate if (lfn_offset != -1) { 441*0Sstevel@tonic-gate brelse(slot.sl_bp); 442*0Sstevel@tonic-gate error = pc_remove_long_fn(dp, lfn_offset); 443*0Sstevel@tonic-gate if (error) { 444*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 445*0Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp)); 446*0Sstevel@tonic-gate return (EIO); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate } else { 449*0Sstevel@tonic-gate slot.sl_ep->pcd_filename[0] = PCD_ERASED; 450*0Sstevel@tonic-gate bwrite2(slot.sl_bp); 451*0Sstevel@tonic-gate error = geterror(slot.sl_bp); 452*0Sstevel@tonic-gate brelse(slot.sl_bp); 453*0Sstevel@tonic-gate } 454*0Sstevel@tonic-gate if (error) { 455*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 456*0Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp)); 457*0Sstevel@tonic-gate return (EIO); 458*0Sstevel@tonic-gate } else if (type == VDIR) { 459*0Sstevel@tonic-gate error = pc_truncate(pcp, 0L); 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate } else { 463*0Sstevel@tonic-gate brelse(slot.sl_bp); 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate if (error == 0) { 467*0Sstevel@tonic-gate if (type == VDIR) { 468*0Sstevel@tonic-gate vnevent_rmdir(PCTOV(pcp)); 469*0Sstevel@tonic-gate } else { 470*0Sstevel@tonic-gate vnevent_remove(PCTOV(pcp)); 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate return (error); 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * Determine whether a directory is empty. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate static int 483*0Sstevel@tonic-gate pc_dirempty(struct pcnode *pcp) 484*0Sstevel@tonic-gate { 485*0Sstevel@tonic-gate struct buf *bp; 486*0Sstevel@tonic-gate struct pcdir *ep; 487*0Sstevel@tonic-gate offset_t offset; 488*0Sstevel@tonic-gate int boff; 489*0Sstevel@tonic-gate char c; 490*0Sstevel@tonic-gate int error; 491*0Sstevel@tonic-gate struct vnode *vp; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate vp = PCTOV(pcp); 494*0Sstevel@tonic-gate bp = NULL; 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate offset = 0; 497*0Sstevel@tonic-gate for (;;) { 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * If offset is on a block boundary, 501*0Sstevel@tonic-gate * read in the next directory block. 502*0Sstevel@tonic-gate * Release previous if it exists. 503*0Sstevel@tonic-gate */ 504*0Sstevel@tonic-gate boff = pc_blkoff(VFSTOPCFS(vp->v_vfsp), offset); 505*0Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 506*0Sstevel@tonic-gate if (bp != NULL) 507*0Sstevel@tonic-gate brelse(bp); 508*0Sstevel@tonic-gate if (error = pc_blkatoff(pcp, offset, &bp, &ep)) { 509*0Sstevel@tonic-gate return (error); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate if (PCDL_IS_LFN(ep)) { 513*0Sstevel@tonic-gate error = pc_extract_long_fn(pcp, NULL, &ep, &offset, 514*0Sstevel@tonic-gate &bp); 515*0Sstevel@tonic-gate /* 516*0Sstevel@tonic-gate * EINVAL means the lfn was invalid, so start with 517*0Sstevel@tonic-gate * the next entry. Otherwise, an error occurred _or_ 518*0Sstevel@tonic-gate * the lfn is valid, either of which means the 519*0Sstevel@tonic-gate * directory is not empty. 520*0Sstevel@tonic-gate */ 521*0Sstevel@tonic-gate if (error == EINVAL) 522*0Sstevel@tonic-gate continue; 523*0Sstevel@tonic-gate else { 524*0Sstevel@tonic-gate if (bp) 525*0Sstevel@tonic-gate brelse(bp); 526*0Sstevel@tonic-gate return (error); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate c = ep->pcd_filename[0]; 530*0Sstevel@tonic-gate if (c == PCD_UNUSED) 531*0Sstevel@tonic-gate break; 532*0Sstevel@tonic-gate if ((c != '.') && (c != PCD_ERASED)) { 533*0Sstevel@tonic-gate brelse(bp); 534*0Sstevel@tonic-gate return (0); 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate if ((c == '.') && !PC_SHORTNAME_IS_DOT(ep->pcd_filename) && 537*0Sstevel@tonic-gate !PC_SHORTNAME_IS_DOTDOT(ep->pcd_filename)) { 538*0Sstevel@tonic-gate brelse(bp); 539*0Sstevel@tonic-gate return (0); 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate ep++; 542*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate if (bp != NULL) 545*0Sstevel@tonic-gate brelse(bp); 546*0Sstevel@tonic-gate return (1); 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* 550*0Sstevel@tonic-gate * Rename a file. 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate int 553*0Sstevel@tonic-gate pc_rename( 554*0Sstevel@tonic-gate struct pcnode *dp, /* parent directory */ 555*0Sstevel@tonic-gate struct pcnode *tdp, /* target directory */ 556*0Sstevel@tonic-gate char *snm, /* source file name */ 557*0Sstevel@tonic-gate char *tnm) /* target file name */ 558*0Sstevel@tonic-gate { 559*0Sstevel@tonic-gate struct pcnode *pcp; /* pcnode we are trying to rename */ 560*0Sstevel@tonic-gate struct pcnode *tpcp; /* pcnode that's in our way */ 561*0Sstevel@tonic-gate struct slot slot; 562*0Sstevel@tonic-gate int error; 563*0Sstevel@tonic-gate struct vnode *vp = PCTOV(dp); 564*0Sstevel@tonic-gate struct vnode *svp = NULL; 565*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 566*0Sstevel@tonic-gate int filecasechange = 0; 567*0Sstevel@tonic-gate int oldisdir = 0; 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate PC_DPRINTF3(4, "pc_rename(0x%p, %s, %s)\n", (void *)dp, snm, tnm); 570*0Sstevel@tonic-gate /* 571*0Sstevel@tonic-gate * Leading spaces are not allowed in DOS. 572*0Sstevel@tonic-gate */ 573*0Sstevel@tonic-gate if (*tnm == ' ') 574*0Sstevel@tonic-gate return (EINVAL); 575*0Sstevel@tonic-gate /* 576*0Sstevel@tonic-gate * No dot or dotdot. 577*0Sstevel@tonic-gate */ 578*0Sstevel@tonic-gate if (PC_NAME_IS_DOT(snm) || PC_NAME_IS_DOTDOT(snm) || 579*0Sstevel@tonic-gate PC_NAME_IS_DOT(tnm) || PC_NAME_IS_DOTDOT(tnm)) 580*0Sstevel@tonic-gate return (EINVAL); 581*0Sstevel@tonic-gate /* 582*0Sstevel@tonic-gate * Get the source node. We'll jump back to here if trying to 583*0Sstevel@tonic-gate * move on top of an existing file, after deleting that file. 584*0Sstevel@tonic-gate */ 585*0Sstevel@tonic-gate top: 586*0Sstevel@tonic-gate error = pc_findentry(dp, snm, &slot, NULL); 587*0Sstevel@tonic-gate if (error) { 588*0Sstevel@tonic-gate return (error); 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate pcp = pc_getnode(VFSTOPCFS(vp->v_vfsp), 591*0Sstevel@tonic-gate slot.sl_blkno, slot.sl_offset, slot.sl_ep); 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate brelse(slot.sl_bp); 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate if (pcp) 596*0Sstevel@tonic-gate svp = PCTOV(pcp); 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /* 599*0Sstevel@tonic-gate * is the rename invalid, i.e. rename("a", "a/a") 600*0Sstevel@tonic-gate */ 601*0Sstevel@tonic-gate if (pcp == tdp) { 602*0Sstevel@tonic-gate if (svp) 603*0Sstevel@tonic-gate VN_RELE(svp); 604*0Sstevel@tonic-gate return (EINVAL); 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate /* 608*0Sstevel@tonic-gate * Are we just changing the case of an existing name? 609*0Sstevel@tonic-gate */ 610*0Sstevel@tonic-gate if ((dp->pc_scluster == tdp->pc_scluster) && 611*0Sstevel@tonic-gate (strcasecmp(snm, tnm) == 0)) { 612*0Sstevel@tonic-gate filecasechange = 1; 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate oldisdir = pcp->pc_entry.pcd_attr & PCA_DIR; 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate /* 618*0Sstevel@tonic-gate * see if the target exists 619*0Sstevel@tonic-gate */ 620*0Sstevel@tonic-gate error = pc_findentry(tdp, tnm, &slot, NULL); 621*0Sstevel@tonic-gate if (error == 0 && filecasechange == 0) { 622*0Sstevel@tonic-gate /* 623*0Sstevel@tonic-gate * Target exists. If it's a file, delete it. If it's 624*0Sstevel@tonic-gate * a directory, bail. 625*0Sstevel@tonic-gate */ 626*0Sstevel@tonic-gate int newisdir; 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate tpcp = pc_getnode(VFSTOPCFS(vp->v_vfsp), 629*0Sstevel@tonic-gate slot.sl_blkno, slot.sl_offset, slot.sl_ep); 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate newisdir = tpcp->pc_entry.pcd_attr & PCA_DIR; 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate brelse(slot.sl_bp); 634*0Sstevel@tonic-gate vnevent_rename_dest(PCTOV(tpcp)); 635*0Sstevel@tonic-gate VN_RELE(PCTOV(tpcp)); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate /* 638*0Sstevel@tonic-gate * Error cases (from rename(2)): 639*0Sstevel@tonic-gate * old is dir, new is dir: EEXIST 640*0Sstevel@tonic-gate * old is dir, new is nondir: ENOTDIR 641*0Sstevel@tonic-gate * old is nondir, new is dir: EISDIR 642*0Sstevel@tonic-gate */ 643*0Sstevel@tonic-gate if (!newisdir) { 644*0Sstevel@tonic-gate if (oldisdir) { 645*0Sstevel@tonic-gate error = ENOTDIR; 646*0Sstevel@tonic-gate } else { 647*0Sstevel@tonic-gate /* nondir/nondir, remove target */ 648*0Sstevel@tonic-gate error = pc_dirremove(tdp, tnm, 649*0Sstevel@tonic-gate (struct vnode *)NULL, VREG); 650*0Sstevel@tonic-gate if (error == 0) { 651*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 652*0Sstevel@tonic-gate goto top; 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate } else if (oldisdir) { 656*0Sstevel@tonic-gate /* dir/dir, remove target */ 657*0Sstevel@tonic-gate error = pc_dirremove(tdp, tnm, 658*0Sstevel@tonic-gate (struct vnode *)NULL, VDIR); 659*0Sstevel@tonic-gate if (error == 0) { 660*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 661*0Sstevel@tonic-gate goto top; 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate /* Follow rename(2)'s spec... */ 664*0Sstevel@tonic-gate if (error == ENOTEMPTY) { 665*0Sstevel@tonic-gate error = EEXIST; 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate } else { 668*0Sstevel@tonic-gate /* nondir/dir, bail */ 669*0Sstevel@tonic-gate error = EISDIR; 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate if ((error == 0) || (error == ENOENT)) { 674*0Sstevel@tonic-gate offset_t lfn_offset = -1; 675*0Sstevel@tonic-gate int blkno; 676*0Sstevel@tonic-gate struct pcdir *direntries; 677*0Sstevel@tonic-gate struct pcdir *ep; 678*0Sstevel@tonic-gate int ndirentries; 679*0Sstevel@tonic-gate pc_cluster16_t pct_lo; 680*0Sstevel@tonic-gate pc_cluster16_t pct_hi; 681*0Sstevel@tonic-gate offset_t offset; 682*0Sstevel@tonic-gate int boff; 683*0Sstevel@tonic-gate struct buf *bp = NULL; 684*0Sstevel@tonic-gate uchar_t attr; 685*0Sstevel@tonic-gate int size; 686*0Sstevel@tonic-gate struct pctime mtime; 687*0Sstevel@tonic-gate struct pctime crtime; 688*0Sstevel@tonic-gate uchar_t ntattr; 689*0Sstevel@tonic-gate ushort_t ladate; 690*0Sstevel@tonic-gate ushort_t eattr; 691*0Sstevel@tonic-gate uchar_t crtime_msec; 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate /* 694*0Sstevel@tonic-gate * Rename the source. 695*0Sstevel@tonic-gate */ 696*0Sstevel@tonic-gate /* 697*0Sstevel@tonic-gate * Delete the old name, and create a new name. 698*0Sstevel@tonic-gate */ 699*0Sstevel@tonic-gate if (filecasechange == 1 && error == 0) 700*0Sstevel@tonic-gate brelse(slot.sl_bp); 701*0Sstevel@tonic-gate ndirentries = direntries_needed(tdp, tnm); 702*0Sstevel@tonic-gate if (ndirentries == -1) { 703*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 704*0Sstevel@tonic-gate return (EINVAL); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate /* 707*0Sstevel@tonic-gate * first see if we have enough space to create the new 708*0Sstevel@tonic-gate * name before destroying the old one. 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate offset = pc_find_free_space(tdp, ndirentries); 711*0Sstevel@tonic-gate if (offset == -1) { 712*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 713*0Sstevel@tonic-gate return (ENOSPC); 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate error = pc_findentry(dp, snm, &slot, &lfn_offset); 717*0Sstevel@tonic-gate if (error) { 718*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 719*0Sstevel@tonic-gate return (error); 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate pct_lo = slot.sl_ep->pcd_scluster_lo; 722*0Sstevel@tonic-gate if (IS_FAT32(fsp)) 723*0Sstevel@tonic-gate pct_hi = slot.sl_ep->un.pcd_scluster_hi; 724*0Sstevel@tonic-gate else 725*0Sstevel@tonic-gate eattr = slot.sl_ep->un.pcd_eattr; 726*0Sstevel@tonic-gate size = slot.sl_ep->pcd_size; 727*0Sstevel@tonic-gate attr = slot.sl_ep->pcd_attr; 728*0Sstevel@tonic-gate mtime = slot.sl_ep->pcd_mtime; 729*0Sstevel@tonic-gate crtime = slot.sl_ep->pcd_crtime; 730*0Sstevel@tonic-gate crtime_msec = slot.sl_ep->pcd_crtime_msec; 731*0Sstevel@tonic-gate ntattr = slot.sl_ep->pcd_ntattr; 732*0Sstevel@tonic-gate ladate = slot.sl_ep->pcd_ladate; 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate if (lfn_offset != -1) { 735*0Sstevel@tonic-gate brelse(slot.sl_bp); 736*0Sstevel@tonic-gate error = pc_remove_long_fn(dp, lfn_offset); 737*0Sstevel@tonic-gate if (error) { 738*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 739*0Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp)); 740*0Sstevel@tonic-gate return (error); 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate } else { 743*0Sstevel@tonic-gate slot.sl_ep->pcd_filename[0] = 744*0Sstevel@tonic-gate pcp->pc_entry.pcd_filename[0] = PCD_ERASED; 745*0Sstevel@tonic-gate bwrite2(slot.sl_bp); 746*0Sstevel@tonic-gate error = geterror(slot.sl_bp); 747*0Sstevel@tonic-gate brelse(slot.sl_bp); 748*0Sstevel@tonic-gate } 749*0Sstevel@tonic-gate if (error) { 750*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 751*0Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp)); 752*0Sstevel@tonic-gate return (EIO); 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate /* 756*0Sstevel@tonic-gate * Make an entry from the supplied attributes. 757*0Sstevel@tonic-gate */ 758*0Sstevel@tonic-gate direntries = pc_name_to_pcdir(tdp, tnm, ndirentries, &error); 759*0Sstevel@tonic-gate if (direntries == NULL) { 760*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 761*0Sstevel@tonic-gate return (error); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate error = pc_makedirentry(tdp, direntries, ndirentries, NULL, 764*0Sstevel@tonic-gate offset); 765*0Sstevel@tonic-gate kmem_free(direntries, ndirentries * sizeof (struct pcdir)); 766*0Sstevel@tonic-gate if (error) { 767*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 768*0Sstevel@tonic-gate return (error); 769*0Sstevel@tonic-gate } 770*0Sstevel@tonic-gate /* advance to short name */ 771*0Sstevel@tonic-gate offset += (ndirentries - 1) * sizeof (struct pcdir); 772*0Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 773*0Sstevel@tonic-gate error = pc_blkatoff(tdp, offset, &bp, &ep); 774*0Sstevel@tonic-gate if (error) { 775*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 776*0Sstevel@tonic-gate return (error); 777*0Sstevel@tonic-gate } 778*0Sstevel@tonic-gate blkno = pc_daddrdb(fsp, bp->b_blkno); 779*0Sstevel@tonic-gate ep->pcd_scluster_lo = pct_lo; 780*0Sstevel@tonic-gate if (IS_FAT32(fsp)) 781*0Sstevel@tonic-gate ep->un.pcd_scluster_hi = pct_hi; 782*0Sstevel@tonic-gate else 783*0Sstevel@tonic-gate ep->un.pcd_eattr = eattr; 784*0Sstevel@tonic-gate ep->pcd_size = size; 785*0Sstevel@tonic-gate ep->pcd_attr = attr; 786*0Sstevel@tonic-gate ep->pcd_mtime = mtime; 787*0Sstevel@tonic-gate ep->pcd_crtime = crtime; 788*0Sstevel@tonic-gate ep->pcd_crtime_msec = crtime_msec; 789*0Sstevel@tonic-gate ep->pcd_ntattr = ntattr; 790*0Sstevel@tonic-gate ep->pcd_ladate = ladate; 791*0Sstevel@tonic-gate bwrite2(bp); 792*0Sstevel@tonic-gate error = geterror(bp); 793*0Sstevel@tonic-gate pcp->pc_eblkno = blkno; 794*0Sstevel@tonic-gate pcp->pc_eoffset = boff; 795*0Sstevel@tonic-gate pcp->pc_entry = *ep; 796*0Sstevel@tonic-gate pcp->pc_flags |= PC_CHG; 797*0Sstevel@tonic-gate brelse(bp); 798*0Sstevel@tonic-gate if (error) { 799*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 800*0Sstevel@tonic-gate pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp)); 801*0Sstevel@tonic-gate return (EIO); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate /* No need to fix ".." if we're renaming within a dir */ 804*0Sstevel@tonic-gate if (oldisdir && dp != tdp) { 805*0Sstevel@tonic-gate if ((error = pc_dirfixdotdot(pcp, dp, tdp)) != 0) { 806*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 807*0Sstevel@tonic-gate return (error); 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate if ((error = pc_nodeupdate(pcp)) != 0) { 811*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 812*0Sstevel@tonic-gate return (error); 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate out: 816*0Sstevel@tonic-gate vnevent_rename_src(PCTOV(pcp)); 817*0Sstevel@tonic-gate VN_RELE(PCTOV(pcp)); 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate return (error); 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate /* 823*0Sstevel@tonic-gate * Fix the ".." entry of the child directory so that it points to the 824*0Sstevel@tonic-gate * new parent directory instead of the old one. 825*0Sstevel@tonic-gate */ 826*0Sstevel@tonic-gate static int 827*0Sstevel@tonic-gate pc_dirfixdotdot(struct pcnode *dp, /* child directory being moved */ 828*0Sstevel@tonic-gate struct pcnode *opdp, /* old parent directory */ 829*0Sstevel@tonic-gate struct pcnode *npdp) /* new parent directory */ 830*0Sstevel@tonic-gate { 831*0Sstevel@tonic-gate pc_cluster32_t cn; 832*0Sstevel@tonic-gate struct vnode *vp = PCTOV(dp); 833*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 834*0Sstevel@tonic-gate int error = 0; 835*0Sstevel@tonic-gate struct buf *bp = NULL; 836*0Sstevel@tonic-gate struct pcdir *ep = NULL; 837*0Sstevel@tonic-gate struct pcdir *tep = NULL; 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate /* 840*0Sstevel@tonic-gate * set the new child's ".." directory entry starting cluster to 841*0Sstevel@tonic-gate * point to the new parent's starting cluster 842*0Sstevel@tonic-gate */ 843*0Sstevel@tonic-gate ASSERT(opdp != npdp); 844*0Sstevel@tonic-gate error = pc_blkatoff(dp, (offset_t)0, &bp, &ep); 845*0Sstevel@tonic-gate if (error) { 846*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_dirfixdotdot: error in blkatoff\n"); 847*0Sstevel@tonic-gate return (error); 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate tep = ep; 850*0Sstevel@tonic-gate ep++; 851*0Sstevel@tonic-gate if (!PC_SHORTNAME_IS_DOT(tep->pcd_filename) && 852*0Sstevel@tonic-gate !PC_SHORTNAME_IS_DOTDOT(ep->pcd_filename)) { 853*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_dirfixdotdot: mangled directory entry\n"); 854*0Sstevel@tonic-gate error = ENOTDIR; 855*0Sstevel@tonic-gate return (error); 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate cn = pc_getstartcluster(fsp, &npdp->pc_entry); 858*0Sstevel@tonic-gate pc_setstartcluster(fsp, ep, cn); 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate bwrite2(bp); 861*0Sstevel@tonic-gate error = geterror(bp); 862*0Sstevel@tonic-gate brelse(bp); 863*0Sstevel@tonic-gate if (error) { 864*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_dirfixdotdot: error in write\n"); 865*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 866*0Sstevel@tonic-gate return (EIO); 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate return (0); 869*0Sstevel@tonic-gate } 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* 873*0Sstevel@tonic-gate * Search a directory for an entry. 874*0Sstevel@tonic-gate * The directory should be locked as this routine 875*0Sstevel@tonic-gate * will sleep on I/O while searching. 876*0Sstevel@tonic-gate */ 877*0Sstevel@tonic-gate static int 878*0Sstevel@tonic-gate pc_findentry( 879*0Sstevel@tonic-gate struct pcnode *dp, /* parent directory */ 880*0Sstevel@tonic-gate char *namep, /* name to lookup */ 881*0Sstevel@tonic-gate struct slot *slotp, 882*0Sstevel@tonic-gate offset_t *lfn_offset) 883*0Sstevel@tonic-gate { 884*0Sstevel@tonic-gate offset_t offset; 885*0Sstevel@tonic-gate struct pcdir *ep = NULL; 886*0Sstevel@tonic-gate int boff; 887*0Sstevel@tonic-gate int error; 888*0Sstevel@tonic-gate struct vnode *vp; 889*0Sstevel@tonic-gate struct pcfs *fsp; 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate vp = PCTOV(dp); 892*0Sstevel@tonic-gate PC_DPRINTF2(6, "pc_findentry: looking for %s in dir 0x%p\n", namep, 893*0Sstevel@tonic-gate (void *)dp); 894*0Sstevel@tonic-gate slotp->sl_status = SL_NONE; 895*0Sstevel@tonic-gate if (!(dp->pc_entry.pcd_attr & PCA_DIR)) { 896*0Sstevel@tonic-gate return (ENOTDIR); 897*0Sstevel@tonic-gate } 898*0Sstevel@tonic-gate /* 899*0Sstevel@tonic-gate * Verify that the dp is still valid on the disk 900*0Sstevel@tonic-gate */ 901*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 902*0Sstevel@tonic-gate error = pc_verify(fsp); 903*0Sstevel@tonic-gate if (error) 904*0Sstevel@tonic-gate return (error); 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate slotp->sl_bp = NULL; 907*0Sstevel@tonic-gate offset = 0; 908*0Sstevel@tonic-gate for (;;) { 909*0Sstevel@tonic-gate /* 910*0Sstevel@tonic-gate * If offset is on a block boundary, 911*0Sstevel@tonic-gate * read in the next directory block. 912*0Sstevel@tonic-gate * Release previous if it exists. 913*0Sstevel@tonic-gate */ 914*0Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 915*0Sstevel@tonic-gate if (boff == 0 || slotp->sl_bp == NULL || 916*0Sstevel@tonic-gate boff >= slotp->sl_bp->b_bcount) { 917*0Sstevel@tonic-gate if (slotp->sl_bp != NULL) { 918*0Sstevel@tonic-gate brelse(slotp->sl_bp); 919*0Sstevel@tonic-gate slotp->sl_bp = NULL; 920*0Sstevel@tonic-gate } 921*0Sstevel@tonic-gate error = pc_blkatoff(dp, offset, &slotp->sl_bp, &ep); 922*0Sstevel@tonic-gate if (error == ENOENT && slotp->sl_status == SL_NONE) { 923*0Sstevel@tonic-gate slotp->sl_status = SL_EXTEND; 924*0Sstevel@tonic-gate slotp->sl_offset = (int)offset; 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate if (error) 927*0Sstevel@tonic-gate return (error); 928*0Sstevel@tonic-gate } 929*0Sstevel@tonic-gate if ((ep->pcd_filename[0] == PCD_UNUSED) || 930*0Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED)) { 931*0Sstevel@tonic-gate /* 932*0Sstevel@tonic-gate * note empty slots, in case name is not found 933*0Sstevel@tonic-gate */ 934*0Sstevel@tonic-gate if (slotp->sl_status == SL_NONE) { 935*0Sstevel@tonic-gate slotp->sl_status = SL_FOUND; 936*0Sstevel@tonic-gate slotp->sl_blkno = pc_daddrdb(fsp, 937*0Sstevel@tonic-gate slotp->sl_bp->b_blkno); 938*0Sstevel@tonic-gate slotp->sl_offset = boff; 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate /* 941*0Sstevel@tonic-gate * If unused we've hit the end of the directory 942*0Sstevel@tonic-gate */ 943*0Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_UNUSED) 944*0Sstevel@tonic-gate break; 945*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 946*0Sstevel@tonic-gate ep++; 947*0Sstevel@tonic-gate continue; 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate if (PCDL_IS_LFN(ep)) { 950*0Sstevel@tonic-gate offset_t t = offset; 951*0Sstevel@tonic-gate if (pc_match_long_fn(dp, namep, &ep, 952*0Sstevel@tonic-gate slotp, &offset) == 0) { 953*0Sstevel@tonic-gate if (lfn_offset != NULL) 954*0Sstevel@tonic-gate *lfn_offset = t; 955*0Sstevel@tonic-gate return (0); 956*0Sstevel@tonic-gate } 957*0Sstevel@tonic-gate continue; 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate if (pc_match_short_fn(dp, namep, &ep, slotp, &offset) == 0) 960*0Sstevel@tonic-gate return (0); 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate if (slotp->sl_bp != NULL) { 963*0Sstevel@tonic-gate brelse(slotp->sl_bp); 964*0Sstevel@tonic-gate slotp->sl_bp = NULL; 965*0Sstevel@tonic-gate } 966*0Sstevel@tonic-gate return (ENOENT); 967*0Sstevel@tonic-gate } 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate /* 970*0Sstevel@tonic-gate * Obtain the block at offset "offset" in file pcp. 971*0Sstevel@tonic-gate */ 972*0Sstevel@tonic-gate int 973*0Sstevel@tonic-gate pc_blkatoff( 974*0Sstevel@tonic-gate struct pcnode *pcp, 975*0Sstevel@tonic-gate offset_t offset, 976*0Sstevel@tonic-gate struct buf **bpp, 977*0Sstevel@tonic-gate struct pcdir **epp) 978*0Sstevel@tonic-gate { 979*0Sstevel@tonic-gate struct pcfs *fsp; 980*0Sstevel@tonic-gate struct buf *bp; 981*0Sstevel@tonic-gate int size; 982*0Sstevel@tonic-gate int error; 983*0Sstevel@tonic-gate daddr_t bn; 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate fsp = VFSTOPCFS(PCTOV(pcp)->v_vfsp); 986*0Sstevel@tonic-gate size = pc_blksize(fsp, pcp, offset); 987*0Sstevel@tonic-gate if (pc_blkoff(fsp, offset) >= size) { 988*0Sstevel@tonic-gate PC_DPRINTF0(5, "pc_blkatoff: ENOENT\n"); 989*0Sstevel@tonic-gate return (ENOENT); 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate error = pc_bmap(pcp, pc_lblkno(fsp, offset), &bn, (uint_t *)0); 992*0Sstevel@tonic-gate if (error) 993*0Sstevel@tonic-gate return (error); 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate bp = bread(fsp->pcfs_xdev, bn, size); 996*0Sstevel@tonic-gate if (bp->b_flags & B_ERROR) { 997*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_blkatoff: error\n"); 998*0Sstevel@tonic-gate brelse(bp); 999*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 1000*0Sstevel@tonic-gate return (EIO); 1001*0Sstevel@tonic-gate } 1002*0Sstevel@tonic-gate if (epp) { 1003*0Sstevel@tonic-gate *epp = 1004*0Sstevel@tonic-gate (struct pcdir *)(bp->b_un.b_addr + pc_blkoff(fsp, offset)); 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate *bpp = bp; 1007*0Sstevel@tonic-gate return (0); 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate /* 1011*0Sstevel@tonic-gate * Parse user filename into the pc form of "filename.extension". 1012*0Sstevel@tonic-gate * If names are too long for the format (and enable_long_filenames is set) 1013*0Sstevel@tonic-gate * it returns EINVAL (since either this name was read from the disk (so 1014*0Sstevel@tonic-gate * it must fit), _or_ we're trying to match a long file name (so we 1015*0Sstevel@tonic-gate * should fail). Tests for characters that are invalid in PCDOS and 1016*0Sstevel@tonic-gate * converts to upper case (unless foldcase is 0). 1017*0Sstevel@tonic-gate */ 1018*0Sstevel@tonic-gate static int 1019*0Sstevel@tonic-gate pc_parsename( 1020*0Sstevel@tonic-gate char *namep, 1021*0Sstevel@tonic-gate char *fnamep, 1022*0Sstevel@tonic-gate char *fextp) 1023*0Sstevel@tonic-gate { 1024*0Sstevel@tonic-gate int n; 1025*0Sstevel@tonic-gate char c; 1026*0Sstevel@tonic-gate 1027*0Sstevel@tonic-gate n = PCFNAMESIZE; 1028*0Sstevel@tonic-gate c = *namep++; 1029*0Sstevel@tonic-gate if (c == 0) 1030*0Sstevel@tonic-gate return (EINVAL); 1031*0Sstevel@tonic-gate if (c == '.') { 1032*0Sstevel@tonic-gate /* 1033*0Sstevel@tonic-gate * check for "." and "..". 1034*0Sstevel@tonic-gate */ 1035*0Sstevel@tonic-gate *fnamep++ = c; 1036*0Sstevel@tonic-gate n--; 1037*0Sstevel@tonic-gate if (c = *namep++) { 1038*0Sstevel@tonic-gate if ((c != '.') || (c = *namep)) /* ".x" or "..x" */ 1039*0Sstevel@tonic-gate return (EINVAL); 1040*0Sstevel@tonic-gate *fnamep++ = '.'; 1041*0Sstevel@tonic-gate n--; 1042*0Sstevel@tonic-gate } 1043*0Sstevel@tonic-gate } else { 1044*0Sstevel@tonic-gate /* 1045*0Sstevel@tonic-gate * filename up to '.' 1046*0Sstevel@tonic-gate */ 1047*0Sstevel@tonic-gate do { 1048*0Sstevel@tonic-gate if (n-- > 0) { 1049*0Sstevel@tonic-gate c = toupper(c); 1050*0Sstevel@tonic-gate if (!pc_validchar(c)) 1051*0Sstevel@tonic-gate return (EINVAL); 1052*0Sstevel@tonic-gate *fnamep++ = c; 1053*0Sstevel@tonic-gate } else { 1054*0Sstevel@tonic-gate /* not short */ 1055*0Sstevel@tonic-gate if (enable_long_filenames) 1056*0Sstevel@tonic-gate return (EINVAL); 1057*0Sstevel@tonic-gate } 1058*0Sstevel@tonic-gate } while ((c = *namep++) != '\0' && c != '.'); 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate while (n-- > 0) { /* fill with blanks */ 1061*0Sstevel@tonic-gate *fnamep++ = ' '; 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate /* 1064*0Sstevel@tonic-gate * remainder is extension 1065*0Sstevel@tonic-gate */ 1066*0Sstevel@tonic-gate n = PCFEXTSIZE; 1067*0Sstevel@tonic-gate if (c == '.') { 1068*0Sstevel@tonic-gate while ((c = *namep++) != '\0' && n--) { 1069*0Sstevel@tonic-gate c = toupper(c); 1070*0Sstevel@tonic-gate if (!pc_validchar(c)) 1071*0Sstevel@tonic-gate return (EINVAL); 1072*0Sstevel@tonic-gate *fextp++ = c; 1073*0Sstevel@tonic-gate } 1074*0Sstevel@tonic-gate if (enable_long_filenames && (c != '\0')) { 1075*0Sstevel@tonic-gate /* not short */ 1076*0Sstevel@tonic-gate return (EINVAL); 1077*0Sstevel@tonic-gate } 1078*0Sstevel@tonic-gate } 1079*0Sstevel@tonic-gate while (n-- > 0) { /* fill with blanks */ 1080*0Sstevel@tonic-gate *fextp++ = ' '; 1081*0Sstevel@tonic-gate } 1082*0Sstevel@tonic-gate return (0); 1083*0Sstevel@tonic-gate } 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate /* 1086*0Sstevel@tonic-gate * Match a long filename entry with 'namep'. Also return failure 1087*0Sstevel@tonic-gate * if the long filename isn't valid. 1088*0Sstevel@tonic-gate */ 1089*0Sstevel@tonic-gate int 1090*0Sstevel@tonic-gate pc_match_long_fn(struct pcnode *pcp, char *namep, struct pcdir **epp, 1091*0Sstevel@tonic-gate struct slot *slotp, offset_t *offset) 1092*0Sstevel@tonic-gate { 1093*0Sstevel@tonic-gate struct pcdir *ep = (struct pcdir *)*epp; 1094*0Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 1095*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1096*0Sstevel@tonic-gate int error = 0; 1097*0Sstevel@tonic-gate char lfn[PCMAXNAMLEN+1]; 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate error = pc_extract_long_fn(pcp, lfn, epp, offset, &slotp->sl_bp); 1100*0Sstevel@tonic-gate if (error) { 1101*0Sstevel@tonic-gate if (error == EINVAL) { 1102*0Sstevel@tonic-gate return (ENOENT); 1103*0Sstevel@tonic-gate } else 1104*0Sstevel@tonic-gate return (error); 1105*0Sstevel@tonic-gate } 1106*0Sstevel@tonic-gate ep = *epp; 1107*0Sstevel@tonic-gate if (strcasecmp(lfn, namep) == 0) { 1108*0Sstevel@tonic-gate /* match */ 1109*0Sstevel@tonic-gate slotp->sl_flags = 0; 1110*0Sstevel@tonic-gate slotp->sl_blkno = pc_daddrdb(fsp, slotp->sl_bp->b_blkno); 1111*0Sstevel@tonic-gate slotp->sl_offset = pc_blkoff(fsp, *offset); 1112*0Sstevel@tonic-gate slotp->sl_ep = ep; 1113*0Sstevel@tonic-gate return (0); 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 1116*0Sstevel@tonic-gate ep++; 1117*0Sstevel@tonic-gate *epp = ep; 1118*0Sstevel@tonic-gate return (ENOENT); 1119*0Sstevel@tonic-gate } 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate /* 1122*0Sstevel@tonic-gate * Match a short filename entry with namep. 1123*0Sstevel@tonic-gate */ 1124*0Sstevel@tonic-gate int 1125*0Sstevel@tonic-gate pc_match_short_fn(struct pcnode *pcp, char *namep, struct pcdir **epp, 1126*0Sstevel@tonic-gate struct slot *slotp, offset_t *offset) 1127*0Sstevel@tonic-gate { 1128*0Sstevel@tonic-gate char fname[PCFNAMESIZE]; 1129*0Sstevel@tonic-gate char fext[PCFEXTSIZE]; 1130*0Sstevel@tonic-gate struct pcdir *ep = *epp; 1131*0Sstevel@tonic-gate int error; 1132*0Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 1133*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1134*0Sstevel@tonic-gate int boff = pc_blkoff(fsp, *offset); 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) { 1137*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 1138*0Sstevel@tonic-gate ep++; 1139*0Sstevel@tonic-gate *epp = ep; 1140*0Sstevel@tonic-gate return (ENOENT); 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate error = pc_parsename(namep, fname, fext); 1144*0Sstevel@tonic-gate if (error) { 1145*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 1146*0Sstevel@tonic-gate ep++; 1147*0Sstevel@tonic-gate *epp = ep; 1148*0Sstevel@tonic-gate return (error); 1149*0Sstevel@tonic-gate } 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate if ((bcmp(fname, ep->pcd_filename, PCFNAMESIZE) == 0) && 1152*0Sstevel@tonic-gate (bcmp(fext, ep->pcd_ext, PCFEXTSIZE) == 0)) { 1153*0Sstevel@tonic-gate /* 1154*0Sstevel@tonic-gate * found the file 1155*0Sstevel@tonic-gate */ 1156*0Sstevel@tonic-gate if (fname[0] == '.') { 1157*0Sstevel@tonic-gate if (fname[1] == '.') 1158*0Sstevel@tonic-gate slotp->sl_flags = SL_DOTDOT; 1159*0Sstevel@tonic-gate else 1160*0Sstevel@tonic-gate slotp->sl_flags = SL_DOT; 1161*0Sstevel@tonic-gate } else { 1162*0Sstevel@tonic-gate slotp->sl_flags = 0; 1163*0Sstevel@tonic-gate } 1164*0Sstevel@tonic-gate slotp->sl_blkno = 1165*0Sstevel@tonic-gate pc_daddrdb(fsp, slotp->sl_bp->b_blkno); 1166*0Sstevel@tonic-gate slotp->sl_offset = boff; 1167*0Sstevel@tonic-gate slotp->sl_ep = ep; 1168*0Sstevel@tonic-gate return (0); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate *offset += sizeof (struct pcdir); 1171*0Sstevel@tonic-gate ep++; 1172*0Sstevel@tonic-gate *epp = ep; 1173*0Sstevel@tonic-gate return (ENOENT); 1174*0Sstevel@tonic-gate } 1175*0Sstevel@tonic-gate 1176*0Sstevel@tonic-gate /* 1177*0Sstevel@tonic-gate * Remove a long filename entry starting at lfn_offset. It must be 1178*0Sstevel@tonic-gate * a valid entry or we wouldn't have gotten here. Also remove the 1179*0Sstevel@tonic-gate * short filename entry. 1180*0Sstevel@tonic-gate */ 1181*0Sstevel@tonic-gate static int 1182*0Sstevel@tonic-gate pc_remove_long_fn(struct pcnode *pcp, offset_t lfn_offset) 1183*0Sstevel@tonic-gate { 1184*0Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 1185*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1186*0Sstevel@tonic-gate int boff; 1187*0Sstevel@tonic-gate struct buf *bp = NULL; 1188*0Sstevel@tonic-gate struct pcdir *ep = NULL; 1189*0Sstevel@tonic-gate int error = 0; 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate /* 1192*0Sstevel@tonic-gate * if we're in here, we know that the lfn is in the proper format 1193*0Sstevel@tonic-gate * of <series-of-lfn-entries> followed by <sfn-entry> 1194*0Sstevel@tonic-gate */ 1195*0Sstevel@tonic-gate for (;;) { 1196*0Sstevel@tonic-gate boff = pc_blkoff(fsp, lfn_offset); 1197*0Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 1198*0Sstevel@tonic-gate if (bp != NULL) { 1199*0Sstevel@tonic-gate bwrite2(bp); 1200*0Sstevel@tonic-gate error = geterror(bp); 1201*0Sstevel@tonic-gate brelse(bp); 1202*0Sstevel@tonic-gate if (error) 1203*0Sstevel@tonic-gate return (error); 1204*0Sstevel@tonic-gate bp = NULL; 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate error = pc_blkatoff(pcp, lfn_offset, &bp, &ep); 1207*0Sstevel@tonic-gate if (error) 1208*0Sstevel@tonic-gate return (error); 1209*0Sstevel@tonic-gate } 1210*0Sstevel@tonic-gate if (!PCDL_IS_LFN(ep)) { 1211*0Sstevel@tonic-gate /* done */ 1212*0Sstevel@tonic-gate break; 1213*0Sstevel@tonic-gate } 1214*0Sstevel@tonic-gate /* zap it */ 1215*0Sstevel@tonic-gate ep->pcd_filename[0] = PCD_ERASED; 1216*0Sstevel@tonic-gate ep->pcd_attr = 0; 1217*0Sstevel@tonic-gate lfn_offset += sizeof (struct pcdir); 1218*0Sstevel@tonic-gate ep++; 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate /* now we're on the short entry */ 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate ep->pcd_filename[0] = PCD_ERASED; 1223*0Sstevel@tonic-gate ep->pcd_attr = 0; 1224*0Sstevel@tonic-gate 1225*0Sstevel@tonic-gate if (bp != NULL) { 1226*0Sstevel@tonic-gate bwrite2(bp); 1227*0Sstevel@tonic-gate error = geterror(bp); 1228*0Sstevel@tonic-gate brelse(bp); 1229*0Sstevel@tonic-gate if (error) 1230*0Sstevel@tonic-gate return (error); 1231*0Sstevel@tonic-gate } 1232*0Sstevel@tonic-gate return (0); 1233*0Sstevel@tonic-gate } 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate /* 1236*0Sstevel@tonic-gate * Find (and allocate) space in the directory denoted by 1237*0Sstevel@tonic-gate * 'pcp'. for 'ndirentries' pcdir structures. 1238*0Sstevel@tonic-gate * Return the offset at which to start, or -1 for failure. 1239*0Sstevel@tonic-gate */ 1240*0Sstevel@tonic-gate static offset_t 1241*0Sstevel@tonic-gate pc_find_free_space(struct pcnode *pcp, int ndirentries) 1242*0Sstevel@tonic-gate { 1243*0Sstevel@tonic-gate offset_t offset = 0; 1244*0Sstevel@tonic-gate offset_t spaceneeded = ndirentries * sizeof (struct pcdir); 1245*0Sstevel@tonic-gate offset_t spaceoffset; 1246*0Sstevel@tonic-gate offset_t spaceavail = 0; 1247*0Sstevel@tonic-gate int boff; 1248*0Sstevel@tonic-gate struct buf *bp = NULL; 1249*0Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp); 1250*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1251*0Sstevel@tonic-gate struct pcdir *ep; 1252*0Sstevel@tonic-gate int error; 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate spaceoffset = offset; 1255*0Sstevel@tonic-gate while (spaceneeded > spaceavail) { 1256*0Sstevel@tonic-gate /* 1257*0Sstevel@tonic-gate * If offset is on a block boundary, 1258*0Sstevel@tonic-gate * read in the next directory block. 1259*0Sstevel@tonic-gate * Release previous if it exists. 1260*0Sstevel@tonic-gate */ 1261*0Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 1262*0Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 1263*0Sstevel@tonic-gate if (bp != NULL) { 1264*0Sstevel@tonic-gate brelse(bp); 1265*0Sstevel@tonic-gate bp = NULL; 1266*0Sstevel@tonic-gate } 1267*0Sstevel@tonic-gate error = pc_blkatoff(pcp, offset, &bp, &ep); 1268*0Sstevel@tonic-gate if (error == ENOENT) { 1269*0Sstevel@tonic-gate daddr_t bn; 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate /* extend directory */ 1272*0Sstevel@tonic-gate if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) 1273*0Sstevel@tonic-gate return (-1); 1274*0Sstevel@tonic-gate while (spaceneeded > spaceavail) { 1275*0Sstevel@tonic-gate error = pc_balloc(pcp, 1276*0Sstevel@tonic-gate pc_lblkno(fsp, offset), 1, &bn); 1277*0Sstevel@tonic-gate if (error) 1278*0Sstevel@tonic-gate return (-1); 1279*0Sstevel@tonic-gate pcp->pc_size += fsp->pcfs_clsize; 1280*0Sstevel@tonic-gate spaceavail += fsp->pcfs_clsize; 1281*0Sstevel@tonic-gate offset += fsp->pcfs_clsize; 1282*0Sstevel@tonic-gate } 1283*0Sstevel@tonic-gate return (spaceoffset); 1284*0Sstevel@tonic-gate } 1285*0Sstevel@tonic-gate if (error) 1286*0Sstevel@tonic-gate return (-1); 1287*0Sstevel@tonic-gate } 1288*0Sstevel@tonic-gate if ((ep->pcd_filename[0] == PCD_UNUSED) || 1289*0Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED)) { 1290*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 1291*0Sstevel@tonic-gate spaceavail += sizeof (struct pcdir); 1292*0Sstevel@tonic-gate ep++; 1293*0Sstevel@tonic-gate continue; 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 1296*0Sstevel@tonic-gate spaceavail = 0; 1297*0Sstevel@tonic-gate spaceoffset = offset; 1298*0Sstevel@tonic-gate ep++; 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate if (bp != NULL) { 1301*0Sstevel@tonic-gate brelse(bp); 1302*0Sstevel@tonic-gate } 1303*0Sstevel@tonic-gate return (spaceoffset); 1304*0Sstevel@tonic-gate } 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate /* 1307*0Sstevel@tonic-gate * Return how many long filename entries are needed. 1308*0Sstevel@tonic-gate * A maximum of PCLFNCHUNKSIZE characters per entry, plus one for a 1309*0Sstevel@tonic-gate * short filename. 1310*0Sstevel@tonic-gate */ 1311*0Sstevel@tonic-gate static int 1312*0Sstevel@tonic-gate direntries_needed(struct pcnode *dp, char *namep) 1313*0Sstevel@tonic-gate { 1314*0Sstevel@tonic-gate int ndirentries; 1315*0Sstevel@tonic-gate int n; 1316*0Sstevel@tonic-gate struct pcdir ep; 1317*0Sstevel@tonic-gate 1318*0Sstevel@tonic-gate if (enable_long_filenames == 0) { 1319*0Sstevel@tonic-gate return (1); 1320*0Sstevel@tonic-gate } 1321*0Sstevel@tonic-gate if (pc_is_short_file_name(namep, 0)) { 1322*0Sstevel@tonic-gate (void) pc_parsename(namep, ep.pcd_filename, ep.pcd_ext); 1323*0Sstevel@tonic-gate if (!shortname_exists(dp, ep.pcd_filename, ep.pcd_ext)) { 1324*0Sstevel@tonic-gate return (1); 1325*0Sstevel@tonic-gate } 1326*0Sstevel@tonic-gate } 1327*0Sstevel@tonic-gate if (pc_valid_long_fn(namep)) { 1328*0Sstevel@tonic-gate n = strlen(namep); 1329*0Sstevel@tonic-gate ndirentries = 1 + n / PCLFNCHUNKSIZE; 1330*0Sstevel@tonic-gate if ((n % PCLFNCHUNKSIZE) != 0) 1331*0Sstevel@tonic-gate ndirentries++; 1332*0Sstevel@tonic-gate return (ndirentries); 1333*0Sstevel@tonic-gate } 1334*0Sstevel@tonic-gate return (-1); 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate /* 1338*0Sstevel@tonic-gate * Allocate and return an array of pcdir structures for the passed-in 1339*0Sstevel@tonic-gate * name. ndirentries tells how many are required (including the short 1340*0Sstevel@tonic-gate * filename entry). Just allocate and fill them in properly here so they 1341*0Sstevel@tonic-gate * can be written out. 1342*0Sstevel@tonic-gate */ 1343*0Sstevel@tonic-gate static struct pcdir * 1344*0Sstevel@tonic-gate pc_name_to_pcdir(struct pcnode *dp, char *namep, int ndirentries, int *errret) 1345*0Sstevel@tonic-gate { 1346*0Sstevel@tonic-gate struct pcdir *bpcdir; 1347*0Sstevel@tonic-gate struct pcdir *ep; 1348*0Sstevel@tonic-gate struct pcdir_lfn *lep; 1349*0Sstevel@tonic-gate int i; 1350*0Sstevel@tonic-gate uchar_t cksum; 1351*0Sstevel@tonic-gate int nchars; 1352*0Sstevel@tonic-gate int error = 0; 1353*0Sstevel@tonic-gate int n; 1354*0Sstevel@tonic-gate char *nameend; 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate bpcdir = kmem_zalloc(ndirentries * sizeof (struct pcdir), KM_SLEEP); 1357*0Sstevel@tonic-gate ep = &bpcdir[ndirentries - 1]; 1358*0Sstevel@tonic-gate if (ndirentries == 1) { 1359*0Sstevel@tonic-gate (void) pc_parsename(namep, ep->pcd_filename, ep->pcd_ext); 1360*0Sstevel@tonic-gate return (bpcdir); 1361*0Sstevel@tonic-gate } 1362*0Sstevel@tonic-gate n = strlen(namep); 1363*0Sstevel@tonic-gate nchars = PCLFNCHUNKSIZE; 1364*0Sstevel@tonic-gate nameend = namep + n; 1365*0Sstevel@tonic-gate if ((n % PCLFNCHUNKSIZE) != 0) { 1366*0Sstevel@tonic-gate nchars = (n % PCLFNCHUNKSIZE) + 1; /* null */ 1367*0Sstevel@tonic-gate nameend++; 1368*0Sstevel@tonic-gate } 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate /* short file name */ 1371*0Sstevel@tonic-gate error = generate_short_name(dp, namep, ep); 1372*0Sstevel@tonic-gate if (error) { 1373*0Sstevel@tonic-gate kmem_free(bpcdir, ndirentries * sizeof (struct pcdir)); 1374*0Sstevel@tonic-gate *errret = error; 1375*0Sstevel@tonic-gate return (NULL); 1376*0Sstevel@tonic-gate } 1377*0Sstevel@tonic-gate cksum = pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext); 1378*0Sstevel@tonic-gate for (i = 0; i < (ndirentries - 1); i++) { 1379*0Sstevel@tonic-gate /* long file name */ 1380*0Sstevel@tonic-gate nameend -= nchars; 1381*0Sstevel@tonic-gate lep = (struct pcdir_lfn *)&bpcdir[i]; 1382*0Sstevel@tonic-gate set_long_fn_chunk(lep, nameend, nchars); 1383*0Sstevel@tonic-gate lep->pcdl_attr = PCDL_LFN_BITS; 1384*0Sstevel@tonic-gate lep->pcdl_checksum = cksum; 1385*0Sstevel@tonic-gate lep->pcdl_ordinal = (uchar_t)(ndirentries - i - 1); 1386*0Sstevel@tonic-gate nchars = PCLFNCHUNKSIZE; 1387*0Sstevel@tonic-gate } 1388*0Sstevel@tonic-gate lep = (struct pcdir_lfn *)&bpcdir[0]; 1389*0Sstevel@tonic-gate lep->pcdl_ordinal |= 0x40; 1390*0Sstevel@tonic-gate return (bpcdir); 1391*0Sstevel@tonic-gate } 1392*0Sstevel@tonic-gate 1393*0Sstevel@tonic-gate static int 1394*0Sstevel@tonic-gate generate_short_name(struct pcnode *dp, char *namep, struct pcdir *inep) 1395*0Sstevel@tonic-gate { 1396*0Sstevel@tonic-gate int rev; 1397*0Sstevel@tonic-gate int nchars; 1398*0Sstevel@tonic-gate int i, j; 1399*0Sstevel@tonic-gate char *dot = NULL; 1400*0Sstevel@tonic-gate char fname[PCFNAMESIZE+1]; 1401*0Sstevel@tonic-gate char fext[PCFEXTSIZE+1]; 1402*0Sstevel@tonic-gate char scratch[8]; 1403*0Sstevel@tonic-gate int error = 0; 1404*0Sstevel@tonic-gate struct slot slot; 1405*0Sstevel@tonic-gate char shortname[20]; 1406*0Sstevel@tonic-gate int force_tilde = 0; 1407*0Sstevel@tonic-gate 1408*0Sstevel@tonic-gate /* 1409*0Sstevel@tonic-gate * generate a unique short file name based on the long input name. 1410*0Sstevel@tonic-gate * 1411*0Sstevel@tonic-gate * Say, for "This is a very long filename.txt" generate 1412*0Sstevel@tonic-gate * "THISIS~1.TXT", or "THISIS~2.TXT" if that's already there. 1413*0Sstevel@tonic-gate * Skip invalid short name characters in the long name, plus 1414*0Sstevel@tonic-gate * a couple NT skips (space and reverse backslash). 1415*0Sstevel@tonic-gate * 1416*0Sstevel@tonic-gate * Unfortunately, since this name would be hidden by the normal 1417*0Sstevel@tonic-gate * lookup routine, we need to look for it ourselves. But luckily 1418*0Sstevel@tonic-gate * we don't need to look at the lfn entries themselves. 1419*0Sstevel@tonic-gate */ 1420*0Sstevel@tonic-gate force_tilde = !pc_is_short_file_name(namep, 1); 1421*0Sstevel@tonic-gate 1422*0Sstevel@tonic-gate /* 1423*0Sstevel@tonic-gate * Strip off leading invalid characters. 1424*0Sstevel@tonic-gate * We need this because names like '.login' are now ok, but the 1425*0Sstevel@tonic-gate * short name needs to be something like LOGIN~1. 1426*0Sstevel@tonic-gate */ 1427*0Sstevel@tonic-gate for (; *namep != '\0'; namep++) { 1428*0Sstevel@tonic-gate if (*namep == ' ') 1429*0Sstevel@tonic-gate continue; 1430*0Sstevel@tonic-gate if (!pc_validchar(*namep) && !pc_validchar(toupper(*namep))) 1431*0Sstevel@tonic-gate continue; 1432*0Sstevel@tonic-gate break; 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate if (*namep == '\0') 1435*0Sstevel@tonic-gate return (EINVAL); 1436*0Sstevel@tonic-gate dot = strrchr(namep, '.'); 1437*0Sstevel@tonic-gate if (dot != NULL) { 1438*0Sstevel@tonic-gate dot++; 1439*0Sstevel@tonic-gate for (j = 0, i = 0; j < PCFEXTSIZE; i++) { 1440*0Sstevel@tonic-gate if (dot[i] == '\0') 1441*0Sstevel@tonic-gate break; 1442*0Sstevel@tonic-gate /* skip valid, but not generally good characters */ 1443*0Sstevel@tonic-gate if (dot[i] == ' ' || dot[i] == '\\') 1444*0Sstevel@tonic-gate continue; 1445*0Sstevel@tonic-gate if (pc_validchar(dot[i])) 1446*0Sstevel@tonic-gate fext[j++] = dot[i]; 1447*0Sstevel@tonic-gate else if (pc_validchar(toupper(dot[i]))) 1448*0Sstevel@tonic-gate fext[j++] = toupper(dot[i]); 1449*0Sstevel@tonic-gate } 1450*0Sstevel@tonic-gate for (i = j; i < PCFEXTSIZE; i++) 1451*0Sstevel@tonic-gate fext[i] = ' '; 1452*0Sstevel@tonic-gate dot--; 1453*0Sstevel@tonic-gate } else { 1454*0Sstevel@tonic-gate for (i = 0; i < PCFEXTSIZE; i++) { 1455*0Sstevel@tonic-gate fext[i] = ' '; 1456*0Sstevel@tonic-gate } 1457*0Sstevel@tonic-gate } 1458*0Sstevel@tonic-gate /* 1459*0Sstevel@tonic-gate * We know we're a long name, not a short name (or we wouldn't 1460*0Sstevel@tonic-gate * be here at all. But if uppercasing ourselves would be a short 1461*0Sstevel@tonic-gate * name, then we can possibly avoid the ~N format. 1462*0Sstevel@tonic-gate */ 1463*0Sstevel@tonic-gate if (!force_tilde) 1464*0Sstevel@tonic-gate rev = 0; 1465*0Sstevel@tonic-gate else 1466*0Sstevel@tonic-gate rev = 1; 1467*0Sstevel@tonic-gate for (;;) { 1468*0Sstevel@tonic-gate bzero(fname, sizeof (fname)); 1469*0Sstevel@tonic-gate nchars = PCFNAMESIZE; 1470*0Sstevel@tonic-gate if (rev) { 1471*0Sstevel@tonic-gate nchars--; /* ~ */ 1472*0Sstevel@tonic-gate i = rev; 1473*0Sstevel@tonic-gate do { 1474*0Sstevel@tonic-gate nchars--; 1475*0Sstevel@tonic-gate i /= 10; 1476*0Sstevel@tonic-gate } while (i); 1477*0Sstevel@tonic-gate if (nchars <= 0) { 1478*0Sstevel@tonic-gate return (ENOSPC); 1479*0Sstevel@tonic-gate } 1480*0Sstevel@tonic-gate } 1481*0Sstevel@tonic-gate for (j = 0, i = 0; j < nchars; i++) { 1482*0Sstevel@tonic-gate if ((&namep[i] == dot) || (namep[i] == '\0')) 1483*0Sstevel@tonic-gate break; 1484*0Sstevel@tonic-gate /* skip valid, but not generally good characters */ 1485*0Sstevel@tonic-gate if (namep[i] == ' ' || namep[i] == '\\') 1486*0Sstevel@tonic-gate continue; 1487*0Sstevel@tonic-gate if (pc_validchar(namep[i])) 1488*0Sstevel@tonic-gate fname[j++] = namep[i]; 1489*0Sstevel@tonic-gate else if (pc_validchar(toupper(namep[i]))) 1490*0Sstevel@tonic-gate fname[j++] = toupper(namep[i]); 1491*0Sstevel@tonic-gate } 1492*0Sstevel@tonic-gate if (j == 0) { 1493*0Sstevel@tonic-gate /* no characters in the prefix? */ 1494*0Sstevel@tonic-gate return (EINVAL); 1495*0Sstevel@tonic-gate } 1496*0Sstevel@tonic-gate if (rev) { 1497*0Sstevel@tonic-gate (void) sprintf(scratch, "~%d", rev); 1498*0Sstevel@tonic-gate (void) strcat(fname, scratch); 1499*0Sstevel@tonic-gate } 1500*0Sstevel@tonic-gate for (i = strlen(fname); i < PCFNAMESIZE; i++) 1501*0Sstevel@tonic-gate fname[i] = ' '; 1502*0Sstevel@tonic-gate /* now see if it exists */ 1503*0Sstevel@tonic-gate (void) pc_fname_ext_to_name(shortname, fname, fext, 0); 1504*0Sstevel@tonic-gate error = pc_findentry(dp, shortname, &slot, NULL); 1505*0Sstevel@tonic-gate if (error == 0) { 1506*0Sstevel@tonic-gate /* found it */ 1507*0Sstevel@tonic-gate brelse(slot.sl_bp); 1508*0Sstevel@tonic-gate rev++; 1509*0Sstevel@tonic-gate continue; 1510*0Sstevel@tonic-gate } 1511*0Sstevel@tonic-gate if (!shortname_exists(dp, fname, fext)) 1512*0Sstevel@tonic-gate break; 1513*0Sstevel@tonic-gate rev++; 1514*0Sstevel@tonic-gate } 1515*0Sstevel@tonic-gate (void) strncpy(inep->pcd_filename, fname, PCFNAMESIZE); 1516*0Sstevel@tonic-gate (void) strncpy(inep->pcd_ext, fext, PCFEXTSIZE); 1517*0Sstevel@tonic-gate return (0); 1518*0Sstevel@tonic-gate } 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate /* 1521*0Sstevel@tonic-gate * Returns 1 if the passed-in filename is a short name, 0 if not. 1522*0Sstevel@tonic-gate */ 1523*0Sstevel@tonic-gate static int 1524*0Sstevel@tonic-gate pc_is_short_file_name(char *namep, int foldcase) 1525*0Sstevel@tonic-gate { 1526*0Sstevel@tonic-gate int i; 1527*0Sstevel@tonic-gate char c; 1528*0Sstevel@tonic-gate 1529*0Sstevel@tonic-gate for (i = 0; i < PCFNAMESIZE; i++, namep++) { 1530*0Sstevel@tonic-gate if (*namep == '\0') 1531*0Sstevel@tonic-gate return (1); 1532*0Sstevel@tonic-gate if (*namep == '.') 1533*0Sstevel@tonic-gate break; 1534*0Sstevel@tonic-gate if (foldcase) 1535*0Sstevel@tonic-gate c = toupper(*namep); 1536*0Sstevel@tonic-gate else 1537*0Sstevel@tonic-gate c = *namep; 1538*0Sstevel@tonic-gate if (!pc_validchar(c)) 1539*0Sstevel@tonic-gate return (0); 1540*0Sstevel@tonic-gate } 1541*0Sstevel@tonic-gate if (*namep == '\0') 1542*0Sstevel@tonic-gate return (1); 1543*0Sstevel@tonic-gate if (*namep != '.') 1544*0Sstevel@tonic-gate return (0); 1545*0Sstevel@tonic-gate namep++; 1546*0Sstevel@tonic-gate for (i = 0; i < PCFEXTSIZE; i++, namep++) { 1547*0Sstevel@tonic-gate if (*namep == '\0') 1548*0Sstevel@tonic-gate return (1); 1549*0Sstevel@tonic-gate if (foldcase) 1550*0Sstevel@tonic-gate c = toupper(*namep); 1551*0Sstevel@tonic-gate else 1552*0Sstevel@tonic-gate c = *namep; 1553*0Sstevel@tonic-gate if (!pc_validchar(c)) 1554*0Sstevel@tonic-gate return (0); 1555*0Sstevel@tonic-gate } 1556*0Sstevel@tonic-gate /* we should be done. If not... */ 1557*0Sstevel@tonic-gate if (*namep == '\0') 1558*0Sstevel@tonic-gate return (1); 1559*0Sstevel@tonic-gate return (0); 1560*0Sstevel@tonic-gate 1561*0Sstevel@tonic-gate } 1562*0Sstevel@tonic-gate 1563*0Sstevel@tonic-gate /* 1564*0Sstevel@tonic-gate * We call this when we want to see if a short filename already exists 1565*0Sstevel@tonic-gate * in the filesystem as part of a long filename. When creating a short 1566*0Sstevel@tonic-gate * name (FILENAME.TXT from the user, or when generating one for a long 1567*0Sstevel@tonic-gate * filename), we cannot allow one that is part of a long filename. 1568*0Sstevel@tonic-gate * pc_findentry will find all the names that are visible (long or short), 1569*0Sstevel@tonic-gate * but will not crack any long filename entries. 1570*0Sstevel@tonic-gate */ 1571*0Sstevel@tonic-gate static int 1572*0Sstevel@tonic-gate shortname_exists(struct pcnode *dp, char *fname, char *fext) 1573*0Sstevel@tonic-gate { 1574*0Sstevel@tonic-gate struct buf *bp = NULL; 1575*0Sstevel@tonic-gate int offset = 0; 1576*0Sstevel@tonic-gate int match = 0; 1577*0Sstevel@tonic-gate struct pcdir *ep; 1578*0Sstevel@tonic-gate struct vnode *vp = PCTOV(dp); 1579*0Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp); 1580*0Sstevel@tonic-gate int boff; 1581*0Sstevel@tonic-gate int error = 0; 1582*0Sstevel@tonic-gate 1583*0Sstevel@tonic-gate for (;;) { 1584*0Sstevel@tonic-gate boff = pc_blkoff(fsp, offset); 1585*0Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) { 1586*0Sstevel@tonic-gate if (bp != NULL) { 1587*0Sstevel@tonic-gate brelse(bp); 1588*0Sstevel@tonic-gate bp = NULL; 1589*0Sstevel@tonic-gate } 1590*0Sstevel@tonic-gate error = pc_blkatoff(dp, offset, &bp, &ep); 1591*0Sstevel@tonic-gate if (error == ENOENT) 1592*0Sstevel@tonic-gate break; 1593*0Sstevel@tonic-gate if (error) { 1594*0Sstevel@tonic-gate return (1); 1595*0Sstevel@tonic-gate } 1596*0Sstevel@tonic-gate } 1597*0Sstevel@tonic-gate if (PCDL_IS_LFN(ep) || 1598*0Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED)) { 1599*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 1600*0Sstevel@tonic-gate ep++; 1601*0Sstevel@tonic-gate continue; 1602*0Sstevel@tonic-gate } 1603*0Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_UNUSED) 1604*0Sstevel@tonic-gate break; 1605*0Sstevel@tonic-gate /* 1606*0Sstevel@tonic-gate * in use, and a short file name (either standalone 1607*0Sstevel@tonic-gate * or associated with a long name 1608*0Sstevel@tonic-gate */ 1609*0Sstevel@tonic-gate if ((bcmp(fname, ep->pcd_filename, PCFNAMESIZE) == 0) && 1610*0Sstevel@tonic-gate (bcmp(fext, ep->pcd_ext, PCFEXTSIZE) == 0)) { 1611*0Sstevel@tonic-gate match = 1; 1612*0Sstevel@tonic-gate break; 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate offset += sizeof (struct pcdir); 1615*0Sstevel@tonic-gate ep++; 1616*0Sstevel@tonic-gate } 1617*0Sstevel@tonic-gate if (bp) { 1618*0Sstevel@tonic-gate brelse(bp); 1619*0Sstevel@tonic-gate bp = NULL; 1620*0Sstevel@tonic-gate } 1621*0Sstevel@tonic-gate return (match); 1622*0Sstevel@tonic-gate } 1623*0Sstevel@tonic-gate 1624*0Sstevel@tonic-gate pc_cluster32_t 1625*0Sstevel@tonic-gate pc_getstartcluster(struct pcfs *fsp, struct pcdir *ep) 1626*0Sstevel@tonic-gate { 1627*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 1628*0Sstevel@tonic-gate pc_cluster32_t cn; 1629*0Sstevel@tonic-gate pc_cluster16_t hi16; 1630*0Sstevel@tonic-gate pc_cluster16_t lo16; 1631*0Sstevel@tonic-gate 1632*0Sstevel@tonic-gate hi16 = ltohs(ep->un.pcd_scluster_hi); 1633*0Sstevel@tonic-gate lo16 = ltohs(ep->pcd_scluster_lo); 1634*0Sstevel@tonic-gate cn = (hi16 << 16) | lo16; 1635*0Sstevel@tonic-gate return (cn); 1636*0Sstevel@tonic-gate } else { 1637*0Sstevel@tonic-gate return (ltohs(ep->pcd_scluster_lo)); 1638*0Sstevel@tonic-gate } 1639*0Sstevel@tonic-gate } 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate void 1642*0Sstevel@tonic-gate pc_setstartcluster(struct pcfs *fsp, struct pcdir *ep, pc_cluster32_t cln) 1643*0Sstevel@tonic-gate { 1644*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 1645*0Sstevel@tonic-gate pc_cluster16_t hi16; 1646*0Sstevel@tonic-gate pc_cluster16_t lo16; 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate hi16 = (cln >> 16) & 0xFFFF; 1649*0Sstevel@tonic-gate lo16 = cln & 0xFFFF; 1650*0Sstevel@tonic-gate ep->un.pcd_scluster_hi = htols(hi16); 1651*0Sstevel@tonic-gate ep->pcd_scluster_lo = htols(lo16); 1652*0Sstevel@tonic-gate } else { 1653*0Sstevel@tonic-gate pc_cluster16_t cln16; 1654*0Sstevel@tonic-gate 1655*0Sstevel@tonic-gate cln16 = (pc_cluster16_t)cln; 1656*0Sstevel@tonic-gate ep->pcd_scluster_lo = htols(cln16); 1657*0Sstevel@tonic-gate } 1658*0Sstevel@tonic-gate } 1659