static long GetCatalogEntry(long long * dirIndex, char ** name, long * flags, long * time, FinderInfo * finderInfo, long * infoValid) { long extentSize, nodeSize, curNode, index; void *extent; char *nodeBuf, *testKey, *entry; BTNodeDescriptor *node; if (gIsHFSPlus) { extent = &gHFSPlus->catalogFile.extents; extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); } else { extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); } nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize); nodeBuf = (char *)malloc(nodeSize); node = (BTNodeDescriptor *)nodeBuf; index = (long) (*dirIndex % nodeSize); curNode = (long) (*dirIndex / nodeSize); // Read the BTree node and get the record for index. ReadExtent(extent, extentSize, kHFSCatalogFileID, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1); GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry); GetCatalogEntryInfo(entry, flags, time, finderInfo, infoValid); // Get the file name. if (gIsHFSPlus) { utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode, SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length), (u_int8_t *)gTempStr, 256, OSBigEndian); } else { strncpy(gTempStr, (const char *)&((HFSCatalogKey *)testKey)->nodeName[1], ((HFSCatalogKey *)testKey)->nodeName[0]); gTempStr[((HFSCatalogKey *)testKey)->nodeName[0]] = '\0'; } *name = gTempStr; // Update dirIndex. index++; if (index == SWAP_BE16(node->numRecords)) { index = 0; curNode = SWAP_BE32(node->fLink); } *dirIndex = (long long) curNode * nodeSize + index; free(nodeBuf); return 0; }
long HFSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length) { char entry[512]; char devStr[12]; long dirID, result, flags; if (HFSInitPartition(ih) == -1) return -1; dirID = kHFSRootFolderID; // Skip a lead '\'. Start in the system folder if there are two. if (filePath[0] == '/') { if (filePath[1] == '/') { if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]); else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]); if (dirID == 0) { return -1; } filePath++; } filePath++; } result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0); if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) { return -1; } #if UNUSED // Not yet for Intel. System.config/Default.table will fail this check. // Check file owner and permissions. if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1; #endif result = ReadFile(entry, &length, base, offset); if (result == -1) { return -1; } getDeviceDescription(ih, devStr); /*if (strstr(filePath, ".plist")) verbose("LoadConfig: [%s/%s] %d bytes.\n", devStr, filePath, (uint32_t)length);*/ if (strstr(filePath, "com.apple.Boot.plist")) verbose("Config: [%s/%s] %d bytes.\n", devStr, filePath, (uint32_t)length); if (strstr(filePath, "theme.plist")) { //valv: inspired from toitione's rtrim int t_len = strlen(filePath) - 12; char *themePath = strncpy(malloc(t_len + 1), filePath, t_len); themePath[t_len+1] = '\0'; verbose("Theme: [%s]/%s\n", devStr, themePath); } // if (strstr(filePath, "theme.plist")) verbose("Theme: [%s].\n", devStr); if (strstr(filePath, "smbios.plist")) verbose("SMBios: [%s/%s] %d bytes.\n", devStr, filePath, (uint32_t)length); if (strstr(filePath, ".aml")) verbose("ACPI: [%s/%s] %d bytes.\n", devStr, filePath, (uint32_t)length); return length; }
static long CompareHFSPlusExtentsKeys(void * key, void * testKey) { HFSPlusExtentKey *searchKey, *trialKey; long result; searchKey = key; trialKey = testKey; // assume searchKey < trialKey result = -1; if (searchKey->fileID == trialKey->fileID) { // FileNum's are equal; compare fork types if (searchKey->forkType == trialKey->forkType) { // Fork types are equal; compare allocation block number if (searchKey->startBlock == trialKey->startBlock) { // Everything is equal result = 0; } else { // Allocation block numbers differ; determine sign if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock)) { result = 1; } } } else { // Fork types differ; determine sign if (searchKey->forkType > trialKey->forkType) { result = 1; } } } else { // FileNums differ; determine sign if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID)) { result = 1; } } return result; }
static long ResolvePathToCatalogEntry(char * filePath, long * flags, void * entry, long dirID, long long * dirIndex) { char *restPath; long result, cnt, subFolderID = 0; long long tmpDirIndex; HFSPlusCatalogFile *hfsPlusFile; // Copy the file name to gTempStr cnt = 0; while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++; strlcpy(gTempStr, filePath, cnt+1); // Move restPath to the right place. if (filePath[cnt] != '\0') cnt++; restPath = filePath + cnt; // gTempStr is a name in the current Dir. // restPath is the rest of the path if any. result = ReadCatalogEntry(gTempStr, dirID, entry, dirIndex); if (result == -1) { return -1; } GetCatalogEntryInfo(entry, flags, 0, 0, 0); if ((*flags & kFileTypeMask) == kFileTypeDirectory) { if (gIsHFSPlus) subFolderID = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->folderID); else subFolderID = SWAP_BE32(((HFSCatalogFolder *)entry)->folderID); } if ((*flags & kFileTypeMask) == kFileTypeDirectory) result = ResolvePathToCatalogEntry(restPath, flags, entry, subFolderID, dirIndex); if (gIsHFSPlus && ((*flags & kFileTypeMask) == kFileTypeFlat)) { hfsPlusFile = (HFSPlusCatalogFile *)entry; if ((SWAP_BE32(hfsPlusFile->userInfo.fdType) == kHardLinkFileType) && (SWAP_BE32(hfsPlusFile->userInfo.fdCreator) == kHFSPlusCreator)) { sprintf(gLinkTemp, "%s/%s%ld", HFSPLUSMETADATAFOLDER, HFS_INODE_PREFIX, SWAP_BE32(hfsPlusFile->bsdInfo.special.iNodeNum)); result = ResolvePathToCatalogEntry(gLinkTemp, flags, entry, kHFSRootFolderID, &tmpDirIndex); } } return result; }
/* * Create a new indirect link * * An indirect link is a reference to a data node. The only useable * fields in the link are the link number, parentID, name and text * encoding. All other catalog fields are ignored. */ static int createindirectlink(struct hfsmount *hfsmp, u_int32_t linknum, u_int32_t linkparid, char *linkName, cnid_t *linkcnid) { struct FndrFileInfo *fip; struct cat_desc desc; struct cat_attr attr; int result; /* Setup the descriptor */ bzero(&desc, sizeof(desc)); desc.cd_nameptr = linkName; desc.cd_namelen = strlen(linkName); desc.cd_parentcnid = linkparid; /* Setup the default attributes */ bzero(&attr, sizeof(attr)); /* links are matched to data nodes by link ID and to volumes by create date */ attr.ca_rdev = linknum; /* note: cat backend overloads ca_rdev to be the linknum when nlink = 0 */ attr.ca_itime = HFSTOVCB(hfsmp)->vcbCrDate; attr.ca_mode = S_IFREG; fip = (struct FndrFileInfo *)&attr.ca_finderinfo; fip->fdType = SWAP_BE32 (kHardLinkFileType); /* 'hlnk' */ fip->fdCreator = SWAP_BE32 (kHFSPlusCreator); /* 'hfs+' */ fip->fdFlags = SWAP_BE16 (kHasBeenInited); hfs_global_shared_lock_acquire(hfsmp); if (hfsmp->jnl) { if (journal_start_transaction(hfsmp->jnl) != 0) { hfs_global_shared_lock_release(hfsmp); return EINVAL; } } /* Create the indirect link directly in the catalog */ result = cat_create(hfsmp, &desc, &attr, NULL); if (result == 0 && linkcnid != NULL) *linkcnid = attr.ca_fileid; if (hfsmp->jnl) { journal_end_transaction(hfsmp->jnl); } hfs_global_shared_lock_release(hfsmp); return (result); }
long HFSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length) { char entry[512]; char devStr[12]; long dirID, result, flags = 0; if (HFSInitPartition(ih) == -1) return -1; dirID = kHFSRootFolderID; // Skip a lead '\'. Start in the system folder if there are two. if (filePath[0] == '/') { if (filePath[1] == '/') { if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]); else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]); if (dirID == 0) { return -1; } filePath++; } filePath++; } result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0); if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) { return -1; } #if UNUSED // Not yet for Intel. System.config/Default.table will fail this check. // Check file owner and permissions. if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1; #endif result = ReadFile(entry, &length, base, offset); if (result == -1) { return -1; } getDeviceDescription(ih, devStr, sizeof(devStr)); if (get_env(envHFSLoadVerbose)) { verbose("Read HFS%s file: [%s/%s] %d bytes.\n", (gIsHFSPlus ? "+" : ""), devStr, filePath, (uint32_t)length); } else if (get_env(envHFSLoadVerbose) == 0) { safe_set_env(envHFSLoadVerbose, 1); } return length; }
void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p) { /* We have user reports of failure to load 3MB module * on a 16MB RAM machine. Apparently even a transient * memory spike to 6MB during module load * is too big for that system. */ void *image; struct stat st; int fd; fd = xopen(filename, O_RDONLY); fstat(fd, &st); image = NULL; /* st.st_size is off_t, we can't just pass it to mmap */ if (st.st_size <= *image_size_p) { size_t image_size = st.st_size; image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0); if (image == MAP_FAILED) { image = NULL; } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) { /* No ELF signature. Compressed module? */ munmap(image, image_size); image = NULL; } else { /* Success. Report the size */ *image_size_p = image_size; } } close(fd); return image; }
void HFSGetDescription(CICell ih, char *str, long strMaxLen) { UInt16 nodeSize; UInt32 firstLeafNode; long dirIndex; char *name; long flags, time; if (HFSInitPartition(ih) == -1) { return; } /* Fill some crucial data structures by side effect. */ dirIndex = 0; HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0); /* Now we can loook up the volume name node. */ nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize); firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode); dirIndex = firstLeafNode * nodeSize; GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0); strncpy(str, name, strMaxLen); str[strMaxLen] = '\0'; }
static long ReadFile(void * file, uint64_t * length, void * base, uint64_t offset) { void *extents; long fileID; uint64_t fileLength; HFSCatalogFile *hfsFile = file; HFSPlusCatalogFile *hfsPlusFile = file; if (gIsHFSPlus) { fileID = SWAP_BE32(hfsPlusFile->fileID); fileLength = (uint64_t)SWAP_BE64(hfsPlusFile->dataFork.logicalSize); extents = &hfsPlusFile->dataFork.extents; } else { fileID = SWAP_BE32(hfsFile->fileID); fileLength = SWAP_BE32(hfsFile->dataLogicalSize); extents = &hfsFile->dataExtents; } if (offset > fileLength) { printf("Offset is too large.\n"); return -1; } if ((*length == 0) || ((offset + *length) > fileLength)) { *length = fileLength - offset; } /* if (*length > kLoadSize) { printf("File is too large.\n"); return -1; } */ *length = ReadExtent((char *)extents, fileLength, fileID, offset, *length, (char *)base, 0); return 0; }
/* * hfs_swap_HFSPlusForkData * * There's still a few spots where we still need to swap the fork data. */ void hfs_swap_HFSPlusForkData ( HFSPlusForkData *src ) { int i; src->logicalSize = SWAP_BE64 (src->logicalSize); src->clumpSize = SWAP_BE32 (src->clumpSize); src->totalBlocks = SWAP_BE32 (src->totalBlocks); for (i = 0; i < kHFSPlusExtentDensity; i++) { src->extents[i].startBlock = SWAP_BE32 (src->extents[i].startBlock); src->extents[i].blockCount = SWAP_BE32 (src->extents[i].blockCount); } }
static long CompareHFSPlusCatalogKeys(void * key, void * testKey) { HFSPlusCatalogKey *searchKey, *trialKey; long result, searchParentID, trialParentID; searchKey = key; trialKey = testKey; searchParentID = SWAP_BE32(searchKey->parentID); trialParentID = SWAP_BE32(trialKey->parentID); // parent dirID is unsigned if (searchParentID > trialParentID) { result = 1; } else if (searchParentID < trialParentID) { result = -1; } else { // parent dirID's are equal, compare names if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0)) { result = searchKey->nodeName.length - trialKey->nodeName.length; } else if (gCaseSensitive) { result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0], SWAP_BE16(searchKey->nodeName.length), &trialKey->nodeName.unicode[0], SWAP_BE16(trialKey->nodeName.length)); } else { result = FastUnicodeCompare(&searchKey->nodeName.unicode[0], SWAP_BE16(searchKey->nodeName.length), &trialKey->nodeName.unicode[0], SWAP_BE16(trialKey->nodeName.length), OSBigEndian); } } return result; }
long HFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock) { char entry[512]; long dirID, result, flags; void *extents; HFSCatalogFile *hfsFile = (void *)entry; HFSPlusCatalogFile *hfsPlusFile = (void *)entry; if (HFSInitPartition(ih) == -1) return -1; dirID = kHFSRootFolderID; // Skip a lead '\'. Start in the system folder if there are two. if (filePath[0] == '/') { if (filePath[1] == '/') { if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]); else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]); if (dirID == 0) { return -1; } filePath++; } filePath++; } result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0); if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) { printf("HFS: Resolve path %s failed\n", filePath); return -1; } if (gIsHFSPlus) { extents = &hfsPlusFile->dataFork.extents; } else { extents = &hfsFile->dataExtents; } #if DEBUG printf("extent start 0x%x\n", (unsigned long)GetExtentStart(extents, 0)); printf("block size 0x%x\n", (unsigned long)gBlockSize); printf("Allocation offset 0x%x\n", (unsigned long)gAllocationOffset); #endif *firstBlock = ((unsigned long long)GetExtentStart(extents, 0) * (unsigned long long) gBlockSize + gAllocationOffset) / 512ULL; return 0; }
/* * GNU tar uses "base-256 encoding" for very large numbers (>8 billion). * Encoding is binary, with highest bit always set as a marker * and sign in next-highest bit: * 80 00 .. 00 - zero * bf ff .. ff - largest positive number * ff ff .. ff - minus 1 * c0 00 .. 00 - smallest negative number * * We expect it only in size field, where negative numbers don't make sense. */ static off_t getBase256_len12(const char *str) { off_t value; int len; /* if (*str & 0x40) error; - caller prevents this */ if (sizeof(off_t) >= 12) { /* Probably 128-bit (16 byte) off_t. Can be optimized. */ len = 12; value = *str++ & 0x3f; while (--len) value = (value << 8) + (unsigned char) *str++; return value; } #ifdef CHECK_FOR_OVERFLOW /* Can be optimized to eat 32-bit chunks */ char c = *str++ & 0x3f; len = 12; while (1) { if (c) bb_error_msg_and_die("overflow in base-256 encoded file size"); if (--len == sizeof(off_t)) break; c = *str++; } #else str += (12 - sizeof(off_t)); #endif /* Now str points to sizeof(off_t) least significant bytes. * * Example of tar file with 8914993153 (0x213600001) byte file. * Field starts at offset 7c: * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....| * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336| * * str is at offset 80 or 84 now (64-bit or 32-bit off_t). * We (ab)use the fact that value happens to be aligned, * and fetch it in one go: */ if (sizeof(off_t) == 8) { value = *(off_t*)str; value = SWAP_BE64(value); } else if (sizeof(off_t) == 4) { value = *(off_t*)str; value = SWAP_BE32(value); } else { value = 0; len = sizeof(off_t); while (--len) value = (value << 8) + (unsigned char) *str++; } return value; }
static long ReadExtentsEntry(long fileID, long startBlock, void * entry) { char key[sizeof(HFSPlusExtentKey)]; HFSExtentKey *hfsKey = (HFSExtentKey *)key; HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey *)key; // Make the extents key. if (gIsHFSPlus) { hfsPlusKey->forkType = 0; hfsPlusKey->fileID = SWAP_BE32(fileID); hfsPlusKey->startBlock = SWAP_BE32(startBlock); } else { hfsKey->forkType = 0; hfsKey->fileID = SWAP_BE32(fileID); hfsKey->startBlock = SWAP_BE16(startBlock); } return ReadBTreeEntry(kBTreeExtents, &key, entry, 0); }
long HFSReadFile(CICell ih, char * filePath, void *base, unsigned long offset, unsigned long length) { char entry[512]; long dirID, result, flags; verbose("Loading HFS%s file: [%s] from %x.\n", (gIsHFSPlus ? "+" : ""), filePath, ih); if (HFSInitPartition(ih) == -1) return -1; dirID = kHFSRootFolderID; // Skip a lead '\'. Start in the system folder if there are two. if (filePath[0] == '/') { if (filePath[1] == '/') { if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]); else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]); if (dirID == 0) { return -1; } filePath++; } filePath++; } result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0); if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) { return -1; } #if UNUSED // Not yet for Intel. System.config/Default.table will fail this check. // Check file owner and permissions. if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1; #endif result = ReadFile(entry, &length, base, offset); if (result == -1) { return -1; } return length; }
static long GetExtentStart(void * extents, long index) { long start; HFSExtentDescriptor *hfsExtents = extents; HFSPlusExtentDescriptor *hfsPlusExtents = extents; if (gIsHFSPlus) start = SWAP_BE32(hfsPlusExtents[index].startBlock); else start = SWAP_BE16(hfsExtents[index].startBlock); return start; }
static long GetExtentSize(void * extents, long index) { long size; HFSExtentDescriptor *hfsExtents = extents; HFSPlusExtentDescriptor *hfsPlusExtents = extents; if (gIsHFSPlus) size = SWAP_BE32(hfsPlusExtents[index].blockCount); else size = SWAP_BE16(hfsExtents[index].blockCount); return size; }
static long CompareHFSCatalogKeys(void * key, void * testKey) { HFSCatalogKey *searchKey, *trialKey; long result, searchParentID, trialParentID; searchKey = key; trialKey = testKey; searchParentID = SWAP_BE32(searchKey->parentID); trialParentID = SWAP_BE32(trialKey->parentID); // parent dirID is unsigned if (searchParentID > trialParentID) result = 1; else if (searchParentID < trialParentID) result = -1; else { // parent dirID's are equal, compare names result = FastRelString(searchKey->nodeName, trialKey->nodeName); } return result; }
static long ReadCatalogEntry(char * fileName, long dirID, void * entry, long long * dirIndex) { long length = 0; char key[sizeof(HFSPlusCatalogKey)]; HFSCatalogKey *hfsKey = (HFSCatalogKey *)key; HFSPlusCatalogKey *hfsPlusKey = (HFSPlusCatalogKey *)key; // Make the catalog key. if (gIsHFSPlus) { hfsPlusKey->parentID = SWAP_BE32(dirID); length = strlen(fileName); if (length > 255) { length = 255; } utf_decodestr((u_int8_t *)fileName, hfsPlusKey->nodeName.unicode, &(hfsPlusKey->nodeName.length), 512, OSBigEndian); } else { hfsKey->parentID = SWAP_BE32(dirID); length = strlen(fileName); if (length > 31) { length = 31; } hfsKey->nodeName[0] = length; strncpy((char *)(hfsKey->nodeName + 1), fileName, length); } return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex); }
static u_int32_t GetExtentSize(void * extents, u_int32_t index) { u_int32_t size = 0; HFSExtentDescriptor *hfsExtents = extents; HFSPlusExtentDescriptor *hfsPlusExtents = extents; if (gIsHFSPlus) { size = SWAP_BE32(hfsPlusExtents[index].blockCount); } else { size = SWAP_BE16(hfsExtents[index].blockCount); } return size; }
static u_int32_t GetExtentStart(void * extents, u_int32_t index) { u_int32_t start; HFSExtentDescriptor *hfsExtents = extents; HFSPlusExtentDescriptor *hfsPlusExtents = extents; if (gIsHFSPlus) { start = SWAP_BE32(hfsPlusExtents[index].startBlock); } else { start = SWAP_BE16(hfsExtents[index].startBlock); } return start; }
long HFSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex, char ** name, long * flags, long * time, FinderInfo * finderInfo, long * infoValid) { char entry[512]; long dirID, dirFlags = 0; if (HFSInitPartition(ih) == -1) { return -1; } if (*dirIndex == -1) { return -1; } dirID = kHFSRootFolderID; // Skip a lead '\'. Start in the system folder if there are two. if (dirPath[0] == '/') { if (dirPath[1] == '/') { if (gIsHFSPlus) { dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]); } else { dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]); } if (dirID == 0) { return -1; } dirPath++; } dirPath++; } if (*dirIndex == 0) { ResolvePathToCatalogEntry(dirPath, &dirFlags, entry, dirID, dirIndex); if (*dirIndex == 0) { *dirIndex = -1; } if ((dirFlags & kFileTypeMask) != kFileTypeUnknown) { return -1; } } GetCatalogEntry(dirIndex, name, flags, time, finderInfo, infoValid); if (*dirIndex == 0) { *dirIndex = -1; } if ((*flags & kFileTypeMask) == kFileTypeUnknown) { return -1; } return 0; }
/* _______________________________________________________________________ Routine: BlockAllocateAny Function: Allocate one or more allocation blocks. If there are fewer free blocks than requested, all free blocks will be allocated. The caller guarantees that there is at least one free block. Inputs: vcb Pointer to volume where space is to be allocated startingBlock Preferred first block for allocation endingBlock Last block to check + 1 maxBlocks Maximum number of contiguous blocks to allocate useMetaZone Outputs: actualStartBlock First block of range allocated, or 0 if error actualNumBlocks Number of blocks allocated, or 0 if error _______________________________________________________________________ */ static OSErr BlockAllocateAny( ExtendedVCB *vcb, u_int32_t startingBlock, register u_int32_t endingBlock, u_int32_t maxBlocks, Boolean useMetaZone, u_int32_t *actualStartBlock, u_int32_t *actualNumBlocks) { OSErr err; register u_int32_t block; // current block number register u_int32_t currentWord; // Pointer to current word within bitmap block register u_int32_t bitMask; // Word with given bits already set (ready to OR in) register u_int32_t wordsLeft; // Number of words left in this bitmap block u_int32_t *buffer = NULL; u_int32_t *currCache = NULL; u_int32_t blockRef; u_int32_t bitsPerBlock; u_int32_t wordsPerBlock; Boolean dirty = false; struct hfsmount *hfsmp = VCBTOHFS(vcb); /* * When we're skipping the metadata zone and the start/end * range overlaps with the metadata zone then adjust the * start to be outside of the metadata zone. If the range * is entirely inside the metadata zone then we can deny the * request (dskFulErr). */ if (!useMetaZone && (vcb->hfs_flags & HFS_METADATA_ZONE)) { if (startingBlock <= vcb->hfs_metazone_end) { if (endingBlock > (vcb->hfs_metazone_end + 2)) startingBlock = vcb->hfs_metazone_end + 1; else { err = dskFulErr; goto Exit; } } } // Since this routine doesn't wrap around if (maxBlocks > (endingBlock - startingBlock)) { maxBlocks = endingBlock - startingBlock; } // // Pre-read the first bitmap block // err = ReadBitmapBlock(vcb, startingBlock, &currCache, &blockRef); if (err != noErr) goto Exit; buffer = currCache; // // Set up the current position within the block // { u_int32_t wordIndexInBlock; bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte; wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord; wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord; buffer += wordIndexInBlock; wordsLeft = wordsPerBlock - wordIndexInBlock; currentWord = SWAP_BE32 (*buffer); bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask); } // // Find the first unallocated block // block=startingBlock; while (block < endingBlock) { if ((currentWord & bitMask) == 0) break; // Next bit ++block; bitMask >>= 1; if (bitMask == 0) { // Next word bitMask = kHighBitInWordMask; ++buffer; if (--wordsLeft == 0) { // Next block buffer = currCache = NULL; err = ReleaseBitmapBlock(vcb, blockRef, false); if (err != noErr) goto Exit; /* * Skip over metadata blocks. */ if (!useMetaZone) { block = NextBitmapBlock(vcb, block); } if (block >= endingBlock) { err = dskFulErr; goto Exit; } err = ReadBitmapBlock(vcb, block, &currCache, &blockRef); if (err != noErr) goto Exit; buffer = currCache; wordsLeft = wordsPerBlock; } currentWord = SWAP_BE32 (*buffer); } } // Did we get to the end of the bitmap before finding a free block? // If so, then couldn't allocate anything. if (block >= endingBlock) { err = dskFulErr; goto Exit; } // Return the first block in the allocated range *actualStartBlock = block; dirty = true; // If we could get the desired number of blocks before hitting endingBlock, // then adjust endingBlock so we won't keep looking. Ideally, the comparison // would be (block + maxBlocks) < endingBlock, but that could overflow. The // comparison below yields identical results, but without overflow. if (block < (endingBlock-maxBlocks)) { endingBlock = block + maxBlocks; // if we get this far, we've found enough } // XXXdbg if (hfsmp->jnl) { journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef); } // // Allocate all of the consecutive blocks // while ((currentWord & bitMask) == 0) { // Allocate this block currentWord |= bitMask; // Move to the next block. If no more, then exit. ++block; if (block == endingBlock) break; // Next bit bitMask >>= 1; if (bitMask == 0) { *buffer = SWAP_BE32 (currentWord); // update value in bitmap // Next word bitMask = kHighBitInWordMask; ++buffer; if (--wordsLeft == 0) { // Next block buffer = currCache = NULL; err = ReleaseBitmapBlock(vcb, blockRef, true); if (err != noErr) goto Exit; /* * Skip over metadata blocks. */ if (!useMetaZone) { u_int32_t nextBlock; nextBlock = NextBitmapBlock(vcb, block); if (nextBlock != block) { goto Exit; /* allocation gap, so stop */ } } err = ReadBitmapBlock(vcb, block, &currCache, &blockRef); if (err != noErr) goto Exit; buffer = currCache; // XXXdbg if (hfsmp->jnl) { journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef); } wordsLeft = wordsPerBlock; } currentWord = SWAP_BE32 (*buffer); } } *buffer = SWAP_BE32 (currentWord); // update the last change Exit: if (err == noErr) { *actualNumBlocks = block - *actualStartBlock; // sanity check if ((*actualStartBlock + *actualNumBlocks) > vcb->allocLimit) panic("BlockAllocateAny: allocation overflow on \"%s\"", vcb->vcbVN); } else { *actualStartBlock = 0; *actualNumBlocks = 0; } if (currCache) (void) ReleaseBitmapBlock(vcb, blockRef, dirty); return err; }
static long ReadBTreeEntry(long btree, void * key, char * entry, long * dirIndex) { long extentSize; void *extent; short extentFile; char *nodeBuf; BTNodeDescriptor *node; long nodeSize, result = 0, entrySize = 0; long curNode, index = 0, lowerBound, upperBound; char *testKey, *recordData; // Figure out which tree is being looked at. if (btree == kBTreeCatalog) { if (gIsHFSPlus) { extent = &gHFSPlus->catalogFile.extents; extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); } else { extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); } extentFile = kHFSCatalogFileID; } else { if (gIsHFSPlus) { extent = &gHFSPlus->extentsFile.extents; extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize); } else { extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec; extentSize = SWAP_BE32(gHFSMDB->drXTFlSize); } extentFile = kHFSExtentsFileID; } // Read the BTree Header if needed. if (gBTHeaders[btree] == 0) { ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + btree * 256, 0); gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 + sizeof(BTNodeDescriptor)); if ((gIsHFSPlus && btree == kBTreeCatalog) && (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare)) { gCaseSensitive = 1; } } curNode = SWAP_BE32(gBTHeaders[btree]->rootNode); nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize); nodeBuf = (char *)malloc(nodeSize); node = (BTNodeDescriptor *)nodeBuf; while (1) { // Read the current node. ReadExtent(extent, extentSize, extentFile, curNode * nodeSize, nodeSize, nodeBuf, 1); // Find the matching key. lowerBound = 0; upperBound = SWAP_BE16(node->numRecords) - 1; while (lowerBound <= upperBound) { index = (lowerBound + upperBound) / 2; GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData); if (gIsHFSPlus) { if (btree == kBTreeCatalog) { result = CompareHFSPlusCatalogKeys(key, testKey); } else { result = CompareHFSPlusExtentsKeys(key, testKey); } } else { if (btree == kBTreeCatalog) { result = CompareHFSCatalogKeys(key, testKey); } else { result = CompareHFSExtentsKeys(key, testKey); } } if (result < 0) upperBound = index - 1; // search < trial else if (result > 0) lowerBound = index + 1; // search > trial else break; // search = trial } if (result < 0) { index = upperBound; GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData); } // Found the closest key... Recurse on it if this is an index node. if (node->kind == kBTIndexNode) { curNode = SWAP_BE32( *((long *)recordData) ); } else break; } // Return error if the file was not found. if (result != 0) { free(nodeBuf); return -1; } if (btree == kBTreeCatalog) { switch (SWAP_BE16(*(short *)recordData)) { case kHFSFolderRecord : entrySize = 70; break; case kHFSFileRecord : entrySize = 102; break; case kHFSFolderThreadRecord : entrySize = 46; break; case kHFSFileThreadRecord : entrySize = 46; break; case kHFSPlusFolderRecord : entrySize = 88; break; case kHFSPlusFileRecord : entrySize = 248; break; case kHFSPlusFolderThreadRecord : entrySize = 264; break; case kHFSPlusFileThreadRecord : entrySize = 264; break; } } else { if (gIsHFSPlus) entrySize = sizeof(HFSPlusExtentRecord); else entrySize = sizeof(HFSExtentRecord); } bcopy(recordData, entry, entrySize); // Update dirIndex. if (dirIndex != 0) { index++; if (index == SWAP_BE16(node->numRecords)) { index = 0; curNode = SWAP_BE32(node->fLink); } *dirIndex = curNode * nodeSize + index; } free(nodeBuf); return 0; }
/* * hfs_swap_HFSPlusVolumeHeader */ void hfs_swap_HFSPlusVolumeHeader ( void *buf ) { HFSPlusVolumeHeader *src = (HFSPlusVolumeHeader *)buf; src->signature = SWAP_BE16 (src->signature); src->version = SWAP_BE16 (src->version); src->attributes = SWAP_BE32 (src->attributes); src->lastMountedVersion = SWAP_BE32 (src->lastMountedVersion); src->journalInfoBlock = SWAP_BE32 (src->journalInfoBlock); src->createDate = SWAP_BE32 (src->createDate); src->modifyDate = SWAP_BE32 (src->modifyDate); src->backupDate = SWAP_BE32 (src->backupDate); src->checkedDate = SWAP_BE32 (src->checkedDate); src->fileCount = SWAP_BE32 (src->fileCount); src->folderCount = SWAP_BE32 (src->folderCount); src->blockSize = SWAP_BE32 (src->blockSize); src->totalBlocks = SWAP_BE32 (src->totalBlocks); src->freeBlocks = SWAP_BE32 (src->freeBlocks); src->nextAllocation = SWAP_BE32 (src->nextAllocation); src->rsrcClumpSize = SWAP_BE32 (src->rsrcClumpSize); src->dataClumpSize = SWAP_BE32 (src->dataClumpSize); src->nextCatalogID = SWAP_BE32 (src->nextCatalogID); src->writeCount = SWAP_BE32 (src->writeCount); src->encodingsBitmap = SWAP_BE64 (src->encodingsBitmap); /* Don't swap finderInfo */ hfs_swap_HFSPlusForkData (&src->allocationFile); hfs_swap_HFSPlusForkData (&src->extentsFile); hfs_swap_HFSPlusForkData (&src->catalogFile); hfs_swap_HFSPlusForkData (&src->attributesFile); hfs_swap_HFSPlusForkData (&src->startupFile); }
static long GetCatalogEntryInfo(void * entry, long * flags, long * time, FinderInfo * finderInfo, long * infoValid) { long tmpTime = 0; long valid = 0; // Get information about the file. switch ( SWAP_BE16(*(short *)entry) ) { case kHFSFolderRecord : *flags = kFileTypeDirectory; tmpTime = SWAP_BE32(((HFSCatalogFolder *)entry)->modifyDate); break; case kHFSPlusFolderRecord : *flags = kFileTypeDirectory | (SWAP_BE16(((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode) & kPermMask); if (SWAP_BE32(((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID) != 0) *flags |= kOwnerNotRoot; tmpTime = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->contentModDate); break; case kHFSFileRecord : *flags = kFileTypeFlat; tmpTime = SWAP_BE32(((HFSCatalogFile *)entry)->modifyDate); if (finderInfo) { SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSCatalogFile *)entry)->userInfo); valid = 1; } break; case kHFSPlusFileRecord : *flags = kFileTypeFlat | (SWAP_BE16(((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode) & kPermMask); if (SWAP_BE32(((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID) != 0) *flags |= kOwnerNotRoot; tmpTime = SWAP_BE32(((HFSPlusCatalogFile *)entry)->contentModDate); if (finderInfo) { SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSPlusCatalogFile *)entry)->userInfo); valid = 1; } break; case kHFSFileThreadRecord : case kHFSPlusFileThreadRecord : case kHFSFolderThreadRecord : case kHFSPlusFolderThreadRecord : *flags = kFileTypeUnknown; tmpTime = 0; break; } if (time != 0) { // Convert base time from 1904 to 1970. *time = tmpTime - 2082844800; } if (infoValid) *infoValid = valid; return 0; }
static void update_status(struct svdir *s) { ssize_t sz; int fd; svstatus_t status; /* pid */ if (pidchanged) { fd = open_trunc_or_warn("supervise/pid.new"); if (fd < 0) return; if (s->pid) { char spid[sizeof(int)*3 + 2]; int size = sprintf(spid, "%u\n", (unsigned)s->pid); write(fd, spid, size); } close(fd); if (rename_or_warn("supervise/pid.new", s->islog ? "log/supervise/pid" : "log/supervise/pid"+4)) return; pidchanged = 0; } /* stat */ fd = open_trunc_or_warn("supervise/stat.new"); if (fd < -1) return; { char stat_buf[sizeof("finish, paused, got TERM, want down\n")]; char *p = stat_buf; switch (s->state) { case S_DOWN: p = stpcpy(p, "down"); break; case S_RUN: p = stpcpy(p, "run"); break; case S_FINISH: p = stpcpy(p, "finish"); break; } if (s->ctrl & C_PAUSE) p = stpcpy(p, ", paused"); if (s->ctrl & C_TERM) p = stpcpy(p, ", got TERM"); if (s->state != S_DOWN) switch (s->sd_want) { case W_DOWN: p = stpcpy(p, ", want down"); break; case W_EXIT: p = stpcpy(p, ", want exit"); break; } *p++ = '\n'; write(fd, stat_buf, p - stat_buf); close(fd); } rename_or_warn("supervise/stat.new", s->islog ? "log/supervise/stat" : "log/supervise/stat"+4); /* supervise compatibility */ memset(&status, 0, sizeof(status)); status.time_be64 = SWAP_BE64(s->start.tv_sec + 0x400000000000000aULL); status.time_nsec_be32 = SWAP_BE32(s->start.tv_nsec); status.pid_le32 = SWAP_LE32(s->pid); if (s->ctrl & C_PAUSE) status.paused = 1; if (s->sd_want == W_UP) status.want = 'u'; else status.want = 'd'; if (s->ctrl & C_TERM) status.got_term = 1; status.run_or_finish = s->state; fd = open_trunc_or_warn("supervise/status.new"); if (fd < 0) return; sz = write(fd, &status, sizeof(status)); close(fd); if (sz != sizeof(status)) { warn_cannot("write supervise/status.new"); unlink("supervise/status.new"); return; } rename_or_warn("supervise/status.new", s->islog ? "log/supervise/status" : "log/supervise/status"+4); }
long HFSInitPartition(CICell ih) { long extentSize, extentFile, nodeSize; void *extent; if (ih == gCurrentIH) { #ifdef __i386__ CacheInit(ih, gCacheBlockSize); #endif return 0; } #ifdef __i386__ if (!gTempStr) gTempStr = (char *)malloc(4096); if (!gLinkTemp) gLinkTemp = (char *)malloc(64); if (!gBTreeHeaderBuffer) gBTreeHeaderBuffer = (char *)malloc(512); if (!gHFSMdbVib) { gHFSMdbVib = (char *)malloc(kBlockSize); gHFSMDB = (HFSMasterDirectoryBlock *)gHFSMdbVib; } if (!gHFSPlusHeader) { gHFSPlusHeader = (char *)malloc(kBlockSize); gHFSPlus = (HFSPlusVolumeHeader *)gHFSPlusHeader; } if (!gTempStr || !gLinkTemp || !gBTreeHeaderBuffer || !gHFSMdbVib || !gHFSPlusHeader) return -1; #endif /* __i386__ */ gAllocationOffset = 0; gIsHFSPlus = 0; gCaseSensitive = 0; gBTHeaders[0] = 0; gBTHeaders[1] = 0; // Look for the HFS MDB Seek(ih, kMDBBaseOffset); Read(ih, (long)gHFSMdbVib, kBlockSize); if ( SWAP_BE16(gHFSMDB->drSigWord) == kHFSSigWord ) { gAllocationOffset = SWAP_BE16(gHFSMDB->drAlBlSt) * kBlockSize; // See if it is HFSPlus if (SWAP_BE16(gHFSMDB->drEmbedSigWord) != kHFSPlusSigWord) { // Normal HFS; gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSMDB->drAlBlkSiz); CacheInit(ih, gCacheBlockSize); gCurrentIH = ih; // grab the 64 bit volume ID bcopy(&gHFSMDB->drFndrInfo[6], &gVolID, 8); // Get the Catalog BTree node size. extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; extentSize = SWAP_BE32(gHFSMDB->drCTFlSize); extentFile = kHFSCatalogFileID; ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize); // If the BTree node size is larger than the block size, reset the cache. if (nodeSize > gBlockSize) { gCacheBlockSize = nodeSize; CacheInit(ih, gCacheBlockSize); } return 0; } // Calculate the offset to the embeded HFSPlus volume. gAllocationOffset += (long long)SWAP_BE16(gHFSMDB->drEmbedExtent.startBlock) * SWAP_BE32(gHFSMDB->drAlBlkSiz); } // Look for the HFSPlus Header Seek(ih, gAllocationOffset + kMDBBaseOffset); Read(ih, (long)gHFSPlusHeader, kBlockSize); // Not a HFS+ or HFSX volume. if (SWAP_BE16(gHFSPlus->signature) != kHFSPlusSigWord && SWAP_BE16(gHFSPlus->signature) != kHFSXSigWord) { verbose("HFS signature was not present.\n"); gCurrentIH = 0; return -1; } gIsHFSPlus = 1; gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize); CacheInit(ih, gCacheBlockSize); gCurrentIH = ih; // grab the 64 bit volume ID bcopy(&gHFSPlus->finderInfo[24], &gVolID, 8); // Get the Catalog BTree node size. extent = &gHFSPlus->catalogFile.extents; extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize); extentFile = kHFSCatalogFileID; ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0); nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize); // If the BTree node size is larger than the block size, reset the cache. if (nodeSize > gBlockSize) { gCacheBlockSize = nodeSize; CacheInit(ih, gCacheBlockSize); } return 0; }
/* * hfs_swap_HFSMasterDirectoryBlock * * Specially modified to swap parts of the finder info */ void hfs_swap_HFSMasterDirectoryBlock ( void *buf ) { HFSMasterDirectoryBlock *src = (HFSMasterDirectoryBlock *)buf; src->drSigWord = SWAP_BE16 (src->drSigWord); src->drCrDate = SWAP_BE32 (src->drCrDate); src->drLsMod = SWAP_BE32 (src->drLsMod); src->drAtrb = SWAP_BE16 (src->drAtrb); src->drNmFls = SWAP_BE16 (src->drNmFls); src->drVBMSt = SWAP_BE16 (src->drVBMSt); src->drAllocPtr = SWAP_BE16 (src->drAllocPtr); src->drNmAlBlks = SWAP_BE16 (src->drNmAlBlks); src->drAlBlkSiz = SWAP_BE32 (src->drAlBlkSiz); src->drClpSiz = SWAP_BE32 (src->drClpSiz); src->drAlBlSt = SWAP_BE16 (src->drAlBlSt); src->drNxtCNID = SWAP_BE32 (src->drNxtCNID); src->drFreeBks = SWAP_BE16 (src->drFreeBks); /* Don't swap drVN */ src->drVolBkUp = SWAP_BE32 (src->drVolBkUp); src->drVSeqNum = SWAP_BE16 (src->drVSeqNum); src->drWrCnt = SWAP_BE32 (src->drWrCnt); src->drXTClpSiz = SWAP_BE32 (src->drXTClpSiz); src->drCTClpSiz = SWAP_BE32 (src->drCTClpSiz); src->drNmRtDirs = SWAP_BE16 (src->drNmRtDirs); src->drFilCnt = SWAP_BE32 (src->drFilCnt); src->drDirCnt = SWAP_BE32 (src->drDirCnt); /* Swap just the 'blessed folder' in drFndrInfo */ src->drFndrInfo[0] = SWAP_BE32 (src->drFndrInfo[0]); src->drEmbedSigWord = SWAP_BE16 (src->drEmbedSigWord); src->drEmbedExtent.startBlock = SWAP_BE16 (src->drEmbedExtent.startBlock); src->drEmbedExtent.blockCount = SWAP_BE16 (src->drEmbedExtent.blockCount); src->drXTFlSize = SWAP_BE32 (src->drXTFlSize); src->drXTExtRec[0].startBlock = SWAP_BE16 (src->drXTExtRec[0].startBlock); src->drXTExtRec[0].blockCount = SWAP_BE16 (src->drXTExtRec[0].blockCount); src->drXTExtRec[1].startBlock = SWAP_BE16 (src->drXTExtRec[1].startBlock); src->drXTExtRec[1].blockCount = SWAP_BE16 (src->drXTExtRec[1].blockCount); src->drXTExtRec[2].startBlock = SWAP_BE16 (src->drXTExtRec[2].startBlock); src->drXTExtRec[2].blockCount = SWAP_BE16 (src->drXTExtRec[2].blockCount); src->drCTFlSize = SWAP_BE32 (src->drCTFlSize); src->drCTExtRec[0].startBlock = SWAP_BE16 (src->drCTExtRec[0].startBlock); src->drCTExtRec[0].blockCount = SWAP_BE16 (src->drCTExtRec[0].blockCount); src->drCTExtRec[1].startBlock = SWAP_BE16 (src->drCTExtRec[1].startBlock); src->drCTExtRec[1].blockCount = SWAP_BE16 (src->drCTExtRec[1].blockCount); src->drCTExtRec[2].startBlock = SWAP_BE16 (src->drCTExtRec[2].startBlock); src->drCTExtRec[2].blockCount = SWAP_BE16 (src->drCTExtRec[2].blockCount); }
void nbd_client_main(void) { int sock = -1, nbd, flags; unsigned long timeout = 0; char *host=toys.optargs[0], *port=toys.optargs[1], *device=toys.optargs[2]; uint64_t devsize; // Repeat until spanked nbd = xopen(device, O_RDWR); for (;;) { int temp; // Find and connect to server sock = xconnect(xgetaddrinfo(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0)); temp = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &temp, sizeof(int)); // Read login data xreadall(sock, toybuf, 152); if (memcmp(toybuf, "NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53", 16)) error_exit("bad login %s:%s", host, port); devsize = SWAP_BE64(*(uint64_t *)(toybuf+16)); flags = SWAP_BE32(*(int *)(toybuf+24)); // Set 4k block size. Everything uses that these days. ioctl(nbd, NBD_SET_BLKSIZE, 4096); ioctl(nbd, NBD_SET_SIZE_BLOCKS, devsize/4096); ioctl(nbd, NBD_CLEAR_SOCK); // If the sucker was exported read only, respect that locally. temp = (flags & 2) ? 1 : 0; xioctl(nbd, BLKROSET, &temp); if (timeout && ioctl(nbd, NBD_SET_TIMEOUT, timeout)<0) break; if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) break; if (toys.optflags & FLAG_s) mlockall(MCL_CURRENT|MCL_FUTURE); // Open the device to force reread of the partition table. if ((toys.optflags & FLAG_n) || !xfork()) { char *s = strrchr(device, '/'); int i; sprintf(toybuf, "/sys/block/%.32s/pid", s ? s+1 : device); // Is it up yet? (Give it 10 seconds.) for (i=0; i<100; i++) { temp = open(toybuf, O_RDONLY); if (temp == -1) msleep(100); else { close(temp); break; } } close(open(device, O_RDONLY)); if (!(toys.optflags & FLAG_n)) exit(0); } // Daemonize here. if (daemon(0,0)) perror_exit("daemonize"); // Process NBD requests until further notice. if (ioctl(nbd, NBD_DO_IT)>=0 || errno==EBADR) break; close(sock); } // Flush queue and exit. ioctl(nbd, NBD_CLEAR_QUE); ioctl(nbd, NBD_CLEAR_SOCK); if (CFG_TOYBOX_FREE) close(nbd); }