{"record":{"id":"130496906b502706","repo":"can1357/oh-my-pi","slug":"unsupported-rock-ridge-relocated-directory-susp","errorCode":null,"errorMessage":"Unsupported Rock Ridge relocated directory (${susp.relocation})","messagePattern":"Unsupported Rock Ridge relocated directory \\((.+?)\\)","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/iso.ts","lineNumber":521,"sourceCode":"\twhile (work.length > 0) {\n\t\tconst directory = work.pop()!;\n\t\tif (directory.depth > MAX_DIRECTORY_DEPTH) {\n\t\t\tthrow invalidIso(`directory hierarchy exceeds ${MAX_DIRECTORY_DEPTH} levels`);\n\t\t}\n\t\tconst records = await readDirectoryRecords(source, directory.record, blockSize, budget, limits);\n\t\tif (\n\t\t\tdirectory.depth === 0 &&\n\t\t\trecords.length > 0 &&\n\t\t\trecords[0]!.identifier.byteLength === 1 &&\n\t\t\trecords[0]!.identifier[0] === 0\n\t\t) {\n\t\t\tsuspSkip = findSuspSkip(records[0]!);\n\t\t}\n\t\tfor (const record of records) {\n\t\t\tif (record.identifier.byteLength === 1 && (record.identifier[0] === 0 || record.identifier[0] === 1)) continue;\n\t\t\tconst susp = await parseSusp(record, suspSkip, source, blockSize, budget, limits);\n\t\t\tif (susp.relocation) {\n\t\t\t\tthrow new ArchiveError(`Unsupported Rock Ridge relocated directory (${susp.relocation})`);\n\t\t\t}\n\t\t\tconst rawName = susp.name ?? decodeIdentifier(record.identifier, false);\n\t\t\tassertArchivePathBytes(Buffer.byteLength(rawName, \"utf-8\"), \"member name\", limits.maxPathBytes);\n\t\t\tconst rawPath = directory.parentPath ? `${directory.parentPath}/${rawName}` : rawName;\n\t\t\tconst normalizedPath = normalizeArchiveEntryPath(rawPath);\n\t\t\tif (!normalizedPath) continue;\n\t\t\tassertArchivePathBytes(Buffer.byteLength(normalizedPath, \"utf-8\"), \"member path\", limits.maxPathBytes);\n\t\t\tif (susp.symlink !== undefined) {\n\t\t\t\tassertArchivePathBytes(Buffer.byteLength(susp.symlink, \"utf-8\"), \"link target\", limits.maxPathBytes);\n\t\t\t\tconst targetPath = path.posix.isAbsolute(susp.symlink)\n\t\t\t\t\t? undefined\n\t\t\t\t\t: normalizeArchiveLookupPath(path.posix.join(path.posix.dirname(normalizedPath), susp.symlink));\n\t\t\t\tupsertArchiveEntry(entries, {\n\t\t\t\t\tpath: normalizedPath,\n\t\t\t\t\tisDirectory: false,\n\t\t\t\t\tsize: 0,\n\t\t\t\t\tmtimeMs: record.mtimeMs,\n\t\t\t\t\tmode: susp.mode,","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/iso.ts#L503-L539","documentation":"Rock Ridge allows directories to be 'relocated' (deep-directory hacks via CL/RE and PL/NM SUSP entries) so ISO 9660's 8-level nesting limit can be bypassed. This reader does not follow relocated directories: when parseSusp reports a relocation target for a directory record during full traversal, it throws instead of silently misrepresenting the tree.","triggerScenarios":"Reading an ISO image (entry/traversal path in iso.ts around line 521) that contains a Rock Ridge relocated directory — i.e. a directory record carrying the CL (child link) SUSP entry marking it as moved to a deeper level — encountered while walking directory records.","commonSituations":"ISO images with directory nesting deeper than 8 levels produced by mkisofs' -hide-rr-moved-style relocation or modern -rr defaults on very deep trees, notably some Linux distribution trees and backup archives with deep paths.","solutions":["Re-generate the image without directory relocation: mkisofs/xorriso with -r plus avoiding >8-level nesting (or use -joliet-long/UDF to carry deep paths)","Flatten or restructure the source directory tree to at most 8 levels before creating the ISO","Use an extraction tool that supports RR relocation (e.g. 7z, xorriso -osirrox) to get the files, then re-pack into a supported archive","If you control the image source, disable deep-relocation (mkisofs -D, accepting the ISO limit) or enable UDF"],"exampleFix":"// before\n$ genisoimage -R -o img.iso deepTree/        # deep relocation dir created -> throws\n// after\n$ xorriso -as mkisofs -r -D -o img.iso deepTree/  # or restructure tree to <=8 levels","handlingStrategy":"fallback","validationCode":"// detect deep relocation marker before reading: look for /RR_MOVED. or hidden relocation dir in listing\nconst names = await listIsoNames(image);\nif (names.some(n => /RR_MOVED/i.test(n))) throw new Error('image uses Rock Ridge deep relocation');","typeGuard":"null","tryCatchPattern":"try {\n  entries = await readIsoEntries(image);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('relocated directory')) {\n    return extractWith7z(image); // relocation-aware extractor, then re-pack\n  }\n  throw err;\n}","preventionTips":["Build ISOs with -D (no deep relocation) or keep trees <=8 levels","Enable UDF (-udf) for deep directory trees","Prefer xorriso for authoring; it handles deep trees without legacy RR relocation"],"tags":["iso9660","rock-ridge","relocation","unsupported-feature"],"backgroundTag":"unsupported-iso-extension","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}