]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_vfsutils.c
xnu-201.5.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsutils.c
index 077b9a13ab63fbd098baf3f9c84b68b461d9f436..29dab58567de51a129b8481eba09fead409eaffe 100644 (file)
@@ -622,6 +622,7 @@ void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp)
        char iNodeName[32];
        UInt32 hint;
        UInt32 indlinkno;
+       UInt32 linkparid, linkcnid;
        OSErr result;
 
        fip = (struct FInfo *) &cndp->cnd_finderInfo;
@@ -641,7 +642,10 @@ void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp)
                /*
                 * Get nodeData from the data node file. 
                 * Flag the node data to NOT copy the name (ie preserve the original)
+                * Also preserve the parent directory ID.
                 */
+               linkparid = cndp->cnm_parID;
+               linkcnid = cndp->cnd_nodeID;
                cndp->cnm_flags |= kCatNameNoCopyName;
                result = GetCatalogNode(vcb, VCBTOHFS(vcb)->hfs_private_metadata_dir,
                                iNodeName, 0, 0, cndp, &hint);
@@ -653,6 +657,8 @@ void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp)
                        
                        /* Keep a copy of iNodeNum to put into h_indnodeno */
                        cndp->cnd_iNodeNumCopy = indlinkno;
+                       cndp->cnm_parID = linkparid;
+                       cndp->cnd_linkCNID = linkcnid;
                }
        }
 }
@@ -837,8 +843,26 @@ short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, str
                *vpp = NULL;
                return (EPERM);
        }
-       DBG_UTILS(("\thfs_vcreate: On '%s' with forktype of %d, nodeType of 0x%08lX\n", catInfo->nodeData.cnm_nameptr, forkType, (unsigned long)catInfo->nodeData.cnd_type));
-       
+
+       /*
+        * If this is a hard link then check if the
+        * data node already exists in our hash.
+        */
+       if ((forkType == kDataFork)
+               && (catInfo->nodeData.cnd_type == kCatalogFileNode)
+               && ((catInfo->nodeData.cnd_mode & IFMT) == IFREG)
+               && (catInfo->nodeData.cnd_linkCount > 0)) {
+               vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, kDataFork);
+               if (vp != NULL) {
+                       /* Use the name of the link and it's parent ID. */
+                       hp = VTOH(vp);
+                       H_DIRID(hp) = catInfo->nodeData.cnm_parID;
+                       hfs_set_metaname(catInfo->nodeData.cnm_nameptr, hp->h_meta, hfsmp);
+                       *vpp = vp;
+                       return (0);
+               }
+       }
+
        /* Must malloc() here, since getnewvnode() can sleep */
        MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
        bzero((caddr_t)hp, sizeof(struct hfsnode));
@@ -2095,15 +2119,27 @@ void PackCommonCatalogInfoAttributeBlock(struct attrlist                *alist,
                        };
                }
                if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = root_vp->v_tag;
-        if (a & ATTR_CMN_OBJID)
-        {
-            ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.cnd_nodeID;
+        if (a & ATTR_CMN_OBJID) {
+            u_int32_t cnid;
+            /* For hard links use the link's cnid */
+            if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0)
+                               cnid = catalogInfo->nodeData.cnd_linkCNID;
+            else
+                               cnid = catalogInfo->nodeData.cnd_nodeID;
+            ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
             ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
             ++((fsobj_id_t *)attrbufptr);
         };
-        if (a & ATTR_CMN_OBJPERMANENTID)
-        {
-            ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.cnd_nodeID;
+        if (a & ATTR_CMN_OBJPERMANENTID) {
+            u_int32_t cnid;
+            /* For hard links use the link's cnid */
+            if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0)
+                               cnid = catalogInfo->nodeData.cnd_linkCNID;
+                       else
+                               cnid = catalogInfo->nodeData.cnd_nodeID;
+            ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
             ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
             ++((fsobj_id_t *)attrbufptr);
         };
@@ -2210,24 +2246,23 @@ void PackCommonCatalogInfoAttributeBlock(struct attrlist                *alist,
                        (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
                        ++((struct attrreference *)attrbufptr);
                };
-        if (a & ATTR_CMN_FLAGS) {
-               if (catalogInfo->nodeData.cnd_mode & IFMT) {
-                       if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask) {
-                               *((u_long *)attrbufptr)++ =
-                                       (u_long) (catalogInfo->nodeData.cnd_ownerFlags |
-                                                         (catalogInfo->nodeData.cnd_adminFlags << 16)) |
-                                                         UF_IMMUTABLE;
-                       } else {
-                               *((u_long *)attrbufptr)++ =
-                                       (u_long) (catalogInfo->nodeData.cnd_ownerFlags |
-                                                         (catalogInfo->nodeData.cnd_adminFlags << 16)) & ~UF_IMMUTABLE;
-                       }
-               } else {
-                       /* The information in the node flag fields is not valid: */
-                       *((u_long *)attrbufptr)++ =
-                               (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask) ? UF_IMMUTABLE : 0;
-               };
-        };
+               if (a & ATTR_CMN_FLAGS) {
+                       u_long flags;
+
+                       if (catalogInfo->nodeData.cnd_mode & IFMT)
+                               flags = catalogInfo->nodeData.cnd_ownerFlags |
+                                       catalogInfo->nodeData.cnd_adminFlags << 16;
+                       else
+                               flags = 0;
+
+                       if (catalogInfo->nodeData.cnd_type == kCatalogFileNode) {
+                               if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask)
+                                       flags |= UF_IMMUTABLE;
+                               else
+                                       flags &= ~UF_IMMUTABLE;
+                       };
+                       *((u_long *)attrbufptr)++ = flags;
+               };
                if (a & ATTR_CMN_USERACCESS) {
                        if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) ||
                                ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) {
@@ -2291,12 +2326,26 @@ void PackCommonAttributeBlock(struct attrlist *alist,
                if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = vp->v_type;
                if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = vp->v_tag;
         if (a & ATTR_CMN_OBJID)        {
-            ((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp);
+            u_int32_t cnid;
+
+            /* For hard links use the link's cnid */
+            if (hp->h_meta->h_metaflags & IN_DATANODE)
+                cnid = catInfo->nodeData.cnd_linkCNID;
+            else
+                cnid = H_FILEID(hp);
+            ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
                        ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
                        ++((fsobj_id_t *)attrbufptr);
                };
         if (a & ATTR_CMN_OBJPERMANENTID)       {
-            ((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp);
+            u_int32_t cnid;
+
+            /* For hard links use the link's cnid */
+            if (hp->h_meta->h_metaflags & IN_DATANODE)
+                cnid = catInfo->nodeData.cnd_linkCNID;
+            else
+                cnid = H_FILEID(hp);
+            ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
             ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
             ++((fsobj_id_t *)attrbufptr);
         };