storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/lock/lock_nix.go (about) 1 //go:build !windows && !plan9 && !solaris 2 // +build !windows,!plan9,!solaris 3 4 /* 5 * MinIO Cloud Storage, (C) 2016 MinIO, Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package lock 21 22 import ( 23 "os" 24 "syscall" 25 ) 26 27 // Internal function implements support for both 28 // blocking and non blocking lock type. 29 func lockedOpenFile(path string, flag int, perm os.FileMode, lockType int) (*LockedFile, error) { 30 switch flag { 31 case syscall.O_RDONLY: 32 lockType |= syscall.LOCK_SH 33 case syscall.O_WRONLY: 34 fallthrough 35 case syscall.O_RDWR: 36 fallthrough 37 case syscall.O_WRONLY | syscall.O_CREAT: 38 fallthrough 39 case syscall.O_RDWR | syscall.O_CREAT: 40 lockType |= syscall.LOCK_EX 41 default: 42 return nil, &os.PathError{ 43 Op: "open", 44 Path: path, 45 Err: syscall.EINVAL, 46 } 47 } 48 49 f, err := os.OpenFile(path, flag|syscall.O_SYNC, perm) 50 if err != nil { 51 return nil, err 52 } 53 54 if err = syscall.Flock(int(f.Fd()), lockType); err != nil { 55 f.Close() 56 if err == syscall.EWOULDBLOCK { 57 err = ErrAlreadyLocked 58 } 59 return nil, err 60 } 61 62 st, err := os.Stat(path) 63 if err != nil { 64 f.Close() 65 return nil, err 66 } 67 68 if st.IsDir() { 69 f.Close() 70 return nil, &os.PathError{ 71 Op: "open", 72 Path: path, 73 Err: syscall.EISDIR, 74 } 75 } 76 77 return &LockedFile{File: f}, nil 78 } 79 80 // TryLockedOpenFile - tries a new write lock, functionality 81 // it is similar to LockedOpenFile with with syscall.LOCK_EX 82 // mode but along with syscall.LOCK_NB such that the function 83 // doesn't wait forever but instead returns if it cannot 84 // acquire a write lock. 85 func TryLockedOpenFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { 86 return lockedOpenFile(path, flag, perm, syscall.LOCK_NB) 87 } 88 89 // LockedOpenFile - initializes a new lock and protects 90 // the file from concurrent access across mount points. 91 // This implementation doesn't support all the open 92 // flags and shouldn't be considered as replacement 93 // for os.OpenFile(). 94 func LockedOpenFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { 95 return lockedOpenFile(path, flag, perm, 0) 96 } 97 98 // Open - Call os.OpenFile 99 func Open(path string, flag int, perm os.FileMode) (*os.File, error) { 100 return os.OpenFile(path, flag, perm) 101 }