From e4b2ebd80779a44d24fe87af26ef278c1e2d97d2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 6 Oct 2023 02:04:49 +0200 Subject: Add wrappers around boost::filesystem methods that handle the required mangling of long filenames on Windows. Also wrap lots of missing places (e.g. calls to asdcplib, libxml++, libcxml etc.) in dcp::filesystem::fix_long_path(). The idea is to keep paths un-mangled until they we call some filesystem-related API and mangle them at that point. Otherwise we end up serialising mangled names, which seems like it will not end well. Should fix DoM #2623. --- test/encryption_test.cc | 6 +++ test/file_test.cc | 88 ---------------------------------------- test/filesystem_test.cc | 97 +++++++++++++++++++++++++++++++++++++++++++++ test/long_filenames_test.cc | 59 +++++++++++++++++++++++++++ test/wscript | 3 +- 5 files changed, 164 insertions(+), 89 deletions(-) delete mode 100644 test/file_test.cc create mode 100644 test/filesystem_test.cc create mode 100644 test/long_filenames_test.cc (limited to 'test') diff --git a/test/encryption_test.cc b/test/encryption_test.cc index f2a40843..358a3fd9 100644 --- a/test/encryption_test.cc +++ b/test/encryption_test.cc @@ -36,6 +36,7 @@ #include "dcp.h" #include "certificate_chain.h" #include "cpl.h" +#include "filesystem.h" #include "mono_picture_asset.h" #include "picture_asset_writer.h" #include "sound_asset_writer.h" @@ -155,6 +156,11 @@ BOOST_AUTO_TEST_CASE (encryption_test) kdm.encrypt (signer, signer->leaf(), vector(), dcp::Formulation::MODIFIED_TRANSITIONAL_1, true, 0).as_xml("build/test/encryption_test.kdm.xml"); + /* Make sure we aren't in a UNC current working directory otherwise the use of cmd.exe + * in system() below will fail. + */ + boost::filesystem::current_path(dcp::filesystem::unfix_long_path(boost::filesystem::current_path())); + int r = system ( "xmllint --path schema --nonet --noout --schema schema/SMPTE-430-1-2006-Amd-1-2009-KDM.xsd build/test/encryption_test.kdm.xml " #ifndef LIBDCP_WINDOWS diff --git a/test/file_test.cc b/test/file_test.cc deleted file mode 100644 index 8c6ded29..00000000 --- a/test/file_test.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (C) 2022 Carl Hetherington - - This file is part of libdcp. - - libdcp is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - libdcp is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libdcp. If not, see . - - In addition, as a special exception, the copyright holders give - permission to link the code of portions of this program with the - OpenSSL library under certain conditions as described in each - individual source file, and distribute linked combinations - including the two. - - You must obey the GNU General Public License in all respects - for all of the code used other than OpenSSL. If you modify - file(s) with this exception, you may extend this exception to your - version of the file(s), but you are not obligated to do so. If you - do not wish to do so, delete this exception statement from your - version. If you delete this exception statement from all source - files in the program, then also delete it here. -*/ - - -#include "file.h" -#include -#include - - -BOOST_AUTO_TEST_CASE (fix_long_path_test) -{ -#ifdef LIBDCP_WINDOWS - BOOST_CHECK_EQUAL (dcp::fix_long_path("c:\\foo"), "\\\\?\\c:\\foo"); - BOOST_CHECK_EQUAL (dcp::fix_long_path("c:\\foo\\bar"), "\\\\?\\c:\\foo\\bar"); - boost::filesystem::path fixed_bar = "\\\\?\\"; - fixed_bar += boost::filesystem::current_path(); - fixed_bar /= "bar"; - BOOST_CHECK_EQUAL (dcp::fix_long_path("bar"), fixed_bar); - - BOOST_CHECK_EQUAL (dcp::fix_long_path("\\\\?\\c:\\foo"), "\\\\?\\c:\\foo"); -#else - BOOST_CHECK_EQUAL (dcp::fix_long_path("foo/bar/baz"), "foo/bar/baz"); -#endif -} - - -#ifdef LIBDCP_WINDOWS -BOOST_AUTO_TEST_CASE (windows_long_filename_test) -{ - using namespace boost::filesystem; - - path too_long = current_path() / "build\\test\\a\\really\\very\\long\\filesystem\\path\\indeed\\that\\will\\be\\so\\long\\that\\windows\\cannot\\normally\\cope\\with\\it\\unless\\we\\add\\this\\crazy\\prefix\\and\\then\\magically\\it\\can\\do\\it\\fine\\I\\dont\\really\\know\\why\\its\\like\\that\\but\\hey\\it\\is\\so\\here\\we\\are\\what\\can\\we\\do\\other\\than\\bodge\\it"; - - BOOST_CHECK (too_long.string().length() > 260); - boost::system::error_code ec; - create_directories (too_long, ec); - BOOST_CHECK (ec); - - path fixed_path = dcp::fix_long_path(too_long); - create_directories (fixed_path, ec); - BOOST_CHECK (!ec); - - { - dcp::File file(too_long / "hello", "w"); - BOOST_REQUIRE (file); - fprintf (file.get(), "Hello_world"); - } - - { - dcp::File file(too_long / "hello", "r"); - BOOST_REQUIRE (file); - char buffer[64]; - fscanf (file.get(), "%63s", buffer); - BOOST_CHECK_EQUAL (strcmp(buffer, "Hello_world"), 0); - } -} -#endif - diff --git a/test/filesystem_test.cc b/test/filesystem_test.cc new file mode 100644 index 00000000..fc13db99 --- /dev/null +++ b/test/filesystem_test.cc @@ -0,0 +1,97 @@ +/* + Copyright (C) 2022 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +#include "file.h" +#include "filesystem.h" +#include +#include + + +BOOST_AUTO_TEST_CASE (fix_long_path_test) +{ +#ifdef LIBDCP_WINDOWS + BOOST_CHECK_EQUAL(dcp::filesystem::fix_long_path("c:\\foo"), "\\\\?\\c:\\foo"); + BOOST_CHECK_EQUAL(dcp::filesystem::fix_long_path("c:\\foo\\bar"), "\\\\?\\c:\\foo\\bar"); + BOOST_CHECK_EQUAL(dcp::filesystem::fix_long_path("\\\\?\\c:\\foo"), "\\\\?\\c:\\foo"); +#else + BOOST_CHECK_EQUAL(dcp::filesystem::fix_long_path("foo/bar/baz"), "foo/bar/baz"); +#endif +} + + +BOOST_AUTO_TEST_CASE(unfix_long_path_test) +{ +#ifdef LIBDCP_WINDOWS + BOOST_CHECK_EQUAL(dcp::filesystem::unfix_long_path("c:\\foo"), "c:\\foo"); + BOOST_CHECK_EQUAL(dcp::filesystem::unfix_long_path("\\\\?\\c:\\foo"), "c:\\foo"); +#else + BOOST_CHECK_EQUAL(dcp::filesystem::unfix_long_path("c:\\foo"), "c:\\foo"); + BOOST_CHECK_EQUAL(dcp::filesystem::unfix_long_path("\\\\?\\c:\\foo"), "\\\\?\\c:\\foo"); +#endif +} + + +#ifdef LIBDCP_WINDOWS +BOOST_AUTO_TEST_CASE (windows_long_filename_test) +{ + using namespace boost::filesystem; + + /* Make sure current_path() is not already fixed by using our dcp::filesystem version */ + path too_long = dcp::filesystem::current_path() / "build\\test\\a\\really\\very\\long\\filesystem\\path\\indeed\\that\\will\\be\\so\\long\\that\\windows\\cannot\\normally\\cope\\with\\it\\unless\\we\\add\\this\\crazy\\prefix\\and\\then\\magically\\it\\can\\do\\it\\fine\\I\\dont\\really\\know\\why\\its\\like\\that\\but\\hey\\it\\is\\so\\here\\we\\are\\what\\can\\we\\do\\other\\than\\bodge\\it"; + + BOOST_CHECK (too_long.string().length() > 260); + boost::system::error_code ec; + create_directories (too_long, ec); + BOOST_CHECK (ec); + + path fixed_path = dcp::filesystem::fix_long_path(too_long); + create_directories (fixed_path, ec); + BOOST_CHECK (!ec); + + { + dcp::File file(too_long / "hello", "w"); + BOOST_REQUIRE (file); + fprintf (file.get(), "Hello_world"); + } + + { + dcp::File file(too_long / "hello", "r"); + BOOST_REQUIRE (file); + char buffer[64]; + fscanf (file.get(), "%63s", buffer); + BOOST_CHECK_EQUAL (strcmp(buffer, "Hello_world"), 0); + } +} +#endif + diff --git a/test/long_filenames_test.cc b/test/long_filenames_test.cc new file mode 100644 index 00000000..f8189884 --- /dev/null +++ b/test/long_filenames_test.cc @@ -0,0 +1,59 @@ +/* + Copyright (C) 2023 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +#include "dcp.h" +#include "filesystem.h" +#include +#include + + +BOOST_AUTO_TEST_CASE(load_dcp_with_long_filename) +{ + boost::filesystem::path long_name = "build/test"; + for (int i = 0; i < 27; ++i) { + long_name /= "letsmakeitlong"; + } + + dcp::filesystem::remove_all(long_name); + dcp::filesystem::create_directories(long_name); + for (auto file: dcp::filesystem::directory_iterator("test/ref/DCP/dcp_test1")) { + dcp::filesystem::copy(file.path(), long_name / file.path().filename()); + } + + dcp::DCP dcp(long_name); + BOOST_CHECK_NO_THROW(dcp.read()); +} + + + diff --git a/test/wscript b/test/wscript index bc786322..4d9278eb 100644 --- a/test/wscript +++ b/test/wscript @@ -82,7 +82,7 @@ def build(bld): effect_test.cc encryption_test.cc exception_test.cc - file_test.cc + filesystem_test.cc fraction_test.cc frame_info_hash_test.cc gamma_transfer_function_test.cc @@ -90,6 +90,7 @@ def build(bld): interop_load_font_test.cc interop_subtitle_test.cc local_time_test.cc + long_filenames_test.cc make_digest_test.cc markers_test.cc mca_test.cc -- cgit v1.2.3