From e9e32b1d8815531f4d66907b063da84b41a5ea45 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Wed, 8 May 2013 12:48:54 +1000 Subject: [PATCH] MDL-39177 File reference is not updated when overwriting the file --- lang/en/repository.php | 1 + lib/filelib.php | 9 +++++++-- lib/filestorage/stored_file.php | 30 ++++++++++++++++++++++++++++++ repository/lib.php | 7 +++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lang/en/repository.php b/lang/en/repository.php index a99a4c6dfba..a8b62a74fa6 100644 --- a/lang/en/repository.php +++ b/lang/en/repository.php @@ -101,6 +101,7 @@ $string['enter'] = 'Enter'; $string['entername'] = 'Please enter folder name'; $string['enternewname'] = 'Please enter the new file name'; $string['error'] = 'An unknown error occurred!'; +$string['errordoublereference'] = 'Unable to overwrite file with a shortcut/alias because shortcuts to this file already exist.'; $string['errornotyourfile'] = 'You cannot pick file which is not added by your'; $string['erroruniquename'] = 'Repository instance name should be unique'; $string['errorpostmaxsize'] = 'The uploaded file may exceed the post_max_size directive in php.ini.'; diff --git a/lib/filelib.php b/lib/filelib.php index 5a03a7ee937..87bb91889e4 100644 --- a/lib/filelib.php +++ b/lib/filelib.php @@ -889,9 +889,14 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea $oldfile->set_timemodified($newfile->get_timemodified()); } + if ($newfile->is_external_file() && !$allowreferences) { + continue; + } // Replaced file content - if ($oldfile->get_contenthash() != $newfile->get_contenthash() || $oldfile->get_filesize() != $newfile->get_filesize()) { - $oldfile->replace_content_with($newfile); + else if ($oldfile->get_contenthash() != $newfile->get_contenthash() || + $oldfile->get_filesize() != $newfile->get_filesize() || + $oldfile->get_referencefileid() != $newfile->get_referencefileid()) { + $oldfile->replace_file_with($newfile); // push changes to all local files that are referencing this file $fs->update_references_to_storedfile($oldfile); } diff --git a/lib/filestorage/stored_file.php b/lib/filestorage/stored_file.php index 84d9510627e..e73a85eb3a1 100644 --- a/lib/filestorage/stored_file.php +++ b/lib/filestorage/stored_file.php @@ -210,6 +210,36 @@ class stored_file { $this->set_filesize($storedfile->get_filesize()); } + /** + * Replaces the fields that might have changed when file was overriden in filepicker: + * reference, contenthash, filesize + * + * Note that field source must be updated separately + * + * @param stored_file $newfile + * @throws coding_exception + */ + public function replace_file_with(stored_file $newfile) { + if ($newfile->get_referencefileid() && + $this->fs->get_references_count_by_storedfile($this)) { + // The new file is a reference. + // The current file has other local files referencing to it. + // Double reference is not allowed. + throw new moodle_exception('errordoublereference', 'repository'); + } + + $filerecord = new stdClass; + $contenthash = $newfile->get_contenthash(); + if ($this->fs->content_exists($contenthash)) { + $filerecord->contenthash = $contenthash; + } else { + throw new file_exception('storedfileproblem', 'Invalid contenthash, content must be already in filepool', $contenthash); + } + $filerecord->filesize = $newfile->get_filesize(); + $filerecord->referencefileid = $newfile->get_referencefileid(); + $this->update($filerecord); + } + /** * Unlink the stored file from the referenced file * diff --git a/repository/lib.php b/repository/lib.php index 5ee8c91e945..47f554697cc 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -2546,6 +2546,13 @@ abstract class repository implements cacheable_object { $user_context = context_user::instance($USER->id); if ($file = $fs->get_file($user_context->id, 'user', 'draft', $itemid, $filepath, $filename)) { if ($tempfile = $fs->get_file($user_context->id, 'user', 'draft', $itemid, $newfilepath, $newfilename)) { + if ($tempfile->is_external_file()) { + // New file is a reference. Check that existing file does not have any other files referencing to it + $source = @unserialize($file->get_source()); + if (isset($source->original) && $fs->search_references_count($source->original)) { + return (object)array('error' => get_string('errordoublereference', 'repository')); + } + } // delete existing file to release filename $file->delete(); // create new file