Artifact ef0fd3de8ae0bc005d762c88ce702d11b900115283fcd263828b6c8445f08a8a:
- File
simio/storage.go
— part of check-in
[8cad365e82]
at
2026-10-19 18:27:23
on branch feat/submanifest-reader
— fix(checkout): write symlink entries as fossil does, so a fresh checkout extracts
Since the scan began recording islink and chnged 7/9, Create followed by Extract without Force failed on any repository with an "l" file: the file was missing, the scan read it as UNLINK, and the missing-file skip only covered plain edits.
Extract and Update now write a symlink entry as fossil's vfile_to_disk does: as a symlink to the blob content while allow-symlinks is on and the storage can make links, otherwise as a plain file holding the target. A symlink is deleted before a file is written over it, and setMergedMode leaves symlinks and directories alone, as file_setexe does. Extract's missing-file skip covers mode changes too, so the first Extract after Create plays fossil's open whatever the entry.
With allow-symlinks off, fossil itself reports such a file UNLINK and its checkout refuses without --force; Extract keeps that behavior, and an interop test pins it against fossil's open in both modes.
ScanENotFile no longer refuses a directory at a pending add or removal recorded with chnged=0, matching the else-if in vfile_check_signature.
Tracked in #449 (user: [email protected], size: 2202) [annotate] [blame] [check-ins using] [more...]
package simio import ( "io/fs" "os" "time" ) // Storage abstracts filesystem operations for WASM portability. type Storage interface { Stat(path string) (os.FileInfo, error) Remove(path string) error MkdirAll(path string, perm os.FileMode) error ReadFile(path string) ([]byte, error) WriteFile(path string, data []byte, perm os.FileMode) error ReadDir(path string) ([]fs.DirEntry, error) Chtimes(path string, atime, mtime time.Time) error } // OSStorage delegates to the os package. Used in production and WASI. type OSStorage struct{} func (OSStorage) Stat(path string) (os.FileInfo, error) { return os.Stat(path) } func (OSStorage) Remove(path string) error { return os.Remove(path) } func (OSStorage) MkdirAll(path string, perm os.FileMode) error { return os.MkdirAll(path, perm) } func (OSStorage) ReadFile(path string) ([]byte, error) { return os.ReadFile(path) } func (OSStorage) WriteFile(path string, data []byte, perm os.FileMode) error { return os.WriteFile(path, data, perm) } func (OSStorage) ReadDir(path string) ([]fs.DirEntry, error) { return os.ReadDir(path) } func (OSStorage) Chtimes(path string, atime, mtime time.Time) error { return os.Chtimes(path, atime, mtime) } // Chmod changes a file's mode. It is not part of Storage, since not every // storage has file modes; callers that need it check for it. func (OSStorage) Chmod(path string, mode os.FileMode) error { return os.Chmod(path, mode) } // Lstat is Stat without following a final symbolic link. It is not part of // Storage, since not every storage has symbolic links or file modes; // callers that need it check for it. func (OSStorage) Lstat(path string) (os.FileInfo, error) { return os.Lstat(path) } // Readlink returns the target a symbolic link names. Like Lstat, it is not // part of Storage. func (OSStorage) Readlink(path string) (string, error) { return os.Readlink(path) } // Symlink creates newname as a symbolic link to oldname. Like Lstat, it is // not part of Storage. func (OSStorage) Symlink(oldname, newname string) error { return os.Symlink(oldname, newname) }