-
Notifications
You must be signed in to change notification settings - Fork 221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handled chown Scenario #1655
base: main
Are you sure you want to change the base?
Handled chown Scenario #1655
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,8 @@ const ( | |
UserAgentHeader = "User-Agent" | ||
|
||
BlockCacheRWErrMsg = "Notice: The random write flow using block cache is temporarily blocked due to potential data integrity issues. This is a precautionary measure. \nIf you see this message, contact [email protected] or create a GitHub issue. We're working on a fix. More details: https://aka.ms/blobfuse2warnings." | ||
OwnerID = "Uid" | ||
GroupId = "Gid" | ||
) | ||
|
||
func FuseIgnoredFlags() []string { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -666,6 +666,8 @@ func (bb *BlockBlob) getBlobAttr(blobInfo *container.BlobItem) (*internal.ObjAtt | |
Flags: internal.NewFileBitMap(), | ||
MD5: blobInfo.Properties.ContentMD5, | ||
ETag: sanitizeEtag(blobInfo.Properties.ETag), | ||
GID: blobInfo.Metadata["gid"], | ||
UID: blobInfo.Metadata["uid"], | ||
} | ||
|
||
parseMetadata(attr, blobInfo.Metadata) | ||
|
@@ -1629,3 +1631,67 @@ func (bb *BlockBlob) SetFilter(filter string) error { | |
bb.Config.filter = &blobfilter.BlobFilter{} | ||
return bb.Config.filter.Configure(filter) | ||
} | ||
|
||
func (bb *BlockBlob) updateMetadata(name string, metadata map[string]*string) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changeowner method anyways gets the uid and gid so there is no need to implement another method as this could have been done in that method itself, |
||
if len(metadata) == 0 { | ||
log.Info("BlockBlob::updateMetadata: No metadata to update for %s", name) | ||
return nil | ||
} | ||
|
||
blobClient := bb.Container.NewBlockBlobClient(filepath.Join(bb.Config.prefixPath, name)) | ||
|
||
// Fetch existing properties | ||
prop, err := blobClient.GetProperties(context.Background(), &blob.GetPropertiesOptions{ | ||
CPKInfo: bb.blobCPKOpt, | ||
}) | ||
if err != nil { | ||
log.Err("BlockBlob::updateMetadata: Failed to fetch properties for %s [%s]", name, err.Error()) | ||
return err | ||
} | ||
|
||
// Update metadata if needed | ||
if prop.Metadata == nil { | ||
prop.Metadata = make(map[string]*string) | ||
} | ||
|
||
update := false | ||
for key, value := range metadata { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we are doing so much of processing. We can get the metadata and set uid/gid related keys irrespective of whether they are there or not and send the metadata back. |
||
matchedKey := "" | ||
// prop.Metadata having key like Gid and Uid, while I have inserted it gid, uid | ||
for storageKey := range prop.Metadata { | ||
if strings.EqualFold(storageKey, key) { | ||
matchedKey = storageKey | ||
break | ||
} | ||
} | ||
if matchedKey == "" { | ||
// key not found; add it | ||
prop.Metadata[key] = value | ||
update = true | ||
} else { | ||
// key found; compare values | ||
existingValue := prop.Metadata[matchedKey] | ||
if *existingValue != *value { | ||
prop.Metadata[matchedKey] = value | ||
update = true | ||
} | ||
} | ||
} | ||
|
||
// Skip update if nothing changed | ||
if !update { | ||
log.Info("BlockBlob::updateMetadata: No changes needed for %s", name) | ||
return nil | ||
} | ||
|
||
// Apply metadata update | ||
if _, err := blobClient.SetMetadata(context.Background(), prop.Metadata, &blob.SetMetadataOptions{ | ||
CPKInfo: bb.blobCPKOpt, | ||
}); err != nil { | ||
log.Err("BlockBlob::updateMetadata: Failed to set metadata for %s [%s]", name, err.Error()) | ||
return err | ||
} | ||
|
||
log.Info("BlockBlob::updateMetadata: Metadata updated for %s - %v", name, prop.Metadata) | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ import ( | |
"net/url" | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
"strings" | ||
"syscall" | ||
|
||
|
@@ -402,6 +403,8 @@ func (dl *Datalake) GetAttr(name string) (blobAttr *internal.ObjAttr, err error) | |
Crtime: *prop.LastModified, | ||
Flags: internal.NewFileBitMap(), | ||
ETag: sanitizeEtag(prop.ETag), | ||
UID: prop.Metadata[common.OwnerID], | ||
GID: prop.Metadata[common.GroupId], | ||
} | ||
parseMetadata(blobAttr, prop.Metadata) | ||
|
||
|
@@ -561,28 +564,23 @@ func (dl *Datalake) ChangeMod(name string, mode os.FileMode) error { | |
} | ||
|
||
// ChangeOwner : Change owner of a path | ||
func (dl *Datalake) ChangeOwner(name string, _ int, _ int) error { | ||
func (dl *Datalake) ChangeOwner(name string, uid int, gid int) error { | ||
log.Trace("Datalake::ChangeOwner : name %s", name) | ||
|
||
if dl.Config.ignoreAccessModifiers { | ||
// for operations like git clone where transaction fails if chown is not successful | ||
// return success instead of ENOSYS | ||
return nil | ||
metadata := make(map[string]*string) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just pass the uid/gid as is to blockblob changeOwner method and it can take care of the rest. There is no need to implement this here. |
||
uidStr := strconv.Itoa(uid) | ||
gidStr := strconv.Itoa(gid) | ||
metadata[common.OwnerID] = &uidStr | ||
metadata[common.GroupId] = &gidStr | ||
err := dl.BlockBlob.updateMetadata(name, metadata) | ||
e := storeDatalakeErrToErr(err) | ||
if e == ErrFileNotFound { | ||
return syscall.ENOENT | ||
} else if err != nil { | ||
log.Err("Datalake::ChangeOwner : Failed to change ownership of file %s to [%s]", name, err.Error()) | ||
return err | ||
} | ||
|
||
// TODO: This is not supported for now. | ||
// fileURL := dl.Filesystem.NewRootDirectoryURL().NewFileURL(filepath.Join(dl.Config.prefixPath, name)) | ||
// group := strconv.Itoa(gid) | ||
// owner := strconv.Itoa(uid) | ||
// _, err := fileURL.SetAccessControl(context.Background(), azbfs.BlobFSAccessControl{Group: group, Owner: owner}) | ||
// e := storeDatalakeErrToErr(err) | ||
// if e == ErrFileNotFound { | ||
// return syscall.ENOENT | ||
// } else if err != nil { | ||
// log.Err("Datalake::ChangeOwner : Failed to change ownership of file %s to %s [%s]", name, mode, err.Error()) | ||
// return err | ||
// } | ||
return syscall.ENOTSUP | ||
return nil | ||
} | ||
|
||
// GetCommittedBlockList : Get the list of committed blocks | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shall not use random names, check what azcopy uses and we shall be using the same key name in metadata to cross tool compatibility.