storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/lock/lock.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2016 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Package lock - implements filesystem locking wrappers around an 18 // open file descriptor. 19 package lock 20 21 import ( 22 "errors" 23 "os" 24 "sync" 25 ) 26 27 var ( 28 // ErrAlreadyLocked is returned if the underlying fd is already locked. 29 ErrAlreadyLocked = errors.New("file already locked") 30 ) 31 32 // RLockedFile represents a read locked file, implements a special 33 // closer which only closes the associated *os.File when the ref count. 34 // has reached zero, i.e when all the readers have given up their locks. 35 type RLockedFile struct { 36 *LockedFile 37 mutex sync.Mutex 38 refs int // Holds read lock refs. 39 } 40 41 // IsClosed - Check if the rlocked file is already closed. 42 func (r *RLockedFile) IsClosed() bool { 43 r.mutex.Lock() 44 defer r.mutex.Unlock() 45 return r.refs == 0 46 } 47 48 // IncLockRef - is used by called to indicate lock refs. 49 func (r *RLockedFile) IncLockRef() { 50 r.mutex.Lock() 51 r.refs++ 52 r.mutex.Unlock() 53 } 54 55 // Close - this closer implements a special closer 56 // closes the underlying fd only when the refs 57 // reach zero. 58 func (r *RLockedFile) Close() (err error) { 59 r.mutex.Lock() 60 defer r.mutex.Unlock() 61 62 if r.refs == 0 { 63 return os.ErrInvalid 64 } 65 66 r.refs-- 67 if r.refs == 0 { 68 err = r.File.Close() 69 } 70 71 return err 72 } 73 74 // Provides a new initialized read locked struct from *os.File 75 func newRLockedFile(lkFile *LockedFile) (*RLockedFile, error) { 76 if lkFile == nil { 77 return nil, os.ErrInvalid 78 } 79 80 return &RLockedFile{ 81 LockedFile: lkFile, 82 refs: 1, 83 }, nil 84 } 85 86 // RLockedOpenFile - returns a wrapped read locked file, if the file 87 // doesn't exist at path returns an error. 88 func RLockedOpenFile(path string) (*RLockedFile, error) { 89 lkFile, err := LockedOpenFile(path, os.O_RDONLY, 0666) 90 if err != nil { 91 return nil, err 92 } 93 94 return newRLockedFile(lkFile) 95 96 } 97 98 // LockedFile represents a locked file 99 type LockedFile struct { 100 *os.File 101 }