func (d *S3Driver) DeleteDir(path string) bool {
	return false
}
DeleteDir would delete a directory, but isn't currently implemented
package s3driver
import (
	"bytes"
	"fmt"
	"io"
	"mime"
	"os"
	"path/filepath"
	"strings"
	"time"
	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/aws/awsutil"
	"github.com/awslabs/aws-sdk-go/service/s3"
	"github.com/koofr/graval"
)
type S3Driver struct {
	Username               string
	Password               string
	AWSRegion              string
	AWSCredentialsProvider aws.CredentialsProvider
	AWSBucketName          string
	WorkingDirectory       string
}
func (d *S3Driver) s3service() *s3.S3 {
	svc := s3.New(&aws.Config{
		Credentials: d.AWSCredentialsProvider,
		Region:      d.AWSRegion,
	})
	return svc
}
func pathToS3PathPrefix(path string) *string {
	path = strings.TrimPrefix(path, "/")
	if path == "" || strings.HasSuffix(path, "/") {
		return aws.String(path)
	}
	p := string(path) + "/"
	return aws.String(p)
}
func (d *S3Driver) s3DirContents(path string, maxKeys int64, marker string) (*s3.ListObjectsOutput, error) {
	svc := d.s3service()
	prefix := pathToS3PathPrefix(path)
	params := &s3.ListObjectsInput{
		Bucket:    aws.String(d.AWSBucketName),  
		Delimiter: aws.String(d.WorkingDirectory),
		MaxKeys: aws.Long(maxKeys),
		Prefix:  prefix,
	}
	if marker != "" {
		params.Marker = aws.String(marker)
	}
	resp, err := svc.ListObjects(params)
	if awserr := aws.Error(err); awserr != nil {
		fmt.Println("Error: ", awserr)
	} else if err != nil {
		panic(err)
	}
	return resp, err
}
func (d *S3Driver) Authenticate(username string, password string) bool {
	return username == d.Username && password == d.Password
}
func (d *S3Driver) Bytes(path string) int64 {
	svc := d.s3service()
	path = strings.TrimPrefix(path, "/")
	params := &s3.HeadObjectInput{
		Bucket: aws.String(d.AWSBucketName),  
		Key:    aws.String(path),             
	}
	resp, err := svc.HeadObject(params)
	if awserr := aws.Error(err); awserr != nil {
		fmt.Println("Error:", awserr.Code, awserr.Message)
		return -1
	} else if err != nil {
		panic(err)
		return -1
	}
	return *resp.ContentLength
}
func (d *S3Driver) ModifiedTime(path string) (time.Time, bool) {
	svc := d.s3service()
	path = strings.TrimPrefix(path, "/")
	params := &s3.HeadObjectInput{
		Bucket: aws.String(d.AWSBucketName),  
		Key:    aws.String(path),             
	}
	resp, err := svc.HeadObject(params)
	if awserr := aws.Error(err); awserr != nil {
		fmt.Println("Error:", awserr.Code, awserr.Message)
		return time.Now(), false
	} else if err != nil {
		panic(err)
		return time.Now(), false
	}
	return *resp.LastModified, true
}
func (d *S3Driver) ChangeDir(path string) bool {
	if strings.HasPrefix(path, "/") {
		d.WorkingDirectory = strings.TrimPrefix(path, "/")
	} else {
		if strings.HasSuffix(d.WorkingDirectory, "/") {
			d.WorkingDirectory = d.WorkingDirectory + path
		} else {
			d.WorkingDirectory = d.WorkingDirectory + "/" + path
		}
	}
	fmt.Println("PWD:", d.WorkingDirectory)
	return true
}
func (d *S3Driver) DirContents(path string) ([]os.FileInfo, bool) {
	moreObjects := true
	var objects []*s3.Object
	var resp *s3.ListObjectsOutput
	var err error
	marker := ""
	for moreObjects {
		resp, err = d.s3DirContents(path, 1000, marker)
		if err == nil {
			for _, obj := range resp.Contents {
				objects = append(objects, obj)
			}
			moreObjects = *resp.IsTruncated
			if moreObjects {
				last := objects[len(objects)-1]
				marker = *last.Key
			}
		}
	}
	prefix := pathToS3PathPrefix(path)
	var files []os.FileInfo
	var dirs []string
	for _, object := range objects {
		p := *object.Key
		p = strings.TrimPrefix(p, *prefix)
		var fi os.FileInfo
		if strings.Contains(p, "/") || p == "" {
			parts := strings.Split(p, "/")
			dirPart := parts[0]
			if dirPart != d.WorkingDirectory && dirPart != "" && dirPart != "/" && !stringInSlice(dirPart, dirs) {
				fi = graval.NewDirItem(dirPart)
				files = append(files, fi)
				dirs = append(dirs, dirPart)
			}
		} else {
			fi = graval.NewFileItem(*object.Key, *object.Size, *object.LastModified)
			files = append(files, fi)
		}
	}
	return files, true
}