]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_catalog.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_catalog.c
index bb4e69620df727872c02110b8778ce6550ddd3c7..75c7701ee0ce7606e7e050f0d5ef5c789e7251bd 100644 (file)
@@ -513,6 +513,18 @@ cat_idlookup(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *outdescp,
        }
 
        result = cat_lookupbykey(hfsmp, keyp, 0, 0, outdescp, attrp, forkp, NULL);
+       if (!result && outdescp) {
+               cnid_t dcnid = outdescp->cd_cnid;
+               /*
+                * Just for sanity's sake, let's make sure that
+                * the key in the thread matches the key in the record.
+                */
+               if (cnid != dcnid) {
+                       printf("Requested cnid (%d / 0x%08lx) != dcnid (%d / 0x%08lx)\n", cnid, cnid, dcnid, dcnid);                    
+                       result = ENOENT;
+               }
+       }
+
 exit:
        FREE(recp, M_TEMP);
        FREE(iterator, M_TEMP);
@@ -536,9 +548,16 @@ cat_lookupmangled(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc,
                return (ENOENT);
 
        fileID = GetEmbeddedFileID(descp->cd_nameptr, descp->cd_namelen, &prefixlen);
-       if (fileID < kHFSFirstUserCatalogNodeID)
+
+       if (fileID < (cnid_t)kHFSFirstUserCatalogNodeID)
                return (ENOENT);
 
+       if(fileID == hfsmp->hfs_privdir_desc.cd_cnid ||
+               fileID == hfsmp->hfs_jnlfileid ||
+               fileID == hfsmp->hfs_jnlinfoblkid) {
+               return (ENOENT);
+       }
+
        result = cat_idlookup(hfsmp, fileID, outdescp, attrp, forkp);
        if (result)
                return (ENOENT);
@@ -653,6 +672,9 @@ cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantr
                        bcopy(&recp->hfsPlusFile.resourceFork.extents[0],
                              &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord));
                } else {
+                       int i;
+                       u_int32_t validblks;
+
                        /* Convert the data fork. */
                        forkp->cf_size = recp->hfsPlusFile.dataFork.logicalSize;
                        forkp->cf_blocks = recp->hfsPlusFile.dataFork.totalBlocks;
@@ -667,6 +689,36 @@ cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantr
                        forkp->cf_vblocks = 0;
                        bcopy(&recp->hfsPlusFile.dataFork.extents[0],
                              &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord));
+
+                       /* Validate the fork's resident extents. */
+                       validblks = 0;
+                       for (i = 0; i < kHFSPlusExtentDensity; ++i) {
+                               if (forkp->cf_extents[i].startBlock + forkp->cf_extents[i].blockCount >= hfsmp->totalBlocks) {
+                                       /* Suppress any bad extents so a remove can succeed. */
+                                       forkp->cf_extents[i].startBlock = 0;
+                                       forkp->cf_extents[i].blockCount = 0;
+                                       /* Disable writes */
+                                       if (attrp != NULL) {
+                                               attrp->ca_mode &= S_IFMT | S_IRUSR | S_IRGRP | S_IROTH;
+                                       }
+                               } else {
+                                       validblks += forkp->cf_extents[i].blockCount;
+                               }
+                       }
+                       /* Adjust for any missing blocks. */
+                       if ((validblks < forkp->cf_blocks) && (forkp->cf_extents[7].blockCount == 0)) {
+                               u_int64_t psize;
+
+                               forkp->cf_blocks = validblks;
+                               if (attrp != NULL) {
+                                       attrp->ca_blocks = validblks + recp->hfsPlusFile.resourceFork.totalBlocks;
+                               }
+                               psize = (u_int64_t)validblks * (u_int64_t)hfsmp->blockSize;
+                               if (psize < forkp->cf_size) {
+                                       forkp->cf_size = psize;
+                               }
+
+                       }
                }
        }
        if (descp != NULL) {
@@ -2167,6 +2219,20 @@ cat_getdirentries(struct hfsmount *hfsmp, int entrycnt, directoryhint_t *dirhint
        result = BTIterateRecords(fcb, op, iterator,
                                  (IterateCallBackProcPtr)cat_packdirentry, &state);
 
+       /* If readdir is called for NFS and BTIterateRecords reaches the end of the
+        * Catalog BTree, call cat_packdirentry() with dummy values to copy previous 
+        * direntry stored in state to the user buffer.
+        */
+       if (state.cbs_extended && (result == fsBTRecordNotFoundErr)) {
+               CatalogKey ckp;
+               CatalogRecord crp;
+
+               bzero(&ckp, sizeof(ckp));
+               bzero(&crp, sizeof(crp));
+
+               result = cat_packdirentry(&ckp, &crp, &state);
+       }
+
        /* Note that state.cbs_index is still valid on errors */
        *items = state.cbs_index - index;
        index = state.cbs_index;