The problem

file_unmanaged_save_data() calls file_unmanaged_move().

file_unmanaged_move() calls file_unmanaged_copy(), which calls cp.

cp is not atomic, mv is (per http://stackoverflow.com/questions/11231198/should-my-script-use-cp-or-m... and others).

This can and does lead to race conditions where one process starts writing a file, and another starts reading it before it's finished, and gets an incomplete/empty file.

At least three contrib projects have their own versions of file_unmanaged_save_data(), dating back to 2012 or earlier, but I couldn't find a core issue:

boost: http://api.drupal.psu.edu/api/drupal/modules!contrib!boost!boost.module/...
advagg: http://www.rit.edu/drupal/api/drupal/sites!all!modules!advagg!advagg.mis...
agrcache: #2628918: Address deployment race conditions

Proposed solution

1. fix file_unmanaged_save_data() to use rename() instead of copy()

If that's too much of a behaviour change, we could add a new function/method, but don't really see why it'd be a problem to just fix it.

Remaining tasks

CommentFileSizeAuthor
#2 2688389-1.patch4.32 KBAnonymous (not verified)
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

catch created an issue. See original summary.

Anonymous’s picture

Version: 8.1.x-dev » 8.2.x-dev
Assigned: Unassigned »
Status: Active » Needs review
FileSize
4.32 KB

how about this.

Status: Needs review » Needs work

The last submitted patch, 2: 2688389-1.patch, failed testing.

catch’s picture

Status: Needs work » Closed (duplicate)

Just found #2688389: file_unmanaged_save_data()/file_unmanaged_move() are not atomic, marking this as duplicate of that, let's continue over there.

mcdruid’s picture

AFAICS this should be marked as a duplicate of #1377740: file_unmanaged_move() should issue rename() where possible instead of copy() & unlink() rather than of itself :)