Documentation
¶
Overview ¶
Package writegate is the one question every person-facing write asks before it touches a storage: may this path be changed?
Two rules, one call, so that a door cannot honour one and forget the other:
- filex's own names (syspath): `.filex-trash`, `.versions`, `.thumbs`, the desktop's `.filex-open` and the `.keepdir` marker are never written by a person — except the desktop's open-with round trip, which the caller claims with a syspath.Verb (syspath.Refused).
- app locks: while an app holds a lock on a path (the signing app freezes a document while signatures are collected, `files:lock`), nothing changes it, moves it or removes the folder around it — whoever asks, administrators included — except the app that holds the lock.
⚠⚠ Why one package (2026-09-21). The lock check lived in five handlers (the explorer's verbs, the queue, the text editor, two upload paths) and nowhere else. Measured before this package: the document server's save callback overwrote a frozen document ({"error":0}); an agent's delete of the folder holding it answered {"ok":true}; an archive extracted over it; a WebDAV DELETE of its folder answered 204; FTP and SFTP sessions opened before the freeze overwrote and renamed it; NFS renamed it. The signing app's own hash check caught the change later — the request then died as "the document changed", and the freeze the person was promised on screen ("… dondurulmuş; imzalar toplanırken kimse değiştiremez") was never real. The reserved-name rule had just been written into the same doors, one call each; the lock rule now rides in that call.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrLocked = errors.New("locked by an app")
ErrLocked is what a refused write wraps when an app holds a lock.
Functions ¶
func Check ¶
Check reports whether a write that names targets may happen: nil, a *syspath.ReservedError, or a *LockedError. Reserved names are judged first and without a database: a name that can never be written is refused the same way whether or not anything is locked.
app is the app plugin doing the write — 0 for a person, a protocol client or a document server. A lock held by that same app does not stop it: the app that froze the document is the one that must still write into it (the signed output), exactly the waiver acl.Set.EffectiveIgnoringLocks gives its jobs.
locks may be nil (no ACL resolver wired): then only names are judged.
func RefusesMounted ¶
RefusesMounted is Check for a protocol client (WebDAV, SFTP, FTPS, NFS, S3): filex's own directories (syspath.Mounted — the keep marker is an ordinary file there) and the storage's live locks.
⚠ Pass locks read NOW (acl.Resolver.Locks), not a session's cached permission set: SFTP, FTPS and NFS load that set once when the session starts, so it does not see a freeze taken afterwards. Measured before this (2026-09-21): a session opened before the signing app froze imza/NDA.docx overwrote it, renamed it and renamed the folder holding it.
Types ¶
type LockedError ¶
type LockedError struct {
Lock *model.AppPluginLock
Rel string
}
LockedError names the lock that refused a write and the path it was asked about, so the answer can say who froze it and why (handlers.lockedAnswer).
func (*LockedError) Error ¶
func (e *LockedError) Error() string
func (*LockedError) Unwrap ¶
func (e *LockedError) Unwrap() error
type Locks ¶
type Locks interface {
Lock(rel string) *model.AppPluginLock
LockWithin(rel string) *model.AppPluginLock
}
Locks answers which app lock covers a path: on it (Lock) or on it or anything under it (LockWithin). *acl.Set implements it; a nil *acl.Set answers "none".
type Target ¶
type Target struct {
Rel string
// Verb is the syspath exception this target may claim (the desktop's
// open-with round trip, a person's own draft); syspath.Change — the zero
// value — for every other write.
Verb syspath.Verb
// Person is who the write is FOR, when the exception depends on it
// (syspath.OwnDraft: a draft is written only by its owner's editor). 0
// when nobody is named, which is what every other write passes.
Person int64
// contains filtered or unexported fields
}
Target is one path a write names.
func Names ¶
Names is a path the write names without changing it: the folder a file is created, moved or extracted INTO, a source that is only read (a copy, an archive being packed or unpacked), the target of a share or a grant. Judged on reserved names only — a lock freezes a document and the folder entry that holds it, not what may be added beside it.
func Writes ¶
Writes is a path the write changes: its content is created or replaced, or the entry is created, moved or removed — and, for a folder, everything under it goes along. Judged on reserved names AND on app locks on the path or anywhere below it.