azureblob: ignore directory markers in inital Fs creation too - fixes #2806

This is a follow-up to feea0532 including the initial Fs creation
where the backend detects whether the path is pointing to a file or a
directory.
This commit is contained in:
Nick Craig-Wood 2019-01-04 12:32:28 +00:00
parent 2d01a65e36
commit 733b072d4f

View file

@ -417,8 +417,8 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
} }
_, err := f.NewObject(remote) _, err := f.NewObject(remote)
if err != nil { if err != nil {
if err == fs.ErrorObjectNotFound { if err == fs.ErrorObjectNotFound || err == fs.ErrorNotAFile {
// File doesn't exist so return old f // File doesn't exist or is a directory so return old f
f.root = oldRoot f.root = oldRoot
return f, nil return f, nil
} }
@ -474,6 +474,21 @@ func (o *Object) updateMetadataWithModTime(modTime time.Time) {
o.meta[modTimeKey] = modTime.Format(timeFormatOut) o.meta[modTimeKey] = modTime.Format(timeFormatOut)
} }
// Returns whether file is a directory marker or not
func isDirectoryMarker(size int64, metadata azblob.Metadata, remote string) bool {
// Directory markers are 0 length
if size == 0 {
// Note that metadata with hdi_isfolder = true seems to be a
// defacto standard for marking blobs as directories.
endsWithSlash := strings.HasSuffix(remote, "/")
if endsWithSlash || remote == "" || metadata["hdi_isfolder"] == "true" {
return true
}
}
return false
}
// listFn is called from list to handle an object // listFn is called from list to handle an object
type listFn func(remote string, object *azblob.BlobItem, isDirectory bool) error type listFn func(remote string, object *azblob.BlobItem, isDirectory bool) error
@ -539,13 +554,8 @@ func (f *Fs) list(dir string, recurse bool, maxResults uint, fn listFn) error {
continue continue
} }
remote := file.Name[len(f.root):] remote := file.Name[len(f.root):]
// is this a directory marker? if isDirectoryMarker(*file.Properties.ContentLength, file.Metadata, remote) {
if *file.Properties.ContentLength == 0 { if strings.HasSuffix(remote, "/") {
// Note that metadata with hdi_isfolder = true seems to be a
// defacto standard for marking blobs as directories.
endsWithSlash := strings.HasSuffix(remote, "/")
if endsWithSlash || remote == "" || file.Metadata["hdi_isfolder"] == "true" {
if endsWithSlash {
remote = remote[:len(remote)-1] remote = remote[:len(remote)-1]
} }
err = fn(remote, file, true) err = fn(remote, file, true)
@ -559,7 +569,6 @@ func (f *Fs) list(dir string, recurse bool, maxResults uint, fn listFn) error {
} }
continue // skip directory marker continue // skip directory marker
} }
}
// Send object // Send object
err = fn(remote, file, false) err = fn(remote, file, false)
if err != nil { if err != nil {
@ -981,27 +990,37 @@ func (o *Object) setMetadata(metadata azblob.Metadata) {
// o.md5 // o.md5
// o.meta // o.meta
func (o *Object) decodeMetaDataFromPropertiesResponse(info *azblob.BlobGetPropertiesResponse) (err error) { func (o *Object) decodeMetaDataFromPropertiesResponse(info *azblob.BlobGetPropertiesResponse) (err error) {
metadata := info.NewMetadata()
size := info.ContentLength()
if isDirectoryMarker(size, metadata, o.remote) {
return fs.ErrorNotAFile
}
// NOTE - Client library always returns MD5 as base64 decoded string, Object needs to maintain // NOTE - Client library always returns MD5 as base64 decoded string, Object needs to maintain
// this as base64 encoded string. // this as base64 encoded string.
o.md5 = base64.StdEncoding.EncodeToString(info.ContentMD5()) o.md5 = base64.StdEncoding.EncodeToString(info.ContentMD5())
o.mimeType = info.ContentType() o.mimeType = info.ContentType()
o.size = info.ContentLength() o.size = size
o.modTime = time.Time(info.LastModified()) o.modTime = time.Time(info.LastModified())
o.accessTier = azblob.AccessTierType(info.AccessTier()) o.accessTier = azblob.AccessTierType(info.AccessTier())
o.setMetadata(info.NewMetadata()) o.setMetadata(metadata)
return nil return nil
} }
func (o *Object) decodeMetaDataFromBlob(info *azblob.BlobItem) (err error) { func (o *Object) decodeMetaDataFromBlob(info *azblob.BlobItem) (err error) {
metadata := info.Metadata
size := *info.Properties.ContentLength
if isDirectoryMarker(size, metadata, o.remote) {
return fs.ErrorNotAFile
}
// NOTE - Client library always returns MD5 as base64 decoded string, Object needs to maintain // NOTE - Client library always returns MD5 as base64 decoded string, Object needs to maintain
// this as base64 encoded string. // this as base64 encoded string.
o.md5 = base64.StdEncoding.EncodeToString(info.Properties.ContentMD5) o.md5 = base64.StdEncoding.EncodeToString(info.Properties.ContentMD5)
o.mimeType = *info.Properties.ContentType o.mimeType = *info.Properties.ContentType
o.size = *info.Properties.ContentLength o.size = size
o.modTime = info.Properties.LastModified o.modTime = info.Properties.LastModified
o.accessTier = info.Properties.AccessTier o.accessTier = info.Properties.AccessTier
o.setMetadata(info.Metadata) o.setMetadata(metadata)
return nil return nil
} }