//! Use key + salt to encrypt the header, and write it to disk. status_t VolumeCryptContext::_WriteHeader(int fd, const uint8* key, uint32 keyLength, off_t headerOffset, uint8* buffer) { uint8 diskKey[DISK_KEY_SIZE]; derive_key(key, keyLength, buffer, PKCS5_SALT_SIZE, diskKey, DISK_KEY_SIZE); status_t status = Init(ALGORITHM_AES, MODE_XTS, diskKey, DISK_KEY_SIZE); if (status != B_OK) return status; true_crypt_header& header = *(true_crypt_header*)&buffer[PKCS5_SALT_SIZE]; Encrypt((uint8*)&header, BLOCK_SIZE - PKCS5_SALT_SIZE); ssize_t bytesWritten = write_pos(fd, headerOffset, buffer, BLOCK_SIZE); if (bytesWritten < 0) return errno; // use the decrypted header to init the volume encryption Decrypt((uint8*)&header, BLOCK_SIZE - PKCS5_SALT_SIZE); SetKey(header.disk_key, sizeof(header.disk_key)); return B_OK; }
status_t Volume::WriteSuperBlock() { if (write_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block)) != sizeof(disk_super_block)) return B_IO_ERROR; return B_OK; }
/*! Erase the first boot block, as we don't use it and there * might be leftovers from other file systems. This can cause * confusion for identifying the partition if not erased. */ status_t Volume::_EraseUnusedBootBlock() { const int32 blockSize = 512; const char emptySector[blockSize] = { 0 }; if (write_pos(fDevice, 0, emptySector, blockSize) != blockSize) return B_IO_ERROR; return B_OK; }
status_t Header::_Write(int fd, off_t offset, const void* data, size_t size) const { ssize_t bytesWritten = write_pos(fd, offset, data, size); if (bytesWritten < 0) return bytesWritten; if (bytesWritten != (ssize_t)size) return B_IO_ERROR; return B_OK; }
// write_boot_code_part static void write_boot_code_part(const char *fileName, int fd, off_t imageOffset, const uint8 *bootCodeData, int offset, int size, bool dryRun) { if (!dryRun) { ssize_t bytesWritten = write_pos(fd, imageOffset + offset, bootCodeData + offset, size); if (bytesWritten != size) { fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName, strerror(bytesWritten < 0 ? errno : B_ERROR)); } } }
// Write status_t FileHandle::Write(off_t pos, const void* buffer, size_t size, size_t* _bytesWritten) { if (fFD < 0) return B_BAD_VALUE; ssize_t bytesWritten = write_pos(fFD, pos, buffer, size); if (bytesWritten < 0) return errno; *_bytesWritten = bytesWritten; return B_OK; }
ssize_t Partition::WriteAt(void *cookie, off_t position, const void *buffer, size_t bufferSize) { if (position > this->size) return 0; if (position < 0) return B_BAD_VALUE; if (position + bufferSize > this->size) bufferSize = this->size - position; ssize_t result = write_pos(fFD, this->offset + position, buffer, bufferSize); return result < 0 ? errno : result; }
status_t Initialize(int fatbits, const char *device, const char *label, bool noprompt, bool testmode) { if (fatbits != 0 && fatbits != 12 && fatbits != 16 && fatbits != 32) { fprintf(stderr,"Error: don't know how to create a %d bit fat\n",fatbits); return B_ERROR; } //XXX the following two checks can be removed when this is fixed: #ifndef WITH_FLOPPY_SUPPORT if (0 != strstr(device,"floppy")) { fprintf(stderr,"Error: floppy B_GET_GEOMETRY and B_GET_BIOS_GEOMETRY calls are broken, floppy not supported\n"); return B_ERROR; } if (fatbits == 12) { fprintf(stderr,"Error: can't create a 12 bit fat on a device other than floppy\n"); return B_ERROR; } #endif printf("device = %s\n",device); int fd = open(device, O_RDWR); if (fd < 0) { fprintf(stderr, "Error: couldn't open file for device %s (%s)\n", device, strerror(errno)); return B_ERROR; } bool isRawDevice; bool hasBiosGeometry; bool hasDeviceGeometry; bool hasPartitionInfo; device_geometry biosGeometry; device_geometry deviceGeometry; partition_info partitionInfo; isRawDevice = 0 != strstr(device, "/raw"); hasBiosGeometry = B_OK == ioctl(fd, B_GET_BIOS_GEOMETRY, &biosGeometry, sizeof(biosGeometry)); hasDeviceGeometry = B_OK == ioctl(fd, B_GET_GEOMETRY, &deviceGeometry, sizeof(deviceGeometry)); hasPartitionInfo = B_OK == ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo, sizeof(partitionInfo)); if (!isRawDevice && !hasBiosGeometry && !hasDeviceGeometry && !hasPartitionInfo) isRawDevice = true; if (hasBiosGeometry) { printf("bios geometry: %ld heads, %ld cylinders, %ld sectors/track, %ld bytes/sector\n", biosGeometry.head_count,biosGeometry.cylinder_count,biosGeometry.sectors_per_track,biosGeometry.bytes_per_sector); } if (hasBiosGeometry) { printf("device geometry: %ld heads, %ld cylinders, %ld sectors/track, %ld bytes/sector\n", deviceGeometry.head_count,deviceGeometry.cylinder_count,deviceGeometry.sectors_per_track,deviceGeometry.bytes_per_sector); } if (hasPartitionInfo) { printf("partition info: start at %Ld bytes (%Ld sectors), %Ld KB, %Ld MB, %Ld GB\n", partitionInfo.offset, partitionInfo.offset / 512, partitionInfo.offset / 1024, partitionInfo.offset / (1024 * 1024), partitionInfo.offset / (1024 * 1024 * 1024)); printf("partition info: size %Ld bytes, %Ld KB, %Ld MB, %Ld GB\n", partitionInfo.size, partitionInfo.size / 1024, partitionInfo.size / (1024 * 1024), partitionInfo.size / (1024 * 1024 * 1024)); } if (!isRawDevice && !hasPartitionInfo) { fprintf(stderr,"Warning: couldn't get partition information\n"); } if ((hasBiosGeometry && biosGeometry.bytes_per_sector != 512) || (hasDeviceGeometry && deviceGeometry.bytes_per_sector != 512)) { fprintf(stderr,"Error: geometry block size not 512 bytes\n"); close(fd); return B_ERROR; } else if (hasPartitionInfo && partitionInfo.logical_block_size != 512) { printf("partition logical block size is not 512, it's %ld bytes\n", partitionInfo.logical_block_size); } if (hasDeviceGeometry && deviceGeometry.read_only) { fprintf(stderr,"Error: this is a read-only device\n"); close(fd); return B_ERROR; } if (hasDeviceGeometry && deviceGeometry.write_once) { fprintf(stderr,"Error: this is a write-once device\n"); close(fd); return B_ERROR; } uint64 size = 0; if (hasPartitionInfo) { size = partitionInfo.size; } else if (hasDeviceGeometry) { size = uint64(deviceGeometry.bytes_per_sector) * deviceGeometry.sectors_per_track * deviceGeometry.cylinder_count * deviceGeometry.head_count; } else if (hasBiosGeometry) { size = uint64(biosGeometry.bytes_per_sector) * biosGeometry.sectors_per_track * biosGeometry.cylinder_count * biosGeometry.head_count; } else { // maybe it's just a file struct stat stat; if (fstat(fd, &stat) < 0) { fprintf(stderr, "Error: couldn't get device partition or geometry information, nor size\n"); close(fd); return B_ERROR; } size = stat.st_size; } // TODO still valid on Haiku ? /*if (isRawDevice && size > FLOPPY_MAX_SIZE) { fprintf(stderr,"Error: device too large for floppy, or raw devices not supported\n"); close(fd); return B_ERROR; }*/ printf("size = %Ld bytes (%Ld sectors), %Ld KB, %Ld MB, %Ld GB\n", size, size / 512, size / 1024, size / (1024 * 1024), size / (1024 * 1024 * 1024)); if (fatbits == 0) { //auto determine fat type if (isRawDevice && size <= FLOPPY_MAX_SIZE && (size / FAT12_CLUSTER_MAX_SIZE) < FAT12_MAX_CLUSTER_COUNT) { fatbits = 12; } else if ((size / CLUSTER_MAX_SIZE) < FAT16_MAX_CLUSTER_COUNT) { fatbits = 16; } else if ((size / CLUSTER_MAX_SIZE) < FAT32_MAX_CLUSTER_COUNT) { fatbits = 32; } } if (fatbits == 0) { fprintf(stderr,"Error: device too large for 32 bit fat\n"); close(fd); return B_ERROR; } int sectorPerCluster; sectorPerCluster = 0; if (fatbits == 12) { sectorPerCluster = 0; if (size <= 4182016LL) sectorPerCluster = 2; // XXX don't know the correct value if (size <= 2091008LL) sectorPerCluster = 1; // XXX don't know the correct value } else if (fatbits == 16) { // special BAD_CLUSTER value is 0xFFF7, // but this should work anyway, since space required by // two FATs will make maximum cluster count smaller. // at least, this is what I think *should* happen sectorPerCluster = 0; //larger than 2 GB must fail if (size <= (2048 * 1024 * 1024LL)) // up to 2GB, use 32k clusters sectorPerCluster = 64; if (size <= (1024 * 1024 * 1024LL)) // up to 1GB, use 16k clusters sectorPerCluster = 32; if (size <= (512 * 1024 * 1024LL)) // up to 512MB, use 8k clusters sectorPerCluster = 16; if (size <= (256 * 1024 * 1024LL)) // up to 256MB, use 4k clusters sectorPerCluster = 8; if (size <= (128 * 1024 * 1024LL)) // up to 128MB, use 2k clusters sectorPerCluster = 4; if (size <= (16 * 1024 * 1024LL)) // up to 16MB, use 2k clusters sectorPerCluster = 2; if (size <= 4182016LL) // smaller than fat32 must fail sectorPerCluster = 0; } if (fatbits == 32) { sectorPerCluster = 64; // default is 32k clusters if (size <= (32 * 1024 * 1024 * 1024LL)) // up to 32GB, use 16k clusters sectorPerCluster = 32; if (size <= (16 * 1024 * 1024 * 1024LL)) // up to 16GB, use 8k clusters sectorPerCluster = 16; if (size <= (8 * 1024 * 1024 * 1024LL)) // up to 8GB, use 4k clusters sectorPerCluster = 8; if (size <= (532480 * 512LL)) // up to 260 MB, use 0.5k clusters sectorPerCluster = 1; if (size <= (66600 * 512LL)) // smaller than 32.5 MB must fail sectorPerCluster = 0; } if (sectorPerCluster == 0) { fprintf(stderr,"Error: failed to determine sector per cluster value, partition too large for %d bit fat\n",fatbits); close(fd); return B_ERROR; } int reservedSectorCount = 0; // avoid compiler warning int rootEntryCount = 0; // avoid compiler warning int numFATs; int sectorSize; uint8 biosDriveId; // get bios drive-id, or use 0x80 if (B_OK != ioctl(fd, B_GET_BIOS_DRIVE_ID, &biosDriveId, sizeof(biosDriveId))) { biosDriveId = 0x80; } else { printf("bios drive id: 0x%02x\n", (int)biosDriveId); } // default parameters for the bootsector numFATs = 2; sectorSize = 512; if (fatbits == 12 || fatbits == 16) reservedSectorCount = 1; if (fatbits == 32) reservedSectorCount = 32; if (fatbits == 12) rootEntryCount = 128; // XXX don't know the correct value if (fatbits == 16) rootEntryCount = 512; if (fatbits == 32) rootEntryCount = 0; // Determine FATSize // calculation done as MS recommends uint64 dskSize = size / sectorSize; uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1)) / sectorSize; uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors); uint64 tmpVal2 = (256 * sectorPerCluster) + numFATs; if (fatbits == 32) tmpVal2 = tmpVal2 / 2; uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2; // FATSize should now contain the size of *one* FAT, measured in sectors // RootDirSectors should now contain the size of the fat12/16 root directory, measured in sectors printf("fatbits = %d, clustersize = %d\n", fatbits, sectorPerCluster * 512); printf("FAT size is %ld sectors\n", FATSize); printf("disk label: %s\n", label); char bootsector[512]; memset(bootsector,0x00,512); memcpy(bootsector + BOOTJMP_START_OFFSET, bootjmp, sizeof(bootjmp)); memcpy(bootsector + BOOTCODE_START_OFFSET, bootcode, sizeof(bootcode)); if (fatbits == 32) { bootsector32 *bs = (bootsector32 *)bootsector; uint16 temp16; uint32 temp32; memcpy(bs->BS_OEMName,"Haiku ",8); bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize); bs->BPB_SecPerClus = sectorPerCluster; bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount); bs->BPB_NumFATs = numFATs; bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount); bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(0); bs->BPB_Media = 0xF8; bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(0); temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63; bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16); temp16 = hasBiosGeometry ? biosGeometry.head_count : 255; bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16); temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0; bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32); temp32 = size / 512; bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32); bs->BPB_FATSz32 = B_HOST_TO_LENDIAN_INT32(FATSize); bs->BPB_ExtFlags = B_HOST_TO_LENDIAN_INT16(0); bs->BPB_FSVer = B_HOST_TO_LENDIAN_INT16(0); bs->BPB_RootClus = B_HOST_TO_LENDIAN_INT32(FAT32_ROOT_CLUSTER); bs->BPB_FSInfo = B_HOST_TO_LENDIAN_INT16(FSINFO_SECTOR_NUM); bs->BPB_BkBootSec = B_HOST_TO_LENDIAN_INT16(BACKUP_SECTOR_NUM); memset(bs->BPB_Reserved,0,12); bs->BS_DrvNum = biosDriveId; bs->BS_Reserved1 = 0x00; bs->BS_BootSig = 0x29; *(uint32*)bs->BS_VolID = (uint32)system_time(); memcpy(bs->BS_VolLab,"NO NAME ",11); memcpy(bs->BS_FilSysType,"FAT32 ",8); bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55); } else { bootsector1216 *bs = (bootsector1216 *)bootsector; uint16 temp16; uint32 temp32; uint32 sectorcount = size / 512; memcpy(bs->BS_OEMName, "Haiku ", 8); bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize); bs->BPB_SecPerClus = sectorPerCluster; bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount); bs->BPB_NumFATs = numFATs; bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount); temp16 = (sectorcount <= 65535) ? sectorcount : 0; bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(temp16); bs->BPB_Media = 0xF8; bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(FATSize); temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63; bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16); temp16 = hasBiosGeometry ? biosGeometry.head_count : 255; bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16); temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0; bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32); temp32 = (sectorcount <= 65535) ? 0 : sectorcount; bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32); bs->BS_DrvNum = biosDriveId; bs->BS_Reserved1 = 0x00; bs->BS_BootSig = 0x29; *(uint32*)bs->BS_VolID = (uint32)system_time(); memcpy(bs->BS_VolLab,"NO NAME ",11); memcpy(bs->BS_FilSysType,(fatbits == 12) ? "FAT12 " : "FAT16 ",8); bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55); } if (!noprompt) { printf("\n"); printf("Initializing will erase all existing data on the drive.\n"); printf("Do you wish to proceed? "); char answer[1000]; char *p; memset(answer, 0, 1000); fflush(stdout); p = fgets(answer, 1000, stdin); if (p && (p=strchr(p, '\n'))) *p = '\0'; /* remove newline */ if ((p == NULL) || (strlen(answer) < 1) || (0 != strncasecmp(answer, "yes", strlen(answer)))) { printf("drive NOT initialized\n"); close(fd); return B_OK; } } if (testmode) { close(fd); return B_OK; } // Disk layout: // 0) reserved sectors, this includes the bootsector, fsinfosector and bootsector backup // 1) FAT // 2) root directory (not on fat32) // 3) file & directory data ssize_t written; // initialize everything with zero first // avoid doing 512 byte writes here, they are slow printf("Writing FAT\n"); char * zerobuffer = (char *)malloc(65536); memset(zerobuffer,0,65536); int64 bytes_to_write = 512LL * (reservedSectorCount + (numFATs * FATSize) + rootDirSectors); int64 pos = 0; while (bytes_to_write > 0) { ssize_t writesize = min_c(bytes_to_write, 65536); written = write_pos(fd, pos, zerobuffer, writesize); if (written != writesize) { fprintf(stderr,"Error: write error near sector %Ld\n",pos / 512); close(fd); return B_ERROR; } bytes_to_write -= writesize; pos += writesize; } free(zerobuffer); //write boot sector printf("Writing boot block\n"); written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512); if (written != 512) { fprintf(stderr,"Error: write error at sector %d\n", BOOT_SECTOR_NUM); close(fd); return B_ERROR; } if (fatbits == 32) { written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512); if (written != 512) { fprintf(stderr,"Error: write error at sector %d\n", BACKUP_SECTOR_NUM); close(fd); return B_ERROR; } } //write first fat sector printf("Writing first FAT sector\n"); uint8 sec[512]; memset(sec,0,512); if (fatbits == 12) { //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 //FAT[1] contains EOF marker sec[0] = 0xF8; sec[1] = 0xFF; sec[2] = 0xFF; } else if (fatbits == 16) { //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 sec[0] = 0xF8; sec[1] = 0xFF; //FAT[1] contains EOF marker sec[2] = 0xFF; sec[3] = 0xFF; } else if (fatbits == 32) { //FAT[0] contains media byte in lower 8 bits, all other bits set to 1 sec[0] = 0xF8; sec[1] = 0xFF; sec[2] = 0xFF; sec[3] = 0xFF; //FAT[1] contains EOF marker sec[4] = 0xFF; sec[5] = 0xFF; sec[6] = 0xFF; sec[7] = 0x0F; //FAT[2] contains EOF marker, used to terminate root directory sec[8] = 0xFF; sec[9] = 0xFF; sec[10] = 0xFF; sec[11] = 0x0F; } written = write_pos(fd, reservedSectorCount * 512, sec, 512); if (written != 512) { fprintf(stderr,"Error: write error at sector %d\n", reservedSectorCount); close(fd); return B_ERROR; } if (numFATs > 1) { written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512); if (written != 512) { fprintf(stderr,"Error: write error at sector %ld\n", reservedSectorCount + FATSize); close(fd); return B_ERROR; } } //write fsinfo sector if (fatbits == 32) { printf("Writing boot info\n"); //calculate total sector count first uint64 free_count = size / 512; //now account for already by metadata used sectors free_count -= reservedSectorCount + (numFATs * FATSize) + rootDirSectors; //convert from sector to clustercount free_count /= sectorPerCluster; //and account for 1 already used cluster of root directory free_count -= 1; fsinfosector32 fsinfosector; memset(&fsinfosector,0x00,512); fsinfosector.FSI_LeadSig = B_HOST_TO_LENDIAN_INT32(0x41615252); fsinfosector.FSI_StrucSig = B_HOST_TO_LENDIAN_INT32(0x61417272); fsinfosector.FSI_Free_Count = B_HOST_TO_LENDIAN_INT32((uint32)free_count); fsinfosector.FSI_Nxt_Free = B_HOST_TO_LENDIAN_INT32(3); fsinfosector.FSI_TrailSig = B_HOST_TO_LENDIAN_INT32(0xAA550000); written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512); if (written != 512) { fprintf(stderr,"Error: write error at sector %d\n", FSINFO_SECTOR_NUM); close(fd); return B_ERROR; } } //write volume label into root directory printf("Writing root directory\n"); if (fatbits == 12 || fatbits == 16) { uint8 data[512]; memset(data, 0, 512); CreateVolumeLabel(data, label); uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize); written = write_pos(fd, rootDirSector * 512, data, 512); if (written != 512) { fprintf(stderr,"Error: write error at sector %ld\n", rootDirSector); close(fd); return B_ERROR; } } else if (fatbits == 32) { int size = 512 * sectorPerCluster; uint8 *cluster = (uint8*)malloc(size); memset(cluster, 0, size); CreateVolumeLabel(cluster, label); uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize) + rootDirSectors; written = write_pos(fd, rootDirSector * 512, cluster, size); free(cluster); if (written != size) { fprintf(stderr,"Error: write error at sector %ld\n", rootDirSector); close(fd); return B_ERROR; } } ioctl(fd, B_FLUSH_DRIVE_CACHE); close(fd); return B_OK; }
ssize_t __libc_pwrite (int fd, const void *buf, size_t nbyte, off_t offset) { return write_pos (fd, offset, buf, nbyte); }