disko

package module
v0.0.0-...-dbc1dce Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 9, 2024 License: Apache-2.0 Imports: 7 Imported by: 0

README

Disko: A Disk Image Editor
==========================

|go-versions| |platforms|

.. |go-versions| image:: https://img.shields.io/badge/Go-1.19,%201.20,%201.21-blue.svg
.. |platforms| image::  https://img.shields.io/badge/platform-Linux%20%7C%20MacOS%20%7C%20Windows-lightgrey

I've recently gotten into retro computing and found I need to create disk images.
I also wanted to learn Go, so I figured I could kill two birds with one stone
and create a tool for doing this, written in Go.

You'll notice that there are a lot of ancient disk formats here, and nothing more
modern like extfs. This is deliberate; I need this for my retro computing projects,
so a lot of this is of no interest to anyone except those in the retro community.

Why the name? Disk + Go -> DiskGo -> Disko. Obviously.

API
---

Disko's ``Driver`` type requires a file system implementation with a minimal
interface. For details on the functions that need to be implemented, see
``DriverImplementation`` in ``api.go``.

**Symbols**

* ✔: Supported
* ⚠: Partial implementation, see notes
* ✘: Doesn't make sense for this, so the function deliberately wasn't implemented.

**Optional Features**

Implementations of file systems may need to provide support for specific features.
For convenience in the tables below, they are numbered thus:

1. Directories
2. File modes (Unix-style RWX)
3. File ownership (Unix-style UID/GID)
4. Timestamps
5. Hard links
6. Symbolic links


Base Driver
~~~~~~~~~~~

The base driver implements the following functions out of the box:

========= ======= ====================
Function  Support Required FS Features
========= ======= ====================
Chdir     ✔       1
Chmod     ✔       2
Chown     ✔       3
Chtimes   ✔       4
Create    ✔
Flush
Getwd     ✔
Lchown    ✔       3, 6
Link      ✔       5
Lstat     ✔
Mkdir     ✔
MkdirAll  ✔
Open      ✔
OpenFile  ✔
ReadDir   ✔
ReadFile  ✔
Readlink  ✔
Remove    ✔
RemoveAll ✔
Rename
SameFile  ✔
Stat      ✔
Symlink           6
Truncate  ✔
Unmount
Walk
WriteFile ✔
========= ======= ====================


Files
~~~~~

File handles support the following methods from ``os.File``:

================ ======= ====================
Function         Support Required FS Features
================ ======= ====================
Chdir            ✔       1
Chmod            ✔       2
Chown            ✔       3
Close            ✔
Fd               ✘
Name             ✔
Read             ✔
ReadAt           ✔
ReadDir          ✔       1
Readdir          ✔       1
Readdirnames     ✔       1
ReadFrom         ✔
Seek             ✔
SetDeadline      ✘
SetReadDeadline  ✘
SetWriteDeadline ✘
Stat             ✔
Sync             ✔
SyscallConn      ✘
Truncate         ✔
Write            ✔
WriteAt          ✔
WriteString      ✔
WriteTo          ✔
================ ======= ====================

File Systems
------------

The following table shows the file systems that drivers exist (or are planned)
for, as well as the status of the capabilities.

=============== ========== ================ ==== ==================== ================ ============
File System     Introduced Format New Image Read Write Existing Files Create New Files Delete Files
=============== ========== ================ ==== ==================== ================ ============
Unix v1 [#]_    1971       ✔
Unix v2         1972
Unix v5         1973
CP/M 1.4        1974
Unix v6         1975
FAT 8           1977       ✔
CP/M 2.2        1979
Unix v7         1979
FAT 12          1980
CP/M 3.1        1983
FAT 16          1984
CP/M 4.1 [#]_   1985
MINIX 3 [#]_    1987
Unix v10        1989
FAT 32          1996
XV6 (maybe)     2006
=============== ========== ================ ==== ==================== ================ ============

*Legend:*

* ✔: Full support
* ``B``: Beta, largely stable, may contain bugs
* ``A``: Alpha, use at your peril


CLI Features
------------

========================= ======
Feature                   Status
========================= ======
Create blank image
List files
Insert individual files
Insert directory trees
Remove individual files
Remove using shell globs
Remove trees
Extract individual files
Extract directory trees
Extract using shell globs
Interactive editing
========================= ======

Development & Usage
-------------------

I make the following guarantees:

* Versioning strictly follows `the guidelines <https://go.dev/doc/modules/version-numbers>`_
  in Go's documentation.
* This is tested on:

  * The latest three minor versions of Go, e.g. if 1.19.x is the most recent
    release, I will test this on 1.17, 1.18, and 1.19.
  * The latest versions of Ubuntu, Windows, and MacOS that are supported by
    GitHub.

Further Reading
---------------

* `UNIX v1 File System`_
*  `Full UNIX v1 Manual`_, relevant parts pages 171-174.
*  `Full UNIX v2 Manual`_, relevant parts pages 221-224.
*  `Full UNIX v5 Manual`_, relevant parts pages 237-238.
* `UNIX v6 File System`_
* `UNIX v10 File System`_
* `FAT 8`_, documenting FAT 8 on pages 172, 176, and 178.
* `FAT 12/16/32 on Wikipedia`_
* `CP/M file systems`_, including extensions.
* `MINIX 3 <https://flylib.com/books/en/3.275.1.54/1/>`_, shorter explanation `here <http://ohm.hgesser.de/sp-ss2012/Intro-MinixFS.pdf>`_.

.. _UNIX v1 File System: http://man.cat-v.org/unix-1st/5/file
.. _Full UNIX v1 Manual: http://www.bitsavers.org/pdf/bellLabs/unix/UNIX_ProgrammersManual_Nov71.pdf
.. _Full UNIX v2 Manual: https://web.archive.org/web/20161006034736/http://sunsite.icm.edu.pl/pub/unix/UnixArchive/PDP-11/Distributions/research/1972_stuff/unix_2nd_edition_manual.pdf
.. _Full UNIX v5 Manual: https://www.tuhs.org/Archive/Distributions/Research/Dennis_v5/v5man.pdf
.. _UNIX v6 File System: http://man.cat-v.org/unix-6th/5/fs
.. _UNIX v10 File System: http://man.cat-v.org/unix_10th/5/filsys
.. _FAT 12/16/32 on Wikipedia: https://en.wikipedia.org/wiki/File_Allocation_Table
.. _FAT 8: http://bitsavers.trailing-edge.com/pdf/xerox/820-II/BASIC-80_5.0.pdf
.. _CP/M file systems: https://www.seasip.info/Cpm/formats.html

License
-------

This is released under the terms of the Apache 2.0 License. Please see LICENSE.txt
in this repository for the legal text.

Acknowledgments
---------------

This project uses open-source software built by other people, who have my
gratitude for building things so that I don't have to. [#]_

* `Bol Christophe <https://github.com/boljen>`_
* `gocarina <https://github.com/gocarina>`_
* `HashiCorp <https://github.com/hashicorp>`_
* `Tim Scheuermann <https://github.com/noxer>`_
* `urfave <https://github.com/urfave>`_

Footnotes
---------

.. [#] Timestamps are stored according to the 1973 revision that uses the canonical
       Unix epoch. The first version of the specification can't represent
       timestamps past 1973-04-08 12:06:28.250.
.. [#] Also known as "DOS Plus".
.. [#] Note this is version 3 of the file system, not MINIX version 3.
.. [#] This should not be taken to imply that any of the people or organizations
       listed here endorse or are associated with this project. It's just a thank you.

Documentation

Index

Constants

View Source
const (
	// MountFlagsAllowRead indicates to Driver.Mount() that the image should be
	// mounted with read permissions.
	MountFlagsAllowRead = MountFlags(1 << iota)

	// MountFlagsAllowWrite indicates to Driver.Mount() that the image should be
	// mounted with write permissions. Existing files can be modified, but
	// nothing can be created or deleted.
	MountFlagsAllowWrite = MountFlags(1 << iota)

	// MountFlagsAllowInsert indicates to Driver.Mount() that the image should
	// be mounted with insert permissions. New files and directories can be
	// created and modified, but existing files cannot be touched unless
	// MountFlagsAllowWrite is also specified.
	MountFlagsAllowInsert = MountFlags(1 << iota)

	// MountFlagsAllowDelete indicates to Driver.Mount() that the image should
	// be mounted with permissions to delete files and directories.
	MountFlagsAllowDelete = MountFlags(1 << iota)

	// MountFlagsAllowAdminister indicates to Driver.Mount() that the image
	// should be mounted with the ability to change file permissions.
	MountFlagsAllowAdminister = MountFlags(1 << iota)

	// MountFlagsPreserveTimestamps indicates that existing objects'
	// LastAccessed, LastModified, LastChanged, and DeletedAt timestamps should
	// NOT be changed. There are a few exceptions:
	//
	// Objects created or deleted will have their timestamps set appropriately
	// and then left alone for the duration of the mount.
	MountFlagsPreserveTimestamps = MountFlags(1 << iota)

	// MountFlagsCustomStart is the lowest bit flag that is not defined by the
	// API standard and is free for drivers to use in an implementation-specific
	// manner. All bits higher than this are guaranteed to be ignored by drivers
	// that do not recognize them.
	MountFlagsCustomStart = MountFlags(1 << iota)
)

TODO (dargueta): These permissions are too granular and don't make a lot of sense.

View Source
const (
	S_IXOTH = os.FileMode(1 << iota)
	S_IWOTH = os.FileMode(1 << iota)
	S_IROTH = os.FileMode(1 << iota)
	S_IXGRP = os.FileMode(1 << iota)
	S_IWGRP = os.FileMode(1 << iota)
	S_IRGRP = os.FileMode(1 << iota)
	S_IXUSR = os.FileMode(1 << iota)
	S_IWUSR = os.FileMode(1 << iota)
	S_IRUSR = os.FileMode(1 << iota)
	S_ISVTX = os.FileMode(1 << iota)
	S_ISGID = os.FileMode(1 << iota)
	S_ISUID = os.FileMode(1 << iota)
	S_IFIFO = os.FileMode(1 << iota)
	S_IFCHR = os.FileMode(1 << iota)
	S_IFDIR = os.FileMode(1 << iota)
	S_IFREG = os.FileMode(1 << iota)
)
View Source
const DefaultDirModeFlags = os.ModeDir | S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH
View Source
const DefaultFileModeFlags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
View Source
const FSTextEncodingASCII = "ascii"
View Source
const FSTextEncodingBCDIC = "bcdic"
View Source
const FSTextEncodingEBCDIC = "ebcdic"
View Source
const FSTextEncodingUTF8 = "utf8"
View Source
const GiB = MiB * 1024
View Source
const KiB = 1024
View Source
const MiB = KiB * 1024
View Source
const MountFlagsAllowReadWrite = MountFlagsAllowRead | MountFlagsAllowWrite
View Source
const MountFlagsMask = MountFlagsCustomStart - 1
View Source
const O_ACCMODE = O_RDONLY | O_RDWR | O_WRONLY
View Source
const O_APPEND = IOFlags(0x00000008)
View Source
const O_CREATE = IOFlags(0x00000200)
View Source
const O_DIRECTORY = IOFlags(0x00200000)
View Source
const O_EXCL = IOFlags(0x00000800)
View Source
const O_NOATIME = IOFlags(0x01000000)
View Source
const O_NOFOLLOW = IOFlags(0x00100000)
View Source
const O_PATH = IOFlags(0x02000000)
View Source
const O_RDONLY = IOFlags(0x00000000)
View Source
const O_RDWR = IOFlags(0x00000002)
View Source
const O_SYNC = IOFlags(0x00002000)
View Source
const O_TMPFILE = IOFlags(0x00800000) // Probably don't need this
View Source
const O_TRUNC = IOFlags(0x00000400)
View Source
const O_WRONLY = IOFlags(0x00000001)
View Source
const S_IEXEC = S_IXUSR
View Source
const S_IFBLK = 0x6000 // 0110 0000 0000 0000
View Source
const S_IFLNK = 0xa000 // 1010 0000 0000 0000
View Source
const S_IFMT = 0xf000
View Source
const S_IFSOCK = 0xc000 // 1100 0000 0000 0000
View Source
const S_IREAD = S_IRUSR
View Source
const S_IRWXG = S_IXGRP | S_IWGRP | S_IRGRP
View Source
const S_IRWXO = S_IXOTH | S_IWOTH | S_IROTH
View Source
const S_IRWXU = S_IXUSR | S_IWUSR | S_IRUSR
View Source
const S_IWRITE = S_IWUSR

Variables

View Source
var ErrAlreadyInProgress = rootError.WithMessage("Operation already in progress")
View Source
var ErrArgumentOutOfRange = rootError.WithMessage("Numerical argument out of domain")
View Source
var ErrBlockDeviceRequired = rootError.WithMessage("Block device required")
View Source
var ErrBusy = rootError.WithMessage("Device or resource busy")
View Source
var ErrCrossDeviceLink = rootError.WithMessage("Invalid cross-device link")
View Source
var ErrDirectoryNotEmpty = rootError.WithMessage("Directory not empty")
View Source
var ErrDiskQuotaExceeded = rootError.WithMessage("Disk quota exceeded")
View Source
var ErrExists = rootError.WithMessage("File exists")
View Source
var ErrFileDescriptorBadState = rootError.WithMessage("File descriptor in bad state")
View Source
var ErrFileSystemCorrupted = rootError.WithMessage("Structure needs cleaning")
View Source
var ErrFileTooLarge = rootError.WithMessage("File too large")
View Source
var ErrIOFailed = rootError.WithMessage("Input/output error")
View Source
var ErrInvalidArgument = rootError.WithMessage("Invalid argument")
View Source
var ErrInvalidFileDescriptor = rootError.WithMessage("Bad file descriptor")
View Source
var ErrInvalidFileSystem = rootError.WithMessage("Wrong medium type")
View Source
var ErrIsADirectory = rootError.WithMessage("Is a directory")
View Source
var ErrLinkCycleDetected = rootError.WithMessage("Symlink cycle detected")
View Source
var ErrNameTooLong = rootError.WithMessage("File name too long")
View Source
var ErrNoDevice = rootError.WithMessage("No such device")
View Source
var ErrNoSpaceOnDevice = rootError.WithMessage("No space left on device")
View Source
var ErrNotADirectory = rootError.WithMessage("Not a directory")
View Source
var ErrNotFound = rootError.WithMessage("No such file or directory")
View Source
var ErrNotImplemented = rootError.WithMessage("Function not implemented")
View Source
var ErrNotPermitted = rootError.WithMessage("Operation not permitted")
View Source
var ErrNotSupported = rootError.WithMessage("Operation not supported")
View Source
var ErrPermissionDenied = rootError.WithMessage("Permission denied")
View Source
var ErrReadOnlyFileSystem = rootError.WithMessage("Read-only file system")
View Source
var ErrResultOutOfRange = rootError.WithMessage("Numerical result out of range")
View Source
var ErrTooManyLinks = rootError.WithMessage("Too many links")
View Source
var ErrTooManyOpenFiles = rootError.WithMessage("Too many open files in system")
View Source
var ErrTooManyUsers = rootError.WithMessage("Too many users")
View Source
var UndefinedTimestamp = time.Time{}

UndefinedTimestamp is a timestamp that should be used as an invalid value, equivalent to `nil` for pointers.

To check if a timestamp is invalid, use time.Time.IsZero. Direct comparison to this is not recommended.

Functions

This section is empty.

Types

type BootCodeImplementer

type BootCodeImplementer interface {
	// SetBootCode sets the machine code that is executed on startup if the disk
	// image is used as a boot volume. If the code provided is too short then
	// the implementation should pad it with bytes to fit. This is guaranteed to
	// be at most [FSFeatures.MaxBootCodeSize] bytes.
	SetBootCode(code []byte) DriverError

	// GetBootCode returns the machine code that is executed on startup.
	GetBootCode(buffer []byte) (int, DriverError)
}

A BootCodeImplementer implements access to the boot code stored on a file system.

This specifically refers to boot code defined in the file system specification, not a ramdisk image or something stored as a file on the file system that is used by the operating system for booting.

type DirectoryEntry

type DirectoryEntry interface {
	os.DirEntry
	Stat() FileStat
}

DirectoryEntry represents a file, directory, device, or other entity encountered on the file system. It must implement the os.FileInfo interface but [Stat] only needs to fill values in FileStat for features it supports.

type Driver

type Driver interface {
	// NormalizePath converts a path from the user's native file system syntax
	// to an absolute normalized path using forward slashes (/) as the component
	// separator. The return value is always an absolute path. If the argument
	// is a relative path, it's computed relative to the working directory as
	// returned by [Driver.Getwd].
	NormalizePath(path string) string

	// GetFSFeatures returns a struct that gives the various features the file
	// system supports, regardless of whether the driver implements these
	// features or not.
	GetFSFeatures() FSFeatures

	Chdir(path string) error
	Chmod(name string, mode os.FileMode) error
	Chown(name string, uid, gid int) error
	Chtimes(name string, atime time.Time, mtime time.Time) error
	Create(path string) (File, error)
	Getwd() (string, error)
	Lchown(name string, uid, gid int) error
	Link(oldname, newname string) error
	Lstat(path string) (FileStat, error)
	Mkdir(path string, perm os.FileMode) error
	MkdirAll(path string, perm os.FileMode) error
	Open(path string) (File, error)
	OpenFile(path string, flags IOFlags, perm os.FileMode) (File, error)
	ReadDir(path string) ([]DirectoryEntry, error)
	ReadFile(path string) ([]byte, error)
	Readlink(path string) (string, error)
	Remove(path string) error
	RemoveAll(path string) error
	Rename(old string, new string) error
	SameFile(fi1, fi2 os.FileInfo) bool
	Stat(path string) (FileStat, error)
	Symlink(oldname, newname string) error
	Truncate(path string) error
	Unmount() error
	WriteFile(path string, data []byte, perm os.FileMode) error
}

Driver is the interface implemented by the base file system driver that wraps a file system implementation. For most functions, the functionality is the same as the equivalent function in the os package.

The presence of a function doesn't imply that the file system it's wrapping supports or implements that feature, so be sure to check the returned errors if you need something to happen.

For most users, [disko.driver.BasicDriver] will meet most needs.

type DriverError

type DriverError interface {
	error
	WithMessage(message string) DriverError
	Wrap(err error) DriverError
}

func CastToDriverError

func CastToDriverError(err error) DriverError

CastToDriverError ensures that the argument is a DriverError. If `err` is is nil or already a DriverError, it's returned unmodified. Otherwise the error object is wrapped in a generic DriverError.

func NewError

func NewError(message string) DriverError

NewError creates a new basic DriverError with the given message.

type FSFeatures

type FSFeatures struct {
	// DoesNotRequireFormatting is true if and only if a driver doesn't need to
	// format an image before use. This is mostly only used for archive formats.
	DoesNotRequireFormatting bool

	// HasDirectories indicates if the file system supports directories, but
	// makes no assertion as to whether any nesting is supported.
	HasDirectories   bool
	HasSymbolicLinks bool
	HasHardLinks     bool
	HasCreatedTime   bool
	HasAccessedTime  bool
	HasModifiedTime  bool
	HasChangedTime   bool
	HasDeletedTime   bool

	// HasUnixPermissions is true if the file system supports a permissions model
	// similar to user/group/other, read/write/execute model that Unix uses. The
	// file system does not need to support group permissions to set this.
	HasUnixPermissions bool

	HasUserPermissions  bool
	HasGroupPermissions bool
	HasUserID           bool
	HasGroupID          bool

	// TimestampEpoch returns the earliest representable timestamp on this file
	// system. File systems that don't support timestamps of any kind must set
	// this to [UndefinedTimestamp].
	TimestampEpoch time.Time

	// DefaultNameEncoding gives the name of the text encoding natively used by
	// the file system for directory and file names (not file contents!).
	//
	// This must be lowercase with no symbols (e.g. "utf8" not "UTF-8"). For
	// systems this old it will most likely be either "ascii" or "ebcdic".
	DefaultNameEncoding string
	SupportsBootCode    bool

	// MaxBootCodeSize gives the maximum number of bytes that can be stored as
	// boot code in the file system. File systems that don't support boot code
	// must return 0. File systems that don't have a theoretical upper limit
	// should set this to [math.MaxInt].
	MaxBootCodeSize int

	// DefaultBlockSize gives the default size of a single block in the file
	// system, in bytes. File systems that don't have fixed block sizes (such as
	// certain types of archives) must set this to 0.
	DefaultBlockSize int

	// MinTotalBlocks is the smallest possible size of the file system, in blocks.
	MinTotalBlocks int64

	// MaxTotalBlocks is the largest possible size of the file system, in blocks.
	MaxTotalBlocks int64

	// MaxVolumeLabelSize gives the maximum size of the volume label for the
	// file system, in bytes. If volume labels are not supported by the file
	// system, this should be 0. If there's no length limit, this should be
	// [math.MaxInt].
	MaxVolumeLabelSize int
}

FSFeatures indicates the features available for the file system. If a file system supports a feature, driver implementations MUST declare it as available even if it hasn't implemented it yet.

type FSStat

type FSStat struct {
	// BlockSize is the size of a logical block on the file system, in bytes.
	BlockSize uint

	// TotalBlocks is the total number of blocks on the disk image.
	TotalBlocks uint64

	// BlocksFree is the number of unallocated blocks on the image.
	BlocksFree uint64

	// BlocksAvailable is the number of blocks available for use by user data.
	// This should always be less than or equal to [FSStat.BlocksFree].
	BlocksAvailable uint64

	// Files is the total number of used directory entries on the file system.
	// Implementations should return 0 if the information is not available.
	Files uint64

	// FilesFree is the number of remaining directory entries available for use.
	// Implementations should return [math.MaxUint64] for file systems that have
	// no limit on the maximum number of directory entries.
	FilesFree uint64

	// FileSystemID is the serial number for the disk image, if available.
	FileSystemID string

	// MaxNameLength is the longest possible name for a directory entry, in
	// bytes. Implementations should return [math.MaxUint] if there is no limit.
	MaxNameLength uint

	// Label is the volume label, if available.
	Label string
}

FSStat is a platform-independent form of syscall.Statfs_t.

type File

type File interface {
	io.ReadWriteCloser
	io.Seeker
	io.ReaderAt
	io.ReaderFrom
	io.WriterAt
	io.StringWriter
	common.Truncator

	Chdir() error
	Chmod(mode os.FileMode) error
	Chown(uid, gid int) error
	Name() string
	ReadDir(n int) ([]os.DirEntry, error)
	Readdir(n int) ([]os.FileInfo, error)
	Readdirnames(n int) ([]string, error)
	Stat() (os.FileInfo, error)
	Sync() error
}

File is the expected interface for file handles from drivers.

This interface is intended to be more or less a drop-in replacement for os.File, *however* not all functions are implemented. In particular, all deadline-related functions and `Fd` are excluded. For a full list of what is and isn't supported, see the documentation in the README.

type FileStat

type FileStat struct {
	DeviceID     uint64
	InodeNumber  uint64
	Nlinks       uint64
	ModeFlags    os.FileMode
	Uid          uint32
	Gid          uint32
	Rdev         uint64
	Size         int64
	BlockSize    int64
	NumBlocks    int64
	CreatedAt    time.Time
	LastChanged  time.Time
	LastAccessed time.Time
	LastModified time.Time
	DeletedAt    time.Time
}

FileStat is a platform-independent form of syscall.Stat_t.

If a file system doesn't support a particular feature, implementations should use a reasonable default value. For most of these 0 is fine, but for compatibility they should use 1 for `Nlinks`, and 0o777 for `ModeFlags`. Unsupported timestamps MUST be set to UndefinedTimestamp.

func (*FileStat) IsDir

func (stat *FileStat) IsDir() bool

IsDir returns true if and only if the file descriptor is a directory.

func (*FileStat) IsFile

func (stat *FileStat) IsFile() bool

IsFile returns true if and only if the file descriptor is a normal file; hard links count as normal, symbolic links do not.

func (stat *FileStat) IsSymlink() bool

IsSymlink returns true if and only if the file descriptor is a symbolic link, irrespective of what type of object the symbolic link points to.

type FileSystemImplementer

type FileSystemImplementer interface {
	// Mount initializes the file system implementation with access settings.
	Mount(flags MountFlags) DriverError

	// Flush writes out all pending changes to the disk image. The file system
	// must be left in a valid state once this is finished. Files and file
	// handles *may* be open when this is called, so implementations must
	// ensure these remain in a usable state.
	//
	// This will only be called if [Mount] returned successfully.
	Flush() DriverError

	// Unmount writes out all pending changes to the disk image and releases any
	// resources the implementation may be holding.
	//
	// The following guarantees apply when this function is called:
	//
	//  - [Flush] will already have been called.
	//	- There will be no open files or other handles (directory traversers, etc.)
	//	  when this is called.
	Unmount() DriverError

	// CreateObject creates an object on the file system, such as a file or
	// directory. You can tell what it is based on the [os.FileMode] flags.
	//
	// The following guarantees apply when this function is called:
	//
	// 	- This will never be called for an object that already exists.
	//  - `parent` will always be a valid object handle.
	CreateObject(
		name string,
		parent ObjectHandle,
		perm os.FileMode,
	) (ObjectHandle, DriverError)

	// GetObject returns a handle to an object with the given name in a directory
	// specified by `parent`.
	//
	// The following guarantees apply when this function is called:
	//
	// 	- This will never be called for a nonexistent object.
	//	- `parent` will always be a valid object handle.
	GetObject(name string, parent ObjectHandle) (ObjectHandle, DriverError)

	// GetRootDirectory returns a handle to the root directory of the disk image.
	// This must always be a valid object handle, even if directories are not
	// supported by the file system (e.g. FAT8).
	GetRootDirectory() ObjectHandle

	// FSStat returns information about the file system. Multiple calls to this
	// function must return identical data if no modifications have been made
	// to the file system.
	FSStat() FSStat

	// GetFSFeatures returns a struct that gives the various features the file
	// system specification supports, regardless of whether this driver
	// implementation supports these features or not.
	//
	// The results are independent of the volume's contents, so this must always
	// return a valid value even if the volume isn't mounted or is corrupted.
	GetFSFeatures() FSFeatures
}

FileSystemImplementer is the minimum interface required for all file system implementations.

type FormatImageImplementer

type FormatImageImplementer interface {
	// FormatImage creates a new blank file system on the image this was created
	// with, using characteristics defined in `options`.
	//
	// The following guarantees apply when this function is called:
	//
	//  - The image will already be correctly sized according to `options`.
	//  - It will consist entirely of null bytes.
	FormatImage(options disks.BasicFormatterOptions) DriverError
}

A FormatImageImplementer initializes an empty disk image.

type HardLinkImplementer

type HardLinkImplementer interface {
	// CreateHardLink creates a new file system object that is a hard link from
	// the source to the target.
	//
	// The following guarantees apply when this function is called:
	//
	//	- The target will not already exist.
	//	- `source` will never be a directory.
	//	- `targetParentDir` will always be an existing directory.
	//
	// A thoroug explanation for why hard links are disallowed for directories
	// can be found here: https://askubuntu.com/a/525129
	CreateHardLink(
		source ObjectHandle,
		targetParentDir ObjectHandle,
		targetName string,
	) (ObjectHandle, DriverError)
}

A HardLinkImplementer implements hard linking from one object to another.

type IOFlags

type IOFlags int

func OSFlagsToIOFlags

func OSFlagsToIOFlags(flags int) IOFlags

OSFlagsToIOFlags converts mode flags used for os.OpenFile into IOFlags recognized by Disko.

func (IOFlags) Append

func (flags IOFlags) Append() bool

Append indicates if the mode flags require appending to the end of a file stream.

func (IOFlags) Create

func (flags IOFlags) Create() bool

func (IOFlags) Exclusive

func (flags IOFlags) Exclusive() bool

func (IOFlags) NoFollow

func (flags IOFlags) NoFollow() bool

func (IOFlags) Read

func (flags IOFlags) Read() bool

func (IOFlags) RequiresWritePerm

func (flags IOFlags) RequiresWritePerm() bool

func (IOFlags) Synchronous

func (flags IOFlags) Synchronous() bool

func (IOFlags) Truncate

func (flags IOFlags) Truncate() bool

func (IOFlags) Write

func (flags IOFlags) Write() bool

type ImplementerConstructor

type ImplementerConstructor func(stream io.ReadWriteSeeker) (FileSystemImplementer, DriverError)

type MountFlags

type MountFlags int

func (MountFlags) CanDelete

func (flags MountFlags) CanDelete() bool

func (MountFlags) CanRead

func (flags MountFlags) CanRead() bool

func (MountFlags) CanWrite

func (flags MountFlags) CanWrite() bool

type ObjectHandle

type ObjectHandle interface {
	// Stat returns information on the status of the file as it appears on disk.
	Stat() FileStat

	// Resize changes the size of the object, in bytes. Drivers are responsible
	// for ensuring the needed number of blocks are allocated or freed.
	Resize(newSize uint64) DriverError

	// ReadBlocks fills `buffer` with data from a sequence of logical blocks
	// beginning at `index`. The following guarantees apply when this function
	// is called:
	//
	//   - `buffer` is a nonzero multiple of the size of a block.
	//   - The read range will always be within the current boundaries of the
	//     object.
	ReadBlocks(index common.LogicalBlock, buffer []byte) DriverError

	// WriteBlocks writes bytes from `buffer` into a sequence of logical blocks
	// beginning at `index`. The following guarantees apply when this function
	// is called:
	//
	//   - `buffer` is a nonzero multiple of the size of a block.
	//   - The write range will always be within the current boundaries of the
	//     object.
	WriteBlocks(index common.LogicalBlock, data []byte) DriverError

	// ZeroOutBlocks tells the implementation to treat `count` logical blocks
	// beginning at `startIndex` as consisting entirely of null bytes (0). It
	// does not change the size of the object.
	//
	// Functionally, it's equivalent to:
	//
	//		buffer := make([]byte, BlockSize * NUM_BLOCKS)
	//		WriteBlocks(START_BLOCK, buffer)
	//
	// The following guarantees apply when this function is called:
	//
	//   - `count` is nonzero.
	//   - `[startIndex, startIndex + count)` will always be within the current
	//     boundaries of the object.
	//
	// Some file systems have optimizations for such "holes" that can save disk
	// space. It's up to the file system implementation to handle this case, as
	// well as consolidating holes where possible. The driver doesn't care what
	// the implementation does as long as a subsequent call to [ReadBlocks] on
	// this range returns all null bytes.
	ZeroOutBlocks(startIndex common.LogicalBlock, count uint) DriverError

	// Unlink deletes the file system object. For directories, this is guaranteed
	// to not be called unless [ListDir] returns an empty slice (aside from "."
	// and ".." if present, as the driver cannot assume these exist).
	Unlink() DriverError

	// Name returns the name of the object itself without any path component.
	// The root directory, which technically has no name, must return "/".
	Name() string

	// SameAs returns a boolean indicating if this object handle refers to the
	// same on-disk object as the given handle. A few rules:
	//
	//   - Attributes such as size, timestamps, number of links, etc. should be
	//     ignored. This is only comparing identity, not properties.
	//   - Symbolic links should not be dereferenced, so X and Y are not the same
	//     even if X is a symbolic link to Y.
	//   - Hard links are considered the same as the files they refer to.
	//
	// For a UNIX-like file system, this is equivalent to comparing the inumbers.
	SameAs(other ObjectHandle) bool

	// Close frees any resources associated with the handle, such as open file
	// descriptors or temporary directories. The handle cannot be used after
	// calling this method.
	//
	// 	- Closing a handle on a deleted object must not return an error.
	//	- Subsequent calls should return [disko.ErrFileDescriptorBadState].
	Close() error
}

ObjectHandle is an interface for a way to interact with on-disk file system objects.

type SupportsChmodHandle

type SupportsChmodHandle interface {
	// Chmod changes the permission bits of this file system object. Only the
	// permissions bits will be set in `mode`.
	//
	// File systems that support access controls but not all aspects (e.g. no
	// executable bit, or no group permissions) must silently ignore flags they
	// don't recognize.
	Chmod(mode os.FileMode) DriverError
}

SupportsChmodHandle is an interface for an ObjectHandle that supports changing its mode flags.

type SupportsChownHandle

type SupportsChownHandle interface {
	// Chown sets the ID of the owning user and group for this object. If the
	// file system doesn't support group IDs, implementations must silently
	// ignore `gid`, whatever its value.
	Chown(uid, gid int) DriverError
}

SupportsChownHandle is an interface for an ObjectHandle that supports changing its owning user and group IDs.

type SupportsChtimesHandle

type SupportsChtimesHandle interface {
	// Chtimes changes various timestamps associated with an object. The driver
	// will do its best to ensure that unsupported timestamps are equal to
	// [UndefinedTimestamp], but the implementation must ignore timestamps it
	// doesn't support.
	//
	// The following guarantees apply when this function is called:
	//
	//  - Timestamps known to be unsupported (i.e. the corresponding feature in
	//    [FSFeatures] is false) will always be [UndefinedTimestamp].
	//  - `deletedAt` will only be set if the object has been deleted and the
	//    flag is supported by the file system.
	//
	// If a supported timestamp is passed in as [UndefinedTimestamp],
	// implementations should not modify the existing timestamp for the object.
	Chtimes(
		createdAt,
		lastAccessed,
		lastModified,
		lastChanged,
		deletedAt time.Time,
	) DriverError
}

SupportsChtimesHandle is an interface for an ObjectHandle that supports changing its created/modified/etc. timestamps.

type SupportsListDirHandle

type SupportsListDirHandle interface {
	// ListDir returns a list of the directory entries this object contains. "."
	// and ".." are ignored if present.
	ListDir() ([]string, DriverError)
}

SupportsListDirHandle is an interface for an ObjectHandle that represents a directory to implement so that its contents can be accessed.

type VolumeLabelImplementer

type VolumeLabelImplementer interface {
	// SetVolumeLabel sets the volume label on the file system.
	//
	// `label` is guaranteed to be UTF-8 encoded. Implementations should convert
	// the string to the native character set if needed.
	//
	// To avoid nasty surprises, callers should try to stick to printable ASCII
	// characters and avoid non-punctuation symbols. This is because pre-1977
	// versions of the ASCII standard allowed some variance in how the same
	// character code could be depicted, e.g. `!` could also render as `|`.
	// (This is why on old keyboards the pipe character looks like `╎` to avoid
	// confusion.)
	// Thus, if you set the volume label to "(^_^)" you may get "(¬_¬)" when you
	// read it back -- a very different sentiment.
	SetVolumeLabel(label string) DriverError

	// GetVolumeLabel gets the volume label from the file system.
	//
	// The return value is guaranteed to be UTF-8 encoded. Implementations must
	// remove any padding from the return value, if applicable (and possible).
	GetVolumeLabel() (string, DriverError)
}

A VolumeLabelImplementer allows getting and setting the volume label on the file system for those file systems that support it.

Directories

Path Synopsis
cmd
file_systems
common
Package common contains definitions of fundamental types and functions used across multiple file system implementations.
Package common contains definitions of fundamental types and functions used across multiple file system implementations.
fat
Package fat implements a driver for accessing FAT file systems.
Package fat implements a driver for accessing FAT file systems.
unixv10
http://man.cat-v.org/unix_10th/5/filsys
http://man.cat-v.org/unix_10th/5/filsys
utilities

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL