|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
310c69 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
310c69 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
310c69 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
310c69 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
310c69 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
310c69 |
* GNU General Public License for more details.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
310c69 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
310c69 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
310c69 |
* 02110-1301, USA.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* $Id: //eng/uds-releases/jasper/src/uds/openChapter.c#4 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "openChapter.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "compiler.h"
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
#include "numeric.h"
|
|
Packit Service |
310c69 |
#include "zone.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
static int readOpenChapters(ReadPortal *portal);
|
|
Packit Service |
310c69 |
static int writeOpenChapters(IndexComponent *component,
|
|
Packit Service |
310c69 |
BufferedWriter *writer,
|
|
Packit Service |
310c69 |
unsigned int zone);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
const IndexComponentInfo OPEN_CHAPTER_INFO = {
|
|
Packit Service |
310c69 |
.kind = RL_KIND_OPEN_CHAPTER,
|
|
Packit Service |
310c69 |
.name = "open chapter",
|
|
Packit Service |
310c69 |
.saveOnly = true,
|
|
Packit Service |
310c69 |
.chapterSync = false,
|
|
Packit Service |
310c69 |
.multiZone = false,
|
|
Packit Service |
310c69 |
.ioStorage = true,
|
|
Packit Service |
310c69 |
.loader = readOpenChapters,
|
|
Packit Service |
310c69 |
.saver = writeOpenChapters,
|
|
Packit Service |
310c69 |
.incremental = NULL,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
static const byte OPEN_CHAPTER_MAGIC[] = "ALBOC";
|
|
Packit Service |
310c69 |
static const byte OPEN_CHAPTER_VERSION[] = "02.00";
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
enum {
|
|
Packit Service |
310c69 |
OPEN_CHAPTER_MAGIC_LENGTH = sizeof(OPEN_CHAPTER_MAGIC) - 1,
|
|
Packit Service |
310c69 |
OPEN_CHAPTER_VERSION_LENGTH = sizeof(OPEN_CHAPTER_VERSION) - 1
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static int fillDeltaChapterIndex(OpenChapterZone **chapterZones,
|
|
Packit Service |
310c69 |
unsigned int zoneCount,
|
|
Packit Service |
310c69 |
OpenChapterIndex *index,
|
|
Packit Service |
310c69 |
UdsChunkRecord *collatedRecords)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Find a record to replace any deleted records, and fill the chapter if
|
|
Packit Service |
310c69 |
// it was closed early. The last record in any filled zone is guaranteed
|
|
Packit Service |
310c69 |
// to not have been deleted in this chapter, so use one of those.
|
|
Packit Service |
310c69 |
OpenChapterZone *fillChapterZone = NULL;
|
|
Packit Service |
310c69 |
UdsChunkRecord *fillRecord = NULL;
|
|
Packit Service |
310c69 |
unsigned int z;
|
|
Packit Service |
310c69 |
for (z = 0; z < zoneCount; ++z) {
|
|
Packit Service |
310c69 |
fillChapterZone = chapterZones[z];
|
|
Packit Service |
310c69 |
if (fillChapterZone->size == fillChapterZone->capacity) {
|
|
Packit Service |
310c69 |
fillRecord = &fillChapterZone->records[fillChapterZone->size];
|
|
Packit Service |
310c69 |
break;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
int result = ASSERT((fillRecord != NULL),
|
|
Packit Service |
310c69 |
"some open chapter zone filled");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
result = ASSERT(!fillChapterZone->slots[fillChapterZone->size].recordDeleted,
|
|
Packit Service |
310c69 |
"chapter fill record not deleted");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
const Geometry *geometry = index->geometry;
|
|
Packit Service |
310c69 |
unsigned int pagesPerChapter = geometry->recordPagesPerChapter;
|
|
Packit Service |
310c69 |
unsigned int recordsPerPage = geometry->recordsPerPage;
|
|
Packit Service |
310c69 |
int overflowCount = 0;
|
|
Packit Service |
310c69 |
unsigned int recordsAdded = 0;
|
|
Packit Service |
310c69 |
unsigned int zone = 0;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
unsigned int page;
|
|
Packit Service |
310c69 |
for (page = 0; page < pagesPerChapter; page++) {
|
|
Packit Service |
310c69 |
unsigned int i;
|
|
Packit Service |
310c69 |
for (i = 0;
|
|
Packit Service |
310c69 |
i < recordsPerPage;
|
|
Packit Service |
310c69 |
i++, recordsAdded++, zone = (zone + 1) % zoneCount) {
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// The record arrays are 1-based.
|
|
Packit Service |
310c69 |
unsigned int recordNumber = 1 + (recordsAdded / zoneCount);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// If the zone has been exhausted, or the record was deleted,
|
|
Packit Service |
310c69 |
// add the fill record to the chapter.
|
|
Packit Service |
310c69 |
if (recordNumber > chapterZones[zone]->size
|
|
Packit Service |
310c69 |
|| chapterZones[zone]->slots[recordNumber].recordDeleted) {
|
|
Packit Service |
310c69 |
collatedRecords[1 + recordsAdded] = *fillRecord;
|
|
Packit Service |
310c69 |
continue;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
UdsChunkRecord *nextRecord = &chapterZones[zone]->records[recordNumber];
|
|
Packit Service |
310c69 |
collatedRecords[1 + recordsAdded] = *nextRecord;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
int result = putOpenChapterIndexRecord(index, &nextRecord->name, page);
|
|
Packit Service |
310c69 |
switch (result) {
|
|
Packit Service |
310c69 |
case UDS_SUCCESS:
|
|
Packit Service |
310c69 |
break;
|
|
Packit Service |
310c69 |
case UDS_OVERFLOW:
|
|
Packit Service |
310c69 |
overflowCount++;
|
|
Packit Service |
310c69 |
break;
|
|
Packit Service |
310c69 |
default:
|
|
Packit Service |
310c69 |
logErrorWithStringError(result, "failed to build open chapter index");
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
if (overflowCount > 0) {
|
|
Packit Service |
310c69 |
logWarning("Failed to add %d entries to chapter index", overflowCount);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int closeOpenChapter(OpenChapterZone **chapterZones,
|
|
Packit Service |
310c69 |
unsigned int zoneCount,
|
|
Packit Service |
310c69 |
Volume *volume,
|
|
Packit Service |
310c69 |
OpenChapterIndex *chapterIndex,
|
|
Packit Service |
310c69 |
UdsChunkRecord *collatedRecords,
|
|
Packit Service |
310c69 |
uint64_t virtualChapterNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Empty the delta chapter index, and prepare it for the new virtual chapter.
|
|
Packit Service |
310c69 |
emptyOpenChapterIndex(chapterIndex, virtualChapterNumber);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Map each non-deleted record name to its record page number in the delta
|
|
Packit Service |
310c69 |
// chapter index.
|
|
Packit Service |
310c69 |
int result = fillDeltaChapterIndex(chapterZones, zoneCount, chapterIndex,
|
|
Packit Service |
310c69 |
collatedRecords);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Pass the populated chapter index and the records to the volume, which
|
|
Packit Service |
310c69 |
// will generate and write the index and record pages for the chapter.
|
|
Packit Service |
310c69 |
return writeChapter(volume, chapterIndex, collatedRecords);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int saveOpenChapters(Index *index, BufferedWriter *writer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = writeToBufferedWriter(writer, OPEN_CHAPTER_MAGIC,
|
|
Packit Service |
310c69 |
OPEN_CHAPTER_MAGIC_LENGTH);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = writeToBufferedWriter(writer, OPEN_CHAPTER_VERSION,
|
|
Packit Service |
310c69 |
OPEN_CHAPTER_VERSION_LENGTH);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
uint32_t totalRecords = 0;
|
|
Packit Service |
310c69 |
unsigned int i;
|
|
Packit Service |
310c69 |
for (i = 0; i < index->zoneCount; i++) {
|
|
Packit Service |
310c69 |
totalRecords += openChapterSize(index->zones[i]->openChapter);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Store the record count in little-endian order.
|
|
Packit Service |
310c69 |
byte totalRecordData[sizeof(totalRecords)];
|
|
Packit Service |
310c69 |
storeUInt32LE(totalRecordData, totalRecords);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = writeToBufferedWriter(writer, totalRecordData,
|
|
Packit Service |
310c69 |
sizeof(totalRecordData));
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Only write out the records that have been added and not deleted.
|
|
Packit Service |
310c69 |
uint32_t recordsAdded = 0;
|
|
Packit Service |
310c69 |
unsigned int recordIndex = 1;
|
|
Packit Service |
310c69 |
while(recordsAdded < totalRecords) {
|
|
Packit Service |
310c69 |
unsigned int i;
|
|
Packit Service |
310c69 |
for (i = 0; i < index->zoneCount; i++) {
|
|
Packit Service |
310c69 |
if (recordIndex > index->zones[i]->openChapter->size) {
|
|
Packit Service |
310c69 |
continue;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
if (index->zones[i]->openChapter->slots[recordIndex].recordDeleted) {
|
|
Packit Service |
310c69 |
continue;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
UdsChunkRecord *record
|
|
Packit Service |
310c69 |
= &index->zones[i]->openChapter->records[recordIndex];
|
|
Packit Service |
310c69 |
result = writeToBufferedWriter(writer, record, sizeof(UdsChunkRecord));
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
recordsAdded++;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
recordIndex++;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return flushBufferedWriter(writer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
uint64_t computeSavedOpenChapterSize(Geometry *geometry)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return OPEN_CHAPTER_MAGIC_LENGTH + OPEN_CHAPTER_VERSION_LENGTH +
|
|
Packit Service |
310c69 |
sizeof(uint32_t) + geometry->recordsPerChapter * sizeof(UdsChunkRecord);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static int writeOpenChapters(IndexComponent *component,
|
|
Packit Service |
310c69 |
BufferedWriter *writer,
|
|
Packit Service |
310c69 |
unsigned int zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = ASSERT((zone == 0), "open chapter write not zoned");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
Index *index = indexComponentData(component);
|
|
Packit Service |
310c69 |
return saveOpenChapters(index, writer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Read the version field from a buffered reader, checking whether it is a
|
|
Packit Service |
310c69 |
* supported version. Returns (via a pointer parameter) the matching
|
|
Packit Service |
310c69 |
* version constant, which can be used by comparing to the version
|
|
Packit Service |
310c69 |
* constants using simple pointer equality.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param [in] reader A buffered reader.
|
|
Packit Service |
310c69 |
* @param [out] version The version constant that was matched.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code if the file could not be read or
|
|
Packit Service |
310c69 |
* the version is invalid or unsupported
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static int readVersion(BufferedReader *reader, const byte **version)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
byte buffer[OPEN_CHAPTER_VERSION_LENGTH];
|
|
Packit Service |
310c69 |
int result = readFromBufferedReader(reader, buffer, sizeof(buffer));
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
if (memcmp(OPEN_CHAPTER_VERSION, buffer, sizeof(buffer)) != 0) {
|
|
Packit Service |
310c69 |
return logErrorWithStringError(UDS_CORRUPT_COMPONENT,
|
|
Packit Service |
310c69 |
"Invalid open chapter version: %.*s",
|
|
Packit Service |
310c69 |
(int) sizeof(buffer), buffer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
*version = OPEN_CHAPTER_VERSION;
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static int loadVersion20(Index *index, BufferedReader *reader)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
byte numRecordsData[sizeof(uint32_t)];
|
|
Packit Service |
310c69 |
int result
|
|
Packit Service |
310c69 |
= readFromBufferedReader(reader, &numRecordsData, sizeof(numRecordsData));
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
uint32_t numRecords = getUInt32LE(numRecordsData);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Keep track of which zones cannot accept any more records.
|
|
Packit Service |
310c69 |
bool fullFlags[MAX_ZONES] = { false, };
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Assign records to the correct zones.
|
|
Packit Service |
310c69 |
UdsChunkRecord record;
|
|
Packit Service |
310c69 |
uint32_t records;
|
|
Packit Service |
310c69 |
for (records = 0; records < numRecords; records++) {
|
|
Packit Service |
310c69 |
result = readFromBufferedReader(reader, &record, sizeof(UdsChunkRecord));
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
unsigned int zone = 0;
|
|
Packit Service |
310c69 |
if (index->zoneCount > 1) {
|
|
Packit Service |
310c69 |
// A read-only index has no master index, but it also has only one zone.
|
|
Packit Service |
310c69 |
zone = getMasterIndexZone(index->masterIndex, &record.name);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
// Add records until the open chapter zone almost runs out of space.
|
|
Packit Service |
310c69 |
// The chapter can't be closed here, so don't add the last record.
|
|
Packit Service |
310c69 |
if (!fullFlags[zone]) {
|
|
Packit Service |
310c69 |
unsigned int remaining;
|
|
Packit Service |
310c69 |
result = putOpenChapter(index->zones[zone]->openChapter,
|
|
Packit Service |
310c69 |
&record.name, &record.data, &remaining);
|
|
Packit Service |
310c69 |
fullFlags[zone] = (remaining <= 1);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return UDS_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int loadOpenChapters(Index *index, BufferedReader *reader)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Read and check the magic number.
|
|
Packit Service |
310c69 |
int result =
|
|
Packit Service |
310c69 |
verifyBufferedData(reader, OPEN_CHAPTER_MAGIC, OPEN_CHAPTER_MAGIC_LENGTH);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Read and check the version.
|
|
Packit Service |
310c69 |
const byte *version = NULL;
|
|
Packit Service |
310c69 |
result = readVersion(reader, &version);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return loadVersion20(index, reader);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int readOpenChapters(ReadPortal *portal)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
Index *index = indexComponentData(portal->component);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BufferedReader *reader;
|
|
Packit Service |
310c69 |
int result = getBufferedReaderForPortal(portal, 0, &reader);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
return loadOpenChapters(index, reader);
|
|
Packit Service |
310c69 |
}
|