{"record":{"id":"e3a9c1d150d2d037","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-file-has-an-invalid-dos-times","errorCode":null,"errorMessage":"Invalid CAB archive: file has an invalid DOS timestamp","messagePattern":"Invalid CAB archive: file has an invalid DOS timestamp","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cab.ts","lineNumber":96,"sourceCode":"\nfunction decodeName(bytes: Uint8Array, utf8: boolean): string {\n\ttry {\n\t\treturn utf8 ? UTF8_FATAL_DECODER.decode(bytes) : LEGACY_NAME_DECODER.decode(bytes);\n\t} catch {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: file name is not valid UTF-8\");\n\t}\n}\n\nfunction dosTimestamp(date: number, time: number): number | undefined {\n\tif (date === 0 && time === 0) return undefined;\n\tconst year = 1980 + (date >>> 9);\n\tconst month = (date >>> 5) & 0x0f;\n\tconst day = date & 0x1f;\n\tconst hour = time >>> 11;\n\tconst minute = (time >>> 5) & 0x3f;\n\tconst second = (time & 0x1f) * 2;\n\tif (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: file has an invalid DOS timestamp\");\n\t}\n\treturn new Date(year, month - 1, day, hour, minute, second).getTime();\n}\n\nfunction modeFromAttributes(attributes: number, directory: boolean): number {\n\tif (directory) return 0o040755;\n\tlet permissions = attributes & ATTRIBUTE_READ_ONLY ? 0o444 : 0o644;\n\tif (attributes & ATTRIBUTE_EXECUTE) permissions |= 0o111;\n\treturn 0o100000 | permissions;\n}\n\nclass CabFolder {\n\treadonly #source: ByteSource;\n\treadonly #description: CabFolderDescription;\n\treadonly #dataReserveSize: number;\n\treadonly #limits: ArchiveLimits;\n\t#decoded?: Promise<Uint8Array>;\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cab.ts#L78-L114","documentation":"dosTimestamp converts packed 16-bit DOS date/time fields from CFFILE entries into an epoch timestamp, and rejects field values that decode to an impossible calendar date (month 0 or >12, day 0 or >31, hour >23, minute/second out of range) instead of returning a garbage Date. Zero date AND time means 'no timestamp' and is permitted; any other invalid combination throws.","triggerScenarios":"fileTable()/readCabArchive() encountering a CFFILE whose uDate/uTime fields were not zero but contain bit patterns that decode to an invalid calendar value — e.g. month field = 0 with a nonzero time, or day = 0.","commonSituations":"Archives produced by buggy or nonstandard CAB writers that store sentinel values like 0xFFFF in timestamps; bit-flipped corruption in the header region; files stamped with values generated by hand-rolled packers that mishandle DOS date packing.","solutions":["Identify the offending entry and re-stamp it with a valid DOS timestamp, then rebuild the CAB (touch the source files and re-pack).","Inspect the raw uDate/uTime words in a hex dump to confirm which field is out of range.","If the archive comes from a known-buggy tool, re-create it with cabextract/lcab or a standard Windows archiver.","If corruption is suspected, verify the CAB's integrity (cabextract -t) and re-transfer the file.","If you cannot fix the source, extract with a lenient external tool and feed the extracted files to your pipeline instead of the CAB."],"exampleFix":"// before: CAB with uDate=0xFFFF fails dosTimestamp\nconst table = await reader.fileTable(); // throws\n// after: normalize timestamps before packing\n// $ touch -d '2024-01-15 10:00' src/* && lcab src/ fixed.cab\nconst table = await openCab('fixed.cab').fileTable();","handlingStrategy":"validation","validationCode":"// Validate DOS date/time words yourself before handing the archive to the reader\nfunction validDosStamp(date: number, time: number): boolean {\n  if (date === 0 && time === 0) return true;\n  const month = (date >>> 5) & 0x0f, day = date & 0x1f;\n  const hour = time >>> 11, minute = (time >>> 5) & 0x3f, second = (time & 0x1f) * 2;\n  return month >= 1 && month <= 12 && day >= 1 && day <= 31 && hour <= 23 && minute <= 59 && second <= 59;\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await readCabArchive(bytes);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('invalid DOS timestamp')) {\n    throw new Error('CAB contains out-of-range file timestamps — re-stamp and re-pack the archive');\n  }\n  throw err;\n}","preventionTips":["Rebuild archives from freshly touched files so DOS stamps are valid.","Avoid hand-rolled CAB writers that set sentinel timestamps like 0xFFFF.","Verify fixture CABs with cabextract -t before committing them to tests.","Treat timestamp errors as a corruption signal and re-transfer the archive."],"tags":["datetime","archive","cab","validation"],"backgroundTag":"invalid-dos-timestamp","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}