Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vsimem: Implicitly create parent directories when creating a file #8369

Merged
merged 13 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions MIGRATION_GUIDE.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ MIGRATION GUIDE FROM GDAL 3.7 to GDAL 3.8
of a OGRSpatialReference*. Drivers should clone the passed SRS if they need
to keep it.

- The /vsimem virtual file system is modified to automatically create parent
directories when a file is created. (e.g., creating /vsimem/parent/child.txt
would cause the directory /vsimem/parent to be created.) If the parent
directory cannot be created because the file /vsimem/parent exists, file
creation will now fail.

- In SWIG bindings, the function FileFromMemBuffer now returns an error code
if the file could not be created.


MIGRATION GUIDE FROM GDAL 3.6 to GDAL 3.7
-----------------------------------------

Expand Down
33 changes: 33 additions & 0 deletions autotest/gcore/vsifile.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,39 @@ def test_vsifile_8():
gdal.Rmdir("/vsimem/newdir")


###############################################################################
# Test implicit directory creation in /vsimem


def test_vsifile_implicit_dir_creation_1(tmp_vsimem):

assert gdal.VSIStatL(str(tmp_vsimem)) is not None
assert gdal.VSIStatL(str(tmp_vsimem)).IsDirectory()

fpath = str(tmp_vsimem / "subdir1" / "subdir2" / "subdir3" / "myfile.txt")
fp = gdal.VSIFOpenL(str(fpath), "wb")
assert fp is not None
gdal.VSIFCloseL(fp)

assert gdal.VSIStatL(str(tmp_vsimem / "subdir1")).IsDirectory()
assert gdal.VSIStatL(str(tmp_vsimem / "subdir1" / "subdir2")).IsDirectory()
assert gdal.VSIStatL(
str(tmp_vsimem / "subdir1" / "subdir2" / "subdir3")
).IsDirectory()


def test_vsifile_implicit_dir_creation_2(tmp_vsimem):

fpath = str(tmp_vsimem / "afile")
fp = gdal.VSIFOpenL(str(fpath), "wb")
assert fp is not None
gdal.VSIFCloseL(fp)

fpath = str(tmp_vsimem / "afile" / "anotherfile")
fp = gdal.VSIFOpenL(str(fpath), "wb")
assert fp is None


###############################################################################
# Test ReadDir()

Expand Down
60 changes: 20 additions & 40 deletions autotest/gdrivers/daas.py
Original file line number Diff line number Diff line change
Expand Up @@ -1520,11 +1520,26 @@ def test_daas_getbuffer_raw():
###############################################################################


def _daas_getbuffer(pixel_encoding, drv_name, drv_options, mime_type):
@pytest.mark.parametrize(
"pixel_encoding,drv_name,drv_options,mime_type",
[
(
"JPEG2000",
"JP2OPENJPEG",
["QUALITY=100", "REVERSIBLE=YES", "RESOLUTIONS=1", "CODEC=JP2"],
"image/jp2",
),
("JPEG2000", "JP2KAK", ["QUALITY=100", "CODEC=JP2"], "image/jp2"),
("JPEG", "JPEG", ["QUALITY=100"], "image/jpeg"),
("PNG", "PNG", [], "image/png"),
],
ids=("jpeg2000_jp2openjpeg", "jpeg2000_jp2kak", "jpeg", "png"),
)
def test_daas_getbuffer(tmp_vsimem, pixel_encoding, drv_name, drv_options, mime_type):

drv = gdal.GetDriverByName(drv_name)
if drv is None:
pytest.skip()
pytest.skip(f"Driver {drv_name} not available")

handler = webserver.SequentialHandler()
handler.add(
Expand Down Expand Up @@ -1580,7 +1595,7 @@ def _daas_getbuffer(pixel_encoding, drv_name, drv_options, mime_type):
src_ds.GetRasterBand(1).WriteRaster(0, 0, 100, 100, "A", buf_xsize=1, buf_ysize=1)
src_ds.GetRasterBand(2).WriteRaster(0, 0, 100, 100, "B", buf_xsize=1, buf_ysize=1)
src_ds.GetRasterBand(3).WriteRaster(0, 0, 100, 100, "C", buf_xsize=1, buf_ysize=1)
tmpfile = "/vsimem/tmp"
tmpfile = tmp_vsimem / "tmp"
drv.CreateCopy(tmpfile, src_ds, options=drv_options)
f = gdal.VSIFOpenL(tmpfile, "rb")
content = gdal.VSIFReadL(1, 10000, f)
Expand Down Expand Up @@ -1634,41 +1649,6 @@ def _daas_getbuffer(pixel_encoding, drv_name, drv_options, mime_type):
###############################################################################


def test_daas_getbuffer_png():
_daas_getbuffer("PNG", "PNG", [], "image/png")


###############################################################################


def test_daas_getbuffer_jpeg():
_daas_getbuffer("JPEG", "JPEG", ["QUALITY=100"], "image/jpeg")


###############################################################################


def test_daas_getbuffer_jpeg2000_jp2kak():

_daas_getbuffer("JPEG2000", "JP2KAK", ["QUALITY=100", "CODEC=JP2"], "image/jp2")


###############################################################################


def test_daas_getbuffer_jpeg2000_jp2openjpeg():

_daas_getbuffer(
"JPEG2000",
"JP2OPENJPEG",
["QUALITY=100", "REVERSIBLE=YES", "RESOLUTIONS=1", "CODEC=JP2"],
"image/jp2",
)


###############################################################################


def test_daas_getbuffer_overview():

handler = webserver.SequentialHandler()
Expand Down Expand Up @@ -2169,7 +2149,7 @@ def test_daas_mask():
###############################################################################


def test_daas_png_response_4_bands_for_a_one_band_request():
def test_daas_png_response_4_bands_for_a_one_band_request(tmp_vsimem):

# Valid JSon but invalid height (string)
handler = webserver.SequentialHandler()
Expand Down Expand Up @@ -2228,7 +2208,7 @@ def test_daas_png_response_4_bands_for_a_one_band_request():
src_ds.GetRasterBand(2).WriteRaster(0, 0, 2, 3, "B", buf_xsize=1, buf_ysize=1)
src_ds.GetRasterBand(3).WriteRaster(0, 0, 2, 3, "C", buf_xsize=1, buf_ysize=1)
src_ds.GetRasterBand(4).WriteRaster(0, 0, 2, 3, "D", buf_xsize=1, buf_ysize=1)
tmpfile = "/vsimem/out.png"
tmpfile = tmp_vsimem / "out.png"
gdal.GetDriverByName("PNG").CreateCopy(tmpfile, src_ds)
f = gdal.VSIFOpenL(tmpfile, "rb")
png_content = gdal.VSIFReadL(1, 10000, f)
Expand Down
12 changes: 8 additions & 4 deletions autotest/gdrivers/jp2openjpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2575,8 +2575,10 @@ def test_jp2openjpeg_45():
del out_ds

# Now do the checks
dircontent = gdal.ReadDir("/vsimem/gmljp2")
assert dircontent is None
dircontent = gdal.ReadDir("/vsimem/")
if dircontent:
for filename in dircontent:
assert not filename.startswith("gmljp2")

ds = gdal.Open("/vsimem/jp2openjpeg_45.jp2")
gmljp2 = ds.GetMetadata_List("xml:gml.root-instance")[0]
Expand Down Expand Up @@ -2741,8 +2743,10 @@ def test_jp2openjpeg_45():
)
del out_ds

dircontent = gdal.ReadDir("/vsimem/gmljp2")
assert dircontent is None
dircontent = gdal.ReadDir("/vsimem/")
if dircontent:
for filename in dircontent:
assert not filename.startswith("gmljp2")

ds = ogr.Open("/vsimem/jp2openjpeg_45.jp2")
assert ds.GetLayerCount() == 1
Expand Down
Loading
Loading