clawbot c86694c410 bring the repo up to repo standards (closes #1)
Adopt the standard tooling from sneak/prompts: the Makefile and script/
entrypoints, lint and test stages in one Dockerfile, the lint config, the
CI workflow and the formatter settings. make fmt also formats Go, with a
pinned Go from script/bootstrap. The module path becomes
sneak.berlin/go/dcf.

Fix the lint findings in pkg/dcf. DCFStore becomes Store and DCFObject
becomes Object. Three behaviours change. An error listing mount points is
now returned, where a typo used to drop it. Store.String() prints Store{
instead of DCFStore{, and a negative total as 0 B instead of a huge size.

Replace the placeholder test with real tests. Move the README into the
required sections. make build compiles the library; it pointed at a
command that does not exist.

Model: opus-5-5
2026-11-02 19:09:04 +00:00
2024-05-12 09:37:34 -07:00

dcf

Description

dcf is a WTFPL-licensed Go library by @sneak that reads DCF memory cards from digital cameras.

DCF is the "Design rule for Camera File system". It is also JEITA specification number CP-3461. JEITA is the Japan Electronics and Information Technology Industries Association. Wikipedia describes it at Design rule for Camera File system.

The DCF specification is why your digital camera puts images and videos in DCIM and PRIVATE/M4ROOT directories on the memory card.

dcf is incomplete and under development. It does not work yet.

Getting Started

Add the library to your Go module:

go get sneak.berlin/go/dcf

Then list the DCF stores on the mounted filesystems:

package main

import (
	"fmt"
	"log"

	"sneak.berlin/go/dcf/pkg/dcf"
)

func main() {
	stores, err := dcf.GetDCFStores(0)
	if err != nil {
		log.Fatal(err)
	}

	for _, store := range *stores {
		fmt.Println(store.String())
	}
}

To work on the library itself, you need docker and git:

git clone git@git.eeqj.de:sneak/dcf.git
cd dcf
script/setup
make check

Entrypoints

This repo adheres to the Scripts to Rule Them All standard. Each entrypoint is a POSIX sh script in script/. Use these instead of running the underlying tools directly.

  • script/bootstrap (make bootstrap) installs the tools the host needs. It does not install docker or the linter. It installs:
    • make and git
    • Go into ~/.local/go, at the version in the Dockerfile, unless the go on the PATH is already that version
    • the Go modules
    • node and yarn
    • prettier
  • script/setup (make setup) runs script/bootstrap and then installs the git pre-commit hook.
  • script/test (make test) runs the tests by building the test stage of the Dockerfile.
  • script/lint (make lint) checks the Go code by building the lint stage of the Dockerfile.
  • script/fmt (make fmt) rewrites the Go code with go fmt and the Markdown files with prettier.
  • script/fmt-check (make fmt-check) checks the same formatting and changes nothing.
  • script/check (make check) runs the tests, then the linter, then the formatting check.
  • script/build (make build) compiles every package. It needs the Go that script/bootstrap installs.
  • script/docker (make docker) builds the development image, tagged dcf.
  • script/cibuild runs the whole CI build. The Gitea workflow runs it on every push.
  • script/precommit is what the git pre-commit hook runs. It runs script/check.
  • script/install-precommit (make hooks) installs the git pre-commit hook.
  • script/projectname prints the project name for the other scripts.

The development image cannot be built unless the lint and test stages pass. Run docker run --rm -it dcf for a shell inside it, with Go and make.

Rationale

I wanted to copy images off my memory cards for processing. I also like overengineering and reusable code.

Design

All the code is in the pkg/dcf package. The repo has no commands.

  • dcf.go holds the public API. GetDCFStores finds the DCF stores and lists the files on them.
  • helpers.go finds the mount points that hold a DCF store.

The main types are:

  • Store is one DCF store on one mounted filesystem.
  • Object is one file in a store.
  • Image and Video embed Object. The file extension decides which one a file becomes.

A mounted filesystem is a DCF store when its root holds a DCIM or M4ROOT directory. dcf never mounts a filesystem.

TODO

  • Handle DCF file groups, where multiple objects share the same index number. dcf does not handle these yet. If you need this, send me a link to a zip or tar of a memory card that uses them, and I'll see what I can do.
  • Parse the DCF directory and file names, rather than listing every media file on the filesystem.
  • Look for PRIVATE/M4ROOT rather than M4ROOT when detecting a DCF store.
  • Return exactly the number of stores asked for. GetDCFStores returns one too few when asked for two or more.
  • Read stores through fs.FS, with a context.Context to cancel a walk.
  • Return a plain slice from GetDCFStores, not a pointer to one.
  • Test the walk of a store and the detection of mount points. They only run against real mounted media today.
  • Copy files off a card, and verify each copy against its SHA256 hash.

License

WTFPL. See LICENSE.

Author

@sneak <sneak@sneak.berlin>

S
Description
No description provided
Readme
237 KiB
0 Stars 1 Watchers 1 Forks
Languages
Go 97.5%
Makefile 2.5%