filesystem.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package storage
  2. import (
  3. "io"
  4. "os"
  5. "path/filepath"
  6. )
  7. // Storage defines the interface for object storage operations
  8. type Storage interface {
  9. // Bucket operations
  10. CreateBucket(name string) error
  11. DeleteBucket(name string) error
  12. BucketExists(name string) (bool, error)
  13. ListBuckets() ([]BucketInfo, error)
  14. // Object operations
  15. PutObject(bucket, key string, reader io.Reader) error
  16. GetObject(bucket, key string) (io.ReadCloser, *ObjectInfo, error)
  17. DeleteObject(bucket, key string) error
  18. ObjectExists(bucket, key string) (bool, error)
  19. GetObjectInfo(bucket, key string) (*ObjectInfo, error)
  20. ListObjects(bucket string) ([]ObjectInfo, error)
  21. }
  22. // FileSystemStorage implements Storage using the local file system
  23. type FileSystemStorage struct {
  24. baseDir string
  25. }
  26. // NewFileSystemStorage creates a new file system storage instance
  27. func NewFileSystemStorage(baseDir string) (*FileSystemStorage, error) {
  28. if err := os.MkdirAll(baseDir, 0755); err != nil {
  29. return nil, err
  30. }
  31. return &FileSystemStorage{
  32. baseDir: baseDir,
  33. }, nil
  34. }
  35. // CreateBucket creates a new bucket directory
  36. func (fs *FileSystemStorage) CreateBucket(name string) error {
  37. bucketPath := filepath.Join(fs.baseDir, name)
  38. // Check if bucket already exists
  39. if _, err := os.Stat(bucketPath); err == nil {
  40. return ErrBucketAlreadyExists
  41. }
  42. return os.MkdirAll(bucketPath, 0755)
  43. }
  44. // DeleteBucket removes a bucket directory
  45. func (fs *FileSystemStorage) DeleteBucket(name string) error {
  46. bucketPath := filepath.Join(fs.baseDir, name)
  47. return os.RemoveAll(bucketPath)
  48. }
  49. // BucketExists checks if a bucket exists
  50. func (fs *FileSystemStorage) BucketExists(name string) (bool, error) {
  51. bucketPath := filepath.Join(fs.baseDir, name)
  52. _, err := os.Stat(bucketPath)
  53. if os.IsNotExist(err) {
  54. return false, nil
  55. }
  56. if err != nil {
  57. return false, err
  58. }
  59. return true, nil
  60. }
  61. // ListBuckets lists all buckets
  62. func (fs *FileSystemStorage) ListBuckets() ([]BucketInfo, error) {
  63. entries, err := os.ReadDir(fs.baseDir)
  64. if err != nil {
  65. return nil, err
  66. }
  67. var buckets []BucketInfo
  68. for _, entry := range entries {
  69. if entry.IsDir() {
  70. info, err := entry.Info()
  71. if err != nil {
  72. continue
  73. }
  74. buckets = append(buckets, BucketInfo{
  75. Name: entry.Name(),
  76. CreationDate: info.ModTime(),
  77. })
  78. }
  79. }
  80. return buckets, nil
  81. }
  82. // PutObject stores an object
  83. func (fs *FileSystemStorage) PutObject(bucket, key string, reader io.Reader) error {
  84. bucketPath := filepath.Join(fs.baseDir, bucket)
  85. // Check if bucket exists
  86. if _, err := os.Stat(bucketPath); os.IsNotExist(err) {
  87. return ErrBucketNotFound
  88. }
  89. objectPath := filepath.Join(bucketPath, key)
  90. // Create parent directories if needed
  91. objectDir := filepath.Dir(objectPath)
  92. if err := os.MkdirAll(objectDir, 0755); err != nil {
  93. return err
  94. }
  95. // Create the file
  96. file, err := os.Create(objectPath)
  97. if err != nil {
  98. return err
  99. }
  100. defer file.Close()
  101. // Copy data to file
  102. _, err = io.Copy(file, reader)
  103. return err
  104. }
  105. // GetObject retrieves an object
  106. func (fs *FileSystemStorage) GetObject(bucket, key string) (io.ReadCloser, *ObjectInfo, error) {
  107. objectPath := filepath.Join(fs.baseDir, bucket, key)
  108. fileInfo, err := os.Stat(objectPath)
  109. if os.IsNotExist(err) {
  110. return nil, nil, ErrObjectNotFound
  111. }
  112. if err != nil {
  113. return nil, nil, err
  114. }
  115. file, err := os.Open(objectPath)
  116. if err != nil {
  117. return nil, nil, err
  118. }
  119. info := &ObjectInfo{
  120. Key: key,
  121. Size: fileInfo.Size(),
  122. LastModified: fileInfo.ModTime(),
  123. ETag: generateETag(fileInfo),
  124. }
  125. return file, info, nil
  126. }
  127. // DeleteObject removes an object
  128. func (fs *FileSystemStorage) DeleteObject(bucket, key string) error {
  129. objectPath := filepath.Join(fs.baseDir, bucket, key)
  130. err := os.Remove(objectPath)
  131. if os.IsNotExist(err) {
  132. return nil // S3 returns success even if object doesn't exist
  133. }
  134. return err
  135. }
  136. // ObjectExists checks if an object exists
  137. func (fs *FileSystemStorage) ObjectExists(bucket, key string) (bool, error) {
  138. objectPath := filepath.Join(fs.baseDir, bucket, key)
  139. _, err := os.Stat(objectPath)
  140. if os.IsNotExist(err) {
  141. return false, nil
  142. }
  143. if err != nil {
  144. return false, err
  145. }
  146. return true, nil
  147. }
  148. // GetObjectInfo retrieves object metadata
  149. func (fs *FileSystemStorage) GetObjectInfo(bucket, key string) (*ObjectInfo, error) {
  150. objectPath := filepath.Join(fs.baseDir, bucket, key)
  151. fileInfo, err := os.Stat(objectPath)
  152. if os.IsNotExist(err) {
  153. return nil, ErrObjectNotFound
  154. }
  155. if err != nil {
  156. return nil, err
  157. }
  158. return &ObjectInfo{
  159. Key: key,
  160. Size: fileInfo.Size(),
  161. LastModified: fileInfo.ModTime(),
  162. ETag: generateETag(fileInfo),
  163. }, nil
  164. }
  165. // ListObjects lists all objects in a bucket
  166. func (fs *FileSystemStorage) ListObjects(bucket string) ([]ObjectInfo, error) {
  167. bucketPath := filepath.Join(fs.baseDir, bucket)
  168. if _, err := os.Stat(bucketPath); os.IsNotExist(err) {
  169. return nil, ErrBucketNotFound
  170. }
  171. entries, err := os.ReadDir(bucketPath)
  172. if err != nil {
  173. return nil, err
  174. }
  175. var objects []ObjectInfo
  176. for _, entry := range entries {
  177. if !entry.IsDir() {
  178. info, err := entry.Info()
  179. if err != nil {
  180. continue
  181. }
  182. objects = append(objects, ObjectInfo{
  183. Key: entry.Name(),
  184. Size: info.Size(),
  185. LastModified: info.ModTime(),
  186. ETag: generateETag(info),
  187. })
  188. }
  189. }
  190. return objects, nil
  191. }