Compare commits

...

9 Commits

10 changed files with 175 additions and 94 deletions

View File

@@ -398,27 +398,27 @@ typedef enum
// Advanced Intelligent Tape, types 320 to 339
// Iomega, types 340 to 359
Bernoulli = 340,
Bernoulli2 = 341,
Ditto = 342,
DittoMax = 343,
Jaz = 344,
Jaz2 = 345,
PocketZip = 346,
REV120 = 347,
REV35 = 348,
REV70 = 349,
ZIP100 = 350,
ZIP250 = 351,
ZIP750 = 352,
Bernoulli35 = 353,///< 5⅓" Bernoulli Box II disk with 35Mb capacity
Bernoulli44 = 354,///< 5⅓" Bernoulli Box II disk with 44Mb capacity
Bernoulli65 = 355,///< 5⅓" Bernoulli Box II disk with 65Mb capacity
Bernoulli90 = 356,///< 5⅓" Bernoulli Box II disk with 90Mb capacity
Bernoulli105 = 357,///< 5⅓" Bernoulli Box II disk with 105Mb capacity
Bernoulli150 = 358,///< 5⅓" Bernoulli Box II disk with 150Mb capacity
Bernoulli230 = 359,///< 5⅓" Bernoulli Box II disk with 230Mb capacity
// Iomega, types 340 to 359
Bernoulli = 340,
Bernoulli2 = 341,
Ditto = 342,
DittoMax = 343,
Jaz = 344,
Jaz2 = 345,
PocketZip = 346,
REV120 = 347,
REV35 = 348,
REV70 = 349,
ZIP100 = 350,
ZIP250 = 351,
ZIP750 = 352,
Bernoulli35 = 353, ///< 5⅓" Bernoulli Box II disk with 35Mb capacity
Bernoulli44 = 354, ///< 5⅓" Bernoulli Box II disk with 44Mb capacity
Bernoulli65 = 355, ///< 5⅓" Bernoulli Box II disk with 65Mb capacity
Bernoulli90 = 356, ///< 5⅓" Bernoulli Box II disk with 90Mb capacity
Bernoulli105 = 357, ///< 5⅓" Bernoulli Box II disk with 105Mb capacity
Bernoulli150 = 358, ///< 5⅓" Bernoulli Box II disk with 150Mb capacity
Bernoulli230 = 359, ///< 5⅓" Bernoulli Box II disk with 230Mb capacity
// Iomega, types 340 to 359
// Audio or video media, types 360 to 369
CompactCassette = 360,
@@ -1071,7 +1071,8 @@ typedef enum
MiniDiscDTOC = 72, ///< Not entirely clear kind of TOC that only appears on MD-DATA discs
DVD_DiscKey_Decrypted = 73, ///< Decrypted DVD disc key,
DVD_PFI_2ndLayer = 74, ///< DVD Physical Format Information for the second layer
MaxMediaTag = DVD_PFI_2ndLayer
Floppy_WriteProtect = 75, ///< Write protection status of the floppy disk
MaxMediaTag = Floppy_WriteProtect
} MediaTagType;
/** @} */ /* end of MediaTags group */

View File

@@ -132,7 +132,8 @@ typedef enum
DvdEccBlockPo = 87, ///< DVD Error Correction Code (ECC) Parity of Outer Code (PO)
DvdPfi2ndLayer = 88, ///< DVD Physical Format Information for the second layer
FluxData = 89, ///< Flux data.
BitstreamData = 90 ///< Bitstream data.
BitstreamData = 90, ///< Bitstream data.
FloppyWriteProtectStatus = 91 ///< Floppy write-protect status.
} DataType;
/**
@@ -162,7 +163,8 @@ typedef enum
TapePartitionBlock = 0x54425054, ///< Block containing list of partitions for a tape image.
AaruMetadataJsonBlock = 0x444D534A, ///< Block containing JSON version of Aaru Metadata
FluxDataBlock = 0x58554C46, ///< Block containing flux data metadata.
DataStreamPayloadBlock = 0x4C505344 ///< Block containing compressed data stream payload (e.g., flux data, bitstreams).
DataStreamPayloadBlock =
0x4C505344 ///< Block containing compressed data stream payload (e.g., flux data, bitstreams).
} BlockType;
/**

View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>libaaruformat</id>
<version>1.0.0-alpha.28</version>
<version>1.0.0-alpha.30</version>
<description>Library for management of AaruFormat images.</description>
<authors>claunia</authors>
<projectUrl>https://github.com/aaru-dps/libaaruformat</projectUrl>

View File

@@ -419,6 +419,7 @@ AARU_EXPORT void AARU_CALL *aaruf_create(const char *filepath, const uint32_t me
ctx->user_data_ddt_header.overflow = overflow_sectors;
ctx->user_data_ddt_header.start = 0;
ctx->user_data_ddt_header.blockAlignmentShift = parsed_options.block_alignment;
ctx->header.blockAlignmentShift = parsed_options.block_alignment;
ctx->user_data_ddt_header.dataShift = parsed_options.data_shift;
if(parsed_options.table_shift == -1 || !table_shift_found)

View File

@@ -182,6 +182,8 @@ AARU_LOCAL int32_t AARU_CALL aaruf_get_media_tag_type_for_datatype(const int32_t
return CD_LeadIn;
case DvdDiscKeyDecrypted:
return DVD_DiscKey_Decrypted;
case FloppyWriteProtectStatus:
return Floppy_WriteProtect;
default:
return -1;
}
@@ -342,6 +344,8 @@ AARU_LOCAL int32_t AARU_CALL aaruf_get_datatype_for_media_tag_type(const int32_t
return CompactDiscLeadIn;
case DVD_DiscKey_Decrypted:
return DvdDiscKeyDecrypted;
case Floppy_WriteProtect:
return FloppyWriteProtectStatus;
default:
return -1;
}

View File

@@ -467,8 +467,7 @@ AARU_EXPORT void AARU_CALL *aaruf_open(const char *filepath, const bool resume_m
switch(entry->blockType)
{
case DataBlock:
if(entry->dataType == UserData && ctx->header.biggestSectorSize > 0)
break;
if(entry->dataType == UserData && ctx->header.biggestSectorSize > 0) break;
error_no = process_data_block(ctx, entry);
@@ -508,6 +507,26 @@ AARU_EXPORT void AARU_CALL *aaruf_open(const char *filepath, const bool resume_m
return NULL;
}
switch(entry->dataType)
{
case CdSectorPrefix:
case CdSectorPrefixCorrected:
ctx->readableSectorTags[CdSectorSync] = true;
ctx->readableSectorTags[CdSectorHeader] = true;
break;
case CdSectorSuffix:
case CdSectorSuffixCorrected:
ctx->readableSectorTags[CdSectorSubHeader] = true;
ctx->readableSectorTags[CdSectorEcc] = true;
ctx->readableSectorTags[CdSectorEccP] = true;
ctx->readableSectorTags[CdSectorEccQ] = true;
ctx->readableSectorTags[CdSectorEdc] = true;
break;
default:
break;
}
break;
case GeometryBlock:
process_geometry_block(ctx, entry);

View File

@@ -28,6 +28,7 @@ int info(const char *path);
char *byte_array_to_hex_string(const unsigned char *array, int array_size);
const char *media_type_to_string(MediaType type);
const char *media_tag_type_to_string(int32_t type);
const char *sector_tag_type_to_string(int32_t type);
const char *data_type_to_string(uint16_t type);
int read_sector(unsigned long long sector_no, const char *path);
int printhex(unsigned char *array, unsigned int length, int width, bool color);

View File

@@ -204,6 +204,8 @@ const char *media_tag_type_to_string(int32_t type)
return "DVD Disc Key (decrypted)";
case DVD_PFI_2ndLayer:
return "DVD Physical Format Information (2nd layer)";
case Floppy_WriteProtect:
return "Floppy Write-Protect Status";
default:
return "Unknown Media Tag";
}
@@ -387,6 +389,8 @@ const char *data_type_to_string(uint16_t type)
return "DVD ECC Block Parity Outer";
case DvdPfi2ndLayer:
return "DVD Physical Format Info (2nd layer)";
case FloppyWriteProtectStatus:
return "Floppy Write-Protect Status";
default:
return "Unknown Data Type";
}
@@ -1534,3 +1538,56 @@ const char *media_type_to_string(MediaType type)
return "Unknown Media Type";
}
}
const char *sector_tag_type_to_string(int32_t type)
{
switch(type)
{
case AppleSonyTagAaru:
return "Apple Sony Tag";
case CdSectorSync:
return "CD Sector Sync";
case CdSectorHeader:
return "CD Sector Header";
case CdSectorSubHeader:
return "CD Sector Sub-Header";
case CdSectorEdc:
return "CD Sector EDC";
case CdSectorEccP:
return "CD Sector ECC P";
case CdSectorEccQ:
return "CD Sector ECC Q";
case CdSectorEcc:
return "CD Sector ECC (P+Q)";
case CdSectorSubchannelAaru:
return "CD Sector Subchannel";
case CdTrackIsrc:
return "CD Track ISRC";
case CdTrackText:
return "CD Track Text";
case CdTrackFlags:
return "CD Track Flags";
case DvdCmi:
return "DVD Copyright Management Information";
case FloppyAddressMark:
return "Floppy Address Mark";
case DvdSectorTitleKey:
return "DVD Sector Title Key";
case DvdTitleKeyDecrypted:
return "DVD Title Key (Decrypted)";
case DvdSectorInformation:
return "DVD Sector Information";
case DvdSectorNumber:
return "DVD Sector Number";
case DvdSectorIedAaru:
return "DVD Sector IED";
case DvdSectorEdcAaru:
return "DVD Sector EDC";
case AppleProfileTagAaru:
return "Apple Profile Tag";
case PriamDataTowerTagAaru:
return "Priam DataTower Tag";
default:
return "Unknown Sector Tag";
}
}

View File

@@ -68,17 +68,13 @@ static void init_display(void)
// Enable colors if we have a terminal that likely supports them
// If TERM is not set but we're in a TTY, assume color support (common on macOS)
if(term == NULL)
{
// Default to enabling colors if we're in a TTY
use_colors = true;
}
else if(strstr(term, "color") != NULL || strstr(term, "xterm") != NULL || strstr(term, "screen") != NULL ||
strstr(term, "tmux") != NULL || strcmp(term, "linux") == 0 || strcmp(term, "vt100") == 0)
{
use_colors = true;
}
// Check for explicit no-color requests
if(getenv("NO_COLOR") != NULL) { use_colors = false; }
if(getenv("NO_COLOR") != NULL) use_colors = false;
}
}
@@ -97,7 +93,6 @@ static void cleanup_display(void)
static void draw_box_top(const char *title, int color_pair)
{
if(use_colors)
{
// Select color based on color pair
switch(color_pair)
{
@@ -111,7 +106,6 @@ static void draw_box_top(const char *title, int color_pair)
printf(ANSI_BOLD);
break;
}
}
printf("┌─ %s ", title);
@@ -119,17 +113,16 @@ static void draw_box_top(const char *title, int color_pair)
int title_len = strlen(title);
int padding = 80 - 5 - title_len - 1; // 5 = "┌─ " + " ", -1 for "┐"
for(int i = 0; i < padding; i++) { printf(""); }
for(int i = 0; i < padding; i++) printf("");
printf("\n");
if(use_colors) { printf(ANSI_RESET); }
if(use_colors) printf(ANSI_RESET);
}
// Draw box bottom border
static void draw_box_bottom(int color_pair)
{
if(use_colors)
{
// Select color based on color pair
switch(color_pair)
{
@@ -143,13 +136,12 @@ static void draw_box_bottom(int color_pair)
printf(ANSI_BOLD);
break;
}
}
printf("");
for(int i = 0; i < 77; i++) { printf(""); }
for(int i = 0; i < 77; i++) printf("");
printf("\n\n");
if(use_colors) { printf(ANSI_RESET); }
if(use_colors) printf(ANSI_RESET);
}
// Print a formatted field with label and value, with proper padding
@@ -170,9 +162,7 @@ static void print_field(const char *label, const char *value, int label_width)
printf(ANSI_BLUE "\n" ANSI_RESET);
}
else
{
printf("│ %-76s │\n", line);
}
}
// Converts Windows FILETIME (100ns intervals since 1601-01-01) to time_t (seconds since 1970-01-01)
@@ -186,15 +176,11 @@ static const char *format_filetime(uint64_t filetime)
ft.dwLowDateTime = (DWORD)(filetime & 0xFFFFFFFF);
ft.dwHighDateTime = (DWORD)(filetime >> 32);
if(FileTimeToSystemTime(&ft, &st))
{
// Format: YYYY-MM-DD HH:MM:SS
snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute,
st.wSecond);
}
else
{
snprintf(buf, sizeof(buf), "%llu", filetime);
}
return buf;
#else
time_t t;
@@ -230,13 +216,9 @@ int info(const char *path)
if(ctx == NULL)
{
if(use_colors)
{
printf(ANSI_RED "\n❌ Error: Cannot open AaruFormat image (error code: %d)\n\n" ANSI_RESET, errno);
}
else
{
printf("\n❌ Error: Cannot open AaruFormat image (error code: %d)\n\n", errno);
}
cleanup_display();
return errno;
}
@@ -415,15 +397,11 @@ int info(const char *path)
char table_shift_str[64];
if(ctx->user_data_ddt_header.tableShift > 0)
{
snprintf(table_shift_str, sizeof(table_shift_str), "%u (2^%u = %u sectors/entry)",
ctx->user_data_ddt_header.tableShift, ctx->user_data_ddt_header.tableShift,
1 << ctx->user_data_ddt_header.tableShift);
}
else
{
snprintf(table_shift_str, sizeof(table_shift_str), "0 (single-level)");
}
print_field("Table Shift:", table_shift_str, 25);
char entries_str[32];
@@ -466,9 +444,7 @@ int info(const char *path)
aaruf_get_drive_model(ctx, NULL, &length) == AARUF_ERROR_BUFFER_TOO_SMALL ||
aaruf_get_drive_serial_number(ctx, NULL, &length) == AARUF_ERROR_BUFFER_TOO_SMALL ||
aaruf_get_drive_firmware_revision(ctx, NULL, &length) == AARUF_ERROR_BUFFER_TOO_SMALL)
{
hasMetadata = true;
}
if(hasMetadata)
{
@@ -834,7 +810,6 @@ int info(const char *path)
if(ctx->dump_hardware_entries_with_data[i].entry.extents > 0 &&
ctx->dump_hardware_entries_with_data[i].entry.extents <= 3)
{
for(uint32_t j = 0; j < ctx->dump_hardware_entries_with_data[i].entry.extents; j++)
{
char extent_str[80];
@@ -843,7 +818,6 @@ int info(const char *path)
ctx->dump_hardware_entries_with_data[i].extents[j].end);
print_field(" Extent:", extent_str, 20);
}
}
else if(ctx->dump_hardware_entries_with_data[i].entry.extents > 3)
{
char extent_str[80];
@@ -855,12 +829,13 @@ int info(const char *path)
draw_box_bottom(COLOR_HEADER);
}
if(ctx->flux_data_header.entries > 0) {
if(ctx->flux_data_header.entries > 0)
{
printf("Image contains %d flux captures.\n", ctx->flux_data_header.entries);
// Get flux capture metadata
size_t flux_captures_length = 0;
int32_t res = aaruf_get_flux_captures(ctx, NULL, &flux_captures_length);
size_t flux_captures_length = 0;
int32_t res = aaruf_get_flux_captures(ctx, NULL, &flux_captures_length);
if(res == AARUF_ERROR_BUFFER_TOO_SMALL)
{
uint8_t *flux_captures = malloc(flux_captures_length);
@@ -869,8 +844,8 @@ int info(const char *path)
res = aaruf_get_flux_captures(ctx, flux_captures, &flux_captures_length);
if(res == AARUF_STATUS_OK)
{
size_t capture_count = flux_captures_length / sizeof(FluxCaptureMeta);
const FluxCaptureMeta *captures = (const FluxCaptureMeta *)flux_captures;
size_t capture_count = flux_captures_length / sizeof(FluxCaptureMeta);
const FluxCaptureMeta *captures = (const FluxCaptureMeta *)flux_captures;
printf("Flux capture details:\n");
@@ -883,8 +858,8 @@ int info(const char *path)
// Track unique heads and tracks
uint16_t *seen_tracks = calloc(capture_count, sizeof(uint16_t));
uint32_t *seen_heads = calloc(capture_count, sizeof(uint32_t));
uint32_t track_count = 0;
uint32_t head_count = 0;
uint32_t track_count = 0;
uint32_t head_count = 0;
for(size_t i = 0; i < capture_count; i++)
{
@@ -897,32 +872,22 @@ int info(const char *path)
// Track unique tracks
bool track_seen = false;
for(uint32_t j = 0; j < track_count; j++)
{
if(seen_tracks[j] == captures[i].track)
{
track_seen = true;
break;
}
}
if(!track_seen)
{
seen_tracks[track_count++] = captures[i].track;
}
if(!track_seen) seen_tracks[track_count++] = captures[i].track;
// Track unique heads
bool head_seen = false;
for(uint32_t j = 0; j < head_count; j++)
{
if(seen_heads[j] == captures[i].head)
{
head_seen = true;
break;
}
}
if(!head_seen)
{
seen_heads[head_count++] = captures[i].head;
}
if(!head_seen) seen_heads[head_count++] = captures[i].head;
}
free(seen_tracks);
@@ -933,17 +898,13 @@ int info(const char *path)
printf("\t\tUnique heads: %u\n", head_count);
printf("\t\tUnique tracks: %u\n", track_count);
if(min_index_res != UINT64_MAX)
{
printf("\t\tIndex resolution: %llu - %llu picoseconds (%.3f - %.3f nanoseconds)\n",
(unsigned long long)min_index_res, (unsigned long long)max_index_res,
min_index_res / 1000.0, max_index_res / 1000.0);
}
if(min_data_res != UINT64_MAX)
{
printf("\t\tData resolution: %llu - %llu picoseconds (%.3f - %.3f nanoseconds)\n",
(unsigned long long)min_data_res, (unsigned long long)max_data_res,
min_data_res / 1000.0, max_data_res / 1000.0);
}
// Display individual captures
printf("\tCaptures:\n");
@@ -955,11 +916,9 @@ int info(const char *path)
printf("\t\t\tSubtrack: %u\n", captures[i].subtrack);
printf("\t\t\tCapture index: %u\n", captures[i].captureIndex);
printf("\t\t\tIndex resolution: %llu picoseconds (%.3f nanoseconds)\n",
(unsigned long long)captures[i].indexResolution,
captures[i].indexResolution / 1000.0);
(unsigned long long)captures[i].indexResolution, captures[i].indexResolution / 1000.0);
printf("\t\t\tData resolution: %llu picoseconds (%.3f nanoseconds)\n",
(unsigned long long)captures[i].dataResolution,
captures[i].dataResolution / 1000.0);
(unsigned long long)captures[i].dataResolution, captures[i].dataResolution / 1000.0);
}
}
free(flux_captures);
@@ -996,7 +955,7 @@ int info(const char *path)
free(strBuffer);
}
if(ctx->checksums.hasSpamSum) { print_field("SpamSum:", (char *)ctx->checksums.spamsum, 20); }
if(ctx->checksums.hasSpamSum) print_field("SpamSum:", (char *)ctx->checksums.spamsum, 20);
draw_box_bottom(COLOR_HEADER);
}
@@ -1011,15 +970,13 @@ int info(const char *path)
uint32_t displayed = 0;
HASH_ITER(hh, ctx->mediaTags, mediaTag, tmpMediaTag)
if(displayed < 20) // Limit display to first 20 tags
{
if(displayed < 20) // Limit display to first 20 tags
{
char tag_info[128];
snprintf(tag_info, sizeof(tag_info), "%s (%d bytes)",
media_tag_type_to_string((uint16_t)mediaTag->type), mediaTag->length);
print_field("", tag_info, 0);
displayed++;
}
char tag_info[128];
snprintf(tag_info, sizeof(tag_info), "%s (%d bytes)", media_tag_type_to_string((uint16_t)mediaTag->type),
mediaTag->length);
print_field("", tag_info, 0);
displayed++;
}
if(tag_count > 20)
@@ -1032,6 +989,42 @@ int info(const char *path)
draw_box_bottom(COLOR_HEADER);
}
// Readable Sector Tags Section
if(ctx->readableSectorTags != NULL)
{
draw_box_top("READABLE SECTOR TAGS", COLOR_HEADER);
uint32_t readable_count = 0;
// Count readable tags
for(int i = 0; i <= MaxSectorTag; i++)
if(ctx->readableSectorTags[i]) readable_count++;
if(readable_count > 0)
{
uint32_t displayed = 0;
for(int i = 0; i <= MaxSectorTag; i++)
if(ctx->readableSectorTags[i])
{
print_field("", sector_tag_type_to_string(i), 0);
displayed++;
if(displayed >= 20)
{
if(readable_count > 20)
{
char more_info[64];
snprintf(more_info, sizeof(more_info), "... and %u more tag(s)", readable_count - 20);
print_field("", more_info, 0);
}
break;
}
}
}
else
print_field("", "(No readable sector tags)", 0);
draw_box_bottom(COLOR_HEADER);
}
printf("================================================================================\n\n");
aaruf_close(ctx);

View File

@@ -124,6 +124,7 @@ static const MediaTagTypeMapping media_tag_mappings[] = {
{"MiniDiscDTOC", MiniDiscDTOC},
{"DVD_DiscKey_Decrypted", DVD_DiscKey_Decrypted},
{"DVD_PFI_2ndLayer", DVD_PFI_2ndLayer},
{"Floppy_WriteProtect", Floppy_WriteProtect},
};
// clang-format on
@@ -278,6 +279,8 @@ static int32_t get_datatype_for_media_tag_type(MediaTagType tag_type)
return CompactDiscLeadIn;
case DVD_DiscKey_Decrypted:
return DvdDiscKeyDecrypted;
case Floppy_WriteProtect:
return FloppyWriteProtectStatus;
default:
return -1;
}