pkg/lockedfile/lockedfile_linux.go (65 lines of code) (raw):
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package lockedfile
import (
"github.com/Azure/azure-extension-platform/pkg/constants"
"os"
"syscall"
"time"
)
type lockedFile struct {
fileDescriptor int
metadata *Metadata
}
func newInner(filePath string, timeout time.Duration, metadata *Metadata) (*lockedFile, error) {
file, err := syscall.Open(filePath, os.O_RDWR|os.O_CREATE, constants.FilePermissions_UserOnly_ReadWrite)
if err != nil {
// file cannot be open
return nil, err
}
errChan := make(chan error)
timeoutChan := make(chan struct{})
go func() {
// acquire exclusive lock on file
err := syscall.Flock(file, syscall.LOCK_EX)
select {
case <-timeoutChan:
syscall.Flock(file, syscall.LOCK_UN)
syscall.Close(file)
case errChan <- err:
}
}()
select {
case err := <-errChan:
if err != nil {
return nil, err
}
return &lockedFile{file, metadata}, nil
case <-time.After(timeout):
close(timeoutChan)
return nil, &FileLockTimeoutError{"file lock could not be acquired in the specified time"}
}
}
func (self *lockedFile) ReadLockedFile() ([]byte, error) {
fileBytes := make([]byte, 0, 4096)
buffer := make([]byte, 4096, 4096)
// reset the packageRegistryFileHandle
syscall.Seek(self.fileDescriptor, 0, 0)
for {
nbytes, err := syscall.Read(self.fileDescriptor, buffer)
if err != nil && err.Error() != "EOF" {
return nil, err
}
if nbytes == 0 {
break
}
fileBytes = append(fileBytes, buffer[:nbytes]...)
}
return fileBytes, nil
}
func (self *lockedFile) WriteLockedFile(bytes []byte) error {
syscall.Seek(self.fileDescriptor, 0, 0)
_, err := syscall.Write(self.fileDescriptor, bytes)
if err != nil {
return err
}
return nil
}
func (self *lockedFile) closeInner() error {
return syscall.Close(self.fileDescriptor)
}