// CreateBucket - PUT Bucket func (fs *fsDriver) CreateBucket(bucket, acl string) error { fs.lock.Lock() defer fs.lock.Unlock() // verify bucket path legal if drivers.IsValidBucket(bucket) == false { return iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } // get bucket path bucketDir := filepath.Join(fs.root, bucket) // check if bucket exists if _, err := os.Stat(bucketDir); err == nil { return iodine.New(drivers.BucketExists{ Bucket: bucket, }, nil) } // make bucket err := os.Mkdir(bucketDir, 0700) if err != nil { return iodine.New(err, nil) } return nil }
// CreateObject creates a new object func (d donutDriver) CreateObject(bucketName, objectName, contentType, expectedMD5Sum string, size int64, reader io.Reader) (string, error) { errParams := map[string]string{ "bucketName": bucketName, "objectName": objectName, "contentType": contentType, } if d.donut == nil { return "", iodine.New(drivers.InternalError{}, errParams) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return "", iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if !drivers.IsValidObjectName(objectName) || strings.TrimSpace(objectName) == "" { return "", iodine.New(drivers.ObjectNameInvalid{Object: objectName}, nil) } if strings.TrimSpace(contentType) == "" { contentType = "application/octet-stream" } metadata := make(map[string]string) metadata["contentType"] = strings.TrimSpace(contentType) metadata["contentLength"] = strconv.FormatInt(size, 10) if strings.TrimSpace(expectedMD5Sum) != "" { expectedMD5SumBytes, err := base64.StdEncoding.DecodeString(strings.TrimSpace(expectedMD5Sum)) if err != nil { return "", iodine.New(err, nil) } expectedMD5Sum = hex.EncodeToString(expectedMD5SumBytes) } calculatedMD5Sum, err := d.donut.PutObject(bucketName, objectName, expectedMD5Sum, ioutil.NopCloser(reader), metadata) if err != nil { return "", iodine.New(err, errParams) } return calculatedMD5Sum, nil }
// GetObjectMetadata retrieves an object's metadata func (d donutDriver) GetObjectMetadata(bucketName, objectName string) (drivers.ObjectMetadata, error) { d.lock.RLock() defer d.lock.RUnlock() errParams := map[string]string{ "bucketName": bucketName, "objectName": objectName, } if d.donut == nil { return drivers.ObjectMetadata{}, iodine.New(drivers.InternalError{}, errParams) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return drivers.ObjectMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, errParams) } if !drivers.IsValidObjectName(objectName) || strings.TrimSpace(objectName) == "" { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNameInvalid{Object: objectName}, errParams) } metadata, err := d.donut.GetObjectMetadata(bucketName, objectName) if err != nil { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNotFound{ Bucket: bucketName, Object: objectName, }, errParams) } objectMetadata := drivers.ObjectMetadata{ Bucket: bucketName, Key: objectName, ContentType: metadata.Metadata["contentType"], Created: metadata.Created, Md5: metadata.MD5Sum, Size: metadata.Size, } return objectMetadata, nil }
// ListBuckets - Get service func (fs *fsDriver) ListBuckets() ([]drivers.BucketMetadata, error) { files, err := ioutil.ReadDir(fs.root) if err != nil { return []drivers.BucketMetadata{}, iodine.New(err, nil) } var metadataList []drivers.BucketMetadata for _, file := range files { if !file.IsDir() { // if files found ignore them continue } if file.IsDir() { // if directories found with odd names, skip them too if !drivers.IsValidBucket(file.Name()) { continue } } metadata := drivers.BucketMetadata{ Name: file.Name(), Created: file.ModTime(), } metadataList = append(metadataList, metadata) } return metadataList, nil }
// GetBucketMetadata retrieves an bucket's metadata func (d donutDriver) GetBucketMetadata(bucketName string) (drivers.BucketMetadata, error) { if d.donut == nil { return drivers.BucketMetadata{}, iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return drivers.BucketMetadata{}, drivers.BucketNameInvalid{Bucket: bucketName} } metadata, err := d.donut.GetBucketMetadata(bucketName) if err != nil { return drivers.BucketMetadata{}, iodine.New(drivers.BucketNotFound{Bucket: bucketName}, nil) } created, err := time.Parse(time.RFC3339Nano, metadata["created"]) if err != nil { return drivers.BucketMetadata{}, iodine.New(err, nil) } acl, ok := metadata["acl"] if !ok { return drivers.BucketMetadata{}, iodine.New(drivers.BackendCorrupted{}, nil) } bucketMetadata := drivers.BucketMetadata{ Name: bucketName, Created: created, ACL: drivers.BucketACL(acl), } return bucketMetadata, nil }
// GetPartialObject - GET object from cache buffer range func (cache *cacheDriver) GetPartialObject(w io.Writer, bucket, object string, start, length int64) (int64, error) { errParams := map[string]string{ "bucket": bucket, "object": object, "start": strconv.FormatInt(start, 10), "length": strconv.FormatInt(length, 10), } cache.lock.RLock() if !drivers.IsValidBucket(bucket) { cache.lock.RUnlock() return 0, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, errParams) } if !drivers.IsValidObjectName(object) { cache.lock.RUnlock() return 0, iodine.New(drivers.ObjectNameInvalid{Object: object}, errParams) } if start < 0 { return 0, iodine.New(drivers.InvalidRange{ Start: start, Length: length, }, errParams) } objectKey := bucket + "/" + object data, ok := cache.objects.Get(objectKey) if !ok { cache.lock.RUnlock() return 0, iodine.New(drivers.ObjectNotFound{Bucket: bucket, Object: object}, errParams) } written, err := io.CopyN(w, bytes.NewBuffer(data[start:]), length) cache.lock.RUnlock() return written, iodine.New(err, nil) }
// GetObjectMetadata - HEAD object func (fs *fsDriver) GetObjectMetadata(bucket, object string) (drivers.ObjectMetadata, error) { if drivers.IsValidBucket(bucket) == false { return drivers.ObjectMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if drivers.IsValidObjectName(object) == false { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNameInvalid{Bucket: bucket, Object: bucket}, nil) } // Do not use filepath.Join() since filepath.Join strips off any object names with '/', use them as is // in a static manner so that we can send a proper 'ObjectNotFound' reply back upon os.Stat() objectPath := fs.root + "/" + bucket + "/" + object stat, err := os.Stat(objectPath) if os.IsNotExist(err) { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNotFound{Bucket: bucket, Object: object}, nil) } _, err = os.Stat(objectPath + "$metadata") if os.IsNotExist(err) { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNotFound{Bucket: bucket, Object: object}, nil) } file, err := os.Open(objectPath + "$metadata") defer file.Close() if err != nil { return drivers.ObjectMetadata{}, iodine.New(err, nil) } var deserializedMetadata Metadata decoder := json.NewDecoder(file) err = decoder.Decode(&deserializedMetadata) if err != nil { return drivers.ObjectMetadata{}, iodine.New(err, nil) } contentType := "application/octet-stream" if deserializedMetadata.ContentType != "" { contentType = deserializedMetadata.ContentType } contentType = strings.TrimSpace(contentType) etag := bucket + "#" + filepath.Base(object) if len(deserializedMetadata.Md5sum) != 0 { etag = hex.EncodeToString(deserializedMetadata.Md5sum) } metadata := drivers.ObjectMetadata{ Bucket: bucket, Key: object, Created: stat.ModTime(), Size: stat.Size(), Md5: etag, ContentType: contentType, } return metadata, nil }
// ListObjects - GET bucket (list objects) func (fs *fsDriver) ListObjects(bucket string, resources drivers.BucketResourcesMetadata) ([]drivers.ObjectMetadata, drivers.BucketResourcesMetadata, error) { p := bucketDir{} p.files = make(map[string]os.FileInfo) if drivers.IsValidBucket(bucket) == false { return []drivers.ObjectMetadata{}, resources, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if resources.Prefix != "" && drivers.IsValidObjectName(resources.Prefix) == false { return []drivers.ObjectMetadata{}, resources, iodine.New(drivers.ObjectNameInvalid{Bucket: bucket, Object: resources.Prefix}, nil) } rootPrefix := filepath.Join(fs.root, bucket) // check bucket exists if _, err := os.Stat(rootPrefix); os.IsNotExist(err) { return []drivers.ObjectMetadata{}, resources, iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } p.root = rootPrefix err := filepath.Walk(rootPrefix, p.getAllFiles) if err != nil { return []drivers.ObjectMetadata{}, resources, iodine.New(err, nil) } var metadataList []drivers.ObjectMetadata var metadata drivers.ObjectMetadata // Populate filtering mode resources.Mode = drivers.GetMode(resources) var fileNames []string for name := range p.files { fileNames = append(fileNames, name) } sort.Strings(fileNames) for _, name := range fileNames { if len(metadataList) >= resources.Maxkeys { resources.IsTruncated = true if resources.IsTruncated && resources.IsDelimiterSet() { resources.NextMarker = metadataList[len(metadataList)-1].Key } break } if name > resources.Marker { metadata, resources, err = fs.filterObjects(bucket, name, p.files[name], resources) if err != nil { return []drivers.ObjectMetadata{}, resources, iodine.New(err, nil) } if metadata.Bucket != "" { metadataList = append(metadataList, metadata) } } } sort.Sort(byObjectKey(metadataList)) return metadataList, resources, nil }
func (fs *fsDriver) AbortMultipartUpload(bucket, key, uploadID string) error { fs.lock.Lock() defer fs.lock.Unlock() // check bucket name valid if drivers.IsValidBucket(bucket) == false { return iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } // verify object path legal if drivers.IsValidObjectName(key) == false { return iodine.New(drivers.ObjectNameInvalid{Bucket: bucket, Object: key}, nil) } if !fs.isValidUploadID(key, uploadID) { return iodine.New(drivers.InvalidUploadID{UploadID: uploadID}, nil) } bucketPath := filepath.Join(fs.root, bucket) _, err := os.Stat(bucketPath) // check bucket exists if os.IsNotExist(err) { return iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } if err != nil { return iodine.New(drivers.InternalError{}, nil) } objectPath := filepath.Join(bucketPath, key) multiPartfile, err := os.OpenFile(objectPath+"$multiparts", os.O_RDWR, 0600) if err != nil { return iodine.New(err, nil) } var deserializedMultipartSession MultipartSession decoder := json.NewDecoder(multiPartfile) err = decoder.Decode(&deserializedMultipartSession) if err != nil { return iodine.New(err, nil) } multiPartfile.Close() // close it right here, since we will delete it subsequently delete(fs.multiparts.ActiveSession, key) for _, part := range deserializedMultipartSession.Parts { err = os.RemoveAll(objectPath + fmt.Sprintf("$%d", part.PartNumber)) if err != nil { return iodine.New(err, nil) } } err = os.RemoveAll(objectPath + "$multiparts") if err != nil { return iodine.New(err, nil) } return nil }
// GetBucketMetadata - func (cache *cacheDriver) GetBucketMetadata(bucket string) (drivers.BucketMetadata, error) { cache.lock.RLock() defer cache.lock.RUnlock() if !drivers.IsValidBucket(bucket) { return drivers.BucketMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if _, ok := cache.storedBuckets[bucket]; ok == false { return drivers.BucketMetadata{}, iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } return cache.storedBuckets[bucket].bucketMetadata, nil }
// GetObject retrieves an object and writes it to a writer func (d donutDriver) GetObject(w io.Writer, bucketName, objectName string) (int64, error) { if d.donut == nil { return 0, iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucket(bucketName) { return 0, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if !drivers.IsValidObjectName(objectName) { return 0, iodine.New(drivers.ObjectNameInvalid{Object: objectName}, nil) } if _, ok := d.storedBuckets[bucketName]; ok == false { return 0, iodine.New(drivers.BucketNotFound{Bucket: bucketName}, nil) } d.lock.RLock() defer d.lock.RUnlock() objectKey := bucketName + "/" + objectName data, ok := d.objects.Get(objectKey) if !ok { reader, size, err := d.donut.GetObject(bucketName, objectName) if err != nil { switch iodine.ToError(err).(type) { case donut.BucketNotFound: return 0, iodine.New(drivers.BucketNotFound{Bucket: bucketName}, nil) case donut.ObjectNotFound: return 0, iodine.New(drivers.ObjectNotFound{ Bucket: bucketName, Object: objectName, }, nil) default: return 0, iodine.New(drivers.InternalError{}, nil) } } pw := newProxyWriter(w) n, err := io.CopyN(pw, reader, size) if err != nil { return 0, iodine.New(err, nil) } // Save in memory for future reads d.objects.Set(objectKey, pw.writtenBytes) // free up pw.writtenBytes = nil go debug.FreeOSMemory() return n, nil } written, err := io.Copy(w, bytes.NewBuffer(data)) if err != nil { return 0, iodine.New(err, nil) } return written, nil }
// GetPartialObject retrieves an object range and writes it to a writer func (d donutDriver) GetPartialObject(w io.Writer, bucketName, objectName string, start, length int64) (int64, error) { d.lock.RLock() defer d.lock.RUnlock() if d.donut == nil { return 0, iodine.New(drivers.InternalError{}, nil) } errParams := map[string]string{ "bucketName": bucketName, "objectName": objectName, "start": strconv.FormatInt(start, 10), "length": strconv.FormatInt(length, 10), } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return 0, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, errParams) } if !drivers.IsValidObjectName(objectName) || strings.TrimSpace(objectName) == "" { return 0, iodine.New(drivers.ObjectNameInvalid{Object: objectName}, errParams) } if start < 0 { return 0, iodine.New(drivers.InvalidRange{ Start: start, Length: length, }, errParams) } reader, size, err := d.donut.GetObject(bucketName, objectName) if err != nil { return 0, iodine.New(drivers.ObjectNotFound{ Bucket: bucketName, Object: objectName, }, nil) } defer reader.Close() if start > size || (start+length-1) > size { return 0, iodine.New(drivers.InvalidRange{ Start: start, Length: length, }, errParams) } _, err = io.CopyN(ioutil.Discard, reader, start) if err != nil { return 0, iodine.New(err, errParams) } n, err := io.CopyN(w, reader, length) if err != nil { return 0, iodine.New(err, errParams) } return n, nil }
// ListObjects - returns list of objects func (d donutDriver) ListObjects(bucketName string, resources drivers.BucketResourcesMetadata) ([]drivers.ObjectMetadata, drivers.BucketResourcesMetadata, error) { errParams := map[string]string{ "bucketName": bucketName, } if d.donut == nil { return nil, drivers.BucketResourcesMetadata{}, iodine.New(drivers.InternalError{}, errParams) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return nil, drivers.BucketResourcesMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if !drivers.IsValidObjectName(resources.Prefix) { return nil, drivers.BucketResourcesMetadata{}, iodine.New(drivers.ObjectNameInvalid{Object: resources.Prefix}, nil) } actualObjects, commonPrefixes, isTruncated, err := d.donut.ListObjects(bucketName, resources.Prefix, resources.Marker, resources.Delimiter, resources.Maxkeys) if err != nil { return nil, drivers.BucketResourcesMetadata{}, iodine.New(err, errParams) } resources.CommonPrefixes = commonPrefixes resources.IsTruncated = isTruncated if resources.IsTruncated && resources.IsDelimiterSet() { resources.NextMarker = actualObjects[len(actualObjects)-1] } var results []drivers.ObjectMetadata for _, objectName := range actualObjects { objectMetadata, err := d.donut.GetObjectMetadata(bucketName, objectName) if err != nil { return nil, drivers.BucketResourcesMetadata{}, iodine.New(err, errParams) } t, err := time.Parse(time.RFC3339Nano, objectMetadata["created"]) if err != nil { return nil, drivers.BucketResourcesMetadata{}, iodine.New(err, nil) } size, err := strconv.ParseInt(objectMetadata["size"], 10, 64) if err != nil { return nil, drivers.BucketResourcesMetadata{}, iodine.New(err, nil) } metadata := drivers.ObjectMetadata{ Key: objectName, Created: t, Size: size, } results = append(results, metadata) } sort.Sort(byObjectKey(results)) return results, resources, nil }
// ListObjects - list objects from cache func (cache *cacheDriver) ListObjects(bucket string, resources drivers.BucketResourcesMetadata) ([]drivers.ObjectMetadata, drivers.BucketResourcesMetadata, error) { cache.lock.RLock() defer cache.lock.RUnlock() if !drivers.IsValidBucket(bucket) { return nil, drivers.BucketResourcesMetadata{IsTruncated: false}, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if !drivers.IsValidObjectName(resources.Prefix) { return nil, drivers.BucketResourcesMetadata{IsTruncated: false}, iodine.New(drivers.ObjectNameInvalid{Object: resources.Prefix}, nil) } if _, ok := cache.storedBuckets[bucket]; ok == false { return nil, drivers.BucketResourcesMetadata{IsTruncated: false}, iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } var results []drivers.ObjectMetadata var keys []string storedBucket := cache.storedBuckets[bucket] for key := range storedBucket.objectMetadata { if strings.HasPrefix(key, bucket+"/") { key = key[len(bucket)+1:] keys, resources = cache.listObjects(keys, key, resources) } } var newKeys []string switch { case resources.Marker != "": for _, key := range keys { if key > resources.Marker { newKeys = appendUniq(newKeys, key) } } default: newKeys = keys } sort.Strings(newKeys) for _, key := range newKeys { if len(results) == resources.Maxkeys { resources.IsTruncated = true if resources.IsTruncated && resources.IsDelimiterSet() { resources.NextMarker = results[len(results)-1].Key } return results, resources, nil } object := storedBucket.objectMetadata[bucket+"/"+key] results = append(results, object) } return results, resources, nil }
// GetPartialObject - GET object from range func (fs *fsDriver) GetPartialObject(w io.Writer, bucket, object string, start, length int64) (int64, error) { // validate bucket if drivers.IsValidBucket(bucket) == false { return 0, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } // validate object if drivers.IsValidObjectName(object) == false { return 0, iodine.New(drivers.ObjectNameInvalid{Bucket: bucket, Object: object}, nil) } objectPath := filepath.Join(fs.root, bucket, object) filestat, err := os.Stat(objectPath) switch err := err.(type) { case nil: { if filestat.IsDir() { return 0, iodine.New(drivers.ObjectNotFound{Bucket: bucket, Object: object}, nil) } } default: { if os.IsNotExist(err) { return 0, iodine.New(drivers.ObjectNotFound{Bucket: bucket, Object: object}, nil) } return 0, iodine.New(err, nil) } } file, err := os.Open(objectPath) if err != nil { return 0, iodine.New(err, nil) } defer file.Close() _, err = file.Seek(start, os.SEEK_SET) if err != nil { return 0, iodine.New(err, nil) } count, err := io.CopyN(w, file, length) if err != nil { return count, iodine.New(err, nil) } return count, nil }
// SetBucketMetadata - func (fs *fsDriver) SetBucketMetadata(bucket, acl string) error { fs.lock.Lock() defer fs.lock.Unlock() if !drivers.IsValidBucket(bucket) { return iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if !drivers.IsValidBucketACL(acl) { return iodine.New(drivers.InvalidACL{ACL: acl}, nil) } // get bucket path bucketDir := filepath.Join(fs.root, bucket) err := os.Chmod(bucketDir, aclToPerm(acl)) if err != nil { return iodine.New(err, nil) } return nil }
// SetBucketMetadata sets bucket's metadata func (d donutDriver) SetBucketMetadata(bucketName, acl string) error { if d.donut == nil { return iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if strings.TrimSpace(acl) == "" { acl = "private" } bucketMetadata := make(map[string]string) bucketMetadata["acl"] = acl err := d.donut.SetBucketMetadata(bucketName, bucketMetadata) if err != nil { return iodine.New(drivers.BucketNotFound{Bucket: bucketName}, nil) } return nil }
// GetObjectMetadata retrieves an object's metadata func (d donutDriver) GetObjectMetadata(bucketName, objectName string) (drivers.ObjectMetadata, error) { d.lock.RLock() defer d.lock.RUnlock() errParams := map[string]string{ "bucketName": bucketName, "objectName": objectName, } if d.donut == nil { return drivers.ObjectMetadata{}, iodine.New(drivers.InternalError{}, errParams) } if !drivers.IsValidBucket(bucketName) { return drivers.ObjectMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, errParams) } if !drivers.IsValidObjectName(objectName) { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNameInvalid{Object: objectName}, errParams) } if _, ok := d.storedBuckets[bucketName]; ok { storedBucket := d.storedBuckets[bucketName] objectKey := bucketName + "/" + objectName if object, ok := storedBucket.objectMetadata[objectKey]; ok { return object, nil } } metadata, err := d.donut.GetObjectMetadata(bucketName, objectName) if err != nil { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNotFound{ Bucket: bucketName, Object: objectName, }, errParams) } objectMetadata := drivers.ObjectMetadata{ Bucket: bucketName, Key: objectName, ContentType: metadata.Metadata["contentType"], Created: metadata.Created, Md5: metadata.MD5Sum, Size: metadata.Size, } return objectMetadata, nil }
// GetObject retrieves an object and writes it to a writer func (d donutDriver) GetObject(target io.Writer, bucketName, objectName string) (int64, error) { if d.donut == nil { return 0, iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return 0, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if !drivers.IsValidObjectName(objectName) || strings.TrimSpace(objectName) == "" { return 0, iodine.New(drivers.ObjectNameInvalid{Object: objectName}, nil) } reader, size, err := d.donut.GetObject(bucketName, objectName) if err != nil { return 0, iodine.New(drivers.ObjectNotFound{ Bucket: bucketName, Object: objectName, }, nil) } n, err := io.CopyN(target, reader, size) return n, iodine.New(err, nil) }
// GetObjectMetadata - get object metadata from cache func (cache *cacheDriver) GetObjectMetadata(bucket, key string) (drivers.ObjectMetadata, error) { cache.lock.RLock() defer cache.lock.RUnlock() // check if bucket exists if !drivers.IsValidBucket(bucket) { return drivers.ObjectMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if !drivers.IsValidObjectName(key) { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNameInvalid{Object: key}, nil) } if _, ok := cache.storedBuckets[bucket]; ok == false { return drivers.ObjectMetadata{}, iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } storedBucket := cache.storedBuckets[bucket] objectKey := bucket + "/" + key if object, ok := storedBucket.objectMetadata[objectKey]; ok == true { return object, nil } return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNotFound{Bucket: bucket, Object: key}, nil) }
// GetBucketMetadata retrieves an bucket's metadata func (d donutDriver) GetBucketMetadata(bucketName string) (drivers.BucketMetadata, error) { d.lock.RLock() defer d.lock.RUnlock() if d.donut == nil { return drivers.BucketMetadata{}, iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return drivers.BucketMetadata{}, drivers.BucketNameInvalid{Bucket: bucketName} } metadata, err := d.donut.GetBucketMetadata(bucketName) if err != nil { return drivers.BucketMetadata{}, iodine.New(drivers.BucketNotFound{Bucket: bucketName}, nil) } bucketMetadata := drivers.BucketMetadata{ Name: bucketName, Created: metadata.Created, ACL: drivers.BucketACL(metadata.ACL), } return bucketMetadata, nil }
// CreateBucket creates a new bucket func (d donutDriver) CreateBucket(bucketName, acl string) error { d.lock.Lock() defer d.lock.Unlock() if len(d.storedBuckets) == totalBuckets { return iodine.New(drivers.TooManyBuckets{Bucket: bucketName}, nil) } if d.donut == nil { return iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucketACL(acl) { return iodine.New(drivers.InvalidACL{ACL: acl}, nil) } if drivers.IsValidBucket(bucketName) { if strings.TrimSpace(acl) == "" { acl = "private" } if err := d.donut.MakeBucket(bucketName, acl); err != nil { switch iodine.ToError(err).(type) { case donut.BucketExists: return iodine.New(drivers.BucketExists{Bucket: bucketName}, nil) } return iodine.New(err, nil) } var newBucket = storedBucket{} newBucket.objectMetadata = make(map[string]drivers.ObjectMetadata) newBucket.multiPartSession = make(map[string]multiPartSession) newBucket.partMetadata = make(map[string]drivers.PartMetadata) metadata, err := d.donut.GetBucketMetadata(bucketName) if err != nil { return iodine.New(err, nil) } newBucket.bucketMetadata = drivers.BucketMetadata{ Name: metadata.Name, Created: metadata.Created, ACL: drivers.BucketACL(metadata.ACL), } d.storedBuckets[bucketName] = newBucket return nil } return iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) }
// SetBucketMetadata - func (cache *cacheDriver) SetBucketMetadata(bucket, acl string) error { cache.lock.RLock() if !drivers.IsValidBucket(bucket) { cache.lock.RUnlock() return iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if _, ok := cache.storedBuckets[bucket]; ok == false { cache.lock.RUnlock() return iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } if strings.TrimSpace(acl) == "" { acl = "private" } cache.lock.RUnlock() cache.lock.Lock() defer cache.lock.Unlock() storedBucket := cache.storedBuckets[bucket] storedBucket.bucketMetadata.ACL = drivers.BucketACL(acl) cache.storedBuckets[bucket] = storedBucket return nil }
// GetObjectMetadata retrieves an object's metadata func (d donutDriver) GetObjectMetadata(bucketName, objectName string) (drivers.ObjectMetadata, error) { errParams := map[string]string{ "bucketName": bucketName, "objectName": objectName, } if d.donut == nil { return drivers.ObjectMetadata{}, iodine.New(drivers.InternalError{}, errParams) } if !drivers.IsValidBucket(bucketName) || strings.Contains(bucketName, ".") { return drivers.ObjectMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, errParams) } if !drivers.IsValidObjectName(objectName) || strings.TrimSpace(objectName) == "" { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNameInvalid{Object: objectName}, errParams) } metadata, err := d.donut.GetObjectMetadata(bucketName, objectName) if err != nil { return drivers.ObjectMetadata{}, iodine.New(drivers.ObjectNotFound{ Bucket: bucketName, Object: objectName, }, errParams) } created, err := time.Parse(time.RFC3339Nano, metadata["created"]) if err != nil { return drivers.ObjectMetadata{}, iodine.New(err, errParams) } size, err := strconv.ParseInt(metadata["size"], 10, 64) if err != nil { return drivers.ObjectMetadata{}, iodine.New(err, errParams) } objectMetadata := drivers.ObjectMetadata{ Bucket: bucketName, Key: objectName, ContentType: metadata["contentType"], Created: created, Md5: metadata["md5"], Size: size, } return objectMetadata, nil }
// CreateBucket creates a new bucket func (d donutDriver) CreateBucket(bucketName, acl string) error { if d.donut == nil { return iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucketACL(acl) { return iodine.New(drivers.InvalidACL{ACL: acl}, nil) } if drivers.IsValidBucket(bucketName) && !strings.Contains(bucketName, ".") { if strings.TrimSpace(acl) == "" { acl = "private" } if err := d.donut.MakeBucket(bucketName, acl); err != nil { err = iodine.ToError(err) if err.Error() == "bucket exists" { return iodine.New(drivers.BucketExists{Bucket: bucketName}, nil) } return err } return nil } return iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) }
// SetBucketMetadata sets bucket's metadata func (d donutDriver) SetBucketMetadata(bucketName, acl string) error { d.lock.Lock() defer d.lock.Unlock() if d.donut == nil { return iodine.New(drivers.InternalError{}, nil) } if !drivers.IsValidBucket(bucketName) { return iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if strings.TrimSpace(acl) == "" { acl = "private" } bucketMetadata := make(map[string]string) bucketMetadata["acl"] = acl err := d.donut.SetBucketMetadata(bucketName, bucketMetadata) if err != nil { return iodine.New(drivers.BucketNotFound{Bucket: bucketName}, nil) } storedBucket := d.storedBuckets[bucketName] storedBucket.bucketMetadata.ACL = drivers.BucketACL(acl) d.storedBuckets[bucketName] = storedBucket return nil }
// CreateBucket - create bucket in cache func (cache *cacheDriver) CreateBucket(bucketName, acl string) error { cache.lock.RLock() if len(cache.storedBuckets) == totalBuckets { cache.lock.RUnlock() return iodine.New(drivers.TooManyBuckets{Bucket: bucketName}, nil) } if !drivers.IsValidBucket(bucketName) { cache.lock.RUnlock() return iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if !drivers.IsValidBucketACL(acl) { cache.lock.RUnlock() return iodine.New(drivers.InvalidACL{ACL: acl}, nil) } if _, ok := cache.storedBuckets[bucketName]; ok == true { cache.lock.RUnlock() return iodine.New(drivers.BucketExists{Bucket: bucketName}, nil) } cache.lock.RUnlock() if strings.TrimSpace(acl) == "" { // default is private acl = "private" } var newBucket = storedBucket{} newBucket.objectMetadata = make(map[string]drivers.ObjectMetadata) newBucket.multiPartSession = make(map[string]multiPartSession) newBucket.partMetadata = make(map[string]drivers.PartMetadata) newBucket.bucketMetadata = drivers.BucketMetadata{} newBucket.bucketMetadata.Name = bucketName newBucket.bucketMetadata.Created = time.Now().UTC() newBucket.bucketMetadata.ACL = drivers.BucketACL(acl) cache.lock.Lock() cache.storedBuckets[bucketName] = newBucket cache.lock.Unlock() return nil }
func (memory *memoryDriver) NewMultipartUpload(bucket, key, contentType string) (string, error) { memory.lock.RLock() if !drivers.IsValidBucket(bucket) { memory.lock.RUnlock() return "", iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } if !drivers.IsValidObjectName(key) { memory.lock.RUnlock() return "", iodine.New(drivers.ObjectNameInvalid{Object: key}, nil) } if _, ok := memory.storedBuckets[bucket]; ok == false { memory.lock.RUnlock() return "", iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } storedBucket := memory.storedBuckets[bucket] objectKey := bucket + "/" + key if _, ok := storedBucket.objectMetadata[objectKey]; ok == true { memory.lock.RUnlock() return "", iodine.New(drivers.ObjectExists{Bucket: bucket, Object: key}, nil) } memory.lock.RUnlock() memory.lock.Lock() id := []byte(strconv.FormatInt(rand.Int63(), 10) + bucket + key + time.Now().String()) uploadIDSum := sha512.Sum512(id) uploadID := base64.URLEncoding.EncodeToString(uploadIDSum[:])[:47] memory.storedBuckets[bucket].multiPartSession[key] = multiPartSession{ uploadID: uploadID, initiated: time.Now(), totalParts: 0, } memory.lock.Unlock() return uploadID, nil }
// GetBucketMetadata - func (fs *fsDriver) GetBucketMetadata(bucket string) (drivers.BucketMetadata, error) { fs.lock.Lock() defer fs.lock.Unlock() if !drivers.IsValidBucket(bucket) { return drivers.BucketMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucket}, nil) } // get bucket path bucketDir := filepath.Join(fs.root, bucket) bucketMetadata := drivers.BucketMetadata{} fi, err := os.Stat(bucketDir) // check if bucket exists if os.IsNotExist(err) { return drivers.BucketMetadata{}, iodine.New(drivers.BucketNotFound{Bucket: bucket}, nil) } if err != nil { return drivers.BucketMetadata{}, iodine.New(err, nil) } bucketMetadata.Name = fi.Name() bucketMetadata.Created = fi.ModTime() // TODO convert os.FileMode to meaningful ACL's bucketMetadata.ACL = drivers.BucketACL("private") return bucketMetadata, nil }
// ListObjects - returns list of objects func (d donutDriver) ListObjects(bucketName string, resources drivers.BucketResourcesMetadata) ([]drivers.ObjectMetadata, drivers.BucketResourcesMetadata, error) { d.lock.RLock() defer d.lock.RUnlock() errParams := map[string]string{ "bucketName": bucketName, } if d.donut == nil { return nil, drivers.BucketResourcesMetadata{}, iodine.New(drivers.InternalError{}, errParams) } if !drivers.IsValidBucket(bucketName) { return nil, drivers.BucketResourcesMetadata{}, iodine.New(drivers.BucketNameInvalid{Bucket: bucketName}, nil) } if !drivers.IsValidObjectName(resources.Prefix) { return nil, drivers.BucketResourcesMetadata{}, iodine.New(drivers.ObjectNameInvalid{Object: resources.Prefix}, nil) } listObjects, err := d.donut.ListObjects(bucketName, resources.Prefix, resources.Marker, resources.Delimiter, resources.Maxkeys) if err != nil { return nil, drivers.BucketResourcesMetadata{}, iodine.New(err, errParams) } resources.CommonPrefixes = listObjects.CommonPrefixes resources.IsTruncated = listObjects.IsTruncated var results []drivers.ObjectMetadata for _, objMetadata := range listObjects.Objects { metadata := drivers.ObjectMetadata{ Key: objMetadata.Object, Created: objMetadata.Created, Size: objMetadata.Size, } results = append(results, metadata) } sort.Sort(byObjectName(results)) if resources.IsTruncated && resources.IsDelimiterSet() { resources.NextMarker = results[len(results)-1].Key } return results, resources, nil }