diff options
Diffstat (limited to 'application/service/files.php')
-rw-r--r-- | application/service/files.php | 132 |
1 files changed, 122 insertions, 10 deletions
diff --git a/application/service/files.php b/application/service/files.php index b45ac8e6f..576adb2ef 100644 --- a/application/service/files.php +++ b/application/service/files.php @@ -150,6 +150,7 @@ class files { $hash = md5_file($new_file); $storage_id = null; + $CI->db->trans_start(); $query = $CI->db->select('id, hash') ->from('file_storage') ->where('hash', $hash) @@ -165,6 +166,7 @@ class files { } } + $new_storage_id_created = false; if ($storage_id === null) { $filesize = filesize($new_file); $mimetype = mimetype($new_file); @@ -176,21 +178,33 @@ class files { "date" => time(), )); $storage_id = $CI->db->insert_id(); + $new_storage_id_created = true; + assert(!file_exists($CI->mfile->file($hash."-".$storage_id))); } $data_id = $hash."-".$storage_id; - // TODO: all this doesn't have to run if the file exists. updating the mtime would be enough - // that would also be better for COW filesystems $dir = $CI->mfile->folder($data_id); file_exists($dir) || mkdir ($dir); $new_path = $CI->mfile->file($data_id); - $dest = new \service\storage($new_path); - $tmpfile = $dest->begin(); - rename($new_file, $tmpfile); - $dest->commit(); + // Update mtime for cronjob + touch($new_path); + + // touch may create a new file if the cronjob cleaned up in between the db check and here. + // In that case the file will be empty so move in the data + if ($new_storage_id_created || filesize($new_path) === 0) { + $dest = new \service\storage($new_path); + $tmpfile = $dest->begin(); + + // $new_file may reside on a different file system so this call + // could perform a copy operation internally. $dest->commit() will + // ensure that it performs an atomic overwrite (rename). + rename($new_file, $tmpfile); + $dest->commit(); + } $CI->mfile->add_file($userid, $id, $filename, $storage_id); + $CI->db->trans_complete(); } static public function verify_uploaded_files($files) @@ -228,7 +242,7 @@ class files { } } - $filesize = filesize($file['tmp_name']); + $filesize = isset($file['tmp_name']) ? filesize($file['tmp_name']) : 0; if ($filesize > $CI->config->item('upload_max_size')) { $error_message = "File too big"; } @@ -425,17 +439,115 @@ class files { // likely unsupported filetype } - $tooltip = "${filedata["id"]} - $filesize<br>"; + $tooltip = "{$filedata["id"]} - $filesize<br>"; $tooltip .= "$upload_date<br>"; if ($height > 0 && $width > 0) { - $tooltip .= "${width}x${height} - ${filedata["mimetype"]}<br>"; + $tooltip .= "{$width}x{$height} - {$filedata["mimetype"]}<br>"; } else { - $tooltip .= "${filedata["mimetype"]}<br>"; + $tooltip .= "{$filedata["mimetype"]}<br>"; } return $tooltip; } + static public function clean_multipaste_tarballs() + { + $CI =& get_instance(); + + $tarball_dir = $CI->config->item("upload_path")."/special/multipaste-tarballs"; + if (is_dir($tarball_dir)) { + $tarball_cache_time = $CI->config->item("tarball_cache_time"); + $it = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($tarball_dir), \RecursiveIteratorIterator::SELF_FIRST); + + foreach ($it as $file) { + if ($file->isFile()) { + if ($file->getMTime() < time() - $tarball_cache_time) { + $lock = fopen($file, "r+"); + flock($lock, LOCK_EX); + unlink($file); + flock($lock, LOCK_UN); + } + } + } + } + } + + static public function remove_files_missing_in_db() + { + $CI =& get_instance(); + + $upload_path = $CI->config->item("upload_path"); + $outer_dh = opendir($upload_path); + + while (($dir = readdir($outer_dh)) !== false) { + if (!is_dir($upload_path."/".$dir) || $dir == ".." || $dir == "." || $dir == "special") { + continue; + } + + $dh = opendir($upload_path."/".$dir); + + $empty = true; + + while (($file = readdir($dh)) !== false) { + if ($file == ".." || $file == ".") { + continue; + } + + try { + list($hash, $storage_id) = explode("-", $file); + } catch (\ErrorException $e) { + unlink($upload_path."/".$dir."/".$file); + continue; + } + + $query = $CI->db->select('hash, id') + ->from('file_storage') + ->where('hash', $hash) + ->where('id', $storage_id) + ->limit(1) + ->get()->row_array(); + + if (empty($query)) { + $CI->mfile->delete_data_id($file); + } else { + $empty = false; + } + } + + closedir($dh); + + if ($empty && file_exists($upload_path."/".$dir)) { + rmdir($upload_path."/".$dir); + } + } + closedir($outer_dh); + } + + static public function remove_files_missing_on_disk() + { + $CI =& get_instance(); + + $chunk = 500; + $total = $CI->db->count_all("file_storage"); + + for ($limit = 0; $limit < $total; $limit += $chunk) { + $query = $CI->db->select('hash, id') + ->from('file_storage') + ->limit($chunk, $limit) + ->get()->result_array(); + + foreach ($query as $key => $item) { + $data_id = $item["hash"].'-'.$item['id']; + $file = $CI->mfile->file($data_id); + + if (!$CI->mfile->file_exists($file)) { + $CI->mfile->delete_data_id($data_id); + } + } + } + } + } |