Problem/Motivation

I want to update an object metadata in S3. As stated in https://docs.aws.amazon.com/AmazonS3/latest/userguide/add-object-metadat..., the procedure to update metadata is to copy the object over itself with the new metadata.

It fails because prepareDestination() checks that source and target are not the same. See https://git.drupalcode.org/project/s3fs/-/blob/4.0.x/modules/s3fs_stream...

Steps to reproduce

Roughly I'm doing:

<?php
$s3fs = \Drupal::service('s3fsfileservice');
$image = $entity->get('field_media_image')->entity;
$uri = $image->getFileUri();
$s3fs->copy($uri, $uri, \Drupal\Core\File\FileExists::Replace);
// FTR I'm altering the metadata in hook_s3fs_copy_params_alter()

Proposed resolution

This check was introduced in #3198862: LogicException with latest dev release with no apparent motivation to me.

My proposed resolution is to provide a "update metadata" method. I think it could be done without altering the preparaDirectory() checks, because the directory is already prepared when you're copying a file over itself...

Remaining tasks

Patch.

User interface changes

No.

API changes

No.

Data model changes

No.

Comments

jonhattan created an issue. See original summary.

cmlara’s picture

This check was introduced in #3198862: LogicException with latest dev release with no apparent motivation to me.

Very quick glancing this issue likely has existed before that.. It appears that we already used cores FileSystem::prepareDirectory() (and before we created our own FileSystem service cores was providing this feature itself), once I moved the code to be a proper decorator we didn't have access to the internal protected method and it had to be copied it into S3FS.

The restriction as is somewhat makes sense, Drupal (and most filesystems) don't have a direct external knowledge of copying from a source to same destination. Versioned filesystems and non-modifiable metadata are somewhat an oddity.

something like

copy($original_location, $temp_location);
move($temp_location, $original_location); 

would be closer to how this is done in traditional filesystem terms, and would be somewhat analogous to Copy on Write (COW) filesystem backend design.

My proposed resolution is to provide a "update metadata" method. I think it could be done without altering the preparaDirectory() checks, because the directory is already prepared when you're copying a file over itself...

As long as the AWS API doesn't block the old file until the copy is completed successfully, there could be something there. I suspect this would go at the bucket level instead of the filesystem level in the 4.x design.

Could add some assistance for issues similar to #3552433: Add Cache Header After Implementation