diff --git a/lang/en/repository.php b/lang/en/repository.php index f3f5fbcd7c9..be7cdc10489 100644 --- a/lang/en/repository.php +++ b/lang/en/repository.php @@ -97,6 +97,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 fb81ddda601..9bf64a4d4e3 100644 --- a/lib/filelib.php +++ b/lib/filelib.php @@ -828,9 +828,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 fee7bfa8e4b..d78aac18c85 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 1d893071124..a1c38600b2c 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -2410,6 +2410,13 @@ abstract class repository { $user_context = get_context_instance(CONTEXT_USER, $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