Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15422595
D19817.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Referenced Files
None
Subscribers
None
D19817.diff
View Options
diff --git a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php
--- a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php
+++ b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php
@@ -164,6 +164,16 @@
$this->applyHeraldRefRules($ref_updates);
}
+ try {
+ if (!$is_initial_import) {
+ $this->rejectOversizedFiles($content_updates);
+ }
+ } catch (DiffusionCommitHookRejectException $ex) {
+ // If we're rejecting oversized files, flag everything.
+ $this->rejectCode = PhabricatorRepositoryPushLog::REJECT_OVERSIZED;
+ throw $ex;
+ }
+
try {
if (!$is_initial_import) {
$this->rejectEnormousChanges($content_updates);
@@ -1255,6 +1265,139 @@
return $changesets;
}
+ private function rejectOversizedFiles(array $content_updates) {
+ $repository = $this->getRepository();
+
+ // TODO: Allow repositories to be configured for a maximum filesize.
+ $limit = 0;
+
+ if (!$limit) {
+ return;
+ }
+
+ foreach ($content_updates as $update) {
+ $identifier = $update->getRefNew();
+
+ $sizes = $this->loadFileSizesForCommit($identifier);
+ foreach ($sizes as $path => $size) {
+ if ($size <= $limit) {
+ continue;
+ }
+
+ $message = pht(
+ 'OVERSIZED FILE'.
+ "\n".
+ 'This repository ("%s") is configured with a maximum individual '.
+ 'file size limit, but you are pushing a change ("%s") which causes '.
+ 'the size of a file ("%s") to exceed the limit. The commit makes '.
+ 'the file %s bytes long, but the limit for this repository is '.
+ '%s bytes.',
+ $repository->getDisplayName(),
+ $identifier,
+ $path,
+ new PhutilNumber($size),
+ new PhutilNumber($limit));
+
+ throw new DiffusionCommitHookRejectException($message);
+ }
+ }
+ }
+
+ public function loadFileSizesForCommit($identifier) {
+ $repository = $this->getRepository();
+ $vcs = $repository->getVersionControlSystem();
+
+ $path_sizes = array();
+
+ switch ($vcs) {
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
+ list($paths_raw) = $repository->execxLocalCommand(
+ 'diff-tree -z -r --no-commit-id %s --',
+ $identifier);
+
+ // With "-z" we get "<fields>\0<filename>\0" for each line. Group the
+ // delimited text into "<fields>, <filename>" pairs.
+ $paths_raw = trim($paths_raw, "\0");
+ $paths_raw = explode("\0", $paths_raw);
+ if (count($paths_raw) % 2) {
+ throw new Exception(
+ pht(
+ 'Unexpected number of output lines from "git diff-tree" when '.
+ 'processing commit ("%s"): got %s lines, expected an even '.
+ 'number.',
+ $identifier,
+ phutil_count($paths_raw)));
+ }
+ $paths_raw = array_chunk($paths_raw, 2);
+
+ $paths = array();
+ foreach ($paths_raw as $path_raw) {
+ list($fields, $pathname) = $path_raw;
+ $fields = explode(' ', $fields);
+
+ // Fields are:
+ //
+ // :100644 100644 aaaa bbbb M
+ //
+ // [0] Old file mode.
+ // [1] New file mode.
+ // [2] Old object hash.
+ // [3] New object hash.
+ // [4] Change mode.
+
+ $paths[] = array(
+ 'path' => $pathname,
+ 'newHash' => $fields[3],
+ );
+ }
+
+ if ($paths) {
+ $check_paths = array();
+ foreach ($paths as $path) {
+ if ($path['newHash'] === self::EMPTY_HASH) {
+ $path_sizes[$path['path']] = 0;
+ continue;
+ }
+ $check_paths[$path['newHash']][] = $path['path'];
+ }
+
+ if ($check_paths) {
+ $future = $repository->getLocalCommandFuture(
+ 'cat-file --batch-check=%s',
+ '%(objectsize)')
+ ->write(implode("\n", array_keys($check_paths)));
+
+ list($sizes) = $future->resolvex();
+ $sizes = trim($sizes);
+ $sizes = phutil_split_lines($sizes, false);
+ if (count($sizes) !== count($check_paths)) {
+ throw new Exception(
+ pht(
+ 'Unexpected number of output lines from "git cat-file" when '.
+ 'processing commit ("%s"): got %s lines, expected %s.',
+ $identifier,
+ phutil_count($sizes),
+ phutil_count($check_paths)));
+ }
+
+ foreach ($check_paths as $object_hash => $path_names) {
+ $object_size = (int)array_shift($sizes);
+ foreach ($path_names as $path_name) {
+ $path_sizes[$path_name] = $object_size;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ throw new Exception(
+ pht(
+ 'File size limits are not supported for this VCS.'));
+ }
+
+ return $path_sizes;
+ }
+
public function loadCommitRefForCommit($identifier) {
$repository = $this->getRepository();
$vcs = $repository->getVersionControlSystem();
diff --git a/src/applications/repository/storage/PhabricatorRepositoryPushLog.php b/src/applications/repository/storage/PhabricatorRepositoryPushLog.php
--- a/src/applications/repository/storage/PhabricatorRepositoryPushLog.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryPushLog.php
@@ -24,6 +24,7 @@
const CHANGEFLAG_REWRITE = 8;
const CHANGEFLAG_DANGEROUS = 16;
const CHANGEFLAG_ENORMOUS = 32;
+ const CHANGEFLAG_OVERSIZED = 64;
const REJECT_ACCEPT = 0;
const REJECT_DANGEROUS = 1;
@@ -31,6 +32,7 @@
const REJECT_EXTERNAL = 3;
const REJECT_BROKEN = 4;
const REJECT_ENORMOUS = 5;
+ const REJECT_OVERSIZED = 6;
protected $repositoryPHID;
protected $epoch;
@@ -63,6 +65,7 @@
self::CHANGEFLAG_REWRITE => pht('Rewrite'),
self::CHANGEFLAG_DANGEROUS => pht('Dangerous'),
self::CHANGEFLAG_ENORMOUS => pht('Enormous'),
+ self::CHANGEFLAG_OVERSIZED => pht('Oversized'),
);
}
@@ -74,6 +77,7 @@
self::REJECT_EXTERNAL => pht('Rejected: External Hook'),
self::REJECT_BROKEN => pht('Rejected: Broken'),
self::REJECT_ENORMOUS => pht('Rejected: Enormous'),
+ self::REJECT_OVERSIZED => pht('Rejected: Oversized File'),
);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 23, 9:42 AM (21 h, 13 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7389544
Default Alt Text
D19817.diff (6 KB)
Attached To
Mode
D19817: Support (but do not actually enable) a maximum file size limit for Git repositories
Attached
Detach File
Event Timeline
Log In to Comment