2020-08-18 07:23:45 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package storage
import (
2020-10-13 06:58:34 +03:00
"context"
2020-08-18 07:23:45 +03:00
"io"
"net/url"
"os"
"path/filepath"
"code.gitea.io/gitea/modules/util"
)
var (
_ ObjectStorage = & LocalStorage { }
)
2020-10-13 06:58:34 +03:00
// LocalStorageType is the type descriptor for local storage
const LocalStorageType Type = "local"
// LocalStorageConfig represents the configuration for a local storage
type LocalStorageConfig struct {
Path string ` ini:"PATH" `
}
2020-08-18 07:23:45 +03:00
// LocalStorage represents a local files storage
type LocalStorage struct {
2020-10-13 06:58:34 +03:00
ctx context . Context
2020-08-18 07:23:45 +03:00
dir string
}
// NewLocalStorage returns a local files
2020-10-13 06:58:34 +03:00
func NewLocalStorage ( ctx context . Context , cfg interface { } ) ( ObjectStorage , error ) {
configInterface , err := toConfig ( LocalStorageConfig { } , cfg )
if err != nil {
return nil , err
}
config := configInterface . ( LocalStorageConfig )
if err := os . MkdirAll ( config . Path , os . ModePerm ) ; err != nil {
2020-08-18 07:23:45 +03:00
return nil , err
}
return & LocalStorage {
2020-10-13 06:58:34 +03:00
ctx : ctx ,
dir : config . Path ,
2020-08-18 07:23:45 +03:00
} , nil
}
// Open a file
2020-09-08 18:45:10 +03:00
func ( l * LocalStorage ) Open ( path string ) ( Object , error ) {
2020-08-18 07:23:45 +03:00
return os . Open ( filepath . Join ( l . dir , path ) )
}
// Save a file
func ( l * LocalStorage ) Save ( path string , r io . Reader ) ( int64 , error ) {
p := filepath . Join ( l . dir , path )
if err := os . MkdirAll ( filepath . Dir ( p ) , os . ModePerm ) ; err != nil {
return 0 , err
}
// always override
if err := util . Remove ( p ) ; err != nil {
return 0 , err
}
f , err := os . Create ( p )
if err != nil {
return 0 , err
}
defer f . Close ( )
return io . Copy ( f , r )
}
2020-09-08 18:45:10 +03:00
// Stat returns the info of the file
2020-09-29 12:05:13 +03:00
func ( l * LocalStorage ) Stat ( path string ) ( os . FileInfo , error ) {
2020-09-08 18:45:10 +03:00
return os . Stat ( filepath . Join ( l . dir , path ) )
}
2020-08-18 07:23:45 +03:00
// Delete delete a file
func ( l * LocalStorage ) Delete ( path string ) error {
p := filepath . Join ( l . dir , path )
return util . Remove ( p )
}
// URL gets the redirect URL to a file
func ( l * LocalStorage ) URL ( path , name string ) ( * url . URL , error ) {
return nil , ErrURLNotSupported
}
2020-09-29 12:05:13 +03:00
// IterateObjects iterates across the objects in the local storage
func ( l * LocalStorage ) IterateObjects ( fn func ( path string , obj Object ) error ) error {
return filepath . Walk ( l . dir , func ( path string , info os . FileInfo , err error ) error {
if err != nil {
return err
}
2020-10-13 06:58:34 +03:00
select {
case <- l . ctx . Done ( ) :
return l . ctx . Err ( )
default :
}
2020-09-29 12:05:13 +03:00
if path == l . dir {
return nil
}
if info . IsDir ( ) {
return nil
}
relPath , err := filepath . Rel ( l . dir , path )
if err != nil {
return err
}
obj , err := os . Open ( path )
if err != nil {
return err
}
defer obj . Close ( )
return fn ( relPath , obj )
} )
}
2020-10-13 06:58:34 +03:00
func init ( ) {
RegisterStorageType ( LocalStorageType , NewLocalStorage )
}