summaryrefslogtreecommitdiffstats
path: root/application/service/files.php
diff options
context:
space:
mode:
Diffstat (limited to 'application/service/files.php')
-rw-r--r--application/service/files.php132
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);
+ }
+ }
+ }
+ }
+
}