// Copyright (c) HashiCorp, Inc
// SPDX-License-Identifier: MPL-2.0

package fs

import (
	
	
	
	
	

	
)

// FS implements the wal.VFS interface using GO's built in OS Filesystem (and a
// few helpers).
//
// TODO if we changed the interface to be Dir centric we could cache the open
// dir handle and save some time opening it on each Create in order to fsync.
type FS struct {
}

func () *FS {
	return &FS{}
}

// ListDir returns a list of all files in the specified dir in lexicographical
// order. If the dir doesn't exist, it must return an error. Empty array with
// nil error is assumed to mean that the directory exists and was readable,
// but contains no files.
func ( *FS) ( string) ([]string, error) {
	,  := ioutil.ReadDir()
	if  != nil {
		return nil, 
	}
	 := make([]string, len())
	for ,  := range  {
		if .IsDir() {
			continue
		}
		[] = .Name()
	}
	return , nil
}

// Create creates a new file with the given name. If a file with the same name
// already exists an error is returned. If a non-zero size is given,
// implementations should make a best effort to pre-allocate the file to be
// that size. The dir must already exist and be writable to the current
// process.
func ( *FS) ( string,  string,  uint64) (types.WritableFile, error) {
	,  := os.OpenFile(filepath.Join(, ), os.O_CREATE|os.O_EXCL|os.O_RDWR, os.FileMode(0644))
	if  != nil {
		return nil, 
	}
	// We just created the file. Preallocate it's size.
	if  > 0 {
		if  > math.MaxInt32 {
			return nil, fmt.Errorf("maximum file size is %d bytes", math.MaxInt32)
		}

		if  := prealloc(, int64(), true);  != nil {
			.Close()
			return nil, 
		}
	}
	// We don't fsync here for performance reasons. Technically we need to fsync
	// the file itself to make sure it is really persisted to disk, and you always
	// need to fsync its parent dir after a creation because fsync doesn't ensure
	// the directory entry is persisted - a crash could make the file appear to be
	// missing as there is no directory entry.
	//
	// BUT, it doesn't actually matter if this file is crash safe, right up to the
	// point where we actually commit log data. Since we always fsync the file
	// when we commit logs, we don't need to again here. That does however leave
	// the parent dir fsync which must be done after the first fsync to a newly
	// created file to ensure it survives a crash.
	//
	// To handle that, we return a wrapped io.File that will fsync the parent dir
	// as well the first time Sync is called (and only the first time),
	 := &File{
		new:  0,
		dir:  ,
		File: *,
	}
	return , nil
}

// Delete indicates the file is no longer required. Typically it should be
// deleted from the underlying system to free disk space.
func ( *FS) ( string,  string) error {
	if  := os.Remove(filepath.Join(, ));  != nil {
		return 
	}
	// Make sure parent directory metadata is fsynced too before we call this
	// "done".
	return syncDir()
}

// OpenReader opens an existing file in read-only mode. If the file doesn't
// exist or permission is denied, an error is returned, otherwise no checks
// are made about the well-formedness of the file, it may be empty, the wrong
// size or corrupt in arbitrary ways.
func ( *FS) ( string,  string) (types.ReadableFile, error) {
	return os.OpenFile(filepath.Join(, ), os.O_RDONLY, os.FileMode(0644))
}

// OpenWriter opens a file in read-write mode. If the file doesn't exist or
// permission is denied, an error is returned, otherwise no checks are made
// about the well-formedness of the file, it may be empty, the wrong size or
// corrupt in arbitrary ways.
func ( *FS) ( string,  string) (types.WritableFile, error) {
	return os.OpenFile(filepath.Join(, ), os.O_RDWR, os.FileMode(0644))
}