//go:build !windows && !plan9 && !js && !wasip1 && !aix
// +build !windows,!plan9,!js,!wasip1,!aix

/*
 * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

package badger

import (
	
	
	

	

	
)

// directoryLockGuard holds a lock on a directory and a pid file inside.  The pid file isn't part
// of the locking mechanism, it's just advisory.
type directoryLockGuard struct {
	// File handle on the directory, which we've flocked.
	f *os.File
	// The absolute path to our pid file.
	path string
	// Was this a shared lock for a read-only database?
	readOnly bool
}

// acquireDirectoryLock gets a lock on the directory (using flock). If
// this is not read-only, it will also write our pid to
// dirPath/pidFileName for convenience.
func acquireDirectoryLock( string,  string,  bool) (
	*directoryLockGuard, error) {
	// Convert to absolute path so that Release still works even if we do an unbalanced
	// chdir in the meantime.
	,  := filepath.Abs(filepath.Join(, ))
	if  != nil {
		return nil, y.Wrapf(, "cannot get absolute path for pid lock file")
	}
	,  := os.Open()
	if  != nil {
		return nil, y.Wrapf(, "cannot open directory %q", )
	}
	 := unix.LOCK_EX | unix.LOCK_NB
	if  {
		 = unix.LOCK_SH | unix.LOCK_NB
	}

	 = unix.Flock(int(.Fd()), )
	if  != nil {
		.Close()
		return nil, y.Wrapf(,
			"Cannot acquire directory lock on %q.  Another process is using this Badger database.",
			)
	}

	if ! {
		// Yes, we happily overwrite a pre-existing pid file.  We're the
		// only read-write badger process using this directory.
		 = os.WriteFile(, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0666)
		if  != nil {
			.Close()
			return nil, y.Wrapf(,
				"Cannot write pid file %q", )
		}
	}
	return &directoryLockGuard{, , }, nil
}

// Release deletes the pid file and releases our lock on the directory.
func ( *directoryLockGuard) () error {
	var  error
	if !.readOnly {
		// It's important that we remove the pid file first.
		 = os.Remove(.path)
	}

	if  := .f.Close();  == nil {
		 = 
	}
	.path = ""
	.f = nil

	return 
}

// openDir opens a directory for syncing.
func openDir( string) (*os.File, error) { return os.Open() }

// When you create or delete a file, you have to ensure the directory entry for the file is synced
// in order to guarantee the file is visible (if the system crashes). (See the man page for fsync,
// or see https://github.com/coreos/etcd/issues/6368 for an example.)
func syncDir( string) error {
	,  := openDir()
	if  != nil {
		return y.Wrapf(, "While opening directory: %s.", )
	}

	 = .Sync()
	 := .Close()
	if  != nil {
		return y.Wrapf(, "While syncing directory: %s.", )
	}
	return y.Wrapf(, "While closing directory: %s.", )
}