Files
dicom-iso/todo/02-genisoimage-to-godiskfs.md
2026-06-05 08:11:44 +07:00

4.3 KiB

Replace genisoimage with go-diskfs (pure Go ISO creation)

Why

genisoimage is the only remaining external binary dependency after the dcmtk migration. Replacing it with github.com/diskfs/go-diskfs (pure Go, MIT, 644, v1.9.3) makes the mkiso-server binary fully self-contained — zero external binaries beyond dcmtk storescp/movescu/storescu.

What

Replace pkg/dicom/command.go's RunGenISOImage() (which shells out to genisoimage) with pure Go ISO creation using go-diskfs. This affects:

Current New
service/iso.go calls dicom.RunGenISOImage() Calls isobuilder.BuildFromDirectory()
pkg/dicom/command.go has RunGenISOImage() Remove it
config.go has Tools.Genisoimage + validation Remove field + validation
config.example.yaml has tools.genisoimage Remove
handler/health.go checks genisoimage binary Remove check

go-diskfs API reference

import (
    diskfs "github.com/diskfs/go-diskfs"
    "github.com/diskfs/go-diskfs/disk"
    "github.com/diskfs/go-diskfs/filesystem"
    "github.com/diskfs/go-diskfs/filesystem/iso9660"
)

type FinalizeOptions struct {
    RockRidge        bool      // Rock Ridge extensions (long names, perms)
    Joliet           bool      // Joliet (UCS-2 names for Windows)
    DeepDirectories  bool      // Allow dirs deeper than 8 levels
    ElTorito         *ElTorito
    VolumeIdentifier string    // Volume label, default "ISOIMAGE"
    PublisherIdentifier string
}

ISO creation pattern (from go-diskfs examples/create-iso-from-folder/)

// 1. Calculate total size of directory
folderSize := dirSize(srcDir)

// 2. Create disk image file
mydisk, err := diskfs.Create(isoPath, folderSize, 2048)
mydisk.LogicalBlocksize = 2048

// 3. Create ISO9660 filesystem
fs, err := mydisk.CreateFilesystem(disk.FilesystemSpec{
    Partition:   0,
    FSType:      filesystem.TypeISO9660,
    VolumeLabel: "DICOM",
})

// 4. Walk source dir, copy files
filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
    relPath, _ := filepath.Rel(srcDir, path)
    if info.IsDir() {
        fs.Mkdir(relPath)
    } else {
        rw, _ := fs.OpenFile(relPath, os.O_CREATE|os.O_RDWR)
        io.Copy(rw, file)
        rw.Close()
    }
})

// 5. Finalize with Rock Ridge + Joliet
iso := fs.(*iso9660.FileSystem)
iso.Finalize(iso9660.FinalizeOptions{
    RockRidge:       true,
    Joliet:          true,
    DeepDirectories: true,
    VolumeIdentifier: "DICOM",
})
fs.Close()

Equivalent genisoimage flags to go-diskfs options

genisoimage flag go-diskfs FinalizeOptions
-iso-level 4 DeepDirectories: true
-r (Rock Ridge) RockRidge: true
-V DICOM VolumeIdentifier: "DICOM"
-allow-multidot Implicit via Rock Ridge
-allow-lowercase Implicit via Rock Ridge
-allow-leading-dots Implicit via Rock Ridge
-J (Joliet) Joliet: true

Implementation order

  • 1. Add go-diskfs dependencygo get github.com/diskfs/go-diskfs@v1.9.3
  • 2. Create internal/isobuilder/builder.goBuildFromDirectory(srcDir, isoPath, volumeLabel string) error
    • dirSize() helper (walk dir, sum file sizes + 10% overhead margin)
    • Walk again to create dirs + copy files
    • Finalize with RockRidge + Joliet + DeepDirectories + VolumeIdentifier
  • 3. Update internal/config/config.go
    • Remove ToolsConfig.Genisoimage field
    • Remove validation c.Tools.Genisoimage == ""
    • Remove Tools from Config struct entirely if empty (keep struct, remove field)
  • 4. Update config.example.yaml — remove tools.genisoimage section
  • 5. Update internal/service/iso.go
    • Replace both dicom.RunGenISOImage(...) calls with isobuilder.BuildFromDirectory(tempDir, isoPath, "DICOM")
    • Remove unused dicom import alias (if no longer needed in scope — it's still used for countFiles elsewhere)
  • 6. Update internal/handler/health.go
    • Remove genisoimage from the dependency check array
  • 7. Remove RunGenISOImage from pkg/dicom/command.go
    • Delete the entire function
  • 8. Build and test
    • go build ./... must pass
    • go vet ./... must pass
    • Start server, verify /api/health no longer shows genisoimage
    • Verify ISO endpoint still returns proper errors (PACS unreachable)