1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package filelock provides a platform-independent API for advisory file
6// locking. Calls to functions in this package on platforms that do not support
7// advisory locks will return errors for which IsNotSupported returns true.
8package filelock
9
10import (
11	"errors"
12	"os"
13)
14
15// A File provides the minimal set of methods required to lock an open file.
16// File implementations must be usable as map keys.
17// The usual implementation is *os.File.
18type File interface {
19	// Name returns the name of the file.
20	Name() string
21
22	// Fd returns a valid file descriptor.
23	// (If the File is an *os.File, it must not be closed.)
24	Fd() uintptr
25
26	// Stat returns the FileInfo structure describing file.
27	Stat() (os.FileInfo, error)
28}
29
30// Lock places an advisory write lock on the file, blocking until it can be
31// locked.
32//
33// If Lock returns nil, no other process will be able to place a read or write
34// lock on the file until this process exits, closes f, or calls Unlock on it.
35//
36// If f's descriptor is already read- or write-locked, the behavior of Lock is
37// unspecified.
38//
39// Closing the file may or may not release the lock promptly. Callers should
40// ensure that Unlock is always called when Lock succeeds.
41func Lock(f File) error {
42	return lock(f, writeLock)
43}
44
45// RLock places an advisory read lock on the file, blocking until it can be locked.
46//
47// If RLock returns nil, no other process will be able to place a write lock on
48// the file until this process exits, closes f, or calls Unlock on it.
49//
50// If f is already read- or write-locked, the behavior of RLock is unspecified.
51//
52// Closing the file may or may not release the lock promptly. Callers should
53// ensure that Unlock is always called if RLock succeeds.
54func RLock(f File) error {
55	return lock(f, readLock)
56}
57
58// Unlock removes an advisory lock placed on f by this process.
59//
60// The caller must not attempt to unlock a file that is not locked.
61func Unlock(f File) error {
62	return unlock(f)
63}
64
65// String returns the name of the function corresponding to lt
66// (Lock, RLock, or Unlock).
67func (lt lockType) String() string {
68	switch lt {
69	case readLock:
70		return "RLock"
71	case writeLock:
72		return "Lock"
73	default:
74		return "Unlock"
75	}
76}
77
78// IsNotSupported returns a boolean indicating whether the error is known to
79// report that a function is not supported (possibly for a specific input).
80// It is satisfied by ErrNotSupported as well as some syscall errors.
81func IsNotSupported(err error) bool {
82	return isNotSupported(underlyingError(err))
83}
84
85var ErrNotSupported = errors.New("operation not supported")
86
87// underlyingError returns the underlying error for known os error types.
88func underlyingError(err error) error {
89	switch err := err.(type) {
90	case *os.PathError:
91		return err.Err
92	case *os.LinkError:
93		return err.Err
94	case *os.SyscallError:
95		return err.Err
96	}
97	return err
98}
99