WM: various changes to file writing behavior
Saving with only a filename (from Python) wasn't being prevented, while it would successfully write the file to the working-directory, path remapping and setting relative paths wouldn't work afterwards as `Main.filepath` would have no directory component. Disallow this since it's a corner case which only ever occurs when path names without any directories are used from Python, the overhead of expanding the working-directory for all data saving operations isn't worthwhile. The following changes have been made: - bpy.ops.wm.save_mainfile() without a filepath argument fails & reports and error when the file hasn't been saved. Previously it would write to "untitled.blend" and set the `G.main->filepath` to this as well. - bpy.ops.wm.save_mainfile(filepath="untitled.blend") fails & reports and error as the filename has no directory component. - `BLI_path_is_abs_from_cwd` was added to check if the path would attempt to expand to the CWD.
This commit is contained in:
@@ -323,9 +323,15 @@ void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL();
|
|||||||
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
|
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
|
||||||
*/
|
*/
|
||||||
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
|
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
|
||||||
|
/**
|
||||||
|
* Checks for a relative path (ignoring Blender's "//") prefix
|
||||||
|
* (unlike `!BLI_path_is_rel(path)`).
|
||||||
|
* When false, #BLI_path_abs_from_cwd would expand the absolute path.
|
||||||
|
*/
|
||||||
|
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL();
|
||||||
/**
|
/**
|
||||||
* Checks for relative path, expanding them relative to the current working directory.
|
* Checks for relative path, expanding them relative to the current working directory.
|
||||||
* Returns true if the expansion was performed.
|
* \returns true if the expansion was performed.
|
||||||
*
|
*
|
||||||
* \note Should only be called with command line paths.
|
* \note Should only be called with command line paths.
|
||||||
* This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
|
* This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
|
||||||
|
|||||||
@@ -1002,25 +1002,30 @@ bool BLI_path_abs(char *path, const char *basepath)
|
|||||||
return wasrelative;
|
return wasrelative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BLI_path_is_abs_from_cwd(const char *path)
|
||||||
|
{
|
||||||
|
bool is_abs = false;
|
||||||
|
const int path_len_clamp = BLI_strnlen(path, 3);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if ((ppath_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
|
||||||
|
is_abs = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (path_len_clamp >= 2 && path[0] == '/') {
|
||||||
|
is_abs = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return is_abs;
|
||||||
|
}
|
||||||
|
|
||||||
bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
|
bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_STRSIZE
|
#ifdef DEBUG_STRSIZE
|
||||||
memset(path, 0xff, sizeof(*path) * maxlen);
|
memset(path, 0xff, sizeof(*path) * maxlen);
|
||||||
#endif
|
#endif
|
||||||
bool wasrelative = true;
|
|
||||||
const int filelen = strlen(path);
|
|
||||||
|
|
||||||
#ifdef WIN32
|
if (!BLI_path_is_abs_from_cwd(path)) {
|
||||||
if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
|
|
||||||
wasrelative = false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (filelen >= 2 && path[0] == '/') {
|
|
||||||
wasrelative = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (wasrelative) {
|
|
||||||
char cwd[FILE_MAX];
|
char cwd[FILE_MAX];
|
||||||
/* in case the full path to the blend isn't used */
|
/* in case the full path to the blend isn't used */
|
||||||
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
|
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
|
||||||
@@ -1031,9 +1036,10 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
|
|||||||
else {
|
else {
|
||||||
printf("Could not get the current working directory - $PWD for an unknown reason.\n");
|
printf("Could not get the current working directory - $PWD for an unknown reason.\n");
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wasrelative;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@@ -1319,6 +1319,7 @@ bool BLO_write_file(Main *mainvar,
|
|||||||
ReportList *reports)
|
ReportList *reports)
|
||||||
{
|
{
|
||||||
BLI_assert(!BLI_path_is_rel(filepath));
|
BLI_assert(!BLI_path_is_rel(filepath));
|
||||||
|
BLI_assert(BLI_path_is_abs_from_cwd(filepath));
|
||||||
|
|
||||||
char tempname[FILE_MAX + 1];
|
char tempname[FILE_MAX + 1];
|
||||||
WriteWrap ww;
|
WriteWrap ww;
|
||||||
|
|||||||
@@ -3067,12 +3067,32 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
|
|||||||
BLO_WRITE_PATH_REMAP_NONE;
|
BLO_WRITE_PATH_REMAP_NONE;
|
||||||
save_set_compress(op);
|
save_set_compress(op);
|
||||||
|
|
||||||
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
|
const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath");
|
||||||
|
if (is_filepath_set) {
|
||||||
RNA_string_get(op->ptr, "filepath", path);
|
RNA_string_get(op->ptr, "filepath", path);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BLI_strncpy(path, BKE_main_blendfile_path(bmain), FILE_MAX);
|
STRNCPY(path, BKE_main_blendfile_path(bmain));
|
||||||
wm_filepath_default(bmain, path);
|
}
|
||||||
|
|
||||||
|
if (path[0] == '\0') {
|
||||||
|
BKE_report(op->reports,
|
||||||
|
RPT_ERROR,
|
||||||
|
"Unable to save an unsaved file with an empty or unset \"filepath\" property");
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE(@campbellbarton): 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(path)) {
|
||||||
|
BKE_reportf(op->reports,
|
||||||
|
RPT_ERROR,
|
||||||
|
"The \"filepath\" property was not an absolute path: \"%s\"",
|
||||||
|
path);
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int fileflags_orig = G.fileflags;
|
const int fileflags_orig = G.fileflags;
|
||||||
|
|||||||
Reference in New Issue
Block a user