From e60b5468afe0a0d6aa9dab2e6dcf9d186dd168fd Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Sat, 8 Nov 2014 17:25:31 +0100 Subject: WIP Signed-off-by: Florian Pritz --- application/controllers/file.php | 59 +++++++++++++++++++--------------- application/helpers/filebin_helper.php | 27 ++++++++++++++++ application/models/mfile.php | 53 +++++++++++++++++------------- 3 files changed, 91 insertions(+), 48 deletions(-) diff --git a/application/controllers/file.php b/application/controllers/file.php index 2617d4840..25fbd27e3 100644 --- a/application/controllers/file.php +++ b/application/controllers/file.php @@ -90,7 +90,7 @@ class File extends MY_Controller { $etag = ""; foreach ($files as $filedata) { - $etag = sha1($etag.$filedata["hash"]); + $etag = sha1($etag.$filedata["data_id"]); } // handle some common "lexers" here @@ -128,7 +128,7 @@ class File extends MY_Controller { handle_etag($etag); $filedata = $files[0]; - $filepath = $this->mfile->file($filedata["hash"]); + $filepath = $this->mfile->file($filedata["data_id"]); $this->ddownload->serveFile($filepath, $filedata["filename"], "text/plain"); exit(); } @@ -136,7 +136,7 @@ class File extends MY_Controller { $this->load->library("output_cache"); foreach ($files as $key => $filedata) { - $file = $this->mfile->file($filedata['hash']); + $file = $this->mfile->file($filedata['data_id']); // autodetect the lexer for highlighting if the URL contains a / after the ID (/ID/) // /ID/lexer disables autodetection @@ -272,9 +272,9 @@ class File extends MY_Controller { { // highlight the file and cache the result, fall back to plain text if $lexer fails foreach (array($lexer, "text") as $lexer) { - $highlit = cache_function($filedata['hash'].'_'.$lexer, 100, + $highlit = cache_function($filedata['data_id'].'_'.$lexer, 100, function() use ($filedata, $lexer, $is_multipaste) { - $file = $this->mfile->file($filedata['hash']); + $file = $this->mfile->file($filedata['data_id']); if ($lexer == "rmd") { ob_start(); @@ -323,7 +323,7 @@ class File extends MY_Controller { private function _tooltip_for_image($filedata) { $filesize = format_bytes($filedata["filesize"]); - list($width, $height) = getimagesize($this->mfile->file($filedata["hash"])); + list($width, $height) = getimagesize($this->mfile->file($filedata["data_id"])); $upload_date = date("r", $filedata["date"]); $tooltip = "${filedata["id"]} - $filesize
"; @@ -405,7 +405,7 @@ class File extends MY_Controller { $filename = $filedata["id"]."-".$filedata["filename"]; } assert(!isset($seen[$filename])); - $a->addFile($this->mfile->file($filedata["hash"]), $filename); + $a->addFile($this->mfile->file($filedata["data_id"]), $filename); $seen[$filename] = true; } $archive->gzip_compress(); @@ -457,7 +457,7 @@ class File extends MY_Controller { if (count($ids) == 1) { $filedata = $this->mfile->get_filedata($id); - $file = $this->mfile->file($filedata['hash']); + $file = $this->mfile->file($filedata['data_id']); $type = $filedata['mimetype']; $lexer = $this->mfile->should_highlight($type); @@ -531,7 +531,7 @@ class File extends MY_Controller { $filedata = $this->mfile->get_filedata($repaste_id); if ($filedata !== false && $this->mfile->can_highlight($filedata["mimetype"])) { - $this->data["textarea_content"] = file_get_contents($this->mfile->file($filedata["hash"])); + $this->data["textarea_content"] = file_get_contents($this->mfile->file($filedata["data_id"])); } } @@ -568,11 +568,11 @@ class File extends MY_Controller { show_error("Failed to get file data"); } - $cache_key = $filedata['hash'].'_thumb_'.$thumb_size; + $cache_key = $filedata['data_id'].'_thumb_'.$thumb_size; $thumb = cache_function($cache_key, 100, function() use ($filedata, $thumb_size){ $CI =& get_instance(); - $img = new libraries\Image($this->mfile->file($filedata["hash"])); + $img = new libraries\Image($this->mfile->file($filedata["data_id"])); $img->makeThumb($thumb_size, $thumb_size); $thumb = $img->get(IMAGETYPE_JPEG); @@ -596,8 +596,9 @@ class File extends MY_Controller { $user = $this->muser->get_userid(); $query = $this->db - ->select('id, filename, mimetype, date, hash, filesize') + ->select('files.id, filename, mimetype, date, hash, hash_collision_counter, filesize') ->from('files') + ->join('file_storage', 'file_storage.id = files.file_storage_id') ->where('user', $user) ->where_in('mimetype', array('image/jpeg', 'image/png', 'image/gif')) ->order_by('date', 'desc') @@ -609,7 +610,7 @@ class File extends MY_Controller { continue; } $query[$key]["tooltip"] = $this->_tooltip_for_image($item); - $query[$key]["orientation"] = libraries\Image::get_exif_orientation($this->mfile->file($item["hash"])); + $query[$key]["orientation"] = libraries\Image::get_exif_orientation($this->mfile->file($item["data_id"])); } $this->data["items"] = $query; @@ -630,7 +631,7 @@ class File extends MY_Controller { // key: database field name; value: display name $fields = array( - "id" => "ID", + "files.id" => "ID", "filename" => "Filename", "mimetype" => "Mimetype", "date" => "Date", @@ -647,14 +648,16 @@ class File extends MY_Controller { $items = $this->db->select(implode(',', array_keys($fields))) ->from('files') + ->join('file_storage', 'file_storage.id = files.file_storage_id') ->where('user', $user) ->get()->result_array(); $query = $this->db->query(" - SELECT m.url_id id, sum(f.filesize) filesize, m.date, '' hash, '' mimetype, concat(count(*), ' file(s)') filename + SELECT m.url_id id, sum(fs.filesize) filesize, m.date, '' hash, '' mimetype, concat(count(*), ' file(s)') filename FROM multipaste m JOIN multipaste_file_map mfm ON m.multipaste_id = mfm.multipaste_id JOIN files f ON f.id = mfm.file_url_id + JOIN file_storage fs ON f.file_storage_id = fs.id WHERE m.user_id = ? GROUP BY m.url_id ", array($user))->result_array(); @@ -688,8 +691,9 @@ class File extends MY_Controller { $total_size = $this->db->query(" SELECT sum(filesize) sum FROM ( - SELECT DISTINCT hash, filesize + SELECT DISTINCT hash, hash_collision_counter, filesize FROM files + JOIN file_storage ON file_storage.id = files.file_storage_id WHERE user = ? ) sub ", array($user))->row_array(); @@ -950,6 +954,9 @@ class File extends MY_Controller { } foreach ($files as $key => $file) { + // FIXME: use refactored code from api-rework branch here + // FIXME: remove hash_collision_counter from db and simply use the + // ID (so we can atomically insert and the get the last_insert_id $limits = $this->muser->get_upload_id_limits(); $id = $this->mfile->new_id($limits[0], $limits[1]); $hash = md5_file($file['tmp_name']); @@ -1078,7 +1085,7 @@ class File extends MY_Controller { $small_upload_size = $this->config->item('small_upload_size'); - $query = $this->db->select('hash, id, user') + $query = $this->db->select('hash, hash_collision_counter, id, user') ->from('files') ->where('date <', $oldest_time) ->or_where('('.$this->db->_protect_identifiers('user').' = 0 AND ' @@ -1086,7 +1093,7 @@ class File extends MY_Controller { ->get()->result_array(); foreach($query as $row) { - $file = $this->mfile->file($row['hash']); + $file = $this->mfile->file($row['data_id']); if (!file_exists($file)) { $this->mfile->delete_id($row["id"]); continue; @@ -1095,10 +1102,10 @@ class File extends MY_Controller { if ($row["user"] == 0 || filesize($file) > $small_upload_size) { if (filemtime($file) < $oldest_time) { unlink($file); - $this->mfile->delete_hash($row["hash"]); + $this->mfile->delete_data_id($row["data_id"]); } else { $this->mfile->delete_id($row["id"]); - if ($this->mfile->stale_hash($row["hash"])) { + if ($this->mfile->stale_data_id($row["data_id"])) { unlink($file); } } @@ -1166,9 +1173,9 @@ class File extends MY_Controller { return; } - $hash = $file_data["hash"]; - $this->mfile->delete_hash($hash); - echo "removed hash \"$hash\"\n"; + $data_id = $file_data["data_id"]; + $this->mfile->delete_data_id($data_id); + echo "removed data_id \"$data_id\"\n"; } function update_file_metadata() @@ -1187,9 +1194,9 @@ class File extends MY_Controller { ->get()->result_array(); foreach ($query as $key => $item) { - $hash = $item["hash"]; - $filesize = intval(filesize($this->mfile->file($hash))); - $mimetype = $this->mfile->mimetype($this->mfile->file($hash)); + $data_id = $item["data_id"]; + $filesize = intval(filesize($this->mfile->file($data_id))); + $mimetype = $this->mfile->mimetype($this->mfile->file($data_id)); $this->db->where('hash', $hash) ->set(array( diff --git a/application/helpers/filebin_helper.php b/application/helpers/filebin_helper.php index e5637ce94..acec213a9 100644 --- a/application/helpers/filebin_helper.php +++ b/application/helpers/filebin_helper.php @@ -283,4 +283,31 @@ function cache_function($key, $ttl, $function) return $content; } +function files_are_equal($a, $b) +{ + $chunk_size = 8*1024; + + // Check if filesize is different + if (filesize($a) !== filesize($b)) { + return false; + } + + // Check if content is different + $ah = fopen($a, 'rb'); + $bh = fopen($b, 'rb'); + + $result = true; + while (!feof($ah) && !feof($bh)) { + if (fread($ah, $chunk_size) !== fread($bh, $chunk_size)) { + $result = false; + break; + } + } + + fclose($ah); + fclose($bh); + + return $result; +} + # vim: set noet: diff --git a/application/models/mfile.php b/application/models/mfile.php index eee2c4e5b..d6851a6ef 100644 --- a/application/models/mfile.php +++ b/application/models/mfile.php @@ -70,27 +70,30 @@ class Mfile extends CI_Model { function get_filedata($id) { $query = $this->db - ->select('id, hash, filename, mimetype, date, user, filesize') + ->select('files.id, hash, hash_collision_counter, filename, mimetype, date, user, filesize') ->from('files') - ->where('id', $id) + ->join('file_storage', 'file_storage.id = files.file_storage_id') + ->where('files.id', $id) ->limit(1) ->get(); if ($query->num_rows() > 0) { - return $query->row_array(); + $data = $query->row_array(); + $data["data_id"] = $data["hash"]."-".$data["hash_collision_counter"]; + return $data; } else { return false; } } - // return the folder in which the file with $hash is stored - function folder($hash) { - return $this->config->item('upload_path').'/'.substr($hash, 0, 3); + // return the folder in which the file with $data_id is stored + function folder($data_id) { + return $this->config->item('upload_path').'/'.substr($data_id, 0, 3); } - // Returns the full path to the file with $hash - function file($hash) { - return $this->folder($hash).'/'.$hash; + // Returns the full path to the file with $data_id + function file($data_id) { + return $this->folder($data_id).'/'.$data_id; } // Return mimetype of file @@ -136,10 +139,10 @@ class Mfile extends CI_Model { if (!$filedata) { return false; } - $file = $this->file($filedata['hash']); + $file = $this->file($filedata['data_id']); if (!file_exists($file)) { - $this->delete_hash($filedata["hash"]); + $this->delete_data_id($filedata["data_id"]); return false; } @@ -158,7 +161,7 @@ class Mfile extends CI_Model { // if the file has been uploaded multiple times the mtime is the time // of the last upload if (filemtime($file) < $remove_before) { - $this->delete_hash($filedata["hash"]); + $this->delete_data_id($filedata["data_id"]); } else { $this->delete_id($id); } @@ -171,7 +174,7 @@ class Mfile extends CI_Model { public function get_timeout($id) { $filedata = $this->get_filedata($id); - $file = $this->file($filedata["hash"]); + $file = $this->file($filedata["data_id"]); if ($this->config->item("upload_max_age") == 0) { return -1; @@ -195,11 +198,14 @@ class Mfile extends CI_Model { } } - private function unused_file($hash) + private function unused_file($data_id) { - $query = $this->db->select('id') + list ($hash, $hash_collision_counter) = explode("-", $data_id); + $query = $this->db->select('files.id') ->from('files') + ->join('file_storage', 'file_storage.id = files.file_storage_id') ->where('hash', $hash) + ->where('hash_collision_counter', $hash_collision_counter) ->limit(1) ->get(); @@ -238,12 +244,12 @@ class Mfile extends CI_Model { } if ($filedata !== false) { - assert(isset($filedata["hash"])); - if ($this->unused_file($filedata['hash'])) { - if (file_exists($this->file($filedata['hash']))) { - unlink($this->file($filedata['hash'])); + assert(isset($filedata["data_id"])); + if ($this->unused_file($filedata['data_id'])) { + if (file_exists($this->file($filedata['data_id']))) { + unlink($this->file($filedata['data_id'])); } - $dir = $this->folder($filedata['hash']); + $dir = $this->folder($filedata['data_id']); if (file_exists($dir)) { if (count(scandir($dir)) == 2) { rmdir($dir); @@ -254,11 +260,14 @@ class Mfile extends CI_Model { return true; } - public function delete_hash($hash) + public function delete_data_id($data_id) { - $ids = $this->db->select('id') + list ($hash, $hash_collision_counter) = explode("-", $data_id); + $ids = $this->db->select('files.id') ->from('files') + ->join('file_storage', 'file_storage.id = files.file_storage_id') ->where('hash', $hash) + ->where('hash_collision_counter', $hash_collision_counter) ->get()->result_array(); foreach ($ids as $entry) { -- cgit v1.2.3-24-g4f1b