WM: make all blend file paths absolute & normalized on read/write

Ensure the file path G.main->filepath is always absolute and normalized.

- It was possible to call WM_OT_open_mainfile with only a filename,
  if this resolved from the CWD, Blender's internal filepath
  would not be absolute as expected.

- It was possible to open files on UNIX with an additional forward slash
  causing the blend file path it's self to contain a '//' prefix,
  this is error prone as running BLI_path_abs(..) multiple times would
  add the blend file prefix each time.

- Remove requirement for "filepath" to be an absolute path when saving.
  Instead, expand the path - making it absolute, as this constraint
  wasn't applied open opening files, prefer making save/open behave
  consistently.

- Assert when BLI_path_abs/BLI_path_rel receive a basepath that has
  a "//" (relative) prefix itself.
This commit is contained in:
Campbell Barton
2023-05-15 19:47:54 +10:00
parent 5285cd9a7b
commit 98dd91f418
3 changed files with 14 additions and 13 deletions
@@ -605,6 +605,8 @@ void BLI_path_normalize_unc_16(wchar_t *path_16)
void BLI_path_rel(char path[FILE_MAX], const char *basepath)
{
BLI_string_debug_size_after_nil(path, FILE_MAX);
/* A `basepath` starting with `//` will be be made relative multiple times. */
BLI_assert_msg(!BLI_path_is_rel(basepath), "The 'basepath' cannot start with '//'!");
const char *lslash;
char temp[FILE_MAX];
@@ -1043,6 +1045,8 @@ void BLI_path_to_display_name(char *display_name, int display_name_maxncpy, cons
bool BLI_path_abs(char path[FILE_MAX], const char *basepath)
{
BLI_string_debug_size_after_nil(path, FILE_MAX);
/* A `basepath` starting with `//` will be be made absolute multiple times. */
BLI_assert_msg(!BLI_path_is_rel(basepath), "The 'basepath' cannot start with '//'!");
const bool wasrelative = BLI_path_is_rel(path);
char tmp[FILE_MAX];
@@ -17,6 +17,7 @@
#include "BLI_ghash.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h" /* Only for assertions. */
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -400,6 +401,9 @@ BlendFileData *BLO_read_from_file(const char *filepath,
eBLOReadSkip skip_flags,
BlendFileReadReport *reports)
{
BLI_assert(!BLI_path_is_rel(filepath));
BLI_assert(BLI_path_is_abs_from_cwd(filepath));
BlendFileData *bfd = nullptr;
FileData *fd;
@@ -2797,6 +2797,8 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op)
bool success;
RNA_string_get(op->ptr, "filepath", filepath);
BLI_path_abs_from_cwd(filepath, sizeof(filepath));
BLI_path_normalize_native(filepath);
/* re-use last loaded setting so we can reload a file without changing */
wm_open_init_load_ui(op, false);
@@ -3101,6 +3103,8 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
bool success;
RNA_string_get(op->ptr, "filepath", filepath);
BLI_path_abs_from_cwd(filepath, sizeof(filepath));
BLI_path_normalize_native(filepath);
wm_open_init_use_scripts(op, true);
SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC);
@@ -3242,6 +3246,8 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath");
if (is_filepath_set) {
RNA_string_get(op->ptr, "filepath", filepath);
BLI_path_abs_from_cwd(filepath, sizeof(filepath));
BLI_path_normalize_native(filepath);
}
else {
STRNCPY(filepath, BKE_main_blendfile_path(bmain));
@@ -3254,19 +3260,6 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* NOTE(@ideasman42): only check this for file-path properties so saving an already
* saved file never fails with an error.
* Even though this should never happen, there may be some corner case where a malformed
* path is stored in `G.main->filepath`: when the file path is initialized from recovering
* a blend file - for example, so in this case failing to save isn't ideal. */
if (is_filepath_set && !BLI_path_is_abs_from_cwd(filepath)) {
BKE_reportf(op->reports,
RPT_ERROR,
"The \"filepath\" property was not an absolute path: \"%s\"",
filepath);
return OPERATOR_CANCELLED;
}
const int fileflags_orig = G.fileflags;
int fileflags = G.fileflags;