From 9d58809e8f1fd0c1866e85e9e1724b009a685239 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Thu, 9 Jan 2014 20:11:03 -0800 Subject: [PATCH] lock: Merge added FreeBSD support from upstream. Change-Id: I2cb6de1fe32069a675eed405744d632054d67a11 --- .../github.com/camlistore/lock/lock.go | 10 +-- .../camlistore/lock/lock_freebsd.go | 79 +++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 third_party/github.com/camlistore/lock/lock_freebsd.go diff --git a/third_party/github.com/camlistore/lock/lock.go b/third_party/github.com/camlistore/lock/lock.go index 8a0b02c89..6268527b0 100644 --- a/third_party/github.com/camlistore/lock/lock.go +++ b/third_party/github.com/camlistore/lock/lock.go @@ -34,15 +34,15 @@ import ( // A nil Closer is returned if an error occurred. Otherwise, close that // Closer to release the lock. // -// On Linux and OSX, a lock has the same semantics as fcntl(2)'s advisory -// locks. In particular, closing any other file descriptor for the same -// file will release the lock prematurely. +// On Linux, FreeBSD and OSX, a lock has the same semantics as fcntl(2)'s +// advisory locks. In particular, closing any other file descriptor for the +// same file will release the lock prematurely. // // Attempting to lock a file that is already locked by the current process // has undefined behavior. // -// Lock is not yet implemented on other operating systems, and calling it -// will return an error. +// On other operating systems, lock will fallback to using the presence and +// content of a file named name + '.lock' to implement locking behavior. func Lock(name string) (io.Closer, error) { return lockFn(name) } diff --git a/third_party/github.com/camlistore/lock/lock_freebsd.go b/third_party/github.com/camlistore/lock/lock_freebsd.go new file mode 100644 index 000000000..d3835d624 --- /dev/null +++ b/third_party/github.com/camlistore/lock/lock_freebsd.go @@ -0,0 +1,79 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + // This type matches C's "struct flock" defined in /usr/include/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Start int64 /* off_t starting offset */ + Len int64 /* off_t len = 0 means until end of file */ + Pid int32 /* pid_t lock owner */ + Type int16 /* short lock type: read/write, etc. */ + Whence int16 /* short type of l_start */ + Sysid int32 /* int remote system id or zero for local */ + }{ + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: int32(os.Getpid()), + Type: syscall.F_WRLCK, + Whence: int16(os.SEEK_SET), + Sysid: 0, + } + + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +}