-/*
- * get a cnode
- *
- * called by hfs_lookup and hfs_vget (descp == NULL)
- *
- * returns a locked vnode for cnode for given cnid/fileid
- */
-__private_extern__
-int
-hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wantrsrc,
- struct cat_attr *attrp, struct cat_fork *forkp, struct vnode **vpp)
-{
- dev_t dev = hfsmp->hfs_raw_dev;
- struct vnode *vp = NULL;
- struct vnode *rvp = NULL;
- struct vnode *new_vp = NULL;
- struct cnode *cp = NULL;
- struct proc *p = current_proc();
- int retval = E_NONE;
-
- /* Check if unmount in progress */
- if (HFSTOVFS(hfsmp)->mnt_kern_flag & MNTK_UNMOUNT) {
- *vpp = NULL;
- return (EPERM);
- }
-
- /*
- * Check the hash for an active cnode
- */
- cp = hfs_chashget(dev, cnid, wantrsrc, &vp, &rvp);
- if (cp != NULL) {
- /* hide open files that have been deleted */
- if ((hfsmp->hfs_private_metadata_dir != 0)
- && (cp->c_parentcnid == hfsmp->hfs_private_metadata_dir)
- && (cp->c_nlink == 0)) {
- retval = ENOENT;
- goto exit;
- }
-
- /* Hide private journal files */
- if (hfsmp->jnl &&
- (cp->c_parentcnid == kRootDirID) &&
- ((cp->c_cnid == hfsmp->hfs_jnlfileid) ||
- (cp->c_cnid == hfsmp->hfs_jnlinfoblkid))) {
- retval = ENOENT;
- goto exit;
- }
-
- if (wantrsrc && rvp != NULL) {
- vp = rvp;
- rvp = NULL;
- goto done;
- }
- if (!wantrsrc && vp != NULL) {
- /* Hardlinks need an updated catalog descriptor */
- if (descp && cp->c_flag & C_HARDLINK) {
- replace_desc(cp, descp);
- }
- /* We have a vnode so we're done. */
- goto done;
- }
- }
-
- /*
- * There was no active vnode so get a new one.
- * Use the existing cnode (if any).
- */
- if (descp != NULL) {
- /*
- * hfs_lookup case, use descp, attrp and forkp
- */
- retval = hfs_getnewvnode(hfsmp, cp, descp, wantrsrc, attrp,
- forkp, &new_vp);
- } else {
- struct cat_desc cndesc = {0};
- struct cat_attr cnattr = {0};
- struct cat_fork cnfork = {0};
-
- /*
- * hfs_vget case, need to lookup entry (by file id)
- */
- if (cnid == kRootParID) {
- static char hfs_rootname[] = "/";
-
- cndesc.cd_nameptr = &hfs_rootname[0];
- cndesc.cd_namelen = 1;
- cndesc.cd_parentcnid = kRootParID;
- cndesc.cd_cnid = kRootParID;
- cndesc.cd_flags = CD_ISDIR;
-
- cnattr.ca_fileid = kRootParID;
- cnattr.ca_nlink = 2;
- cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
- } else {
- /* Lock catalog b-tree */
- retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
- if (retval)
- goto exit;
-
- retval = cat_idlookup(hfsmp, cnid, &cndesc, &cnattr, &cnfork);
-
- /* Unlock catalog b-tree */
- (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
- if (retval)
- goto exit;
-
- /* Hide open files that have been deleted */
- if ((hfsmp->hfs_private_metadata_dir != 0) &&
- (cndesc.cd_parentcnid == hfsmp->hfs_private_metadata_dir)) {
- cat_releasedesc(&cndesc);
- retval = ENOENT;
- goto exit;
- }
- }
-
- retval = hfs_getnewvnode(hfsmp, cp, &cndesc, 0, &cnattr, &cnfork, &new_vp);
-
- /* Hardlinks may need an updated catalog descriptor */
- if (retval == 0
- && new_vp
- && (VTOC(new_vp)->c_flag & C_HARDLINK)
- && cndesc.cd_nameptr
- && cndesc.cd_namelen > 0) {
- replace_desc(VTOC(new_vp), &cndesc);
- }
- cat_releasedesc(&cndesc);
- }
-exit:
- /* Release reference taken on opposite vnode (if any). */
- if (vp)
- vput(vp);
- else if (rvp)
- vput(rvp);
-
- if (retval) {
- *vpp = NULL;
- return (retval);
- }
- vp = new_vp;
-done:
- /* The cnode's vnode should be in vp. */
- if (vp == NULL)
- panic("hfs_getcnode: missing vp!");
-
- UBCINFOCHECK("hfs_getcnode", vp);
- *vpp = vp;
- return (0);
-}
-