...

Source file src/github.com/syndtr/goleveldb/leveldb/storage/file_storage_unix.go

Documentation: github.com/syndtr/goleveldb/leveldb/storage

     1  // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
     2  // All rights reserved.
     3  //
     4  // Use of this source code is governed by a BSD-style license that can be
     5  // found in the LICENSE file.
     6  
     7  //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
     8  // +build darwin dragonfly freebsd linux netbsd openbsd
     9  
    10  package storage
    11  
    12  import (
    13  	"os"
    14  	"syscall"
    15  )
    16  
    17  type unixFileLock struct {
    18  	f *os.File
    19  }
    20  
    21  func (fl *unixFileLock) release() error {
    22  	if err := setFileLock(fl.f, false, false); err != nil {
    23  		return err
    24  	}
    25  	return fl.f.Close()
    26  }
    27  
    28  func newFileLock(path string, readOnly bool) (fl fileLock, err error) {
    29  	var flag int
    30  	if readOnly {
    31  		flag = os.O_RDONLY
    32  	} else {
    33  		flag = os.O_RDWR
    34  	}
    35  	f, err := os.OpenFile(path, flag, 0)
    36  	if os.IsNotExist(err) {
    37  		f, err = os.OpenFile(path, flag|os.O_CREATE, 0644)
    38  	}
    39  	if err != nil {
    40  		return
    41  	}
    42  	err = setFileLock(f, readOnly, true)
    43  	if err != nil {
    44  		f.Close()
    45  		return
    46  	}
    47  	fl = &unixFileLock{f: f}
    48  	return
    49  }
    50  
    51  func setFileLock(f *os.File, readOnly, lock bool) error {
    52  	how := syscall.LOCK_UN
    53  	if lock {
    54  		if readOnly {
    55  			how = syscall.LOCK_SH
    56  		} else {
    57  			how = syscall.LOCK_EX
    58  		}
    59  	}
    60  	return syscall.Flock(int(f.Fd()), how|syscall.LOCK_NB)
    61  }
    62  
    63  func rename(oldpath, newpath string) error {
    64  	return os.Rename(oldpath, newpath)
    65  }
    66  
    67  func isErrInvalid(err error) bool {
    68  	if err == os.ErrInvalid {
    69  		return true
    70  	}
    71  	// Go < 1.8
    72  	if syserr, ok := err.(*os.SyscallError); ok && syserr.Err == syscall.EINVAL {
    73  		return true
    74  	}
    75  	// Go >= 1.8 returns *os.PathError instead
    76  	if patherr, ok := err.(*os.PathError); ok && patherr.Err == syscall.EINVAL {
    77  		return true
    78  	}
    79  	return false
    80  }
    81  
    82  func syncDir(name string) error {
    83  	// As per fsync manpage, Linux seems to expect fsync on directory, however
    84  	// some system don't support this, so we will ignore syscall.EINVAL.
    85  	//
    86  	// From fsync(2):
    87  	//   Calling fsync() does not necessarily ensure that the entry in the
    88  	//   directory containing the file has also reached disk. For that an
    89  	//   explicit fsync() on a file descriptor for the directory is also needed.
    90  	f, err := os.Open(name)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	defer f.Close()
    95  	if err := f.Sync(); err != nil && !isErrInvalid(err) {
    96  		return err
    97  	}
    98  	return nil
    99  }
   100  

View as plain text