davlock

package
v0.53.0 Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package davlock is the WebDAV lock system, and it exists because the one filex shipped with was a lie.

What was wrong

/dav used webdav.NewMemLS(). It implements RFC 4918 class-2 locking correctly — the semantics below are its algorithm — but it holds every lock in a Go map, so the locks last exactly as long as the process. Restart filex, deploy a new version, let the container be rescheduled, and EVERY lock silently ceases to exist.

That matters because of what a client does with a lock. Windows Explorer and macOS Finder take one before they write, hold it across the whole edit, and present the token on the PUT. After a restart the token names nothing, the PUT gets 412 Precondition Failed, and the person editing the file sees their save fail with no explanation — while the server, having forgotten, would happily let a SECOND client lock and write the same file. The lock said "exclusive" and stopped being true without telling anybody.

What this does instead

The same algorithm, with the lock table written to a file in the data directory on every change and read back at boot — TOKENS INCLUDED, which is the whole point: a client's token has to keep meaning the same lock across a restart or the durability buys nothing.

⚠ What it does NOT do, stated plainly rather than implied: it is not a distributed lock. Two filex processes serving the same storage each keep their own file and would each grant a lock the other does not know about. One process per deployment is filex's shape today; if that ever changes, this is the thing that has to move into the database, and the honest place to say so is here rather than in an incident.

⚠ WebDAV locks are advisory in the first place (RFC 4918 §6.3): they coordinate polite clients, they do not stop the S3 endpoint or the web explorer from writing the same file. That is the protocol's design, not a gap here.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Lock

type Lock struct {
	Token     string    `json:"token"`
	Root      string    `json:"root"`
	Duration  int64     `json:"duration_ns"`
	OwnerXML  string    `json:"owner_xml"`
	ZeroDepth bool      `json:"zero_depth"`
	Expiry    time.Time `json:"expiry"`
	// contains filtered or unexported fields
}

Lock is one held lock. It is also the on-disk record, so the JSON tags are part of the file format.

type System

type System struct {
	// contains filtered or unexported fields
}

System is a durable webdav.LockSystem.

func New

func New(dir string) (*System, error)

New opens (or creates) a lock system backed by `<dir>/dav-locks.json`.

A missing or unreadable file is not an error: the locks are then simply empty, which is exactly what memLS gave and no worse. Refusing to start /dav because a cache file is corrupt would trade a small problem for an outage.

func NewMemory

func NewMemory() *System

NewMemory returns a lock system that never touches the disk. For tests, and for a deployment that would rather have memLS's behaviour back.

func (*System) Confirm

func (s *System) Confirm(now time.Time, name0, name1 string, conditions ...webdav.Condition) (func(), error)

Confirm claims the locks that cover name0/name1 for one request.

func (*System) Create

func (s *System) Create(now time.Time, details webdav.LockDetails) (string, error)

Create takes a new lock, or refuses with ErrLocked (→ 423).

func (*System) Len

func (s *System) Len() int

Len reports how many locks are held, for a status page or a test.

func (*System) Refresh

func (s *System) Refresh(now time.Time, token string, duration time.Duration) (webdav.LockDetails, error)

Refresh extends a lock's life.

func (*System) Unlock

func (s *System) Unlock(now time.Time, token string) error

Unlock releases a lock.

Jump to

Keyboard shortcuts

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