| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d29cc09 commit 1aafd19
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -387,10 +387,11 @@ class ZipFile { | |||
| 387 | 387 | return this.#enqueue(async () => | |
| 388 | 388 | this.#doAdd(await ZipEntry.create(filename, data, options))); | |
| 389 | 389 | } | |
| 390 | - // Append the entry's bytes where the central directory currently starts, | ||
| 391 | - // then rewrite the directory to include it. On write failure, restore the | ||
| 392 | - // original directory (the partial write may have clobbered it) and rethrow; | ||
| 393 | - // on success, promote a spent stream entry to its on-disk copy. | ||
| 390 | + // Append the entry's bytes where the central directory currently starts, then | ||
| 391 | + // rewrite the directory to include it. If the member write or the directory | ||
| 392 | + // rewrite fails, restore the original directory and drop the half-adopted | ||
| 393 | + // entry so the archive is left exactly as it was, then rethrow; on success, | ||
| 394 | + // promote a spent stream entry to its on-disk copy. | ||
| 394 | 395 | async #doAdd(entry) { | |
| 395 | 396 | const localOffset = this.#centralDirectoryOffset; | |
| 396 | 397 | let written = 0; | |
@@ -413,9 +414,30 @@ class ZipFile { | |||
| 413 | 414 | } | |
| 414 | 415 | throw err; | |
| 415 | 416 | } | |
| 417 | + const previousEntry = MapPrototypeGet(this.#entries, entry.name); | ||
| 416 | 418 | this.#centralDirectoryOffset = localOffset + written; | |
| 417 | 419 | MapPrototypeSet(this.#entries, entry.name, { central: null, entry, localOffset }); | |
| 418 | - await this.#rewriteCentralDirectory(); | ||
| 420 | + try { | ||
| 421 | + await this.#rewriteCentralDirectory(); | ||
| 422 | + } catch (err) { | ||
| 423 | + // The directory rewrite failed after the member bytes landed. Undo the | ||
| 424 | + // in-memory adoption and rewrite the original directory back at its old | ||
| 425 | + // offset (where the failed member bytes started), leaving the archive and | ||
| 426 | + // this handle exactly as before the call. | ||
| 427 | + this.#centralDirectoryOffset = localOffset; | ||
| 428 | + if (previousEntry === undefined) { | ||
| 429 | + MapPrototypeDelete(this.#entries, entry.name); | ||
| 430 | + } else { | ||
| 431 | + MapPrototypeSet(this.#entries, entry.name, previousEntry); | ||
| 432 | + } | ||
| 433 | + try { | ||
| 434 | + await this.#rewriteCentralDirectory(); | ||
| 435 | + } catch { | ||
| 436 | + // Restoring failed too (the device is likely full or gone); the | ||
| 437 | + // original error is the actionable one. | ||
| 438 | + } | ||
| 439 | + throw err; | ||
| 440 | + } | ||
| 419 | 441 | // The entry now has a stable home in this archive; if it was a spent | |
| 420 | 442 | // streaming entry, rebind it to that on-disk copy so it stays readable. | |
| 421 | 443 | entry[kPromote](this.#handle, localOffset); | |
@@ -453,9 +475,27 @@ class ZipFile { | |||
| 453 | 475 | } | |
| 454 | 476 | throw err; | |
| 455 | 477 | } | |
| 478 | + const previousEntry = MapPrototypeGet(this.#entries, entry.name); | ||
| 456 | 479 | this.#centralDirectoryOffset = localOffset + written; | |
| 457 | 480 | MapPrototypeSet(this.#entries, entry.name, { central: null, entry, localOffset }); | |
| 458 | - this.#rewriteCentralDirectorySync(); | ||
| 481 | + try { | ||
| 482 | + this.#rewriteCentralDirectorySync(); | ||
| 483 | + } catch (err) { | ||
| 484 | + // See #doAdd(): undo the in-memory adoption and restore the original | ||
| 485 | + // directory so a failed rewrite leaves the archive exactly as it was. | ||
| 486 | + this.#centralDirectoryOffset = localOffset; | ||
| 487 | + if (previousEntry === undefined) { | ||
| 488 | + MapPrototypeDelete(this.#entries, entry.name); | ||
| 489 | + } else { | ||
| 490 | + MapPrototypeSet(this.#entries, entry.name, previousEntry); | ||
| 491 | + } | ||
| 492 | + try { | ||
| 493 | + this.#rewriteCentralDirectorySync(); | ||
| 494 | + } catch { | ||
| 495 | + // Restoring failed too; the original error is the actionable one. | ||
| 496 | + } | ||
| 497 | + throw err; | ||
| 498 | + } | ||
| 459 | 499 | entry[kPromote](this.#handle, localOffset); | |
| 460 | 500 | return entry; | |
| 461 | 501 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments