extern groupmember(gid_t gid, struct ucred *cred);
+extern void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp);
+
static int hfs_makenode( int mode,
dev_t rawdev, struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp, struct proc *p);
off_t leof;
u_long blks, blocksize;
int retval = E_NONE;
+ int devBlockSize;
+ int forceUpdate = 0;
DBG_FUNC_NAME("close");
DBG_VOP_LOCKS_DECL(1);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
/*
- * Since we can contact switch in vn_lock our vnode
+ * Since we can context switch in vn_lock our vnode
* could get recycled (eg umount -f). Double check
* that its still ours.
*/
return(E_NONE);
}
+ /* Last chance to explicitly zero out the areas that are currently marked invalid: */
+ VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize);
+ while (!CIRCLEQ_EMPTY(&hp->h_invalidranges)) {
+ struct rl_entry *invalid_range = CIRCLEQ_FIRST(&hp->h_invalidranges);
+ off_t start = invalid_range->rl_start;
+ off_t end = invalid_range->rl_end;
+
+ /* The range about to be written must be validated first, so that
+ VOP_CMAP() will return the appropriate mapping for the cluster code: */
+ rl_remove(start, end, &hp->h_invalidranges);
+
+ retval = cluster_write(vp, (struct uio *) 0, fcb->fcbEOF, invalid_range->rl_end + 1, invalid_range->rl_start,
+ (off_t)0, devBlockSize, IO_HEADZEROFILL | 0x8000);
+
+ forceUpdate = 1;
+ };
+ /* Make sure the EOF gets written out at least once more
+ now that all invalid ranges have been zero-filled and validated: */
+ if (forceUpdate) hp->h_nodeflags |= IN_MODIFIED;
+
blocksize = HTOVCB(hp)->blockSize;
blks = leof / blocksize;
if (((off_t)blks * (off_t)blocksize) != leof)
retval = VOP_TRUNCATE(vp, leof, IO_NDELAY, ap->a_cred, p);
}
cluster_push(vp);
+
+ /* If the VOP_TRUNCATE didn't happen to flush the vnode's information out to
+ disk, force it to be updated now that all invalid ranges have been zero-filled
+ and validated:
+ */
+ if (hp->h_nodeflags & IN_MODIFIED) VOP_UPDATE(vp, &time, &time, 0);
+
VOP_UNLOCK(vp, 0, p);
}
if (((alist->volattr == 0) && ((alist->commonattr & HFS_ATTR_CMN_LOOKUPMASK) != 0)) ||
((alist->dirattr & HFS_ATTR_DIR_LOOKUPMASK) != 0) ||
- ((alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK) != 0)) {
+ ((alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK) != 0) ||
+ ((alist->commonattr & (ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID))
+ && (hp->h_meta->h_metaflags & IN_DATANODE))) {
/* lock catalog b-tree */
error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, ap->a_p);
INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName);
catInfo.hint = kNoHint;
-
- /* lock catalog b-tree */
- error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
- if (error != E_NONE) {
- goto FreeBuffer;
- };
filename = H_NAME(hp);
pid = H_DIRID(hp);
}
#endif
+ /* lock catalog b-tree */
+ error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
+ if (error != E_NONE)
+ goto ErrorExit;
error = hfs_getcatalog(VTOVCB(vp), pid, filename, -1, &catInfo);
- if (error != E_NONE) {
- DBG_ERR(("%s: Lookup failed on file '%s'\n", funcname, filename));
- goto ErrorExit;
- };
+
+ /* unlock catalog b-tree */
+ (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
+ if (error != E_NONE)
+ goto ErrorExit;
+
H_HINT(hp) = catInfo.hint; /* Remember the last valid hint */
error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio);
goto ErrorExit;
};
- /* do we have permission to change the dates? */
-// if (alist->commonattr & (ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME)) {
- if (alist->commonattr & (ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) {
- if ((error = hfs_owner_rights(vp, cred, p, true)) != 0) {
- goto ErrorExit;
- };
- };
+ /*
+ * If we are going to change the times:
+ * 1. do we have permission to change the dates?
+ * 2. Is there another fork? If so then clear any flags associated with the times
+ */
+ if (alist->commonattr & (ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) {
+ if (alist->commonattr & (ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) {
+ if ((error = hfs_owner_rights(vp, cred, p, true)) != 0)
+ goto ErrorExit;
+ }
+
+ /* If there is another fork, clear the flags */
+ if ((hp->h_meta->h_usecount > 1) && (H_FORKTYPE(hp) == kDataFork)) {
+ struct vnode *sib_vp = NULL;
+ struct hfsnode *nhp;
+
+ /* Loop through all siblings, skipping ourselves */
+ simple_lock(&hp->h_meta->h_siblinglock);
+ CIRCLEQ_FOREACH(nhp, &hp->h_meta->h_siblinghead, h_sibling) {
+ if (nhp == hp) /* skip ourselves */
+ continue;
+ sib_vp = HTOV(nhp);
+ }
+ simple_unlock(&hp->h_meta->h_siblinglock);
+
+ /*
+ * The only error that vget returns is when the vnode is going away,
+ * so ignore the vnode
+ */
+ if (sib_vp && vget(sib_vp, LK_EXCLUSIVE | LK_RETRY, p) == 0) {
+ if ((sib_vp->v_tag == VT_HFS)
+ && VTOH(sib_vp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) {
+ if (alist->commonattr & ATTR_CMN_MODTIME)
+ VTOH(sib_vp)->h_nodeflags &= ~IN_UPDATE;
+ if (alist->commonattr & ATTR_CMN_CHGTIME)
+ VTOH(sib_vp)->h_nodeflags &= ~IN_CHANGE;
+ if (alist->commonattr & ATTR_CMN_ACCTIME)
+ VTOH(sib_vp)->h_nodeflags &= ~IN_ACCESS;
+ }
+ vput(sib_vp);
+ }
+ }
+ }
/* save these in case hfs_chown() or hfs_chmod() fail */
saved_uid = hp->h_meta->h_uid;
if ((error = hfs_chflags(vp, flags, cred, p)))
goto ErrorExit;
};
+
+
+ /* lock catalog b-tree */
+ error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
+ if (error != E_NONE)
+ goto ErrorExit;
+ /* Update Catalog Tree */
if (alist->volattr == 0) {
error = MacToVFSError( UpdateCatalogNode(HTOVCB(hp), pid, filename, H_HINT(hp), &catInfo.nodeData));
}
- if (alist->volattr & ATTR_VOL_NAME) {
- ExtendedVCB *vcb = VTOVCB(vp);
- int namelen = strlen(vcb->vcbVN);
-
- if (vcb->vcbVN[0] == 0) {
- /*
- Ignore attempts to rename a volume to a zero-length name:
- restore the original name from the metadata.
- */
- copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
- } else {
- error = MoveRenameCatalogNode(vcb, kRootParID, H_NAME(hp), H_HINT(hp), kRootParID, vcb->vcbVN, &H_HINT(hp));
- if (error) {
- VCB_LOCK(vcb);
- copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); /* Restore the old name in the VCB */
- vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty
- VCB_UNLOCK(vcb);
- goto ErrorExit;
- };
+ /* Volume Rename */
+ if (alist->volattr & ATTR_VOL_NAME) {
+ ExtendedVCB *vcb = VTOVCB(vp);
+ int namelen = strlen(vcb->vcbVN);
+
+ if (vcb->vcbVN[0] == 0) {
+ /*
+ * Ignore attempts to rename a volume to a zero-length name:
+ * restore the original name from the metadata.
+ */
+ copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
+ } else {
+ UInt32 tehint = 0;
+
+ /*
+ * Force Carbon renames to have MacUnicode encoding
+ */
+ if ((hp->h_nodeflags & IN_BYCNID) && (!ISSET(p->p_flag, P_TBE))) {
+ tehint = kTextEncodingMacUnicode;
+ }
- hfs_set_metaname(vcb->vcbVN, hp->h_meta, HTOHFS(hp));
- hp->h_nodeflags |= IN_CHANGE;
+ error = MoveRenameCatalogNode(vcb, kRootParID, H_NAME(hp), H_HINT(hp),
+ kRootParID, vcb->vcbVN, &H_HINT(hp), tehint);
+ if (error) {
+ VCB_LOCK(vcb);
+ copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); /* Restore the old name in the VCB */
+ vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty
+ VCB_UNLOCK(vcb);
+ goto UnlockExit;
+ };
-#if 0
- /* if hfs wrapper exists, update its name too */
- if (vcb->vcbSigWord == kHFSPlusSigWord && vcb->vcbAlBlSt != 0) {
- HFSMasterDirectoryBlock *mdb;
- struct buf *bp = NULL;
- int size = kMDBSize; /* 512 */
- int volnamelen = MIN(sizeof(Str27), namelen);
-
- if ( bread(VTOHFS(vp)->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
- IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp) == 0) {
-
- mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
- if (SWAP_BE16 (mdb->drSigWord) == kHFSSigWord) {
- /* Convert the string to MacRoman, ignoring any errors, */
- (void) utf8_to_hfs(vcb, volnamelen, vcb->vcbVN, Str31 mdb->drVN)
- bawrite(bp);
- bp = NULL;
- }
- }
-
- if (bp) brelse(bp);
- }
-#endif
- }; /* vcb->vcbVN[0] == 0 ... else ... */
- }; /* alist->volattr & ATTR_VOL_NAME */
+ hfs_set_metaname(vcb->vcbVN, hp->h_meta, HTOHFS(hp));
+ hp->h_nodeflags |= IN_CHANGE;
+
+ } /* vcb->vcbVN[0] == 0 ... else ... */
+ } /* alist->volattr & ATTR_VOL_NAME */
+
+UnlockExit:
+ /* unlock catalog b-tree */
+ (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
ErrorExit:
- /* unlock catalog b-tree */
- (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
CLEAN_CATALOGDATA(&catInfo.nodeData);
-FreeBuffer:
if (attrbufptr) FREE(attrbufptr, M_TEMP);
DBG_VOP_LOCKS_TEST(error);
struct timeval tv;
int retval, use_count;
int filebusy = 0;
+ int uncache = 0;
DBG_FUNC_NAME("remove");
DBG_VOP_LOCKS_DECL(2);
DBG_VOP_PRINT_FUNCNAME();
if ((ap->a_cnp->cn_flags & (HASBUF | SAVENAME)) == (HASBUF | SAVENAME))
FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
-
+ /*
+ * This is a deleted file no new clients
+ * would be able to look it up. Maked the VM object
+ * not cachable so that it dies as soon as the last
+ * mapping disappears. This will reclaim the disk
+ * space as soon as possible.
+ */
+ uncache = 1;
goto out2; /* link deleted, all done */
}
#endif
H_DIRID(hp) = hfsmp->hfs_private_metadata_dir;
hfs_set_metaname(nodeName, hp->h_meta, HTOHFS(hp));
+ /*
+ * This is an open deleted file no new clients
+ * would be able to look it up. Maked the VM object
+ * not cachable so that it dies as soon as the last
+ * mapping disappears. This will reclaim the disk
+ * space as soon as possible.
+ */
+ uncache = 1;
goto out2; /* all done, unlock the catalog */
}
VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
- if (dvp == vp) {
- vrele(vp);
- } else {
- vput(vp);
- };
-
- vput(dvp);
- DBG_VOP_LOCKS_TEST(retval);
-
- if (UBCINFOEXISTS(vp)) {
- (void) ubc_uncache(vp);
- ubc_release(vp);
- /* WARNING vp may not be valid after this */
- }
- return (retval);
+ uncache = 1;
+ goto done;
out2:
(void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
-out:;
+out:
if (! retval)
VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
- if (dvp == vp) {
- vrele(vp);
- } else {
- vput(vp);
- };
+done:
+ if (dvp != vp)
+ VOP_UNLOCK(vp, 0, p);
+
+ if (uncache)
+ ubc_uncache(vp);
+ vrele(vp);
vput(dvp);
+
DBG_VOP_LOCKS_TEST(retval);
return (retval);
}
int retval = 0;
struct timeval tv;
struct hfsCatalogInfo catInfo;
+ u_int32_t tehint = 0;
DBG_VOP_LOCKS_DECL(4);
DBG_FUNC_NAME("rename");DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR));
target_hp = targetPar_hp = source_hp = sourcePar_hp = 0;
+ /* If fvp is the same as tvp...then we are just changing case, ignore target_vp */
+ /*
+ * This must be done now, since the value of target_vp is used to
+ * determine wether to unlock it (for instance, goto abortit).
+ * In this case, target_vp comes in unlocked
+ */
+ if (source_vp == target_vp)
+ target_vp = NULL;
+
/*
* Check for cross-device rename.
*/
goto abortit;
}
+ /*
+ * Force Carbon renames to have MacUnicode encoding
+ */
+ if ((VTOH(targetPar_vp)->h_nodeflags & IN_BYCNID) && (!ISSET(p->p_flag, P_TBE))) {
+ tehint = kTextEncodingMacUnicode;
+ }
+
if ((retval = vn_lock(source_vp, LK_EXCLUSIVE, p)))
goto abortit;
VOP_UNLOCK(sourcePar_vp, 0, p);
goto bad;
};
-
+
/* use source_cnp instead of H_NAME(source_hp) in case source is a hard link */
- retval = hfsMoveRename( HTOVCB(source_hp), H_DIRID(source_hp), source_cnp->cn_nameptr,
- H_FILEID(VTOH(targetPar_vp)), target_cnp->cn_nameptr, &H_HINT(source_hp));
+ retval = MoveRenameCatalogNode(HTOVCB(source_hp), H_DIRID(source_hp),
+ source_cnp->cn_nameptr, H_HINT(source_hp),
+ H_FILEID(VTOH(targetPar_vp)),
+ target_cnp->cn_nameptr, &H_HINT(source_hp), tehint);
+ retval = MacToVFSError(retval);
if (retval == 0) {
/* Look up the catalog entry just renamed since it might have been auto-decomposed */
register struct vnode *vp, **vpp = ap->a_vpp;
struct proc *p = current_proc();
struct hfsnode *hp;
- u_int32_t dfltClump;
int len, retval;
- DBG_FUNC_NAME("symlink");
- DBG_VOP_LOCKS_DECL(2);
- DBG_VOP_PRINT_FUNCNAME();
- DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
- DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_POS);
+ struct buf *bp = NULL;
+ /* HFS standard disks don't support symbolic links */
if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) {
VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
vput(ap->a_dvp);
- DBG_VOP((" ...sorry HFS disks don't support symbolic links.\n"));
- DBG_VOP_LOCKS_TEST(EOPNOTSUPP);
return (EOPNOTSUPP);
}
+ /* Check for empty target name */
+ if (ap->a_target[0] == 0) {
+ VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
+ vput(ap->a_dvp);
+ return (EINVAL);
+ }
+
/* Create the vnode */
retval = hfs_makenode(IFLNK | ap->a_vap->va_mode, 0, ap->a_dvp,
vpp, ap->a_cnp, p);
DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
if (retval != E_NONE) {
- DBG_VOP_LOCKS_TEST(retval);
return (retval);
}
-
vp = *vpp;
len = strlen(ap->a_target);
hp = VTOH(vp);
- dfltClump = hp->fcbClmpSize;
- /* make clump size minimal */
hp->fcbClmpSize = VTOVCB(vp)->blockSize;
- retval = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
- (struct proc *)0);
- hp->fcbClmpSize = dfltClump;
+ /* Allocate space for the link */
+ retval = VOP_TRUNCATE(vp, len, IO_NOZEROFILL,
+ ap->a_cnp->cn_cred, ap->a_cnp->cn_proc);
+ if (retval)
+ goto out;
+
+ /* Write the link to disk */
+ bp = getblk(vp, 0, roundup((int)hp->fcbEOF, kHFSBlockSize), 0, 0, BLK_META);
+ bzero(bp->b_data, bp->b_bufsize);
+ bcopy(ap->a_target, bp->b_data, len);
+ bp->b_flags |= B_DIRTY;
+ bawrite(bp);
+out:
vput(vp);
- DBG_VOP_LOCKS_TEST(retval);
return (retval);
}
u_long currattrbufsize;
void *attrbufptr = NULL;
void *attrptr;
- void *varptr;
- struct vnode *entryvnode;
-
+ void *varptr;
*(ap->a_actualcount) = 0;
*(ap->a_eofflag) = 0;
index = (uio->uio_offset / sizeof(struct dirent)) + 1;
INIT_CATALOGDATA(&catInfo.nodeData, 0);
- /* Lock catalog b-tree */
- if ((retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, proc)) != E_NONE)
- goto exit;
/* HFS Catalog does not have a bulk directory enumeration call. Do it one at
* time, using hints. GetCatalogOffspring takes care of hfsplus and name issues
* Thus fixedblocksize is too large in some cases.Also, the variable
* part (like name) could be between fixedblocksize and the max.
*/
- OSErr result = GetCatalogOffspring(vcb, dirID, index, &catInfo.nodeData, NULL, NULL);
+ OSErr result;
+
+ /* Lock catalog b-tree */
+ if ((retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, proc)) != E_NONE)
+ goto exit;
+
+ catInfo.nodeData.cnd_iNodeNumCopy = 0;
+ result = GetCatalogOffspring(vcb, dirID, index, &catInfo.nodeData, NULL, NULL);
+ if (result == 0)
+ hfs_resolvelink(vcb, &catInfo.nodeData);
+
+ /* Unlock catalog b-tree, unconditionally . Ties up the everything during enumeration */
+ (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, proc );
+
if (result != noErr) {
if (result == cmNotFound) {
*(ap->a_eofflag) = TRUE;
catInfo.nodeData.cnd_type == kCatalogFolderNode) {
++index;
+ CLEAN_CATALOGDATA(&catInfo.nodeData);
continue;
}
*((u_long *)attrptr)++ = 0; /* move it past length */
- if (ap->a_options & FSOPT_NOINMEMUPDATE) {
- /* vp okay to use instead of root vp */
- PackCatalogInfoAttributeBlock(alist, vp, &catInfo, &attrptr, &varptr);
- } else {
- /* Check to see if there's a vnode for this item in the cache: */
- entryvnode = hfs_vhashget(H_DEV(VTOH(vp)), catInfo.nodeData.cnd_nodeID, kDefault);
- if (entryvnode != NULL) {
- PackAttributeBlock(alist, entryvnode, &catInfo, &attrptr, &varptr);
- vput(entryvnode);
- } else {
- /* vp okay to use instead of root vp */
- PackCatalogInfoAttributeBlock(alist, vp, &catInfo, &attrptr, &varptr);
- };
- };
- currattrbufsize = *((u_long *)attrbufptr) = ((char *)varptr - (char *)attrbufptr);
+ /*
+ * Don't use data from cached vnodes when FSOPT_NOINMEMUPDATE
+ * option is active or if this entry is a hard link.
+ */
+ if ((ap->a_options & FSOPT_NOINMEMUPDATE)
+ || (catInfo.nodeData.cnd_iNodeNumCopy != 0)) {
+ /* vp okay to use instead of root vp */
+ PackCatalogInfoAttributeBlock(alist, vp, &catInfo, &attrptr, &varptr);
+ } else {
+ struct vnode *entry_vp = NULL;
+ struct vnode *rsrc_vp = NULL;
+ int nodetype;
+ UInt32 nodeid;
+
+ /*
+ * Flush out any in-memory state to the catalog record.
+ *
+ * In the HFS locking hierarchy, the data fork vnode must
+ * be acquired before the resource fork vnode.
+ */
+ nodeid = catInfo.nodeData.cnd_nodeID;
+ if (catInfo.nodeData.cnd_type == kCatalogFolderNode)
+ nodetype = kDirectory;
+ else
+ nodetype = kDataFork;
+
+ /* Check for this entry's cached vnode: */
+ entry_vp = hfs_vhashget(H_DEV(VTOH(vp)), nodeid, nodetype);
+
+ /* Also check for a cached resource fork vnode: */
+ if (nodetype == kDataFork) {
+ rsrc_vp = hfs_vhashget(H_DEV(VTOH(vp)), nodeid, kRsrcFork);
+ if ((rsrc_vp != NULL)
+ && (VTOH(rsrc_vp)->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))) {
+ /* Pick up resource fork info */
+ CopyVNodeToCatalogNode(rsrc_vp, &catInfo.nodeData);
+ }
+ }
+
+ if (entry_vp != NULL)
+ PackAttributeBlock(alist, entry_vp, &catInfo, &attrptr, &varptr);
+ else if (rsrc_vp != NULL)
+ PackAttributeBlock(alist, rsrc_vp, &catInfo, &attrptr, &varptr);
+ else
+ PackCatalogInfoAttributeBlock(alist, vp, &catInfo, &attrptr, &varptr);
+
+ if (rsrc_vp)
+ vput(rsrc_vp);
+ if (entry_vp)
+ vput(entry_vp);
+ }
+ currattrbufsize = *((u_long *)attrbufptr) = ((char *)varptr - (char *)attrbufptr);
/* now check if we can't fit in the buffer space remaining */
if (currattrbufsize > uio->uio_resid)
*ap->a_actualcount += 1;
maxcount--;
}
+ /* Clean for the next loop */
+ CLEAN_CATALOGDATA(&catInfo.nodeData);
};
*ap->a_newstate = VTOH(vp)->h_meta->h_mtime;/* before we unlock, know the mod date */
- /* Unlock catalog b-tree, finally. Ties up the everything during enumeration */
- (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, proc );
CLEAN_CATALOGDATA(&catInfo.nodeData);
struct ucred *a_cred;
} */ *ap;
{
- int retval;
- DBG_FUNC_NAME("readlink");
- DBG_VOP_LOCKS_DECL(1);
- DBG_VOP_PRINT_FUNCNAME();
- DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
+ int retval;
+ struct vnode *vp = ap->a_vp;
+ struct hfsnode *hp = VTOH(vp);
- DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
- retval = VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred);
- /* clear IN_ACCESS to prevent needless update of symlink vnode */
- VTOH(ap->a_vp)->h_nodeflags &= ~IN_ACCESS;
+ if (vp->v_type != VLNK)
+ return (EINVAL);
+
+ /* Zero length sym links are not allowed */
+ if (hp->fcbEOF == 0) {
+ VTOVCB(vp)->vcbFlags |= kHFS_DamagedVolume;
+ return (EINVAL);
+ }
+
+ /* Cache the path so we don't waste buffer cache resources */
+ if (hp->h_symlinkptr == NULL) {
+ struct buf *bp = NULL;
+
+ if (H_ISBIGLINK(hp))
+ MALLOC(hp->h_symlinkptr, char *, hp->fcbEOF, M_TEMP, M_WAITOK);
+
+ retval = meta_bread(vp, 0, roundup((int)hp->fcbEOF, kHFSBlockSize), ap->a_cred, &bp);
+ if (retval) {
+ if (bp)
+ brelse(bp);
+ if (hp->h_symlinkptr) {
+ FREE(hp->h_symlinkptr, M_TEMP);
+ hp->h_symlinkptr = NULL;
+ }
+ return (retval);
+ }
+
+ bcopy(bp->b_data, H_SYMLINK(hp), (size_t)hp->fcbEOF);
- DBG_VOP_LOCKS_TEST(retval);
- return (retval);
+ if (bp) {
+ bp->b_flags |= B_INVAL; /* data no longer needed */
+ brelse(bp);
+ }
+ }
+
+ retval = uiomove((caddr_t)H_SYMLINK(hp), (int)hp->fcbEOF, ap->a_uio);
+ return (retval);
}
}
else
DBG_ASSERT(hp->h_meta->h_usecount == 1);
-
+
+ /* Dump cached symlink data */
+ if ((vp->v_type == VLNK) && (hp->h_symlinkptr != NULL)) {
+ if (H_ISBIGLINK(hp))
+ FREE(hp->h_symlinkptr, M_TEMP);
+ hp->h_symlinkptr = NULL;
+ }
/*
* Purge old data structures associated with the inode.
goto Err_Exit;
};
+ if (vp->v_type == VDIR)
+ hp->h_nodeflags &= ~IN_BYCNID;
+
Err_Exit:;
DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
DBG_VOP_LOCKS_TEST(retval);
DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags));
DBG_VOP_LOCKS_INIT(0,vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
+ if (vp->v_type == VDIR)
+ hp->h_nodeflags &= ~IN_BYCNID;
DBG_ASSERT((ap->a_flags & (LK_EXCLUSIVE|LK_SHARED)) == 0);
retval = lockmgr(&hp->h_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p);
case _PC_NO_TRUNC:
*ap->a_retval = 0;
break;
+ case _PC_NAME_CHARS_MAX:
+ *ap->a_retval = kHFSPlusMaxFileNameChars;
+ break;
+ case _PC_CASE_SENSITIVE:
+ *ap->a_retval = 0;
+ break;
+ case _PC_CASE_PRESERVING:
+ *ap->a_retval = 1;
+ break;
default:
retval = EINVAL;
}
UInt8 forkType;
int retval;
int hasmetalock = 0;
+ u_int32_t tehint = 0;
DBG_FUNC_NAME("makenode");
parhp = VTOH(dvp);
else
hasmetalock = 1;
+ /*
+ * Force Carbon creates to have MacUnicode encoding
+ */
+ if ((parhp->h_nodeflags & IN_BYCNID) && (!ISSET(p->p_flag, P_TBE))) {
+ tehint = kTextEncodingMacUnicode;
+ }
+
/* Create the Catalog B*-Tree entry */
- retval = hfsCreate(vcb, H_FILEID(parhp), cnp->cn_nameptr, mode);
+ retval = hfsCreate(vcb, H_FILEID(parhp), cnp->cn_nameptr, mode, tehint);
if (retval != E_NONE) {
DBG_ERR(("%s: hfsCreate FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp)));
goto bad1;