package storage import ( "crypto/sha256" "encoding/hex" "fmt" "io" "os" "path/filepath" "strings" ) type Storage struct { filesDir string } func New(filesDir string) *Storage { return &Storage{filesDir: filesDir} } func (s *Storage) CopyFile(srcPath string, destFilename string) error { src, err := os.Open(srcPath) if err != nil { return fmt.Errorf("failed to open source file: %w", err) } defer src.Close() destPath := filepath.Join(s.filesDir, destFilename) dest, err := os.Create(destPath) if err != nil { return fmt.Errorf("failed to create destination file: %w", err) } defer dest.Close() if _, err := io.Copy(dest, src); err != nil { return fmt.Errorf("failed to copy file: %w", err) } return nil } func (s *Storage) RemoveFile(filename string) error { path := filepath.Join(s.filesDir, filename) return os.Remove(path) } func (s *Storage) CreateSymlink(originalPath, storedFilename string) error { storedPath := filepath.Join(s.filesDir, storedFilename) return os.Symlink(storedPath, originalPath) } func (s *Storage) RemoveSymlink(originalPath string) error { info, err := os.Lstat(originalPath) if err != nil { if os.IsNotExist(err) { return nil } return err } if info.Mode()&os.ModeSymlink != 0 { return os.Remove(originalPath) } return nil } func (s *Storage) FilePath(filename string) string { return filepath.Join(s.filesDir, filename) } func (s *Storage) FileExists(filename string) bool { path := filepath.Join(s.filesDir, filename) _, err := os.Stat(path) return err == nil } func GenerateFilename(originalPath string) string { base := filepath.Base(originalPath) ext := filepath.Ext(base) name := strings.TrimSuffix(base, ext) hash := sha256.Sum256([]byte(originalPath)) shortHash := hex.EncodeToString(hash[:])[:8] return fmt.Sprintf("%s_%s%s", name, shortHash, ext) } func GetAbsolutePath(path string) (string, error) { if filepath.IsAbs(path) { return path, nil } cwd, err := os.Getwd() if err != nil { return "", err } return filepath.Join(cwd, path), nil }