github.com/anthropics/anthropic-sdk-go@v1.70.1/internal/filestore/filestore_unix.go (about)

     1  //go:build !windows
     2  
     3  package filestore
     4  
     5  import (
     6  	"crypto/rand"
     7  	"encoding/hex"
     8  	"errors"
     9  	"os"
    10  	"path/filepath"
    11  	"syscall"
    12  )
    13  
    14  // platformCheck returns an error when the platform cannot uphold the store's
    15  // guarantees; unix has O_NOFOLLOW, so it never fails here.
    16  func platformCheck() error { return nil }
    17  
    18  // replaceViaTemp writes data atomically: a random ".fs-<hex>.tmp" sibling is
    19  // created with O_EXCL|O_NOFOLLOW, then renamed onto dest — a reader never
    20  // sees a half-written file, and a symlink at the leaf is replaced, not
    21  // followed. Best-effort temp cleanup on failure; never masks the original
    22  // error.
    23  func replaceViaTemp(dest string, data []byte, isExecutable bool) error {
    24  	mode := ownerOnlyFileMode
    25  	if isExecutable {
    26  		mode = ownerOnlyExecMode
    27  	}
    28  	var rnd [8]byte
    29  	_, _ = rand.Read(rnd[:])
    30  	tmp := filepath.Join(filepath.Dir(dest), ".fs-"+hex.EncodeToString(rnd[:])+".tmp")
    31  	f, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE|os.O_EXCL|syscall.O_NOFOLLOW, mode)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	if _, err := f.Write(data); err != nil {
    36  		_ = f.Close()
    37  		_ = os.Remove(tmp)
    38  		return err
    39  	}
    40  	if err := f.Close(); err != nil {
    41  		_ = os.Remove(tmp)
    42  		return err
    43  	}
    44  	if err := os.Rename(tmp, dest); err != nil {
    45  		_ = os.Remove(tmp)
    46  		return err
    47  	}
    48  	return nil
    49  }
    50  
    51  // openRegularFile opens dest for reading without following a symlink leaf;
    52  // only a regular file comes back. O_NONBLOCK so a FIFO fails the stat check
    53  // below instead of blocking the open forever.
    54  func openRegularFile(rel, dest string) (*os.File, error) {
    55  	f, err := os.OpenFile(dest, os.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0)
    56  	if err != nil {
    57  		// FreeBSD reports EMLINK rather than ELOOP for O_NOFOLLOW.
    58  		if errors.Is(err, syscall.ELOOP) || errors.Is(err, syscall.EMLINK) {
    59  			return nil, &FileStoreError{Reason: ReasonIsASymlink, RelPath: rel}
    60  		}
    61  		return nil, err
    62  	}
    63  	st, err := f.Stat()
    64  	if err != nil {
    65  		_ = f.Close()
    66  		return nil, err
    67  	}
    68  	if !st.Mode().IsRegular() {
    69  		_ = f.Close()
    70  		return nil, &FileStoreError{Reason: ReasonNotAFile, RelPath: rel}
    71  	}
    72  	return f, nil
    73  }