Describe the bug
The VRT XML write in write_vrt (xrspatial/geotiff/_vrt.py) is not atomic. The final .vrt file is opened and written in place:
xml = '\n'.join(lines) + '\n'
with open(vrt_path, 'w') as f:
f.write(xml)
If the process crashes, the disk fills up, or the write is interrupted between open and the finished write, a truncated .vrt is left at the final path.
This bites hardest on the tiled path. _write_vrt_tiled (xrspatial/geotiff/_writers/eager.py) writes every tile into a staging directory, promotes that directory to its final name with an atomic os.replace, and only then writes the VRT index. The index is the last non-atomic step, so a partial index ends up pointing at a fully-promoted, complete tile set. A reader that picks up the half-written VRT sees a valid tile directory behind a malformed index.
The other local writers in the module already handle this. _write_bytes in _writer.py writes to a temp file in the same directory and then os.replaces it into place. The VRT index write skips that path and writes directly.
Expected behavior
The VRT XML write should be atomic: write to a temp file in the same directory as the destination, then os.replace it into the final path. An interrupted or failed write should never leave a partial .vrt behind. The temp file has to live on the same filesystem as the destination for the rename to stay atomic. The fix should reuse the existing _write_bytes helper instead of duplicating the temp-then-rename logic.
Additional context
- Cited line: the
open(vrt_path, 'w') write at the end of write_vrt in xrspatial/geotiff/_vrt.py.
- Promotion-before-index ordering: the
os.replace(staging_dir, tiles_dir) followed by write_vrt(...) sequence in xrspatial/geotiff/_writers/eager.py.
- Existing atomic helper:
_write_bytes in xrspatial/geotiff/_writer.py.
Describe the bug
The VRT XML write in
write_vrt(xrspatial/geotiff/_vrt.py) is not atomic. The final.vrtfile is opened and written in place:If the process crashes, the disk fills up, or the write is interrupted between
openand the finishedwrite, a truncated.vrtis left at the final path.This bites hardest on the tiled path.
_write_vrt_tiled(xrspatial/geotiff/_writers/eager.py) writes every tile into a staging directory, promotes that directory to its final name with an atomicos.replace, and only then writes the VRT index. The index is the last non-atomic step, so a partial index ends up pointing at a fully-promoted, complete tile set. A reader that picks up the half-written VRT sees a valid tile directory behind a malformed index.The other local writers in the module already handle this.
_write_bytesin_writer.pywrites to a temp file in the same directory and thenos.replaces it into place. The VRT index write skips that path and writes directly.Expected behavior
The VRT XML write should be atomic: write to a temp file in the same directory as the destination, then
os.replaceit into the final path. An interrupted or failed write should never leave a partial.vrtbehind. The temp file has to live on the same filesystem as the destination for the rename to stay atomic. The fix should reuse the existing_write_byteshelper instead of duplicating the temp-then-rename logic.Additional context
open(vrt_path, 'w')write at the end ofwrite_vrtinxrspatial/geotiff/_vrt.py.os.replace(staging_dir, tiles_dir)followed bywrite_vrt(...)sequence inxrspatial/geotiff/_writers/eager.py._write_bytesinxrspatial/geotiff/_writer.py.