afero/swift/swift.go

143 lines
3.7 KiB
Go

package swift
import (
"bytes"
"fmt"
"github.com/ncw/swift"
"log"
"os"
"time"
)
type Fs struct {
Connection *swift.Connection
containerName string
}
func NewSwiftFs(conn *swift.Connection, containerName string) (fs *Fs, err error) {
if containerName == "" {
return fs, fmt.Errorf("container name cannot be empty")
}
fs = &Fs{
Connection: conn,
containerName: containerName,
}
err = fs.Connection.Authenticate()
return
}
func (s *Fs) Name() string {
return "swiftfs"
}
func (s *Fs) Create(name string) (file File, err error) {
objectfile, err := s.Connection.ObjectCreate(s.containerName, name, true, "", "", swift.Headers{})
if err != nil {
return file, err
}
file.objectCreateFile = objectfile
return
}
func (s *Fs) Mkdir(name string, perm os.FileMode) (err error) {
return s.MkdirAll(name, perm)
}
func (s *Fs) MkdirAll(path string, perm os.FileMode) (err error) {
// Swift usually creates all directories deep down, no matter if any of these directories already exist
// Objects created with application/directory are so called "pseudo-directories".
_, err = s.Connection.ObjectPut(s.containerName, path+"/", bytes.NewReader([]byte{}), true, "", "application/directory", swift.Headers{})
return
}
func (s *Fs) Open(name string) (file *File, err error) {
file = new(File)
file.conn = s.Connection
file.containerName = s.containerName
f, headers, err := s.Connection.ObjectOpen(s.containerName, name, true, swift.Headers{})
if err != nil {
return
}
err = file.putFileInfoTogetherFromOpenObject(f, headers, name)
return
}
func (*Fs) OpenFile(name string, flag int, perm os.FileMode) (*File, error) {
return nil, nil
}
func (s *Fs) Remove(name string) error {
return s.Connection.ObjectDelete(s.containerName, name)
}
func (s *Fs) RemoveAll(path string) (err error) {
sinfo, err := s.Connection.QueryInfo()
if err != nil {
return
}
// Get all objects we want to delte
objects, err := s.Connection.ObjectsAll(s.containerName, &swift.ObjectsOpts{Prefix: path})
if err != nil {
return
}
var objectnames []string
for _, o := range objects {
// If the server supports bulk delete, add it to a list to bulkdelete the items later,
// otherwise delete them directly
if sinfo.SupportsBulkDelete() {
objectnames = append(objectnames, o.Name)
} else {
err = s.Connection.ObjectDelete(s.containerName, o.Name)
if err != nil {
return
}
}
}
if sinfo.SupportsBulkDelete() {
_, err = s.Connection.BulkDelete(s.containerName, objectnames)
if err != nil {
return
}
}
return err
}
func (s *Fs) Rename(oldname, newname string) error {
return s.Connection.ObjectMove(s.containerName, oldname, s.containerName, newname)
}
func (s *Fs) Stat(name string) (os.FileInfo, error) {
file, err := s.Open(name)
if err != nil {
return nil, err
}
return file.Stat()
}
func (*Fs) Chmod(name string, mode os.FileMode) error {
log.Println("Swift does not support file modes.")
return nil
}
func (s *Fs) Chtimes(name string, _, mtime time.Time) error {
// While the uncommented code should work, the problem is that we have no way to update the time on
// the server without modifying the time. Whenever we send a request to swift to update the last modified time,
// we modify the file thus setting the last modified time to now...
// Maybe I'll find a solution for this in the future, but for now I'll just diable it because of the reasons above.
return nil
/*
_, headers, err := s.Connection.ObjectOpen(s.containerName, name, true, swift.Headers{})
if err != nil {
return err
}
headers.ObjectMetadata().SetModTime(mtime) // Swift does not support access time so we won't use that.
return s.Connection.ObjectUpdate(s.containerName, name, headers)
*/
}