Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

gpt: Added support for the backup header/entries.

  • Loading branch information...
commit 953d310a47372bb97f2b1154d032aa344dbbcb69 1 parent 90308ec
@axeld axeld authored
View
131 src/add-ons/kernel/partitioning_systems/gpt/Header.cpp
@@ -44,27 +44,37 @@ Header::Header(int fd, uint64 lastBlock, uint32 blockSize)
fStatus(B_NO_INIT),
fEntries(NULL)
{
- // TODO: check the correctness of the protective MBR
+ // TODO: check the correctness of the protective MBR and warn if invalid
- // read and check the partition table header
+ // Read and check the partition table header
- ssize_t bytesRead = read_pos(fd, (uint64)EFI_HEADER_LOCATION * blockSize,
+ fStatus = _Read(fd, (uint64)EFI_HEADER_LOCATION * blockSize,
&fHeader, sizeof(efi_table_header));
- if (bytesRead != (ssize_t)sizeof(efi_table_header)) {
- if (bytesRead < B_OK)
- fStatus = bytesRead;
- else
- fStatus = B_IO_ERROR;
+ if (fStatus == B_OK) {
+ if (!_IsHeaderValid(fHeader, EFI_HEADER_LOCATION))
+ fStatus = B_BAD_DATA;
+ }
- return;
+ // Read backup header, too
+ status_t status = _Read(fd, lastBlock * blockSize, &fBackupHeader,
+ sizeof(efi_table_header));
+ if (status == B_OK) {
+ if (!_IsHeaderValid(fBackupHeader, lastBlock))
+ status = B_BAD_DATA;
}
- if (memcmp(fHeader.header, EFI_PARTITION_HEADER, sizeof(fHeader.header))
- || !_ValidateHeaderCRC()
- || fHeader.AbsoluteBlock() != EFI_HEADER_LOCATION) {
- // TODO: check that partition counts are in valid bounds
- fStatus = B_BAD_DATA;
+ // If both headers are invalid, bail out -- this is probably not a GPT disk
+ if (status != B_OK && fStatus != B_OK)
return;
+
+ if (fStatus != B_OK) {
+ // Recreate primary header from the backup
+ fHeader = fBackupHeader;
+ fHeader.SetAbsoluteBlock(EFI_HEADER_LOCATION);
+ fHeader.SetEntriesBlock(EFI_PARTITION_ENTRIES_BLOCK);
+ } else if (status != B_OK) {
+ // Recreate backup header from primary
+ _SetBackupHeaderFromPrimary(lastBlock);
}
// allocate, read, and check partition entry array
@@ -77,22 +87,22 @@ Header::Header(int fd, uint64 lastBlock, uint32 blockSize)
return;
}
- bytesRead = read_pos(fd, fHeader.EntriesBlock() * blockSize,
+ fStatus = _Read(fd, fHeader.EntriesBlock() * blockSize,
fEntries, _EntryArraySize());
- if (bytesRead != (ssize_t)_EntryArraySize()) {
- if (bytesRead < B_OK)
- fStatus = bytesRead;
- else
- fStatus = B_IO_ERROR;
-
- return;
+ if (fStatus != B_OK || !_ValidateEntriesCRC()) {
+ // Read backup entries instead
+ fStatus = _Read(fd, fBackupHeader.EntriesBlock() * blockSize,
+ fEntries, _EntryArraySize());
+ if (fStatus != B_OK)
+ return;
+
+ if (!_ValidateEntriesCRC()) {
+ fStatus = B_BAD_DATA;
+ return;
+ }
}
- if (!_ValidateEntriesCRC()) {
- // TODO: check overlapping or out of range partitions
- fStatus = B_BAD_DATA;
- return;
- }
+ // TODO: check overlapping or out of range partitions
#ifdef TRACE_EFI_GPT
_Dump();
@@ -140,6 +150,8 @@ Header::Header(uint64 lastBlock, uint32 blockSize)
fHeader.SetFirstUsableBlock(EFI_PARTITION_ENTRIES_BLOCK + entryBlocks);
fHeader.SetLastUsableBlock(lastBlock - 1 - entryBlocks);
+ _SetBackupHeaderFromPrimary(lastBlock);
+
#ifdef TRACE_EFI_GPT
_Dump();
_DumpPartitions();
@@ -168,19 +180,25 @@ status_t
Header::WriteEntry(int fd, uint32 entryIndex)
{
// Determine block to write
- off_t block = fHeader.EntriesBlock()
+ off_t blockOffset =
+ entryIndex * fHeader.EntrySize() / fBlockSize;
uint32 entryOffset = entryIndex * fHeader.EntrySize() % fBlockSize;
- status_t status = _Write(fd, block * fBlockSize, fEntries + entryOffset,
- fBlockSize);
+ status_t status = _Write(fd,
+ (fHeader.EntriesBlock() + blockOffset) * fBlockSize,
+ fEntries + entryOffset, fBlockSize);
if (status != B_OK)
return status;
- // TODO: write mirror at the end
-
// Update header, too -- the entries CRC changed
- return _WriteHeader(fd);
+ status = _WriteHeader(fd);
+
+ // Write backup
+ status_t backupStatus = _Write(fd,
+ (fBackupHeader.EntriesBlock() + blockOffset) * fBlockSize,
+ fEntries + entryOffset, fBlockSize);
+
+ return status == B_OK ? backupStatus : status;
}
@@ -192,9 +210,15 @@ Header::Write(int fd)
if (status != B_OK)
return status;
- // TODO: write mirror at the end
+ // First write the header, so that we have at least one completely correct
+ // data set
+ status = _WriteHeader(fd);
+
+ // Write backup entries
+ status_t backupStatus = _Write(fd,
+ fBackupHeader.EntriesBlock() * fBlockSize, fEntries, _EntryArraySize());
- return _WriteHeader(fd);
+ return status == B_OK ? backupStatus : status;
}
@@ -208,9 +232,8 @@ Header::_WriteHeader(int fd)
if (status != B_OK)
return status;
- // TODO: write mirror at the end
-
- return B_OK;
+ return _Write(fd, fBackupHeader.AbsoluteBlock() * fBlockSize,
+ &fBackupHeader, sizeof(efi_table_header));
}
@@ -227,6 +250,19 @@ Header::_Write(int fd, off_t offset, const void* data, size_t size) const
}
+status_t
+Header::_Read(int fd, off_t offset, void* data, size_t size) const
+{
+ ssize_t bytesRead = read_pos(fd, offset, data, size);
+ if (bytesRead < 0)
+ return bytesRead;
+ if (bytesRead != (ssize_t)size)
+ return B_IO_ERROR;
+
+ return B_OK;
+}
+
+
void
Header::_UpdateCRC()
{
@@ -238,6 +274,15 @@ Header::_UpdateCRC()
bool
+Header::_IsHeaderValid(const efi_table_header& header, uint64 block)
+{
+ return !memcmp(fHeader.header, EFI_PARTITION_HEADER, sizeof(fHeader.header))
+ && _ValidateHeaderCRC()
+ && fHeader.AbsoluteBlock() == block;
+}
+
+
+bool
Header::_ValidateHeaderCRC()
{
uint32 originalCRC = fHeader.HeaderCRC();
@@ -258,6 +303,16 @@ Header::_ValidateEntriesCRC() const
}
+void
+Header::_SetBackupHeaderFromPrimary(uint64 lastBlock)
+{
+ fBackupHeader = fHeader;
+ fBackupHeader.SetAbsoluteBlock(lastBlock);
+ fBackupHeader.SetEntriesBlock(
+ lastBlock - _EntryArraySize() / fBlockSize);
+}
+
+
#ifdef TRACE_EFI_GPT
const char *
Header::_PrintGUID(const guid_t &id)
View
14 src/add-ons/kernel/partitioning_systems/gpt/Header.h
@@ -43,27 +43,33 @@ class Header {
#endif
private:
- const char* _PrintGUID(const guid_t& id);
- void _Dump();
- void _DumpPartitions();
-
#ifndef _BOOT_MODE
status_t _WriteHeader(int fd);
status_t _Write(int fd, off_t offset, const void* data,
size_t size) const;
+ status_t _Read(int fd, off_t offset, void* data,
+ size_t size) const;
void _UpdateCRC();
#endif
+ bool _IsHeaderValid(const efi_table_header& header,
+ uint64 block);
bool _ValidateHeaderCRC();
bool _ValidateEntriesCRC() const;
+ void _SetBackupHeaderFromPrimary(uint64 lastBlock);
size_t _EntryArraySize() const
{ return fHeader.EntrySize()
* fHeader.EntryCount(); }
+ const char* _PrintGUID(const guid_t& id);
+ void _Dump();
+ void _DumpPartitions();
+
private:
uint32 fBlockSize;
status_t fStatus;
efi_table_header fHeader;
+ efi_table_header fBackupHeader;
uint8* fEntries;
};
Please sign in to comment.
Something went wrong with that request. Please try again.