cleanup: Remove definitions and move them to its relative places accordingly

- Move fs-definitions.go and break them into fs-datatypes.go, fs-bucket-acl.go
  and fs-utils.go
- Move api-definitions.go to api-response.go, where they should be.
- Move web-definitions to its related handlers.
This commit is contained in:
Harshavardhana 2016-02-19 16:04:29 -08:00
parent d3966d1dde
commit 800b19d8e5
14 changed files with 358 additions and 457 deletions

View file

@ -1,225 +0,0 @@
/*
* Minio Cloud Storage, (C) 2015 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import "encoding/xml"
// Limit number of objects in a given response.
const (
maxObjectList = 1000
)
// LocationResponse - format for location response.
type LocationResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ LocationConstraint" json:"-"`
Location string `xml:",chardata"`
}
// AccessControlPolicyResponse - format for get bucket acl response.
type AccessControlPolicyResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ AccessControlPolicy" json:"-"`
AccessControlList struct {
Grant []Grant
}
Owner Owner
}
// Grant container for grantee and permission.
type Grant struct {
Grantee struct {
ID string
DisplayName string
EmailAddress string
Type string
URI string
}
Permission string
}
// ListObjectsResponse - format for list objects response.
type ListObjectsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult" json:"-"`
CommonPrefixes []*CommonPrefix
Contents []*Object
Delimiter string
// Encoding type used to encode object keys in the response.
EncodingType string
// A flag that indicates whether or not ListObjects returned all of the results
// that satisfied the search criteria.
IsTruncated bool
Marker string
MaxKeys int
Name string
// When response is truncated (the IsTruncated element value in the response
// is true), you can use the key name in this field as marker in the subsequent
// request to get next set of objects. Server lists objects in alphabetical
// order Note: This element is returned only if you have delimiter request parameter
// specified. If response does not include the NextMaker and it is truncated,
// you can use the value of the last Key in the response as the marker in the
// subsequent request to get the next set of object keys.
NextMarker string
Prefix string
}
// Part container for part metadata.
type Part struct {
PartNumber int
ETag string
LastModified string
Size int64
}
// ListPartsResponse - format for list parts response.
type ListPartsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListPartsResult" json:"-"`
Bucket string
Key string
UploadID string `xml:"UploadId"`
Initiator Initiator
Owner Owner
// The class of storage used to store the object.
StorageClass string
PartNumberMarker int
NextPartNumberMarker int
MaxParts int
IsTruncated bool
// List of parts.
Part []*Part
}
// ListMultipartUploadsResponse - format for list multipart uploads response.
type ListMultipartUploadsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListMultipartUploadsResult" json:"-"`
Bucket string
KeyMarker string
UploadIDMarker string `xml:"UploadIdMarker"`
NextKeyMarker string
NextUploadIDMarker string `xml:"NextUploadIdMarker"`
EncodingType string
MaxUploads int
IsTruncated bool
Upload []*Upload
Prefix string
Delimiter string
CommonPrefixes []*CommonPrefix
}
// ListBucketsResponse - format for list buckets response
type ListBucketsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult" json:"-"`
// Container for one or more buckets.
Buckets struct {
Bucket []*Bucket
} // Buckets are nested
Owner Owner
}
// Upload container for in progress multipart upload
type Upload struct {
Key string
UploadID string `xml:"UploadId"`
Initiator Initiator
Owner Owner
StorageClass string
Initiated string
}
// CommonPrefix container for prefix response in ListObjectsResponse
type CommonPrefix struct {
Prefix string
}
// Bucket container for bucket metadata
type Bucket struct {
Name string
CreationDate string
}
// Object container for object metadata
type Object struct {
ETag string
Key string
LastModified string
Size int64
Owner Owner
// The class of storage used to store the object.
StorageClass string
}
// Initiator inherit from Owner struct, fields are same
type Initiator Owner
// Owner - bucket owner/principal
type Owner struct {
ID string
DisplayName string
}
// InitiateMultipartUploadResponse container for InitiateMultiPartUpload response, provides uploadID to start MultiPart upload
type InitiateMultipartUploadResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult" json:"-"`
Bucket string
Key string
UploadID string `xml:"UploadId"`
}
// CompleteMultipartUploadResponse container for completed multipart upload response
type CompleteMultipartUploadResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult" json:"-"`
Location string
Bucket string
Key string
ETag string
}
// List of not implemented bucket queries
var notimplementedBucketResourceNames = map[string]bool{
"policy": true,
"cors": true,
"lifecycle": true,
"logging": true,
"notification": true,
"replication": true,
"tagging": true,
"versions": true,
"requestPayment": true,
"versioning": true,
"website": true,
}
// List of not implemented object queries
var notimplementedObjectResourceNames = map[string]bool{
"torrent": true,
"acl": true,
"policy": true,
}

View file

@ -1,5 +1,5 @@
/* /*
* Minio Cloud Storage, (C) 2015 Minio, Inc. * Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,16 +17,198 @@
package main package main
import ( import (
"encoding/xml"
"net/http" "net/http"
"github.com/minio/minio/pkg/fs" "github.com/minio/minio/pkg/fs"
) )
// Reply date format
const ( const (
rfcFormat = "2006-01-02T15:04:05.000Z" // Reply date format
timeFormatAMZ = "2006-01-02T15:04:05.000Z"
// Limit number of objects in a given response.
maxObjectList = 1000
) )
// LocationResponse - format for location response.
type LocationResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ LocationConstraint" json:"-"`
Location string `xml:",chardata"`
}
// AccessControlPolicyResponse - format for get bucket acl response.
type AccessControlPolicyResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ AccessControlPolicy" json:"-"`
AccessControlList struct {
Grants []Grant `xml:"Grant"`
}
Owner Owner
}
// Grant container for grantee and permission.
type Grant struct {
Grantee struct {
ID string
DisplayName string
EmailAddress string
Type string
URI string
}
Permission string
}
// ListObjectsResponse - format for list objects response.
type ListObjectsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListBucketResult" json:"-"`
CommonPrefixes []CommonPrefix
Contents []Object
Delimiter string
// Encoding type used to encode object keys in the response.
EncodingType string
// A flag that indicates whether or not ListObjects returned all of the results
// that satisfied the search criteria.
IsTruncated bool
Marker string
MaxKeys int
Name string
// When response is truncated (the IsTruncated element value in the response
// is true), you can use the key name in this field as marker in the subsequent
// request to get next set of objects. Server lists objects in alphabetical
// order Note: This element is returned only if you have delimiter request parameter
// specified. If response does not include the NextMaker and it is truncated,
// you can use the value of the last Key in the response as the marker in the
// subsequent request to get the next set of object keys.
NextMarker string
Prefix string
}
// Part container for part metadata.
type Part struct {
PartNumber int
ETag string
LastModified string
Size int64
}
// ListPartsResponse - format for list parts response.
type ListPartsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListPartsResult" json:"-"`
Bucket string
Key string
UploadID string `xml:"UploadId"`
Initiator Initiator
Owner Owner
// The class of storage used to store the object.
StorageClass string
PartNumberMarker int
NextPartNumberMarker int
MaxParts int
IsTruncated bool
// List of parts.
Parts []Part `xml:"Part"`
}
// ListMultipartUploadsResponse - format for list multipart uploads response.
type ListMultipartUploadsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListMultipartUploadsResult" json:"-"`
Bucket string
KeyMarker string
UploadIDMarker string `xml:"UploadIdMarker"`
NextKeyMarker string
NextUploadIDMarker string `xml:"NextUploadIdMarker"`
EncodingType string
MaxUploads int
IsTruncated bool
Uploads []Upload `xml:"Upload"`
Prefix string
Delimiter string
CommonPrefixes []CommonPrefix
}
// ListBucketsResponse - format for list buckets response
type ListBucketsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult" json:"-"`
// Container for one or more buckets.
Buckets struct {
Buckets []Bucket `xml:"Bucket"`
} // Buckets are nested
Owner Owner
}
// Upload container for in progress multipart upload
type Upload struct {
Key string
UploadID string `xml:"UploadId"`
Initiator Initiator
Owner Owner
StorageClass string
Initiated string
}
// CommonPrefix container for prefix response in ListObjectsResponse
type CommonPrefix struct {
Prefix string
}
// Bucket container for bucket metadata
type Bucket struct {
Name string
CreationDate string // time string of format "2006-01-02T15:04:05.000Z"
}
// Object container for object metadata
type Object struct {
ETag string
Key string
LastModified string // time string of format "2006-01-02T15:04:05.000Z"
Size int64
Owner Owner
// The class of storage used to store the object.
StorageClass string
}
// Initiator inherit from Owner struct, fields are same
type Initiator Owner
// Owner - bucket owner/principal
type Owner struct {
ID string
DisplayName string
}
// InitiateMultipartUploadResponse container for InitiateMultiPartUpload response, provides uploadID to start MultiPart upload
type InitiateMultipartUploadResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult" json:"-"`
Bucket string
Key string
UploadID string `xml:"UploadId"`
}
// CompleteMultipartUploadResponse container for completed multipart upload response
type CompleteMultipartUploadResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult" json:"-"`
Location string
Bucket string
Key string
ETag string
}
// takes an array of Bucketmetadata information for serialization // takes an array of Bucketmetadata information for serialization
// input: // input:
// array of bucket metadata // array of bucket metadata
@ -34,7 +216,7 @@ const (
// output: // output:
// populated struct that can be serialized to match xml and json api spec output // populated struct that can be serialized to match xml and json api spec output
func generateListBucketsResponse(buckets []fs.BucketMetadata) ListBucketsResponse { func generateListBucketsResponse(buckets []fs.BucketMetadata) ListBucketsResponse {
var listbuckets []*Bucket var listbuckets []Bucket
var data = ListBucketsResponse{} var data = ListBucketsResponse{}
var owner = Owner{} var owner = Owner{}
@ -42,14 +224,14 @@ func generateListBucketsResponse(buckets []fs.BucketMetadata) ListBucketsRespons
owner.DisplayName = "minio" owner.DisplayName = "minio"
for _, bucket := range buckets { for _, bucket := range buckets {
var listbucket = &Bucket{} var listbucket = Bucket{}
listbucket.Name = bucket.Name listbucket.Name = bucket.Name
listbucket.CreationDate = bucket.Created.Format(rfcFormat) listbucket.CreationDate = bucket.Created.Format(timeFormatAMZ)
listbuckets = append(listbuckets, listbucket) listbuckets = append(listbuckets, listbucket)
} }
data.Owner = owner data.Owner = owner
data.Buckets.Bucket = listbuckets data.Buckets.Buckets = listbuckets
return data return data
} }
@ -65,7 +247,7 @@ func generateAccessControlPolicyResponse(acl fs.BucketACL) AccessControlPolicyRe
defaultGrant.Grantee.ID = "minio" defaultGrant.Grantee.ID = "minio"
defaultGrant.Grantee.DisplayName = "minio" defaultGrant.Grantee.DisplayName = "minio"
defaultGrant.Permission = "FULL_CONTROL" defaultGrant.Permission = "FULL_CONTROL"
accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, defaultGrant) accessCtrlPolicyResponse.AccessControlList.Grants = append(accessCtrlPolicyResponse.AccessControlList.Grants, defaultGrant)
switch { switch {
case acl.IsPublicRead(): case acl.IsPublicRead():
publicReadGrant := Grant{} publicReadGrant := Grant{}
@ -73,7 +255,7 @@ func generateAccessControlPolicyResponse(acl fs.BucketACL) AccessControlPolicyRe
publicReadGrant.Grantee.DisplayName = "minio" publicReadGrant.Grantee.DisplayName = "minio"
publicReadGrant.Grantee.URI = "http://acs.amazonaws.com/groups/global/AllUsers" publicReadGrant.Grantee.URI = "http://acs.amazonaws.com/groups/global/AllUsers"
publicReadGrant.Permission = "READ" publicReadGrant.Permission = "READ"
accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, publicReadGrant) accessCtrlPolicyResponse.AccessControlList.Grants = append(accessCtrlPolicyResponse.AccessControlList.Grants, publicReadGrant)
case acl.IsPublicReadWrite(): case acl.IsPublicReadWrite():
publicReadGrant := Grant{} publicReadGrant := Grant{}
publicReadGrant.Grantee.ID = "minio" publicReadGrant.Grantee.ID = "minio"
@ -85,16 +267,16 @@ func generateAccessControlPolicyResponse(acl fs.BucketACL) AccessControlPolicyRe
publicReadWriteGrant.Grantee.DisplayName = "minio" publicReadWriteGrant.Grantee.DisplayName = "minio"
publicReadWriteGrant.Grantee.URI = "http://acs.amazonaws.com/groups/global/AllUsers" publicReadWriteGrant.Grantee.URI = "http://acs.amazonaws.com/groups/global/AllUsers"
publicReadWriteGrant.Permission = "WRITE" publicReadWriteGrant.Permission = "WRITE"
accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, publicReadGrant) accessCtrlPolicyResponse.AccessControlList.Grants = append(accessCtrlPolicyResponse.AccessControlList.Grants, publicReadGrant)
accessCtrlPolicyResponse.AccessControlList.Grant = append(accessCtrlPolicyResponse.AccessControlList.Grant, publicReadWriteGrant) accessCtrlPolicyResponse.AccessControlList.Grants = append(accessCtrlPolicyResponse.AccessControlList.Grants, publicReadWriteGrant)
} }
return accessCtrlPolicyResponse return accessCtrlPolicyResponse
} }
// generates an ListObjects response for the said bucket with other enumerated options. // generates an ListObjects response for the said bucket with other enumerated options.
func generateListObjectsResponse(bucket, prefix, marker, delimiter string, maxKeys int, resp fs.ListObjectsResult) ListObjectsResponse { func generateListObjectsResponse(bucket, prefix, marker, delimiter string, maxKeys int, resp fs.ListObjectsResult) ListObjectsResponse {
var contents []*Object var contents []Object
var prefixes []*CommonPrefix var prefixes []CommonPrefix
var owner = Owner{} var owner = Owner{}
var data = ListObjectsResponse{} var data = ListObjectsResponse{}
@ -102,12 +284,12 @@ func generateListObjectsResponse(bucket, prefix, marker, delimiter string, maxKe
owner.DisplayName = "minio" owner.DisplayName = "minio"
for _, object := range resp.Objects { for _, object := range resp.Objects {
var content = &Object{} var content = Object{}
if object.Object == "" { if object.Object == "" {
continue continue
} }
content.Key = object.Object content.Key = object.Object
content.LastModified = object.Created.Format(rfcFormat) content.LastModified = object.Created.Format(timeFormatAMZ)
if object.MD5 != "" { if object.MD5 != "" {
content.ETag = "\"" + object.MD5 + "\"" content.ETag = "\"" + object.MD5 + "\""
} }
@ -128,7 +310,7 @@ func generateListObjectsResponse(bucket, prefix, marker, delimiter string, maxKe
data.NextMarker = resp.NextMarker data.NextMarker = resp.NextMarker
data.IsTruncated = resp.IsTruncated data.IsTruncated = resp.IsTruncated
for _, prefix := range resp.Prefixes { for _, prefix := range resp.Prefixes {
var prefixItem = &CommonPrefix{} var prefixItem = CommonPrefix{}
prefixItem.Prefix = prefix prefixItem.Prefix = prefix
prefixes = append(prefixes, prefixItem) prefixes = append(prefixes, prefixItem)
} }
@ -173,14 +355,14 @@ func generateListPartsResponse(objectMetadata fs.ObjectResourcesMetadata) ListPa
listPartsResponse.IsTruncated = objectMetadata.IsTruncated listPartsResponse.IsTruncated = objectMetadata.IsTruncated
listPartsResponse.NextPartNumberMarker = objectMetadata.NextPartNumberMarker listPartsResponse.NextPartNumberMarker = objectMetadata.NextPartNumberMarker
listPartsResponse.Part = make([]*Part, len(objectMetadata.Part)) listPartsResponse.Parts = make([]Part, len(objectMetadata.Part))
for _, part := range objectMetadata.Part { for _, part := range objectMetadata.Part {
newPart := &Part{} newPart := Part{}
newPart.PartNumber = part.PartNumber newPart.PartNumber = part.PartNumber
newPart.ETag = "\"" + part.ETag + "\"" newPart.ETag = "\"" + part.ETag + "\""
newPart.Size = part.Size newPart.Size = part.Size
newPart.LastModified = part.LastModified.Format(rfcFormat) newPart.LastModified = part.LastModified.Format(timeFormatAMZ)
listPartsResponse.Part = append(listPartsResponse.Part, newPart) listPartsResponse.Parts = append(listPartsResponse.Parts, newPart)
} }
return listPartsResponse return listPartsResponse
} }
@ -199,13 +381,13 @@ func generateListMultipartUploadsResponse(bucket string, metadata fs.BucketMulti
listMultipartUploadsResponse.NextUploadIDMarker = metadata.NextUploadIDMarker listMultipartUploadsResponse.NextUploadIDMarker = metadata.NextUploadIDMarker
listMultipartUploadsResponse.UploadIDMarker = metadata.UploadIDMarker listMultipartUploadsResponse.UploadIDMarker = metadata.UploadIDMarker
listMultipartUploadsResponse.Upload = make([]*Upload, len(metadata.Upload)) listMultipartUploadsResponse.Uploads = make([]Upload, len(metadata.Upload))
for _, upload := range metadata.Upload { for _, upload := range metadata.Upload {
newUpload := &Upload{} newUpload := Upload{}
newUpload.UploadID = upload.UploadID newUpload.UploadID = upload.UploadID
newUpload.Key = upload.Object newUpload.Key = upload.Object
newUpload.Initiated = upload.Initiated.Format(rfcFormat) newUpload.Initiated = upload.Initiated.Format(timeFormatAMZ)
listMultipartUploadsResponse.Upload = append(listMultipartUploadsResponse.Upload, newUpload) listMultipartUploadsResponse.Uploads = append(listMultipartUploadsResponse.Uploads, newUpload)
} }
return listMultipartUploadsResponse return listMultipartUploadsResponse
} }

View file

@ -248,8 +248,7 @@ func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Checks requests for not implemented Bucket resources // Checks requests for not implemented Bucket resources
func ignoreNotImplementedBucketResources(req *http.Request) bool { func ignoreNotImplementedBucketResources(req *http.Request) bool {
q := req.URL.Query() for name := range req.URL.Query() {
for name := range q {
if notimplementedBucketResourceNames[name] { if notimplementedBucketResourceNames[name] {
return true return true
} }
@ -259,11 +258,32 @@ func ignoreNotImplementedBucketResources(req *http.Request) bool {
// Checks requests for not implemented Object resources // Checks requests for not implemented Object resources
func ignoreNotImplementedObjectResources(req *http.Request) bool { func ignoreNotImplementedObjectResources(req *http.Request) bool {
q := req.URL.Query() for name := range req.URL.Query() {
for name := range q {
if notimplementedObjectResourceNames[name] { if notimplementedObjectResourceNames[name] {
return true return true
} }
} }
return false return false
} }
// List of not implemented bucket queries
var notimplementedBucketResourceNames = map[string]bool{
"policy": true,
"cors": true,
"lifecycle": true,
"logging": true,
"notification": true,
"replication": true,
"tagging": true,
"versions": true,
"requestPayment": true,
"versioning": true,
"website": true,
}
// List of not implemented object queries
var notimplementedObjectResourceNames = map[string]bool{
"torrent": true,
"acl": true,
"policy": true,
}

View file

@ -1,5 +1,5 @@
/* /*
* Minio Cloud Storage, (C) 2015 Minio, Inc. * Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View file

@ -1,5 +1,5 @@
/* /*
* Minio Cloud Storage, (C) 2015 Minio, Inc. * Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -48,3 +48,49 @@ func (fs Filesystem) IsReadOnlyBucket(bucket string) bool {
} }
return bucketMetadata.ACL.IsPublicRead() return bucketMetadata.ACL.IsPublicRead()
} }
// BucketACL - bucket level access control
type BucketACL string
// different types of ACL's currently supported for buckets
const (
BucketPrivate = BucketACL("private")
BucketPublicRead = BucketACL("public-read")
BucketPublicReadWrite = BucketACL("public-read-write")
)
func (b BucketACL) String() string {
return string(b)
}
// IsPrivate - is acl Private
func (b BucketACL) IsPrivate() bool {
return b == BucketACL("private")
}
// IsPublicRead - is acl PublicRead
func (b BucketACL) IsPublicRead() bool {
return b == BucketACL("public-read")
}
// IsPublicReadWrite - is acl PublicReadWrite
func (b BucketACL) IsPublicReadWrite() bool {
return b == BucketACL("public-read-write")
}
// IsValidBucketACL - is provided acl string supported
func IsValidBucketACL(acl string) bool {
switch acl {
case "private":
fallthrough
case "public-read":
fallthrough
case "public-read-write":
return true
case "":
// by default its "private"
return true
default:
return false
}
}

View file

@ -96,16 +96,23 @@ func (fs Filesystem) ListBuckets() ([]BucketMetadata, *probe.Error) {
} }
// removeDuplicateBuckets - remove duplicate buckets. // removeDuplicateBuckets - remove duplicate buckets.
func removeDuplicateBuckets(elements []BucketMetadata) (result []BucketMetadata) { func removeDuplicateBuckets(buckets []BucketMetadata) []BucketMetadata {
// Use map to record duplicates as we find them. length := len(buckets) - 1
duplicates := make(map[string]struct{}) for i := 0; i < length; i++ {
for _, element := range elements { for j := i + 1; j <= length; j++ {
if _, ok := duplicates[element.Name]; !ok { if buckets[i].Name == buckets[j].Name {
duplicates[element.Name] = struct{}{} if buckets[i].Created.Sub(buckets[j].Created) > 0 {
result = append(result, element) buckets[i] = buckets[length]
} else {
buckets[j] = buckets[length]
}
buckets = buckets[0:length]
length--
j--
}
} }
} }
return result return buckets
} }
// MakeBucket - PUT Bucket. // MakeBucket - PUT Bucket.

View file

@ -1,94 +0,0 @@
/*
* Minio Cloud Storage, (C) 2015 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fs
import (
"bufio"
"bytes"
"os"
"sort"
"strings"
"time"
)
// Metadata - carries metadata about object
type Metadata struct {
MD5sum []byte
ContentType string
}
// sanitizeWindowsPath - sanitize a path
func sanitizeWindowsPath(path string) string {
return strings.Replace(path, "\\", "/", -1)
}
// sanitizeWindowsPaths - sanitize some windows paths
func sanitizeWindowsPaths(paths ...string) []string {
var results []string
for _, path := range paths {
results = append(results, sanitizeWindowsPath(path))
}
return results
}
// sortUnique returns n, the number of distinct elements in data in sorted order.
func sortUnique(data sort.Interface) (n int) {
if n = data.Len(); n < 2 {
return n
}
sort.Sort(data)
a, b := 0, 1
for b < n {
if data.Less(a, b) {
a++
if a != b {
data.Swap(a, b)
}
}
b++
}
return a + 1
}
type contentInfo struct {
os.FileInfo
Prefix string
Size int64
Mode os.FileMode
ModTime time.Time
}
type bucketDir struct {
files []contentInfo
root string
}
func delimiter(object, delimiter string) string {
readBuffer := bytes.NewBufferString(object)
reader := bufio.NewReader(readBuffer)
stringReader := strings.NewReader(delimiter)
delimited, _ := stringReader.ReadByte()
delimitedStr, _ := reader.ReadString(delimited)
return delimitedStr
}
// byObjectMetadataKey is a sortable interface for UploadMetadata slice
type byUploadMetadataKey []*UploadMetadata
func (b byUploadMetadataKey) Len() int { return len(b) }
func (b byUploadMetadataKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byUploadMetadataKey) Less(i, j int) bool { return b[i].Object < b[j].Object }

View file

@ -1,5 +1,5 @@
/* /*
* Minimalist Object Storage, (C) 2015 Minio, Inc. * Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,40 +18,9 @@ package fs
import ( import (
"os" "os"
"regexp"
"time" "time"
"unicode/utf8"
) )
// BucketACL - bucket level access control
type BucketACL string
// different types of ACL's currently supported for buckets
const (
BucketPrivate = BucketACL("private")
BucketPublicRead = BucketACL("public-read")
BucketPublicReadWrite = BucketACL("public-read-write")
)
func (b BucketACL) String() string {
return string(b)
}
// IsPrivate - is acl Private
func (b BucketACL) IsPrivate() bool {
return b == BucketACL("private")
}
// IsPublicRead - is acl PublicRead
func (b BucketACL) IsPublicRead() bool {
return b == BucketACL("public-read")
}
// IsPublicReadWrite - is acl PublicReadWrite
func (b BucketACL) IsPublicReadWrite() bool {
return b == BucketACL("public-read-write")
}
// BucketMetadata - name and create date // BucketMetadata - name and create date
type BucketMetadata struct { type BucketMetadata struct {
Name string Name string
@ -142,53 +111,3 @@ func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].Part
type CompleteMultipartUpload struct { type CompleteMultipartUpload struct {
Part []CompletePart Part []CompletePart
} }
// IsValidBucketACL - is provided acl string supported
func IsValidBucketACL(acl string) bool {
switch acl {
case "private":
fallthrough
case "public-read":
fallthrough
case "public-read-write":
return true
case "":
// by default its "private"
return true
default:
return false
}
}
// validBucket regexp.
var validBucket = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`)
// IsValidBucketName - verify bucket name in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html
func IsValidBucketName(bucket string) bool {
if bucket == "" {
return false
}
if len(bucket) < 3 || len(bucket) > 63 {
return false
}
if bucket[0] == '.' || bucket[len(bucket)-1] == '.' {
return false
}
return validBucket.MatchString(bucket)
}
// IsValidObjectName - verify object name in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
func IsValidObjectName(object string) bool {
if object == "" {
return true
}
if len(object) > 1024 || len(object) == 0 {
return false
}
if !utf8.ValidString(object) {
return false
}
return true
}

View file

@ -53,6 +53,13 @@ func (fs Filesystem) isValidUploadID(object, uploadID string) (ok bool) {
return return
} }
// byObjectMetadataKey is a sortable interface for UploadMetadata slice
type byUploadMetadataKey []*UploadMetadata
func (b byUploadMetadataKey) Len() int { return len(b) }
func (b byUploadMetadataKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byUploadMetadataKey) Less(i, j int) bool { return b[i].Object < b[j].Object }
// ListMultipartUploads - list incomplete multipart sessions for a given BucketMultipartResourcesMetadata // ListMultipartUploads - list incomplete multipart sessions for a given BucketMultipartResourcesMetadata
func (fs Filesystem) ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error) { func (fs Filesystem) ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error) {
// Input validation. // Input validation.

View file

@ -155,7 +155,7 @@ func getMetadata(rootPath, bucket, object string) (ObjectMetadata, *probe.Error)
} }
contentType := "application/octet-stream" contentType := "application/octet-stream"
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
object = sanitizeWindowsPath(object) object = filepath.ToSlash(object)
} }
if objectExt := filepath.Ext(object); objectExt != "" { if objectExt := filepath.Ext(object); objectExt != "" {

55
pkg/fs/fs-utils.go Normal file
View file

@ -0,0 +1,55 @@
/*
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fs
import (
"regexp"
"unicode/utf8"
)
// validBucket regexp.
var validBucket = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`)
// IsValidBucketName - verify bucket name in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html
func IsValidBucketName(bucket string) bool {
if bucket == "" {
return false
}
if len(bucket) < 3 || len(bucket) > 63 {
return false
}
if bucket[0] == '.' || bucket[len(bucket)-1] == '.' {
return false
}
return validBucket.MatchString(bucket)
}
// IsValidObjectName - verify object name in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
func IsValidObjectName(object string) bool {
if object == "" {
return true
}
if len(object) > 1024 || len(object) == 0 {
return false
}
if !utf8.ValidString(object) {
return false
}
return true
}

View file

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package probe_test package probe_test
import ( import (

View file

@ -1,17 +0,0 @@
/*
* Minio Cloud Storage, (C) 2016 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main