17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*264a6e74Sfrankho * Common Development and Distribution License (the "License"). 6*264a6e74Sfrankho * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*264a6e74Sfrankho * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*264a6e74Sfrankho * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * fsck_pcfs -- routines for manipulating directories. 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate #include <stdio.h> 327c478bd9Sstevel@tonic-gate #include <string.h> 337c478bd9Sstevel@tonic-gate #include <unistd.h> 347c478bd9Sstevel@tonic-gate #include <stdlib.h> 357c478bd9Sstevel@tonic-gate #include <libintl.h> 367c478bd9Sstevel@tonic-gate #include <ctype.h> 37*264a6e74Sfrankho #include <time.h> 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/time.h> 40*264a6e74Sfrankho #include <sys/byteorder.h> 417c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 427c478bd9Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 437c478bd9Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 447c478bd9Sstevel@tonic-gate #include <sys/fs/pc_label.h> 457c478bd9Sstevel@tonic-gate #include "pcfs_common.h" 467c478bd9Sstevel@tonic-gate #include "fsck_pcfs.h" 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate extern int32_t HiddenClusterCount; 497c478bd9Sstevel@tonic-gate extern int32_t FileClusterCount; 507c478bd9Sstevel@tonic-gate extern int32_t DirClusterCount; 517c478bd9Sstevel@tonic-gate extern int32_t HiddenFileCount; 527c478bd9Sstevel@tonic-gate extern int32_t LastCluster; 537c478bd9Sstevel@tonic-gate extern int32_t FileCount; 547c478bd9Sstevel@tonic-gate extern int32_t BadCount; 557c478bd9Sstevel@tonic-gate extern int32_t DirCount; 567c478bd9Sstevel@tonic-gate extern int32_t FATSize; 577c478bd9Sstevel@tonic-gate extern off64_t PartitionOffset; 587c478bd9Sstevel@tonic-gate extern bpb_t TheBIOSParameterBlock; 597c478bd9Sstevel@tonic-gate extern int ReadOnly; 607c478bd9Sstevel@tonic-gate extern int IsFAT32; 617c478bd9Sstevel@tonic-gate extern int Verbose; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate static uchar_t *CHKsList = NULL; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate ClusterContents TheRootDir; 667c478bd9Sstevel@tonic-gate int32_t RootDirSize; 677c478bd9Sstevel@tonic-gate int RootDirModified; 687c478bd9Sstevel@tonic-gate int OkayToRelink = 1; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * We have a bunch of routines for handling CHK names. A CHK name is 727c478bd9Sstevel@tonic-gate * simply a file name of the form "FILEnnnn.CHK", where the n's are the 737c478bd9Sstevel@tonic-gate * digits in the numbers from 1 to 9999. There are always four digits 747c478bd9Sstevel@tonic-gate * used, leading zeros are added as necessary. 757c478bd9Sstevel@tonic-gate * 767c478bd9Sstevel@tonic-gate * We use CHK names to link orphaned cluster chains back into the file 777c478bd9Sstevel@tonic-gate * system's root directory under an auspicious name so that the user 787c478bd9Sstevel@tonic-gate * may be able to recover some of their data. 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * We use these routines to ensure CHK names we use don't conflict 817c478bd9Sstevel@tonic-gate * with any already present in the file system. 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate static int 847c478bd9Sstevel@tonic-gate hasCHKName(struct pcdir *dp) 857c478bd9Sstevel@tonic-gate { 867c478bd9Sstevel@tonic-gate return (dp->pcd_filename[CHKNAME_F] == 'F' && 877c478bd9Sstevel@tonic-gate dp->pcd_filename[CHKNAME_I] == 'I' && 887c478bd9Sstevel@tonic-gate dp->pcd_filename[CHKNAME_L] == 'L' && 897c478bd9Sstevel@tonic-gate dp->pcd_filename[CHKNAME_E] == 'E' && 907c478bd9Sstevel@tonic-gate isdigit(dp->pcd_filename[CHKNAME_THOUSANDS]) && 917c478bd9Sstevel@tonic-gate isdigit(dp->pcd_filename[CHKNAME_HUNDREDS]) && 927c478bd9Sstevel@tonic-gate isdigit(dp->pcd_filename[CHKNAME_TENS]) && 937c478bd9Sstevel@tonic-gate isdigit(dp->pcd_filename[CHKNAME_ONES]) && 947c478bd9Sstevel@tonic-gate dp->pcd_ext[CHKNAME_C] == 'C' && 957c478bd9Sstevel@tonic-gate dp->pcd_ext[CHKNAME_H] == 'H' && 967c478bd9Sstevel@tonic-gate dp->pcd_ext[CHKNAME_K] == 'K'); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate void 1007c478bd9Sstevel@tonic-gate addEntryToCHKList(int chkNumber) 1017c478bd9Sstevel@tonic-gate { 1027c478bd9Sstevel@tonic-gate /* silent failure on bogus value */ 1037c478bd9Sstevel@tonic-gate if (chkNumber < 0 || chkNumber > MAXCHKVAL) 1047c478bd9Sstevel@tonic-gate return; 1057c478bd9Sstevel@tonic-gate CHKsList[chkNumber / NBBY] |= (1 << (chkNumber % NBBY)); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static void 1097c478bd9Sstevel@tonic-gate addToCHKList(struct pcdir *dp) 1107c478bd9Sstevel@tonic-gate { 1117c478bd9Sstevel@tonic-gate int chknum; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate chknum = 1000 * (dp->pcd_filename[CHKNAME_THOUSANDS] - '0'); 1147c478bd9Sstevel@tonic-gate chknum += 100 * (dp->pcd_filename[CHKNAME_HUNDREDS] - '0'); 1157c478bd9Sstevel@tonic-gate chknum += 10 * (dp->pcd_filename[CHKNAME_TENS] - '0'); 1167c478bd9Sstevel@tonic-gate chknum += (dp->pcd_filename[CHKNAME_ONES] - '0'); 1177c478bd9Sstevel@tonic-gate addEntryToCHKList(chknum); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate static int 1217c478bd9Sstevel@tonic-gate inUseCHKName(int chkNumber) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate return (CHKsList[chkNumber / NBBY] & (1 << (chkNumber % NBBY))); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate static void 1277c478bd9Sstevel@tonic-gate appendToPath(struct pcdir *dp, char *thePath, int *theLen) 1287c478bd9Sstevel@tonic-gate { 1297c478bd9Sstevel@tonic-gate int i = 0; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * Sometimes caller doesn't care about keeping track of the path 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate if (thePath == NULL) 1357c478bd9Sstevel@tonic-gate return; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* 1387c478bd9Sstevel@tonic-gate * Prepend / 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate if (*theLen < MAXPATHLEN) 1417c478bd9Sstevel@tonic-gate *(thePath + (*theLen)++) = '/'; 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * Print out the file name part, but only up to the first 1447c478bd9Sstevel@tonic-gate * space. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate while (*theLen < MAXPATHLEN && i < PCFNAMESIZE) { 1477c478bd9Sstevel@tonic-gate /* 1487c478bd9Sstevel@tonic-gate * When we start seeing spaces we assume that's the 1497c478bd9Sstevel@tonic-gate * end of the interesting characters in the name. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate if ((dp->pcd_filename[i] == ' ') || 1527c478bd9Sstevel@tonic-gate !(pc_validchar(dp->pcd_filename[i]))) 1537c478bd9Sstevel@tonic-gate break; 1547c478bd9Sstevel@tonic-gate *(thePath + (*theLen)++) = dp->pcd_filename[i++]; 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate /* 1577c478bd9Sstevel@tonic-gate * Leave now, if we don't have an extension (or room for one) 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate if ((dp->pcd_ext[i] == ' ') || ((*theLen) >= MAXPATHLEN) || 1607c478bd9Sstevel@tonic-gate (!(pc_validchar(dp->pcd_ext[i])))) 1617c478bd9Sstevel@tonic-gate return; 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * Tack on the extension 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate *(thePath + (*theLen)++) = '.'; 1667c478bd9Sstevel@tonic-gate i = 0; 1677c478bd9Sstevel@tonic-gate while ((*theLen < MAXPATHLEN) && (i < PCFEXTSIZE)) { 1687c478bd9Sstevel@tonic-gate if ((dp->pcd_ext[i] == ' ') || !(pc_validchar(dp->pcd_ext[i]))) 1697c478bd9Sstevel@tonic-gate break; 1707c478bd9Sstevel@tonic-gate *(thePath + (*theLen)++) = dp->pcd_ext[i++]; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate static void 1757c478bd9Sstevel@tonic-gate printName(FILE *outDest, struct pcdir *dp) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate int i; 1787c478bd9Sstevel@tonic-gate for (i = 0; i < PCFNAMESIZE; i++) { 1797c478bd9Sstevel@tonic-gate if ((dp->pcd_filename[i] == ' ') || 1807c478bd9Sstevel@tonic-gate !(pc_validchar(dp->pcd_filename[i]))) 1817c478bd9Sstevel@tonic-gate break; 1827c478bd9Sstevel@tonic-gate (void) fprintf(outDest, "%c", dp->pcd_filename[i]); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate (void) fprintf(outDest, "."); 1857c478bd9Sstevel@tonic-gate for (i = 0; i < PCFEXTSIZE; i++) { 1867c478bd9Sstevel@tonic-gate if (!(pc_validchar(dp->pcd_ext[i]))) 1877c478bd9Sstevel@tonic-gate break; 1887c478bd9Sstevel@tonic-gate (void) fprintf(outDest, "%c", dp->pcd_ext[i]); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * sanityCheckSize 1947c478bd9Sstevel@tonic-gate * Make sure the size in the directory entry matches what is 1957c478bd9Sstevel@tonic-gate * actually allocated. If there is a mismatch, orphan all 1967c478bd9Sstevel@tonic-gate * the allocated clusters. Returns SIZE_MATCHED if everything matches 1977c478bd9Sstevel@tonic-gate * up, TRUNCATED to indicate truncation was necessary. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate static int 2007c478bd9Sstevel@tonic-gate sanityCheckSize(int fd, struct pcdir *dp, int32_t actualClusterCount, 2017c478bd9Sstevel@tonic-gate int isDir, int32_t startCluster, struct nameinfo *fullPathName, 2027c478bd9Sstevel@tonic-gate struct pcdir **orphanEntry) 2037c478bd9Sstevel@tonic-gate { 2047c478bd9Sstevel@tonic-gate uint32_t sizeFromDir; 2057c478bd9Sstevel@tonic-gate int32_t ignorei = 0; 2067c478bd9Sstevel@tonic-gate int64_t bpc; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate bpc = TheBIOSParameterBlock.bpb.sectors_per_cluster * 2097c478bd9Sstevel@tonic-gate TheBIOSParameterBlock.bpb.bytes_per_sector; 2107c478bd9Sstevel@tonic-gate sizeFromDir = extractSize(dp); 2117c478bd9Sstevel@tonic-gate if (isDir) { 2127c478bd9Sstevel@tonic-gate if (sizeFromDir == 0) 2137c478bd9Sstevel@tonic-gate return (SIZE_MATCHED); 2147c478bd9Sstevel@tonic-gate } else { 2157c478bd9Sstevel@tonic-gate if ((sizeFromDir > ((actualClusterCount - 1) * bpc)) && 2167c478bd9Sstevel@tonic-gate (sizeFromDir <= (actualClusterCount * bpc))) 2177c478bd9Sstevel@tonic-gate return (SIZE_MATCHED); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate if (fullPathName != NULL) { 2207c478bd9Sstevel@tonic-gate fullPathName->references++; 2217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", fullPathName->fullName); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate squirrelPath(fullPathName, startCluster); 2247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2257c478bd9Sstevel@tonic-gate gettext("Truncating chain due to incorrect size " 2267c478bd9Sstevel@tonic-gate "in directory. Size from directory = %u bytes,\n"), sizeFromDir); 2277c478bd9Sstevel@tonic-gate if (actualClusterCount == 0) { 2287c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2297c478bd9Sstevel@tonic-gate gettext("Zero bytes are allocated to the file.\n")); 2307c478bd9Sstevel@tonic-gate } else { 2317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2327c478bd9Sstevel@tonic-gate gettext("Allocated size in range %llu - %llu bytes.\n"), 2337c478bd9Sstevel@tonic-gate ((actualClusterCount - 1) * bpc) + 1, 2347c478bd9Sstevel@tonic-gate (actualClusterCount * bpc)); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate /* 2377c478bd9Sstevel@tonic-gate * Use splitChain() to make an orphan that is the entire allocation 2387c478bd9Sstevel@tonic-gate * chain. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate splitChain(fd, dp, startCluster, orphanEntry, &ignorei); 2417c478bd9Sstevel@tonic-gate return (TRUNCATED); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate static int 2457c478bd9Sstevel@tonic-gate noteUsage(int fd, int32_t startAt, struct pcdir *dp, struct pcdir *lp, 2467c478bd9Sstevel@tonic-gate int32_t longEntryStartCluster, int isHidden, int isDir, 2477c478bd9Sstevel@tonic-gate struct nameinfo *fullPathName) 2487c478bd9Sstevel@tonic-gate { 2497c478bd9Sstevel@tonic-gate struct pcdir *orphanEntry; 2507c478bd9Sstevel@tonic-gate int32_t chain = startAt; 2517c478bd9Sstevel@tonic-gate int32_t count = 0; 2527c478bd9Sstevel@tonic-gate int savePathNextIteration = 0; 2537c478bd9Sstevel@tonic-gate int haveBad = 0; 2547c478bd9Sstevel@tonic-gate ClusterInfo *tmpl = NULL; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate while ((chain >= FIRST_CLUSTER) && (chain <= LastCluster)) { 2577c478bd9Sstevel@tonic-gate if ((markInUse(fd, chain, dp, lp, longEntryStartCluster, 2587c478bd9Sstevel@tonic-gate isHidden ? HIDDEN : VISIBLE, &tmpl)) 2597c478bd9Sstevel@tonic-gate != CLINFO_NEWLY_ALLOCED) 2607c478bd9Sstevel@tonic-gate break; 2617c478bd9Sstevel@tonic-gate count++; 2627c478bd9Sstevel@tonic-gate if (savePathNextIteration == 1) { 2637c478bd9Sstevel@tonic-gate savePathNextIteration = 0; 2647c478bd9Sstevel@tonic-gate if (fullPathName != NULL) 2657c478bd9Sstevel@tonic-gate fullPathName->references++; 2667c478bd9Sstevel@tonic-gate squirrelPath(fullPathName, chain); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate if (isMarkedBad(chain)) { 2697c478bd9Sstevel@tonic-gate haveBad = 1; 2707c478bd9Sstevel@tonic-gate savePathNextIteration = 1; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate if (isHidden) 2737c478bd9Sstevel@tonic-gate HiddenClusterCount++; 2747c478bd9Sstevel@tonic-gate else if (isDir) 2757c478bd9Sstevel@tonic-gate DirClusterCount++; 2767c478bd9Sstevel@tonic-gate else 2777c478bd9Sstevel@tonic-gate FileClusterCount++; 2787c478bd9Sstevel@tonic-gate chain = nextInChain(chain); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * Do a sanity check on the file size in the directory entry. 2827c478bd9Sstevel@tonic-gate * This may create an orphaned cluster chain. 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate if (sanityCheckSize(fd, dp, count, isDir, startAt, 2857c478bd9Sstevel@tonic-gate fullPathName, &orphanEntry) == TRUNCATED) { 2867c478bd9Sstevel@tonic-gate /* 2877c478bd9Sstevel@tonic-gate * The pre-existing directory entry has been truncated, 2887c478bd9Sstevel@tonic-gate * so the chain associated with it no longer has any 2897c478bd9Sstevel@tonic-gate * bad clusters. Instead, the new orphan has them. 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate if (haveBad > 0) { 2927c478bd9Sstevel@tonic-gate truncChainWithBadCluster(fd, orphanEntry, startAt); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate haveBad = 0; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate return (haveBad); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate static void 3007c478bd9Sstevel@tonic-gate storeInfoAboutEntry(int fd, struct pcdir *dp, struct pcdir *ldp, int depth, 3017c478bd9Sstevel@tonic-gate int32_t longEntryStartCluster, char *fullPath, int *fullLen) 3027c478bd9Sstevel@tonic-gate { 3037c478bd9Sstevel@tonic-gate struct nameinfo *pathCopy; 3047c478bd9Sstevel@tonic-gate int32_t start; 3057c478bd9Sstevel@tonic-gate int haveBad; 3067c478bd9Sstevel@tonic-gate int hidden = (dp->pcd_attr & PCA_HIDDEN || dp->pcd_attr & PCA_SYSTEM); 3077c478bd9Sstevel@tonic-gate int dir = (dp->pcd_attr & PCA_DIR); 3087c478bd9Sstevel@tonic-gate int i; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate if (hidden) 3117c478bd9Sstevel@tonic-gate HiddenFileCount++; 3127c478bd9Sstevel@tonic-gate else if (dir) 3137c478bd9Sstevel@tonic-gate DirCount++; 3147c478bd9Sstevel@tonic-gate else 3157c478bd9Sstevel@tonic-gate FileCount++; 3167c478bd9Sstevel@tonic-gate appendToPath(dp, fullPath, fullLen); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * Make a copy of the name at this point. We may want it to 3207c478bd9Sstevel@tonic-gate * note the original source of an orphaned cluster. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate if ((pathCopy = 3237c478bd9Sstevel@tonic-gate (struct nameinfo *)malloc(sizeof (struct nameinfo))) != NULL) { 3247c478bd9Sstevel@tonic-gate if ((pathCopy->fullName = 3257c478bd9Sstevel@tonic-gate (char *)malloc(*fullLen + 1)) != NULL) { 3267c478bd9Sstevel@tonic-gate pathCopy->references = 0; 3277c478bd9Sstevel@tonic-gate (void) strncpy(pathCopy->fullName, fullPath, *fullLen); 3287c478bd9Sstevel@tonic-gate pathCopy->fullName[*fullLen] = '\0'; 3297c478bd9Sstevel@tonic-gate } else { 3307c478bd9Sstevel@tonic-gate free(pathCopy); 3317c478bd9Sstevel@tonic-gate pathCopy = NULL; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate if (Verbose) { 3357c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) 3367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " "); 3377c478bd9Sstevel@tonic-gate if (hidden) 3387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "["); 3397c478bd9Sstevel@tonic-gate else if (dir) 3407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "|_"); 3417c478bd9Sstevel@tonic-gate else 3427c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("(%06d) "), FileCount); 3437c478bd9Sstevel@tonic-gate printName(stderr, dp); 3447c478bd9Sstevel@tonic-gate if (hidden) 3457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "]"); 3467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3477c478bd9Sstevel@tonic-gate gettext(", %u bytes, start cluster %d"), 3487c478bd9Sstevel@tonic-gate extractSize(dp), extractStartCluster(dp)); 3497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate start = extractStartCluster(dp); 3527c478bd9Sstevel@tonic-gate haveBad = noteUsage(fd, start, dp, ldp, longEntryStartCluster, 3537c478bd9Sstevel@tonic-gate hidden, dir, pathCopy); 3547c478bd9Sstevel@tonic-gate if (haveBad > 0) { 3557c478bd9Sstevel@tonic-gate if (dir && pathCopy->fullName != NULL) { 3567c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3577c478bd9Sstevel@tonic-gate gettext("Adjusting for bad allocation units in " 3587c478bd9Sstevel@tonic-gate "the meta-data of:\n ")); 3597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, pathCopy->fullName); 3607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate truncChainWithBadCluster(fd, dp, start); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate if ((pathCopy != NULL) && (pathCopy->references == 0)) { 3657c478bd9Sstevel@tonic-gate free(pathCopy->fullName); 3667c478bd9Sstevel@tonic-gate free(pathCopy); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate static void 3717c478bd9Sstevel@tonic-gate storeInfoAboutLabel(struct pcdir *dp) 3727c478bd9Sstevel@tonic-gate { 3737c478bd9Sstevel@tonic-gate /* 3747c478bd9Sstevel@tonic-gate * XXX eventually depth should be passed to this routine just 3757c478bd9Sstevel@tonic-gate * as it is with storeInfoAboutEntry(). If it isn't zero, then 3767c478bd9Sstevel@tonic-gate * we've got a bogus directory entry. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate if (Verbose) { 3797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("** ")); 3807c478bd9Sstevel@tonic-gate printName(stderr, dp); 3817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(" **\n")); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate static void 3867c478bd9Sstevel@tonic-gate searchChecks(struct pcdir *dp, int operation, char matchRequired, 3877c478bd9Sstevel@tonic-gate struct pcdir **found) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate /* 3907c478bd9Sstevel@tonic-gate * We support these searching operations: 3917c478bd9Sstevel@tonic-gate * 3927c478bd9Sstevel@tonic-gate * PCFS_FIND_ATTR 3937c478bd9Sstevel@tonic-gate * look for the first file with a certain attribute 3947c478bd9Sstevel@tonic-gate * (e.g, find all hidden files) 3957c478bd9Sstevel@tonic-gate * PCFS_FIND_STATUS 3967c478bd9Sstevel@tonic-gate * look for the first file with a certain status 3977c478bd9Sstevel@tonic-gate * (e.g., the file has been marked deleted; making 3987c478bd9Sstevel@tonic-gate * its directory entry reusable) 3997c478bd9Sstevel@tonic-gate * PCFS_FIND_CHKS 4007c478bd9Sstevel@tonic-gate * look for all files with short names of the form 4017c478bd9Sstevel@tonic-gate * FILENNNN.CHK. These are the file names we give 4027c478bd9Sstevel@tonic-gate * to chains of orphaned clusters we relink into the 4037c478bd9Sstevel@tonic-gate * file system. This find facility allows us to seek 4047c478bd9Sstevel@tonic-gate * out all existing files of this naming form so that 4057c478bd9Sstevel@tonic-gate * we may create unique file names for new orphans. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate if (operation == PCFS_FIND_ATTR && dp->pcd_attr == matchRequired) { 4087c478bd9Sstevel@tonic-gate *found = dp; 4097c478bd9Sstevel@tonic-gate } else if (operation == PCFS_FIND_STATUS && 4107c478bd9Sstevel@tonic-gate dp->pcd_filename[0] == matchRequired) { 4117c478bd9Sstevel@tonic-gate *found = dp; 4127c478bd9Sstevel@tonic-gate } else if (operation == PCFS_FIND_CHKS && hasCHKName(dp)) { 4137c478bd9Sstevel@tonic-gate addToCHKList(dp); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate static void 4187c478bd9Sstevel@tonic-gate catalogEntry(int fd, struct pcdir *dp, struct pcdir *longdp, 4197c478bd9Sstevel@tonic-gate int32_t currentCluster, int depth, char *recordPath, int *pathLen) 4207c478bd9Sstevel@tonic-gate { 4217c478bd9Sstevel@tonic-gate if (dp->pcd_attr & PCA_LABEL) { 4227c478bd9Sstevel@tonic-gate storeInfoAboutLabel(dp); 4237c478bd9Sstevel@tonic-gate } else { 4247c478bd9Sstevel@tonic-gate storeInfoAboutEntry(fd, dp, longdp, depth, currentCluster, 4257c478bd9Sstevel@tonic-gate recordPath, pathLen); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * visitNodes() 4317c478bd9Sstevel@tonic-gate * 4327c478bd9Sstevel@tonic-gate * This is the main workhouse routine for traversing pcfs metadata. 4337c478bd9Sstevel@tonic-gate * There isn't a lot to the metadata. Basically there is a root 4347c478bd9Sstevel@tonic-gate * directory somewhere (either in its own special place outside the 4357c478bd9Sstevel@tonic-gate * data area or in a data cluster). The root directory (and all other 4367c478bd9Sstevel@tonic-gate * directories) are filled with a number of fixed size entries. An 4377c478bd9Sstevel@tonic-gate * entry has the filename and extension, the file's attributes, the 4387c478bd9Sstevel@tonic-gate * file's size, and the starting data cluster of the storage allocated 4397c478bd9Sstevel@tonic-gate * to the file. To determine which clusters are assigned to the file, 4407c478bd9Sstevel@tonic-gate * you start at the starting cluster entry in the FAT, and follow the 4417c478bd9Sstevel@tonic-gate * chain of entries in the FAT. 4427c478bd9Sstevel@tonic-gate * 4437c478bd9Sstevel@tonic-gate * Arguments are: 4447c478bd9Sstevel@tonic-gate * fd 4457c478bd9Sstevel@tonic-gate * descriptor for accessing the raw file system data 4467c478bd9Sstevel@tonic-gate * currentCluster 4477c478bd9Sstevel@tonic-gate * original caller supplies the initial starting cluster, 4487c478bd9Sstevel@tonic-gate * subsequent recursive calls are made with updated 4497c478bd9Sstevel@tonic-gate * cluster numbers for the sub-directories. 4507c478bd9Sstevel@tonic-gate * dirData 4517c478bd9Sstevel@tonic-gate * pointer to the directory data bytes 4527c478bd9Sstevel@tonic-gate * dirDataLen 4537c478bd9Sstevel@tonic-gate * size of the whole buffer of data bytes (usually it is 4547c478bd9Sstevel@tonic-gate * the size of a cluster, but the root directory on 4557c478bd9Sstevel@tonic-gate * FAT12/16 is not necessarily the same size as a cluster). 4567c478bd9Sstevel@tonic-gate * depth 4577c478bd9Sstevel@tonic-gate * original caller should set it to zero (assuming they are 4587c478bd9Sstevel@tonic-gate * starting from the root directory). This number is used to 4597c478bd9Sstevel@tonic-gate * change the indentation of file names presented as debug info. 4607c478bd9Sstevel@tonic-gate * descend 4617c478bd9Sstevel@tonic-gate * boolean indicates if we should descend into subdirectories. 4627c478bd9Sstevel@tonic-gate * operation 4637c478bd9Sstevel@tonic-gate * what, if any, matching should be performed. 4647c478bd9Sstevel@tonic-gate * The PCFS_TRAVERSE_ALL operation is a depth first traversal 4657c478bd9Sstevel@tonic-gate * of all nodes in the metadata tree, that tracks all the 4667c478bd9Sstevel@tonic-gate * clusters in use (according to the meta-data, at least) 4677c478bd9Sstevel@tonic-gate * matchRequired 4687c478bd9Sstevel@tonic-gate * value to be matched (if any) 4697c478bd9Sstevel@tonic-gate * found 4707c478bd9Sstevel@tonic-gate * output parameter 4717c478bd9Sstevel@tonic-gate * used to return pointer to a directory entry that matches 4727c478bd9Sstevel@tonic-gate * the search requirement 4737c478bd9Sstevel@tonic-gate * original caller should pass in a pointer to a NULL pointer. 4747c478bd9Sstevel@tonic-gate * lastDirCluster 4757c478bd9Sstevel@tonic-gate * output parameter 4767c478bd9Sstevel@tonic-gate * if no match found, last cluster num of starting directory 4777c478bd9Sstevel@tonic-gate * dirEnd 4787c478bd9Sstevel@tonic-gate * output parameter 4797c478bd9Sstevel@tonic-gate * if no match found, return parameter stores pointer to where 4807c478bd9Sstevel@tonic-gate * new directory entry could be appended to existing directory 4817c478bd9Sstevel@tonic-gate * recordPath 4827c478bd9Sstevel@tonic-gate * output parameter 4837c478bd9Sstevel@tonic-gate * as files are discovered, and directories traversed, this 4847c478bd9Sstevel@tonic-gate * buffer is used to store the current full path name. 4857c478bd9Sstevel@tonic-gate * pathLen 4867c478bd9Sstevel@tonic-gate * output parameter 4877c478bd9Sstevel@tonic-gate * this is in the integer length of the current full path name. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate static void 4907c478bd9Sstevel@tonic-gate visitNodes(int fd, int32_t currentCluster, ClusterContents *dirData, 4917c478bd9Sstevel@tonic-gate int32_t dirDataLen, int depth, int descend, int operation, 4927c478bd9Sstevel@tonic-gate char matchRequired, struct pcdir **found, int32_t *lastDirCluster, 4937c478bd9Sstevel@tonic-gate struct pcdir **dirEnd, char *recordPath, int *pathLen) 4947c478bd9Sstevel@tonic-gate { 4957c478bd9Sstevel@tonic-gate struct pcdir *longdp = NULL; 4967c478bd9Sstevel@tonic-gate struct pcdir *dp; 4977c478bd9Sstevel@tonic-gate int32_t longStart; 4987c478bd9Sstevel@tonic-gate int withinLongName = 0; 4997c478bd9Sstevel@tonic-gate int saveLen = *pathLen; 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate dp = dirData->dirp; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate * A directory entry where the first character of the name is 5057c478bd9Sstevel@tonic-gate * PCD_UNUSED indicates the end of the directory. 5067c478bd9Sstevel@tonic-gate */ 5077c478bd9Sstevel@tonic-gate while ((uchar_t *)dp < dirData->bytes + dirDataLen && 5087c478bd9Sstevel@tonic-gate dp->pcd_filename[0] != PCD_UNUSED) { 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * Handle the special case find operations. 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate searchChecks(dp, operation, matchRequired, found); 5137c478bd9Sstevel@tonic-gate if (*found) 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * Are we looking at part of a long file name entry? 5177c478bd9Sstevel@tonic-gate * If so, we may need to note the start of the name. 5187c478bd9Sstevel@tonic-gate * We don't do any further processing of long file 5197c478bd9Sstevel@tonic-gate * name entries. 5207c478bd9Sstevel@tonic-gate * 5217c478bd9Sstevel@tonic-gate * We also skip deleted entries and the '.' and '..' 5227c478bd9Sstevel@tonic-gate * entries. 5237c478bd9Sstevel@tonic-gate */ 5247c478bd9Sstevel@tonic-gate if ((dp->pcd_attr & PCDL_LFN_BITS) == PCDL_LFN_BITS) { 5257c478bd9Sstevel@tonic-gate if (!withinLongName) { 5267c478bd9Sstevel@tonic-gate withinLongName++; 5277c478bd9Sstevel@tonic-gate longStart = currentCluster; 5287c478bd9Sstevel@tonic-gate longdp = dp; 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate dp++; 5317c478bd9Sstevel@tonic-gate continue; 5327c478bd9Sstevel@tonic-gate } else if ((dp->pcd_filename[0] == PCD_ERASED) || 5337c478bd9Sstevel@tonic-gate (dp->pcd_filename[0] == '.')) { 5347c478bd9Sstevel@tonic-gate /* 5357c478bd9Sstevel@tonic-gate * XXX - if we were within a long name, then 5367c478bd9Sstevel@tonic-gate * its existence is bogus, because it is not 5377c478bd9Sstevel@tonic-gate * attached to any real file. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate withinLongName = 0; 5407c478bd9Sstevel@tonic-gate dp++; 5417c478bd9Sstevel@tonic-gate continue; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate withinLongName = 0; 5447c478bd9Sstevel@tonic-gate if (operation == PCFS_TRAVERSE_ALL) 5457c478bd9Sstevel@tonic-gate catalogEntry(fd, dp, longdp, longStart, depth, 5467c478bd9Sstevel@tonic-gate recordPath, pathLen); 5477c478bd9Sstevel@tonic-gate longdp = NULL; 5487c478bd9Sstevel@tonic-gate longStart = 0; 5497c478bd9Sstevel@tonic-gate if (dp->pcd_attr & PCA_DIR && descend == PCFS_VISIT_SUBDIRS) { 5507c478bd9Sstevel@tonic-gate traverseDir(fd, extractStartCluster(dp), depth + 1, 5517c478bd9Sstevel@tonic-gate descend, operation, matchRequired, found, 5527c478bd9Sstevel@tonic-gate lastDirCluster, dirEnd, recordPath, pathLen); 5537c478bd9Sstevel@tonic-gate if (*found) 5547c478bd9Sstevel@tonic-gate break; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate dp++; 5577c478bd9Sstevel@tonic-gate *pathLen = saveLen; 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate if (*found) 5607c478bd9Sstevel@tonic-gate return; 5617c478bd9Sstevel@tonic-gate if ((uchar_t *)dp < dirData->bytes + dirDataLen) { 5627c478bd9Sstevel@tonic-gate /* 5637c478bd9Sstevel@tonic-gate * We reached the end of directory before the end of 5647c478bd9Sstevel@tonic-gate * our provided data (a cluster). That means this cluster 5657c478bd9Sstevel@tonic-gate * is the last one in this directory's chain. It also 5667c478bd9Sstevel@tonic-gate * means we've just looked at the last directory entry. 5677c478bd9Sstevel@tonic-gate */ 5687c478bd9Sstevel@tonic-gate *lastDirCluster = currentCluster; 5697c478bd9Sstevel@tonic-gate *dirEnd = dp; 5707c478bd9Sstevel@tonic-gate return; 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate /* 5737c478bd9Sstevel@tonic-gate * If there is more to the directory we'll go get it otherwise we 5747c478bd9Sstevel@tonic-gate * are done traversing this directory. 5757c478bd9Sstevel@tonic-gate */ 5767c478bd9Sstevel@tonic-gate if ((currentCluster == FAKE_ROOTDIR_CLUST) || 5777c478bd9Sstevel@tonic-gate (lastInFAT(currentCluster))) { 5787c478bd9Sstevel@tonic-gate *lastDirCluster = currentCluster; 5797c478bd9Sstevel@tonic-gate return; 5807c478bd9Sstevel@tonic-gate } else { 5817c478bd9Sstevel@tonic-gate traverseDir(fd, nextInChain(currentCluster), 5827c478bd9Sstevel@tonic-gate depth, descend, operation, matchRequired, 5837c478bd9Sstevel@tonic-gate found, lastDirCluster, dirEnd, recordPath, pathLen); 5847c478bd9Sstevel@tonic-gate *pathLen = saveLen; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* 5897c478bd9Sstevel@tonic-gate * traverseFromRoot() 5907c478bd9Sstevel@tonic-gate * For use with 12 and 16 bit FATs that have a root directory outside 5917c478bd9Sstevel@tonic-gate * of the file system. This is a general purpose routine that 5927c478bd9Sstevel@tonic-gate * can be used simply to visit all of the nodes in the metadata or 5937c478bd9Sstevel@tonic-gate * to find the first instance of something, e.g., the first directory 5947c478bd9Sstevel@tonic-gate * entry where the file is marked deleted. 5957c478bd9Sstevel@tonic-gate * 5967c478bd9Sstevel@tonic-gate * Inputs are described in the commentary for visitNodes() above. 5977c478bd9Sstevel@tonic-gate */ 5987c478bd9Sstevel@tonic-gate void 5997c478bd9Sstevel@tonic-gate traverseFromRoot(int fd, int depth, int descend, int operation, 6007c478bd9Sstevel@tonic-gate char matchRequired, struct pcdir **found, int32_t *lastDirCluster, 6017c478bd9Sstevel@tonic-gate struct pcdir **dirEnd, char *recordPath, int *pathLen) 6027c478bd9Sstevel@tonic-gate { 6037c478bd9Sstevel@tonic-gate visitNodes(fd, FAKE_ROOTDIR_CLUST, &TheRootDir, RootDirSize, depth, 6047c478bd9Sstevel@tonic-gate descend, operation, matchRequired, found, lastDirCluster, dirEnd, 6057c478bd9Sstevel@tonic-gate recordPath, pathLen); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* 6097c478bd9Sstevel@tonic-gate * traverseDir() 6107c478bd9Sstevel@tonic-gate * For use with all FATs outside of the initial root directory on 6117c478bd9Sstevel@tonic-gate * 12 and 16 bit FAT file systems. This is a general purpose routine 6127c478bd9Sstevel@tonic-gate * that can be used simply to visit all of the nodes in the metadata or 6137c478bd9Sstevel@tonic-gate * to find the first instance of something, e.g., the first directory 6147c478bd9Sstevel@tonic-gate * entry where the file is marked deleted. 6157c478bd9Sstevel@tonic-gate * 6167c478bd9Sstevel@tonic-gate * Unique Input is: 6177c478bd9Sstevel@tonic-gate * startAt 6187c478bd9Sstevel@tonic-gate * starting cluster of the directory 6197c478bd9Sstevel@tonic-gate * 6207c478bd9Sstevel@tonic-gate * This is the cluster that is the first one in this directory. 6217c478bd9Sstevel@tonic-gate * We read it right away, so we can provide it as data to visitNodes(). 6227c478bd9Sstevel@tonic-gate * Note that we cache this cluster as we read it, because it is 6237c478bd9Sstevel@tonic-gate * metadata and we cache all metadata. By doing so, we can 6247c478bd9Sstevel@tonic-gate * keep pointers to directory entries for quickly moving around and 6257c478bd9Sstevel@tonic-gate * fixing up any problems we find. Of course if we get a big 6267c478bd9Sstevel@tonic-gate * filesystem with a huge amount of metadata we may be hosed, as 6277c478bd9Sstevel@tonic-gate * we'll likely run out of memory. 6287c478bd9Sstevel@tonic-gate * 6297c478bd9Sstevel@tonic-gate * I believe in the future this will have to be addressed. It 6307c478bd9Sstevel@tonic-gate * may be possible to do more of the processing of problems 6317c478bd9Sstevel@tonic-gate * within directories as they are cached, so that when memory 6327c478bd9Sstevel@tonic-gate * runs short we can free cached directories we are already 6337c478bd9Sstevel@tonic-gate * finished visiting. 6347c478bd9Sstevel@tonic-gate * 6357c478bd9Sstevel@tonic-gate * The remainder of inputs are described in visitNodes() comments. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate void 6387c478bd9Sstevel@tonic-gate traverseDir(int fd, int32_t startAt, int depth, int descend, int operation, 6397c478bd9Sstevel@tonic-gate char matchRequired, struct pcdir **found, int32_t *lastDirCluster, 6407c478bd9Sstevel@tonic-gate struct pcdir **dirEnd, char *recordPath, int *pathLen) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate ClusterContents dirdata; 6437c478bd9Sstevel@tonic-gate int32_t dirdatasize = 0; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate if (startAt < FIRST_CLUSTER || startAt > LastCluster) 6467c478bd9Sstevel@tonic-gate return; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if (readCluster(fd, startAt, &(dirdata.bytes), &dirdatasize, 6497c478bd9Sstevel@tonic-gate RDCLUST_DO_CACHE) != RDCLUST_GOOD) { 6507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6517c478bd9Sstevel@tonic-gate gettext("Unable to get more directory entries!\n")); 6527c478bd9Sstevel@tonic-gate return; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate if (operation == PCFS_TRAVERSE_ALL) { 6567c478bd9Sstevel@tonic-gate if (Verbose) 6577c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6587c478bd9Sstevel@tonic-gate gettext("Directory traversal enters " 6597c478bd9Sstevel@tonic-gate "allocation unit %d.\n"), startAt); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate visitNodes(fd, startAt, &dirdata, dirdatasize, depth, descend, 6627c478bd9Sstevel@tonic-gate operation, matchRequired, found, lastDirCluster, dirEnd, 6637c478bd9Sstevel@tonic-gate recordPath, pathLen); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate void 6677c478bd9Sstevel@tonic-gate createCHKNameList(int fd) 6687c478bd9Sstevel@tonic-gate { 6697c478bd9Sstevel@tonic-gate struct pcdir *ignorep1, *ignorep2; 6707c478bd9Sstevel@tonic-gate int32_t ignore32; 6717c478bd9Sstevel@tonic-gate char *ignorecp = NULL; 6727c478bd9Sstevel@tonic-gate char ignore = '\0'; 6737c478bd9Sstevel@tonic-gate int ignoreint = 0; 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate ignorep1 = ignorep2 = NULL; 6767c478bd9Sstevel@tonic-gate if (!OkayToRelink || CHKsList != NULL) 6777c478bd9Sstevel@tonic-gate return; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * Allocate an array to keep a bit map of the integer 6817c478bd9Sstevel@tonic-gate * values used in CHK names. 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate if ((CHKsList = 6847c478bd9Sstevel@tonic-gate (uchar_t *)calloc(1, idivceil(MAXCHKVAL, NBBY))) == NULL) { 6857c478bd9Sstevel@tonic-gate OkayToRelink = 0; 6867c478bd9Sstevel@tonic-gate return; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate /* 6907c478bd9Sstevel@tonic-gate * Search the root directory for all the files with names of 6917c478bd9Sstevel@tonic-gate * the form FILEXXXX.CHK. The root directory is an area 6927c478bd9Sstevel@tonic-gate * outside of the file space on FAT12 and FAT16 file systems. 6937c478bd9Sstevel@tonic-gate * On FAT32 file systems, the root directory is in a file 6947c478bd9Sstevel@tonic-gate * area cluster just like any other directory. 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate if (!IsFAT32) { 6977c478bd9Sstevel@tonic-gate traverseFromRoot(fd, 0, PCFS_NO_SUBDIRS, PCFS_FIND_CHKS, 6987c478bd9Sstevel@tonic-gate ignore, &ignorep1, &ignore32, &ignorep2, ignorecp, 6997c478bd9Sstevel@tonic-gate &ignoreint); 7007c478bd9Sstevel@tonic-gate } else { 7017c478bd9Sstevel@tonic-gate DirCount++; 7027c478bd9Sstevel@tonic-gate traverseDir(fd, TheBIOSParameterBlock.bpb32.root_dir_clust, 7037c478bd9Sstevel@tonic-gate 0, PCFS_NO_SUBDIRS, PCFS_FIND_CHKS, ignore, 7047c478bd9Sstevel@tonic-gate &ignorep1, &ignore32, &ignorep2, ignorecp, &ignoreint); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate char * 7107c478bd9Sstevel@tonic-gate nextAvailableCHKName(int *chosen) 7117c478bd9Sstevel@tonic-gate { 7127c478bd9Sstevel@tonic-gate static char nameBuf[PCFNAMESIZE]; 7137c478bd9Sstevel@tonic-gate int i; 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate if (!OkayToRelink) 7167c478bd9Sstevel@tonic-gate return (NULL); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_F] = 'F'; 7197c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_I] = 'I'; 7207c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_L] = 'L'; 7217c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_E] = 'E'; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate for (i = 1; i <= MAXCHKVAL; i++) { 7247c478bd9Sstevel@tonic-gate if (!inUseCHKName(i)) 7257c478bd9Sstevel@tonic-gate break; 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate if (i <= MAXCHKVAL) { 7287c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_THOUSANDS] = '0' + (i / 1000); 7297c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_HUNDREDS] = '0' + ((i % 1000) / 100); 7307c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_TENS] = '0' + ((i % 100) / 10); 7317c478bd9Sstevel@tonic-gate nameBuf[CHKNAME_ONES] = '0' + (i % 10); 7327c478bd9Sstevel@tonic-gate *chosen = i; 7337c478bd9Sstevel@tonic-gate return (nameBuf); 7347c478bd9Sstevel@tonic-gate } else { 7357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7367c478bd9Sstevel@tonic-gate gettext("Sorry, no names available for " 7377c478bd9Sstevel@tonic-gate "relinking orphan chains!\n")); 7387c478bd9Sstevel@tonic-gate OkayToRelink = 0; 7397c478bd9Sstevel@tonic-gate return (NULL); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate uint32_t 7447c478bd9Sstevel@tonic-gate extractSize(struct pcdir *dp) 7457c478bd9Sstevel@tonic-gate { 7467c478bd9Sstevel@tonic-gate uint32_t returnMe; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate read_32_bits((uchar_t *)&(dp->pcd_size), &returnMe); 7497c478bd9Sstevel@tonic-gate return (returnMe); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate int32_t 7537c478bd9Sstevel@tonic-gate extractStartCluster(struct pcdir *dp) 7547c478bd9Sstevel@tonic-gate { 7557c478bd9Sstevel@tonic-gate uint32_t lo, hi; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if (IsFAT32) { 7587c478bd9Sstevel@tonic-gate read_16_bits((uchar_t *)&(dp->un.pcd_scluster_hi), &hi); 7597c478bd9Sstevel@tonic-gate read_16_bits((uchar_t *)&(dp->pcd_scluster_lo), &lo); 7607c478bd9Sstevel@tonic-gate return ((int32_t)((hi << 16) | lo)); 7617c478bd9Sstevel@tonic-gate } else { 7627c478bd9Sstevel@tonic-gate read_16_bits((uchar_t *)&(dp->pcd_scluster_lo), &lo); 7637c478bd9Sstevel@tonic-gate return ((int32_t)lo); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate static struct pcdir * 7687c478bd9Sstevel@tonic-gate findAvailableRootDirEntSlot(int fd, int32_t *clusterWithSlot) 7697c478bd9Sstevel@tonic-gate { 7707c478bd9Sstevel@tonic-gate struct pcdir *deletedEntry = NULL; 7717c478bd9Sstevel@tonic-gate struct pcdir *appendPoint = NULL; 7727c478bd9Sstevel@tonic-gate char *ignorecp = NULL; 7737c478bd9Sstevel@tonic-gate int ignore = 0; 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate *clusterWithSlot = 0; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate /* 7787c478bd9Sstevel@tonic-gate * First off, try to find an erased entry in the root 7797c478bd9Sstevel@tonic-gate * directory. The root directory is an area outside of the 7807c478bd9Sstevel@tonic-gate * file space on FAT12 and FAT16 file systems. On FAT32 file 7817c478bd9Sstevel@tonic-gate * systems, the root directory is in a file area cluster just 7827c478bd9Sstevel@tonic-gate * like any other directory. 7837c478bd9Sstevel@tonic-gate */ 7847c478bd9Sstevel@tonic-gate if (!IsFAT32) { 7857c478bd9Sstevel@tonic-gate traverseFromRoot(fd, 0, PCFS_NO_SUBDIRS, PCFS_FIND_STATUS, 7867c478bd9Sstevel@tonic-gate PCD_ERASED, &deletedEntry, clusterWithSlot, 7877c478bd9Sstevel@tonic-gate &appendPoint, ignorecp, &ignore); 7887c478bd9Sstevel@tonic-gate } else { 7897c478bd9Sstevel@tonic-gate DirCount++; 7907c478bd9Sstevel@tonic-gate traverseDir(fd, TheBIOSParameterBlock.bpb32.root_dir_clust, 7917c478bd9Sstevel@tonic-gate 0, PCFS_NO_SUBDIRS, PCFS_FIND_STATUS, PCD_ERASED, 7927c478bd9Sstevel@tonic-gate &deletedEntry, clusterWithSlot, &appendPoint, ignorecp, 7937c478bd9Sstevel@tonic-gate &ignore); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate /* 7967c478bd9Sstevel@tonic-gate * If we found a deleted file in the directory we'll overwrite 7977c478bd9Sstevel@tonic-gate * that entry. 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate if (deletedEntry) 8007c478bd9Sstevel@tonic-gate return (deletedEntry); 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * If there is room at the end of the existing directory, we 8037c478bd9Sstevel@tonic-gate * should place the new entry there. 8047c478bd9Sstevel@tonic-gate */ 8057c478bd9Sstevel@tonic-gate if (appendPoint) 8067c478bd9Sstevel@tonic-gate return (appendPoint); 8077c478bd9Sstevel@tonic-gate /* 8087c478bd9Sstevel@tonic-gate * XXX need to grow the directory 8097c478bd9Sstevel@tonic-gate */ 8107c478bd9Sstevel@tonic-gate return (NULL); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate static void 8147c478bd9Sstevel@tonic-gate insertDirEnt(struct pcdir *slot, struct pcdir *entry, int32_t clusterWithSlot) 8157c478bd9Sstevel@tonic-gate { 8167c478bd9Sstevel@tonic-gate (void) memcpy(slot, entry, sizeof (struct pcdir)); 8177c478bd9Sstevel@tonic-gate markClusterModified(clusterWithSlot); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 820*264a6e74Sfrankho /* 821*264a6e74Sfrankho * Convert current UNIX time into a PCFS timestamp (which is in local time). 822*264a6e74Sfrankho * 823*264a6e74Sfrankho * Since the "seconds" field of that is only accurate to 2sec precision, 824*264a6e74Sfrankho * we allow for the optional (used only for creation times on FAT) "msec" 825*264a6e74Sfrankho * parameter that takes the fractional part. 826*264a6e74Sfrankho */ 8277c478bd9Sstevel@tonic-gate static void 828*264a6e74Sfrankho getNow(struct pctime *pctp, uchar_t *msec) 8297c478bd9Sstevel@tonic-gate { 830*264a6e74Sfrankho time_t now; 831*264a6e74Sfrankho struct tm tm; 832*264a6e74Sfrankho ushort_t tim, dat; 8337c478bd9Sstevel@tonic-gate 834*264a6e74Sfrankho /* 835*264a6e74Sfrankho * Disable daylight savings corrections - Solaris PCFS doesn't 836*264a6e74Sfrankho * support such conversions yet. Save timestamps in local time. 837*264a6e74Sfrankho */ 838*264a6e74Sfrankho daylight = 0; 839*264a6e74Sfrankho 840*264a6e74Sfrankho (void) time(&now); 841*264a6e74Sfrankho (void) localtime_r(&now, &tm); 842*264a6e74Sfrankho 843*264a6e74Sfrankho dat = (tm.tm_year - 80) << YEARSHIFT; 844*264a6e74Sfrankho dat |= tm.tm_mon << MONSHIFT; 845*264a6e74Sfrankho dat |= tm.tm_mday << DAYSHIFT; 846*264a6e74Sfrankho tim = tm.tm_hour << HOURSHIFT; 847*264a6e74Sfrankho tim |= tm.tm_min << MINSHIFT; 848*264a6e74Sfrankho tim |= (tm.tm_sec / 2) << SECSHIFT; 849*264a6e74Sfrankho 850*264a6e74Sfrankho /* 851*264a6e74Sfrankho * Sanity check. If we overflow the PCFS timestamp range 852*264a6e74Sfrankho * we set the time to 01/01/1980, 00:00:00 853*264a6e74Sfrankho */ 854*264a6e74Sfrankho if (dat < 80 || dat > 227) 855*264a6e74Sfrankho dat = tim = 0; 856*264a6e74Sfrankho 857*264a6e74Sfrankho pctp->pct_date = LE_16(dat); 858*264a6e74Sfrankho pctp->pct_time = LE_16(tim); 859*264a6e74Sfrankho if (msec) 860*264a6e74Sfrankho *msec = (tm.tm_sec & 1) ? 100 : 0; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * FAT file systems store the following time information in a directory 8657c478bd9Sstevel@tonic-gate * entry: 866*264a6e74Sfrankho * timestamp member of "struct pcdir" 867*264a6e74Sfrankho * ====================================================================== 868*264a6e74Sfrankho * creation time pcd_crtime.pct_time 869*264a6e74Sfrankho * creation date pcd_crtime.pct_date 870*264a6e74Sfrankho * last access date pcd_ladate 871*264a6e74Sfrankho * last modify time pcd_mtime.pct_time 872*264a6e74Sfrankho * last modify date pcd_mtime.pct_date 8737c478bd9Sstevel@tonic-gate * 8747c478bd9Sstevel@tonic-gate * No access time is kept. 8757c478bd9Sstevel@tonic-gate */ 8767c478bd9Sstevel@tonic-gate static void 8777c478bd9Sstevel@tonic-gate updateDirEnt_CreatTime(struct pcdir *dp) 8787c478bd9Sstevel@tonic-gate { 879*264a6e74Sfrankho getNow(&dp->pcd_crtime, &dp->pcd_crtime_msec); 8807c478bd9Sstevel@tonic-gate markClusterModified(findImpactedCluster(dp)); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate static void 8847c478bd9Sstevel@tonic-gate updateDirEnt_ModTimes(struct pcdir *dp) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate timestruc_t ts; 8877c478bd9Sstevel@tonic-gate 888*264a6e74Sfrankho getNow(&dp->pcd_mtime, NULL); 889*264a6e74Sfrankho dp->pcd_ladate = dp->pcd_mtime.pct_date; 8907c478bd9Sstevel@tonic-gate dp->pcd_attr |= PCA_ARCH; 8917c478bd9Sstevel@tonic-gate markClusterModified(findImpactedCluster(dp)); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate struct pcdir * 8957c478bd9Sstevel@tonic-gate addRootDirEnt(int fd, struct pcdir *new) 8967c478bd9Sstevel@tonic-gate { 8977c478bd9Sstevel@tonic-gate struct pcdir *added; 8987c478bd9Sstevel@tonic-gate int32_t inCluster; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate if ((added = findAvailableRootDirEntSlot(fd, &inCluster)) != NULL) { 9017c478bd9Sstevel@tonic-gate insertDirEnt(added, new, inCluster); 9027c478bd9Sstevel@tonic-gate return (added); 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate return (NULL); 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* 9087c478bd9Sstevel@tonic-gate * FAT12 and FAT16 have a root directory outside the normal file space, 9097c478bd9Sstevel@tonic-gate * so we have separate routines for finding and reading the root directory. 9107c478bd9Sstevel@tonic-gate */ 9117c478bd9Sstevel@tonic-gate static off64_t 9127c478bd9Sstevel@tonic-gate seekRootDirectory(int fd) 9137c478bd9Sstevel@tonic-gate { 9147c478bd9Sstevel@tonic-gate off64_t seekto; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate /* 9177c478bd9Sstevel@tonic-gate * The RootDir immediately follows the FATs, which in 9187c478bd9Sstevel@tonic-gate * turn immediately follow the reserved sectors. 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate seekto = (off64_t)TheBIOSParameterBlock.bpb.resv_sectors * 9217c478bd9Sstevel@tonic-gate TheBIOSParameterBlock.bpb.bytes_per_sector + 9227c478bd9Sstevel@tonic-gate (off64_t)FATSize * TheBIOSParameterBlock.bpb.num_fats + 9237c478bd9Sstevel@tonic-gate (off64_t)PartitionOffset; 9247c478bd9Sstevel@tonic-gate if (Verbose) 9257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9267c478bd9Sstevel@tonic-gate gettext("Seeking root directory @%lld.\n"), seekto); 9277c478bd9Sstevel@tonic-gate return (lseek64(fd, seekto, SEEK_SET)); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate void 9317c478bd9Sstevel@tonic-gate getRootDirectory(int fd) 9327c478bd9Sstevel@tonic-gate { 9337c478bd9Sstevel@tonic-gate ssize_t bytesRead; 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate if (TheRootDir.bytes != NULL) 9367c478bd9Sstevel@tonic-gate return; 9377c478bd9Sstevel@tonic-gate else if ((TheRootDir.bytes = (uchar_t *)malloc(RootDirSize)) == NULL) { 9387c478bd9Sstevel@tonic-gate mountSanityCheckFails(); 9397c478bd9Sstevel@tonic-gate perror(gettext("No memory for a copy of the root directory")); 9407c478bd9Sstevel@tonic-gate (void) close(fd); 9417c478bd9Sstevel@tonic-gate exit(8); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate if (seekRootDirectory(fd) < 0) { 9457c478bd9Sstevel@tonic-gate mountSanityCheckFails(); 9467c478bd9Sstevel@tonic-gate perror(gettext("Cannot seek to RootDir")); 9477c478bd9Sstevel@tonic-gate (void) close(fd); 9487c478bd9Sstevel@tonic-gate exit(8); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate if (Verbose) 9527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9537c478bd9Sstevel@tonic-gate gettext("Reading root directory.\n")); 9547c478bd9Sstevel@tonic-gate if ((bytesRead = read(fd, TheRootDir.bytes, RootDirSize)) != 9557c478bd9Sstevel@tonic-gate RootDirSize) { 9567c478bd9Sstevel@tonic-gate mountSanityCheckFails(); 9577c478bd9Sstevel@tonic-gate if (bytesRead < 0) { 9587c478bd9Sstevel@tonic-gate perror(gettext("Cannot read a RootDir")); 9597c478bd9Sstevel@tonic-gate } else { 9607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9617c478bd9Sstevel@tonic-gate gettext("Short read of RootDir\n")); 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate (void) close(fd); 9647c478bd9Sstevel@tonic-gate exit(8); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate if (Verbose) { 9677c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9687c478bd9Sstevel@tonic-gate gettext("Dump of root dir's first 256 bytes.\n")); 9697c478bd9Sstevel@tonic-gate header_for_dump(); 9707c478bd9Sstevel@tonic-gate dump_bytes(TheRootDir.bytes, 256); 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate void 9757c478bd9Sstevel@tonic-gate writeRootDirMods(int fd) 9767c478bd9Sstevel@tonic-gate { 9777c478bd9Sstevel@tonic-gate ssize_t bytesWritten; 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate if (!TheRootDir.bytes) { 9807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9817c478bd9Sstevel@tonic-gate gettext("Internal error: No Root directory to write\n")); 9827c478bd9Sstevel@tonic-gate (void) close(fd); 9837c478bd9Sstevel@tonic-gate exit(12); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate if (!RootDirModified) { 9867c478bd9Sstevel@tonic-gate if (Verbose) { 9877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9887c478bd9Sstevel@tonic-gate gettext("No root directory changes need to " 9897c478bd9Sstevel@tonic-gate "be written.\n")); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate return; 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate if (ReadOnly) 9947c478bd9Sstevel@tonic-gate return; 9957c478bd9Sstevel@tonic-gate if (Verbose) 9967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9977c478bd9Sstevel@tonic-gate gettext("Writing root directory.\n")); 9987c478bd9Sstevel@tonic-gate if (seekRootDirectory(fd) < 0) { 9997c478bd9Sstevel@tonic-gate perror(gettext("Cannot write the RootDir (seek failed)")); 10007c478bd9Sstevel@tonic-gate (void) close(fd); 10017c478bd9Sstevel@tonic-gate exit(12); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate if ((bytesWritten = write(fd, TheRootDir.bytes, RootDirSize)) != 10047c478bd9Sstevel@tonic-gate RootDirSize) { 10057c478bd9Sstevel@tonic-gate if (bytesWritten < 0) { 10067c478bd9Sstevel@tonic-gate perror(gettext("Cannot write the RootDir")); 10077c478bd9Sstevel@tonic-gate } else { 10087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 10097c478bd9Sstevel@tonic-gate gettext("Short write of root directory\n")); 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate (void) close(fd); 10127c478bd9Sstevel@tonic-gate exit(12); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate RootDirModified = 0; 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate struct pcdir * 10187c478bd9Sstevel@tonic-gate newDirEnt(struct pcdir *copyme) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate struct pcdir *ndp; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate if ((ndp = (struct pcdir *)calloc(1, sizeof (struct pcdir))) == NULL) { 10237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Out of memory to create a " 10247c478bd9Sstevel@tonic-gate "new directory entry!\n")); 10257c478bd9Sstevel@tonic-gate return (ndp); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate if (copyme) 10287c478bd9Sstevel@tonic-gate (void) memcpy(ndp, copyme, sizeof (struct pcdir)); 10297c478bd9Sstevel@tonic-gate ndp->pcd_ext[CHKNAME_C] = 'C'; 10307c478bd9Sstevel@tonic-gate ndp->pcd_ext[CHKNAME_H] = 'H'; 10317c478bd9Sstevel@tonic-gate ndp->pcd_ext[CHKNAME_K] = 'K'; 10327c478bd9Sstevel@tonic-gate updateDirEnt_CreatTime(ndp); 10337c478bd9Sstevel@tonic-gate updateDirEnt_ModTimes(ndp); 10347c478bd9Sstevel@tonic-gate return (ndp); 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate void 10387c478bd9Sstevel@tonic-gate updateDirEnt_Size(struct pcdir *dp, uint32_t newSize) 10397c478bd9Sstevel@tonic-gate { 10407c478bd9Sstevel@tonic-gate uchar_t *p = (uchar_t *)&(dp->pcd_size); 10417c478bd9Sstevel@tonic-gate store_32_bits(&p, newSize); 10427c478bd9Sstevel@tonic-gate markClusterModified(findImpactedCluster(dp)); 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate void 10467c478bd9Sstevel@tonic-gate updateDirEnt_Start(struct pcdir *dp, int32_t newStart) 10477c478bd9Sstevel@tonic-gate { 10487c478bd9Sstevel@tonic-gate uchar_t *p = (uchar_t *)&(dp->pcd_scluster_lo); 10497c478bd9Sstevel@tonic-gate store_16_bits(&p, newStart & 0xffff); 10507c478bd9Sstevel@tonic-gate if (IsFAT32) { 10517c478bd9Sstevel@tonic-gate p = (uchar_t *)&(dp->un.pcd_scluster_hi); 10527c478bd9Sstevel@tonic-gate store_16_bits(&p, newStart >> 16); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate markClusterModified(findImpactedCluster(dp)); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate void 10587c478bd9Sstevel@tonic-gate updateDirEnt_Name(struct pcdir *dp, char *newName) 10597c478bd9Sstevel@tonic-gate { 10607c478bd9Sstevel@tonic-gate int i; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate for (i = 0; i < PCFNAMESIZE; i++) { 10637c478bd9Sstevel@tonic-gate if (*newName) 10647c478bd9Sstevel@tonic-gate dp->pcd_filename[i] = *newName++; 10657c478bd9Sstevel@tonic-gate else 10667c478bd9Sstevel@tonic-gate dp->pcd_filename[i] = ' '; 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate markClusterModified(findImpactedCluster(dp)); 10697c478bd9Sstevel@tonic-gate } 1070