@ -42,17 +42,14 @@ import (
)
// isValidUploadID - is upload id.
func ( fs Filesystem ) isValidUploadID ( object , uploadID string ) bool {
func ( fs Filesystem ) isValidUploadID ( object , uploadID string ) ( ok bool ) {
fs . rwLock . RLock ( )
defer fs . rwLock . RUnlock ( )
s , ok : = fs . multiparts . ActiveSession [ object ]
_ , ok = fs . multiparts . ActiveSession [ uploadID ]
if ! ok {
return false
}
if uploadID == s . UploadID {
return true
return
}
return false
return
}
// ListMultipartUploads - list incomplete multipart sessions for a given BucketMultipartResourcesMetadata
@ -73,40 +70,41 @@ func (fs Filesystem) ListMultipartUploads(bucket string, resources BucketMultipa
var uploads [ ] * UploadMetadata
fs . rwLock . RLock ( )
defer fs . rwLock . RUnlock ( )
for object , session := range fs . multiparts . ActiveSession {
if strings . HasPrefix ( object , resources . Prefix ) {
for uploadID , session := range fs . multiparts . ActiveSession {
objectName := session . ObjectName
if strings . HasPrefix ( objectName , resources . Prefix ) {
if len ( uploads ) > resources . MaxUploads {
sort . Sort ( byUploadMetadataKey ( uploads ) )
resources . Upload = uploads
resources . NextKeyMarker = object
resources . NextUploadIDMarker = session . U ploadID
resources . NextKeyMarker = sessi on . O bjectName
resources . NextUploadIDMarker = u ploadID
resources . IsTruncated = true
return resources , nil
}
// UploadIDMarker is ignored if KeyMarker is empty.
switch {
case resources . KeyMarker != "" && resources . UploadIDMarker == "" :
if object > resources . KeyMarker {
if objectName > resources . KeyMarker {
upload := new ( UploadMetadata )
upload . Object = object
upload . UploadID = session . U ploadID
upload . Object = objectName
upload . UploadID = u ploadID
upload . Initiated = session . Initiated
uploads = append ( uploads , upload )
}
case resources . KeyMarker != "" && resources . UploadIDMarker != "" :
if session . UploadID > resources . UploadIDMarker {
if object >= resources . KeyMarker {
if objectName >= resources . KeyMarker {
upload := new ( UploadMetadata )
upload . Object = object
upload . UploadID = session . U ploadID
upload . Object = objectName
upload . UploadID = u ploadID
upload . Initiated = session . Initiated
uploads = append ( uploads , upload )
}
}
default :
upload := new ( UploadMetadata )
upload . Object = object
upload . UploadID = session . U ploadID
upload . Object = objectName
upload . UploadID = u ploadID
upload . Initiated = session . Initiated
uploads = append ( uploads , upload )
}
@ -158,7 +156,7 @@ func removeParts(partPathPrefix string, parts []PartMetadata) *probe.Error {
for _ , part := range parts {
// We are on purpose ignoring the return values here, since
// another thread would have purged these entries.
os . Remove ( partPathPrefix + fmt . Sprintf ( "$%d-$multiparts" , part . PartNumber ) )
os . Remove ( partPathPrefix + part . ETag + fmt . Sprintf ( "$%d-$multiparts" , part . PartNumber ) )
}
return nil
}
@ -168,7 +166,9 @@ func saveParts(partPathPrefix string, mw io.Writer, parts []CompletePart) *probe
var partReaders [ ] io . Reader
var partClosers [ ] io . Closer
for _ , part := range parts {
partFile , e := os . OpenFile ( partPathPrefix + fmt . Sprintf ( "$%d-$multiparts" , part . PartNumber ) , os . O_RDONLY , 0600 )
md5Sum := strings . TrimPrefix ( part . ETag , "\"" )
md5Sum = strings . TrimSuffix ( md5Sum , "\"" )
partFile , e := os . OpenFile ( partPathPrefix + md5Sum + fmt . Sprintf ( "$%d-$multiparts" , part . PartNumber ) , os . O_RDONLY , 0600 )
if e != nil {
return probe . NewError ( e )
}
@ -236,21 +236,22 @@ func (fs Filesystem) NewMultipartUpload(bucket, object string) (string, *probe.E
uploadIDSum := sha512 . Sum512 ( id )
uploadID := base64 . URLEncoding . EncodeToString ( uploadIDSum [ : ] ) [ : 47 ]
fs . rwLock . Lock ( )
// Initialize multipart session.
mpartSession := & MultipartSession { }
mpartSession . TotalParts = 0
mpartSession . ObjectName = object
mpartSession . UploadID = uploadID
mpartSession . Initiated = time . Now ( ) . UTC ( )
var parts [ ] PartMetadata
mpartSession . Parts = parts
fs . rwLock . Lock ( )
fs . multiparts . ActiveSession [ object ] = mpartSession
fs . rwLock . Unlock ( )
fs . multiparts . ActiveSession [ uploadID ] = mpartSession
if err := saveMultipartsSession ( * fs . multiparts ) ; err != nil {
fs . rwLock . Unlock ( )
return "" , err . Trace ( objectPath )
}
fs . rwLock . Unlock ( )
return uploadID , nil
}
@ -317,7 +318,7 @@ func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum s
objectPath := filepath . Join ( bucketPath , object )
partPathPrefix := objectPath + uploadID
partPath := partPathPrefix + fmt . Sprintf ( "$%d-$multiparts" , partID )
partPath := partPathPrefix + expectedMD5Sum + fmt . Sprintf ( "$%d-$multiparts" , partID )
partFile , e := atomic . FileCreateWithPrefix ( partPath , "$multiparts" )
if e != nil {
return "" , probe . NewError ( e )
@ -364,7 +365,7 @@ func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum s
partMetadata . LastModified = fi . ModTime ( )
fs . rwLock . RLock ( )
deserializedMultipartSession , ok := fs . multiparts . ActiveSession [ object ]
deserializedMultipartSession , ok := fs . multiparts . ActiveSession [ uploadID ]
fs . rwLock . RUnlock ( )
if ! ok {
return "" , probe . NewError ( InvalidUploadID { UploadID : uploadID } )
@ -378,16 +379,16 @@ func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum s
deserializedMultipartSession . Parts [ partID - 1 ] = partMetadata
}
deserializedMultipartSession . TotalParts = len ( deserializedMultipartSession . Parts )
fs . rwLock . Lock ( )
fs . multiparts . ActiveSession [ object ] = deserializedMultipartSession
fs . rwLock . Unlock ( )
// Sort by part number before saving.
sort . Sort ( partNumber ( deserializedMultipartSession . Parts ) )
fs . rwLock . Lock ( )
fs . multiparts . ActiveSession [ uploadID ] = deserializedMultipartSession
if err := saveMultipartsSession ( * fs . multiparts ) ; err != nil {
fs . rwLock . Unlock ( )
return "" , err . Trace ( partPathPrefix )
}
fs . rwLock . Unlock ( )
return partMetadata . ETag , nil
}
@ -420,7 +421,7 @@ func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, da
}
objectPath := filepath . Join ( bucketPath , object )
file , e := atomic . FileCreateWithPrefix ( objectPath , "" )
file , e := atomic . FileCreateWithPrefix ( objectPath , "$tmpobject " )
if e != nil {
return ObjectMetadata { } , probe . NewError ( e )
}
@ -459,7 +460,7 @@ func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, da
parts := completeMultipartUpload . Part
fs . rwLock . RLock ( )
savedParts := fs . multiparts . ActiveSession [ object ] . Parts
savedParts := fs . multiparts . ActiveSession [ uploadID ] . Parts
fs . rwLock . RUnlock ( )
if ! doPartsMatch ( parts , savedParts ) {
@ -476,13 +477,14 @@ func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, da
removeParts ( partPathPrefix , savedParts )
fs . rwLock . Lock ( )
delete ( fs . multiparts . ActiveSession , object )
fs . rwLock . Unlock ( )
delete ( fs . multiparts . ActiveSession , uploadID )
if err := saveMultipartsSession ( * fs . multiparts ) ; err != nil {
fs . rwLock . Unlock ( )
file . CloseAndPurge ( )
return ObjectMetadata { } , err . Trace ( partPathPrefix )
}
fs . rwLock . Unlock ( )
file . Close ( )
st , e := os . Stat ( objectPath )
@ -519,9 +521,12 @@ func (fs Filesystem) ListObjectParts(bucket, object string, resources ObjectReso
return ObjectResourcesMetadata { } , probe . NewError ( ObjectNameInvalid { Bucket : bucket , Object : object } )
}
// Save upload id.
uploadID := resources . UploadID
// Verify if upload id is valid for incoming object.
if ! fs . isValidUploadID ( object , resources . UploadID ) {
return ObjectResourcesMetadata { } , probe . NewError ( InvalidUploadID { UploadID : resources . UploadID } )
if ! fs . isValidUploadID ( object , uploadID ) {
return ObjectResourcesMetadata { } , probe . NewError ( InvalidUploadID { UploadID : uploadID } )
}
objectResourcesMetadata := resources
@ -546,7 +551,7 @@ func (fs Filesystem) ListObjectParts(bucket, object string, resources ObjectReso
}
fs . rwLock . RLock ( )
deserializedMultipartSession , ok := fs . multiparts . ActiveSession [ object ]
deserializedMultipartSession , ok := fs . multiparts . ActiveSession [ uploadID ]
fs . rwLock . RUnlock ( )
if ! ok {
return ObjectResourcesMetadata { } , probe . NewError ( InvalidUploadID { UploadID : resources . UploadID } )
@ -596,7 +601,7 @@ func (fs Filesystem) AbortMultipartUpload(bucket, object, uploadID string) *prob
objectPath := filepath . Join ( bucketPath , object )
partPathPrefix := objectPath + uploadID
fs . rwLock . RLock ( )
savedParts := fs . multiparts . ActiveSession [ object ] . Parts
savedParts := fs . multiparts . ActiveSession [ uploadID ] . Parts
fs . rwLock . RUnlock ( )
if err := removeParts ( partPathPrefix , savedParts ) ; err != nil {
@ -604,10 +609,11 @@ func (fs Filesystem) AbortMultipartUpload(bucket, object, uploadID string) *prob
}
fs . rwLock . Lock ( )
delete ( fs . multiparts . ActiveSession , object )
fs . rwLock . Unlock ( )
delete ( fs . multiparts . ActiveSession , uploadID )
if err := saveMultipartsSession ( * fs . multiparts ) ; err != nil {
fs . rwLock . Unlock ( )
return err . Trace ( partPathPrefix )
}
fs . rwLock . Unlock ( )
return nil
}