protected function recover_file(stored_file $file) {
        $contentfile = $this->get_local_path_from_storedfile($file, false);

        if (file_exists($contentfile)) {
            // The file already exists on the file system. No need to recover.
            return true;
        }

        $contenthash = $file->get_contenthash();
        $contentdir = $this->get_fulldir_from_storedfile($file);
        $trashfile = $this->get_trash_fullpath_from_hash($contenthash);
        $alttrashfile = "{$this->trashdir}/{$contenthash}";

        if (!is_readable($trashfile)) {
            // The trash file was not found. Check the alternative trash file too just in case.
            if (!is_readable($alttrashfile)) {
                return false;
            }
            // The alternative trash file in trash root exists.
            $trashfile = $alttrashfile;
        }

        if (filesize($trashfile) != $file->get_filesize() or file_storage::hash_from_path($trashfile) != $contenthash) {
            // The files are different. Leave this one in trash - something seems to be wrong with it.
            return false;
        }

        if (!is_dir($contentdir)) {
            if (!mkdir($contentdir, $this->dirpermissions, true)) {
                // Unable to create the target directory.
                return false;
            }
        }

        // Perform a rename - these are generally atomic which gives us big
        // performance wins, especially for large files.
        return rename($trashfile, $contentfile);
    }