Bug 1741465 - Support reading files larger than UINT32_MAX if using a large enough offset r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D132262
This commit is contained in:
Barret Rennie 2021-12-03 17:21:52 +00:00
Родитель 348d216e58
Коммит 83586dfc28
3 изменённых файлов: 35 добавлений и 24 удалений

Просмотреть файл

@ -284,7 +284,7 @@ dictionary ReadOptions : ReadUTF8Options {
* The offset into the file to read from. If unspecified, the file will be read
* from the start.
*/
unsigned long offset = 0;
unsigned long long offset = 0;
/**
* The max bytes to read from the file at path. If unspecified, the entire

Просмотреть файл

@ -829,7 +829,7 @@ already_AddRefed<Promise> IOUtils::CreateJSPromise(GlobalObject& aGlobal) {
/* static */
Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync(
nsIFile* aFile, const uint32_t aOffset, const Maybe<uint32_t> aMaxBytes,
nsIFile* aFile, const uint64_t aOffset, const Maybe<uint32_t> aMaxBytes,
const bool aDecompress, IOUtils::BufferKind aBufferKind) {
MOZ_ASSERT(!NS_IsMainThread());
@ -840,6 +840,15 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync(
"The `maxBytes` and `decompress` options are not compatible"));
}
if (aOffset > static_cast<uint64_t>(INT64_MAX)) {
return Err(IOError(NS_ERROR_ILLEGAL_INPUT)
.WithMessage("Requested offset is too large (%" PRIu64
" > %" PRId64 ")",
aOffset, INT64_MAX));
}
const int64_t offset = static_cast<int64_t>(aOffset);
RefPtr<nsFileStream> stream = new nsFileStream();
if (nsresult rv =
stream->Init(aFile, PR_RDONLY | nsIFile::OS_READAHEAD, 0666, 0);
@ -847,43 +856,45 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync(
return Err(IOError(rv).WithMessage("Could not open the file at %s",
aFile->HumanReadablePath().get()));
}
int64_t bufSize = 0;
uint32_t bufSize = 0;
if (aMaxBytes.isNothing()) {
// Limitation: We cannot read files that are larger than the max size of a
// TypedArray (UINT32_MAX bytes). Reject if the file is too
// big to be read.
// Limitation: We cannot read more than the maximum size of a TypedArray
// (UINT32_MAX bytes). Reject if we have been requested to
// perform too large of a read.
int64_t streamSize = -1;
if (nsresult rv = stream->GetSize(&streamSize); NS_FAILED(rv)) {
int64_t rawStreamSize = -1;
if (nsresult rv = stream->GetSize(&rawStreamSize); NS_FAILED(rv)) {
return Err(IOError(NS_ERROR_FILE_ACCESS_DENIED)
.WithMessage("Could not get info for the file at %s",
aFile->HumanReadablePath().get()));
}
MOZ_RELEASE_ASSERT(streamSize >= 0);
MOZ_RELEASE_ASSERT(rawStreamSize >= 0);
if (streamSize > static_cast<int64_t>(UINT32_MAX)) {
return Err(
IOError(NS_ERROR_FILE_TOO_BIG)
.WithMessage("Could not read the file at %s because it is too "
"large(size=%" PRId64 " bytes)",
aFile->HumanReadablePath().get(), streamSize));
}
bufSize = static_cast<uint32_t>(streamSize);
if (aOffset >= bufSize) {
uint64_t streamSize = static_cast<uint64_t>(rawStreamSize);
if (aOffset >= streamSize) {
bufSize = 0;
} else {
bufSize = bufSize - aOffset;
if (streamSize - offset > static_cast<int64_t>(UINT32_MAX)) {
return Err(IOError(NS_ERROR_FILE_TOO_BIG)
.WithMessage(
"Could not read the file at %s with offset %" PRIu32
" because it is too large(size=%" PRIu64 " bytes)",
aFile->HumanReadablePath().get(), offset,
streamSize));
}
bufSize = static_cast<uint32_t>(streamSize - offset);
}
} else {
bufSize = aMaxBytes.value();
}
if (aOffset > 0) {
if (nsresult rv = stream->Seek(PR_SEEK_SET, aOffset); NS_FAILED(rv)) {
if (offset > 0) {
if (nsresult rv = stream->Seek(PR_SEEK_SET, offset); NS_FAILED(rv)) {
return Err(IOError(rv).WithMessage(
"Could not seek to position %" PRId64 " in file %s", aOffset,
"Could not seek to position %" PRId64 " in file %s", offset,
aFile->HumanReadablePath().get()));
}
}

Просмотреть файл

@ -197,7 +197,7 @@ class IOUtils final {
* error.
*/
static Result<JsBuffer, IOError> ReadSync(nsIFile* aFile,
const uint32_t aOffset,
const uint64_t aOffset,
const Maybe<uint32_t> aMaxBytes,
const bool aDecompress,
BufferKind aBufferKind);