Move SSD quota checks to typed Kotlin
ober
7d2485b7528b0e492c38109408a323b3375ef1c2
--- a/templates/ssd-review.ss +++ b/templates/ssd-review.ss @@ -1577,6 +1577,9 @@ fileSizeBytes pathIsSymbolicLink safeLocalRegularFile destinationNewFileDelta + storageStatsExceedsQuota storageCapacityWithinQuota + storageEntryBytesAllowed zipExportQuotaExceeded + treeExportQuotaExceeded oldDestinationBytes urlEffectivePort remoteBearerTokenPresent remoteBearerTokenValid remotePinPresent remotePinOrNull remotePinSha256Length @@ -1658,6 +1661,32 @@ (if (fileExists destination) (int32 0) (int32 1))) (def (oldDestinationBytes (destination : File)) : Int (if (fileIsFile destination) (fileLength destination) (int 0))) + (def (storageStatsExceedsQuota (files : Int32) + (bytes : Int) + (maxFiles : Int32) + (maxBytes : Int)) : Bool + (or (> files maxFiles) (> bytes maxBytes))) + (def (storageCapacityWithinQuota (files : Int32) + (bytes : Int) + (maxFiles : Int32) + (maxBytes : Int)) : Bool + (and (<= files maxFiles) (<= bytes maxBytes))) + (def (storageEntryBytesAllowed (bytes : Int) (maxBytes : Int)) : Bool + (and (>= bytes (int 0)) (<= bytes maxBytes))) + (def (zipExportQuotaExceeded (entries : Int32) + (fileBytes : Int) + (sourceBytes : Int) + (maxEntries : Int32) + (maxEntryBytes : Int) + (maxTotalBytes : Int)) : Bool + (or (> entries maxEntries) + (or (> fileBytes maxEntryBytes) + (> sourceBytes maxTotalBytes)))) + (def (treeExportQuotaExceeded (entries : Int32) + (bytes : Int) + (maxEntries : Int32) + (maxTotalBytes : Int)) : Bool + (or (> entries maxEntries) (> bytes maxTotalBytes))) (def (urlEffectivePort (url : URL)) : Int32 (let ((port (urlPort url))) (if (>= port (int32 0)) port (urlDefaultPort url)))) @@ -8091,7 +8120,7 @@ " } else if (fileIsRegular(file)) {" " stats.files += 1" " stats.bytes += fileSizeBytes(file)" - " if (stats.files > MAX_STORAGE_FILES || stats.bytes > MAX_STORAGE_BYTES) {" + " if (storageStatsExceedsQuota(stats.files, stats.bytes, MAX_STORAGE_FILES, MAX_STORAGE_BYTES)) {" " throw IllegalStateException(\"Storage quota exceeded\")" " }" " }" @@ -8101,12 +8130,12 @@ " }" "" " private fun ensureStorageCapacity(destination: File, bytes: Long) {" - " require(bytes in 0..MAX_ZIP_ENTRY_BYTES) { \"Per-file storage limit exceeded\" }" + " require(storageEntryBytesAllowed(bytes, MAX_ZIP_ENTRY_BYTES)) { \"Per-file storage limit exceeded\" }" " val stats = storageStats()" " val oldBytes = oldDestinationBytes(destination)" " val newFiles = stats.files + destinationNewFileDelta(destination)" " val newBytes = stats.bytes - oldBytes + bytes" - " require(newFiles <= MAX_STORAGE_FILES && newBytes <= MAX_STORAGE_BYTES) {" + " require(storageCapacityWithinQuota(newFiles, newBytes, MAX_STORAGE_FILES, MAX_STORAGE_BYTES)) {" " \"Storage quota exceeded\"" " }" " }" @@ -8334,7 +8363,7 @@ " if (fileIsSymbolicLink(file)) throw IllegalStateException(\"Storage symlink rejected\")" " entries += 1" " sourceBytes += fileSizeBytes(file)" - " if (entries > MAX_ZIP_ENTRIES || fileSizeBytes(file) > MAX_ZIP_ENTRY_BYTES || sourceBytes > MAX_ZIP_TOTAL_BYTES) {" + " if (zipExportQuotaExceeded(entries, fileSizeBytes(file), sourceBytes, MAX_ZIP_ENTRIES, MAX_ZIP_ENTRY_BYTES, MAX_ZIP_TOTAL_BYTES)) {" " throw IllegalStateException(\"ZIP export quota exceeded\")" " }" " val relative = root.toPath().relativize(file.toPath()).toString()" @@ -8561,7 +8590,7 @@ " dir.walkTopDown().filter { fileIsRegular(it) }.forEach { file ->" " count += 1" " bytes += fileSizeBytes(file)" - " if (count > MAX_ZIP_ENTRIES || bytes > MAX_ZIP_TOTAL_BYTES) {" + " if (treeExportQuotaExceeded(count, bytes, MAX_ZIP_ENTRIES, MAX_ZIP_TOTAL_BYTES)) {" " throw IllegalStateException(\"Tree export quota exceeded\")" " }" " val relative = dir.toPath().relativize(file.toPath()).toString()"