Problem/Motivation

In Drupal 7, editing a language selection using the Content Translation module will delete any files stored in a file field in the same node. This behavior is likely present in Drupal 8 and will need to be confirmed and fixed there first.

Proposed resolution

A solution has been proposed in #24 with a corresponding D7 patch. This solution approach has not been reviewed for Drupal 8.

Remaining tasks

  1. Test to confirm documented D7 behavior persists in D8
  2. If problem persists in D8, review proposed solution
  3. If problem persists:
    • create D8 patch
    • Test and approve D8 patch
    • Backport solution to D7

User interface changes

TBD

API changes

TBD

#1399846: Make unused file 'cleanup' configurable

Original report by sreynen.

I've tested this a couple dozen times, but haven't found any pattern. Steps to reproduce:

1) Enable File and Content translation modules.
2) Create a content type with a file field.
3) Enable a few languages.
4) Create a node of any language with a file attached.
5) Edit the node and change the language.

Sometimes step 5 needs to be repeated a few times, sometimes it happens the first time, but eventually the file disappears, both in the node and in the file system. The specific languages don't appear to make any difference.

Proposed solution
See #24.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sreynen’s picture

On further testing, the file is not deleted when file_usage_list() returns a count greater than 1, but deleted when file_usage_list() returns a count of only 1. I have no idea what causes that count to sometimes go above 1, as the file is only being used on 1 node.

sreynen’s picture

I found the pattern, and with it the bug.

The pattern is the order of the languages, the order they're in on admin/config/regional/language and in the language drop-down. This is the order of calls from _field_invoke() to file_field_update(), with a separate call for each language instance of the field. If you change languages moving up that list, the file stays, because the new language instance of the file is added before the old language instance is deleted. If you change languages moving down that list, the file is deleted, because the delete happens before the add.

My initial suggestion for fixing this is to move the add functionality to file_field_presave(), forcing it to happen before the deletes in file_field_update().

sreynen’s picture

Title: Changing node language sporadically deletes files in file field » Changing node language by moving down language list deletes files in file field
camdarley’s picture

Same problem for me, changing node language from english to language neutral delete file referenced by filefield...

sreynen’s picture

Priority: Normal » Major

I'm moving this up to major, since it involved data loss.

catch’s picture

Component: field system » file system

Moving this to file module for now, I remember there being issues in file_field_insert()/update() before.

catch’s picture

Version: 7.x-dev » 8.x-dev
catch’s picture

Component: file system » file.module

oh dear.

webchick’s picture

Issue tags: +Needs backport to D7

Fixing tag.

domidc’s picture

I confirm this bug

guillaumev’s picture

I can confirm this as well...

camdarley’s picture

Does anybody knows how to fix it? That's a major bug! I think it should be fixed on D7 before even think to D8...

camdarley’s picture

I made this change in file.field.inc in file_field_delete_file function:

function file_field_delete_file($item, $field, $entity_type, $id, $count = 1) {
  // To prevent the file field from deleting files it doesn't know about, check
  // the file reference count. Temporary files can be deleted because they
  // are not yet associated with any content at all.
  $file = (object) $item;
  $file_usage = file_usage_list($file);
  if ($file->status == 0 || !empty($file_usage['file'])) {
    file_usage_delete($file, 'file', $entity_type, $id, $count);
-    return file_delete($file);
+    //return file_delete($file);
  }

  // Even if the file is not deleted, return TRUE to indicate the file field
  // record can be removed from the field database tables.
  return TRUE;
}

As I use the media module, I can't see any situation where a file need to be deleted after a field change... hope i'm right.

aspilicious’s picture

No thats not ok :) you never going to delete files ever. :)

On the other hand this function has been changed in D8. So I wonder if it's still a bug there.

camdarley’s picture

Actually, files are deleted because, as I said, I use the media module which handle files in a different way. You can remove a file from a field, but it still exist in the "media library", and if you want to delete it you have to go in this library and click on delete, thus media_multiple_delete_confirm_submit() is called, which calls file_delete().
Maybe that issue belong to the media module which has to alter file_field_delete_file to do it on its own way...
Back to D7 if the function has already been changed in D8.
Need confirmation for more experienced developers to move this issue to media module...

camdarley’s picture

Version: 8.x-dev » 7.x-dev
camdarley’s picture

Status: Active » Closed (duplicate)

I just search for file_field_delete_file issues in media module and here's what I found:
#1239056: Remove Media at content edit page cause the file to be completely deleted from server/database?
And the linked core issue:
#1399846: Make unused file 'cleanup' configurable
So I mark this as a duplicate

sreynen’s picture

Status: Closed (duplicate) » Active

This is related to #1399846: Make unused file 'cleanup' configurable, but I disagree on calling this a duplicate. That's a feature request, which could be rejected, and may or may not fix this bug if it is applied. This is a bug, which needs to be fixed regardless.

aspilicious’s picture

Status: Active » Closed (duplicate)

This a problem with the media module NOT drupal core. It's caused by architectural decisions made in that module. So this can't be called a core bug. So yes this is a duplicate of the other issue.

sreynen’s picture

Status: Closed (duplicate) » Needs work

I wasn't even running media module when I ran into this bug, so I'm fairly confident it's not unique to media module. The problem, as documented in #2, is with file field, which is part of core.

sreynen’s picture

Status: Needs work » Active
camdarley’s picture

Actually, I think sreynen is right. Although #1239056: Remove Media at content edit page cause the file to be completely deleted from server/database? should be corrected it belong to media module.
#13 is an easy and dirty workaround for those who use the media module, as it is critical for production sites, but for others, according to aspilicous in #14, files won't be deleted ever.
#2 is actually a start for a solution...

petros’s picture

quick and ugly fix...
in file file_field.inc
added this:

$original_fids2 = array();
  if (!empty($entity->{$field['field_name']})) {
      foreach ($entity->{$field['field_name']} as $lang){
            foreach ($lang as $original_item) {
              $original_fids2[] = $original_item['fid'];
            }
          }
  }

before this

if (!empty($original->{$field['field_name']}[$langcode])) 

also changed the $current_items variable to $original_fids2
very ugly but works. can also be improved with a static variable for caching.

plach’s picture

Status: Active » Needs review
FileSize
4.03 KB

Here is a patch addressing this for D7, for which I need a (hopefully) proper fix.

The change in this patch is pretty invasive, but I think the current logic is deeply flawed and cannot be fixed without a radical change in the approach: currently every field and language is checked for changes in the referenced files in isolation, not taking into account that files might be moved around. Hence, as we are seeing here, removing and then re-adding back simply doesn't work, since meanwhile we lose the file on the file system.

The current patch implements a global check: all fields attached to the entity belonging to the correct field type (file o image, at least in core) are inspected, and all file occurences are collected both for the original values and the submitted values. The occurrences are then compared and only actually removed files are deleted from the file system. The check is performed in file_field_update() to minimize the impact of this patch and reduce the chances of BC issues. A static cache is used to avoid repeating it for each field of the same type and for the various field translations. The static cache is cleared right afterwards to avoid problems of stale data.

The check is extended to all fields of the same type because the issue here is not limited to the use case reported in the OP: if a file is referenced in one file field and then it's moved to another file field on the same entity, chances are that the it will be wiped exactly the same way reported in the OP.

I think this could be a reasonable approach to forward-port to D8, altough it does not address the (rare) case where a file is moved accross different field types. Probably a better way would be to simply drop automatical deletion of files that no longer have references, as discussed in http://groups.drupal.org/node/191183, but this would probably need some kind of file overview page as the one provided by Media.

Anyway, this patch should work in D7. Leaving the version to D7 so that the testbot will pick it up. I won't post a D8 forward-port nor test updates until we agree on a proper strategy to fix this.

plach’s picture

Version: 7.x-dev » 8.x-dev

Leaving to needs review so that we can get some feedback on the approach taken in #24.

plach’s picture

Fixed an edge case.

Status: Needs review » Needs work

The last submitted patch, drupal-files_wiped-1141912-26.D7.patch, failed testing.

plach’s picture

Status: Needs work » Needs review
drzraf’s picture

see #1399846: Make unused file 'cleanup' configurable comment 8 for a testcase.
(advise there was... use file_lock)

plach’s picture

Just a note: #26 is supposed to be good but it has been tested against the 8.x branch, AAMOF the error is it doesn't apply.

plach’s picture

Version: 8.x-dev » 7.x-dev

MMh, let's actually try and test #26 on the correct branch.

plach’s picture

Issue tags: -Needs backport to D7

Status: Needs review » Needs work
Issue tags: +Needs backport to D7

The last submitted patch, drupal-files_wiped-1141912-26.D7.patch, failed testing.

plach’s picture

Status: Needs work » Needs review
FileSize
4.42 KB

Rerolled

plach’s picture

Sorry, wrong merge.

Status: Needs review » Needs work

The last submitted patch, drupal-files_wiped-1141912-35.patch, failed testing.

plach’s picture

Status: Needs work » Needs review
FileSize
4.93 KB

Aw, windows newlines

plach’s picture

Version: 7.x-dev » 8.x-dev

Back to D8 to get feedback about #24.

benjifisher’s picture

dcam’s picture

http://drupal.org/node/1427826 contains instructions for updating the issue summary with the summary template.

The summary may need to be updated with information from comments.

Status: Needs review » Needs work

The last submitted patch, drupal-files_wiped-1141912-37.patch, failed testing.

kbasarab’s picture

Issue summary is being reviewed and updated by bmadore in DrupalCon Portland Core Mentoring sprint.

ibakayoko’s picture

I am working on the reroll

ibakayoko’s picture

Issue summary: View changes

Updated issue summary.

Barry Madore’s picture

Issue summary: View changes

Updated issue summary.

Barry Madore’s picture

Issue summary: View changes

Updated issue summary.

Barry Madore’s picture

Issue summary: View changes

Updated issue summary.

Barry Madore’s picture

Issue summary: View changes

Updated issue summary.

Barry Madore’s picture

I've reviewed the issue and edited the issue summary to update and conform to the correct format.

Barry Madore’s picture

I've tried to replicate this issue in D8 doing the following:

  • Created new D8 site using latest build
  • Enabled Language, Content Translation and Interface Location modules
  • Added two new languages via admin/config/regional/language
  • Added file field to Article content type
  • Configured file field for multiple file extensions
  • Added a node of type Article uploading a text file using the file field
  • Saved the node
  • Clicked on the Edit tab
  • Chose an alternate language from the Languages dropdown
  • Saved the node

Following these steps, I did not encounter the issue described in this issue as occurring with the D7 Content Translation module. The file uploaded with the file field survived when I saved the node. I created several other nodes and tried several language changes. The files remain after editing.

This may not be a D8 issue after all. Can others confirm my findings?

ibakayoko’s picture

I was able to reproduce the issue in D8.

  1. Created new D8 site using latest build
  2. Enabled Language, Content Translation and Interface Location modules
  3. Added two new languages French and Spanish via admin/config/regional/language
    Will have three languages in the following Order:
    English
    French
    Spanish
  4. Added file field to Article content type
  5. Configured file field for multiple file extensions (txt, docx, pdf, doc, ppt, pptx, xlx, xls)
  6. Created three nodes of type article one node on each language
  7. Clicked on the Edit tab
  8. Chose an alternate language from the Languages dropdown
  9. Saved the node

The attached file is deleted in specific cases see #2
The attached is deleted depending on the position of the language.
If the language of the node is the last option in the language select and you change to the first option the attached file will be deleted.

Barry Madore’s picture

I witnessed and confirmed ibakayoko's test at the PDX8 core sprint. But we both acknowledged that his build was a few days old. Given the numerous changes made even that day, I decided to re-test today (5/27) with a fresh install of Drupal 8.

I followed the same steps as ibakayoko in #46 and continued changing languages in nodes both up and down the list of 3 (and including the "not specified" and "not applicable" options). The file was not deleted no matter the original language or its position in the list. I even changed the order of languages and retested.

I suspect that changes have resolved the issue in D8. Can we confirm this? And if so, can someone identify the change that has solved the issue so we can backport the solution to D7?

plach’s picture

can someone identify the change that has solved the issue so we can backport the solution to D7?

Try using git bisect.

slashrsm’s picture

Version: 8.x-dev » 7.x-dev

D7 issue?

sreynen’s picture

Based on a comment at http://drupalcode.org/project/drupal.git/blob/refs/heads/8.x:/core/modul... it appears D8 is marking files for deletion removing usage numbers and only later deleting them on cron rather than deleting them immediately. It makes sense that this would resolve the problem, because there's only a very short period in the node save when the old language's file usage has been removed before the new language's file usage is added. So by the time cron runs, the file is no longer a candidate for deletion.

Is moving file deletes to cron a suitable solution for D7?

plach’s picture

Is moving file deletes to cron a suitable solution for D7?

I don't think that can be backported without providing BC support, that is making the behavior optional. And if it is optional we need a different fix anyway.

sreynen’s picture

plach, I don't know what "BC support" means. Can you explain?

slashrsm’s picture

@sreynen: "backward-compatibility support"

plach’s picture

Status: Needs work » Needs review
Issue tags: -Needs backport to D7

Yep, sorry :)

I think for D7 we still need to go with something like #37.

plach’s picture

Issue summary: View changes

Updated issue summary.

pingwin4eg’s picture

Status: Needs review » Reviewed & tested by the community

Patch in #37 worked for me.

It was the same problem, but it appeared only when I edited the content setting the language from some specific to neutral one (which is above in the select options list) and saved it. Changing back from neutral to some specific language was OK. And from one specific to another was OK too.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 37: drupal-files_wiped-1141912-37.patch, failed testing.

Status: Needs work » Needs review
David_Rothstein’s picture

Status: Needs review » Reviewed & tested by the community

Haven't reviewed the patch, but that looks like a testbot fluke so back to RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 37: drupal-files_wiped-1141912-37.patch, failed testing.

Status: Needs work » Needs review
plach’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC

plach’s picture

Issue tags: +Needs tests

Actually this needs some more work, but I'll leave it to RTBC for now to get @David's feedback about the overall approach. Not worth spending more time on this until it's validated.

+++ b/modules/file/file.field.inc
@@ -255,40 +255,98 @@ function file_field_update($entity_type, $entity, $field, $instance, $langcode,
+  $processed[$entity_type][$id][$type] = TRUE;

We should add also the revision id, I think.

David_Rothstein’s picture

The basic approach looks reasonable to me. It would certainly be cleaner to do the whole thing in hook_field_attach_update() (and then I think supporting the case where the file moves from one field type to another would be simpler also) but I suppose you're right that for backwards compatibility reasons it's best to leave it where it is.

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs work

Back to needs work, I guess, for #62.