[Bf-blender-cvs] [5afb0ab] master: Basic support for UNC paths on Windows

Andrea Weikert noreply at git.blender.org
Mon Apr 21 17:08:20 CEST 2014


Commit: 5afb0abfbd7b93d6b42c594146b53f3ab5d6b9d0
Author: Andrea Weikert
Date:   Mon Apr 21 16:49:35 2014 +0200
https://developer.blender.org/rB5afb0abfbd7b93d6b42c594146b53f3ab5d6b9d0

Basic support for UNC paths on Windows

Differential Revision: https://developer.blender.org/D298

Allows users on Windows to enter UNC paths in the filebrowser and to link to .blend files on a UNC path. Functionality is limited still, we can't browse the network yet and have no support to check user rights so far.

What works:
- enter an UNC path in the file browser manually or via copy/paste
- navigation within the UNC share subfolders
- link to a file on a UNC share

What does not (yet) work:
- browse the network for computers and shares
- browse to a folder that requires entering user credentials

Contributors:
Rob McKay - original patch
Campbell Barton - style fixes

Reviewers:
Campbell Barton, Brecht van Lommel

===================================================================

M	release/datafiles/locale
M	release/scripts/addons
M	release/scripts/addons_contrib
M	scons
M	source/blender/blenlib/BLI_path_util.h
M	source/blender/blenlib/intern/path_util.c
M	source/blender/blenlib/intern/storage.c
M	source/blender/editors/space_file/file_ops.c

===================================================================

diff --git a/release/datafiles/locale b/release/datafiles/locale
index c842f10..cb1967c 160000
--- a/release/datafiles/locale
+++ b/release/datafiles/locale
@@ -1 +1 @@
-Subproject commit c842f10f94dd7e5b8a5f28b1ece91cff3890aed3
+Subproject commit cb1967cc63a6d2d75d2b59cdf91c5f5645285aea
diff --git a/release/scripts/addons b/release/scripts/addons
index 8ad356e..c50944e 160000
--- a/release/scripts/addons
+++ b/release/scripts/addons
@@ -1 +1 @@
-Subproject commit 8ad356e3324cddef42d41f9b9b588ef1ebd2f8bf
+Subproject commit c50944e808d6c74148237e85866e893628f0fee6
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
index 7485bc6..31545d2 160000
--- a/release/scripts/addons_contrib
+++ b/release/scripts/addons_contrib
@@ -1 +1 @@
-Subproject commit 7485bc6b11e32e6c9d4d13b273ec7a2d8eddf594
+Subproject commit 31545d25c9cb41d271a3f3ef84d327708572290e
diff --git a/scons b/scons
index 59512aa..2d6ebcb 160000
--- a/scons
+++ b/scons
@@ -1 +1 @@
-Subproject commit 59512aadd1d16d7b9327f0eefafb23513b4f2137
+Subproject commit 2d6ebcb23909058b846aa232ecb2fee497924cf8
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index efc5731..6e77faf 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -165,6 +165,12 @@ bool BLI_path_cwd(char *path) ATTR_NONNULL();
 void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
 
 bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+bool BLI_path_is_unc(const char *path);
+
+#if defined(WIN32)
+void BLI_cleanup_unc_16(wchar_t *path_16);
+void BLI_cleanup_unc(char *path_16, int maxlen);
+#endif
 
 /* path string comparisons: case-insensitive for Windows, case-sensitive otherwise */
 #if defined(WIN32)
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 594f9bf..118cd50 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -329,7 +329,7 @@ void BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim
 	BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
 }
 
-
+static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
 
 /* ******************** string encoding ***************** */
 
@@ -394,7 +394,9 @@ void BLI_cleanup_path(const char *relabase, char *path)
 		memmove(start, eind, strlen(eind) + 1);
 	}
 
-	while ( (start = strstr(path, "\\\\")) ) {
+	/* remove two consecutive backslashes, but skip the UNC prefix,
+	 * which needs to be preserved */
+	while ( (start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\")) ) {
 		eind = start + strlen("\\\\") - 1;
 		memmove(start, eind, strlen(eind) + 1);
 	}
@@ -463,6 +465,110 @@ bool BLI_path_is_rel(const char *path)
 	return path[0] == '/' && path[1] == '/';
 }
 
+/* return true if the path is a UNC share */
+bool BLI_path_is_unc(const char *name)
+{
+	return name[0] == '\\' && name[1] == '\\';
+}
+
+/**
+ * Returns the length of the identifying prefix
+ * of a UNC path which can start with '\\' (short version)
+ * or '\\?\' (long version)
+ * If the path is not a UNC path, return 0
+ *
+ * \param name  the path name
+ */
+static int BLI_path_unc_prefix_len(const char *path)
+{
+	if (BLI_path_is_unc(path)) {
+		if ((path[2] == '?') && (path[3] == '\\') ) {
+			/* we assume long UNC path like \\?\server\share\folder etc... */
+			return 4;
+		}
+		else {
+			return 2;
+		}
+	}
+
+	return 0;
+}
+
+#if defined(WIN32)
+
+/* return true if the path is absolute ie starts with a drive specifier (eg A:\) or is a UNC path */
+static bool BLI_path_is_abs(const char *name)
+{
+	return (name[1] == ':' && (name[2] == '\\' || name[2] == '/') ) || BLI_path_is_unc(name);
+}
+
+static wchar_t *next_slash(wchar_t *path)
+{
+	wchar_t *slash = path;
+	while (*slash && *slash != L'\\') slash++;
+	return slash;
+}
+
+/* adds a slash if the unc path points sto a share */
+static void BLI_path_add_slash_to_share(wchar_t *uncpath)
+{
+	wchar_t *slash_after_server = next_slash(uncpath + 2);
+	if (*slash_after_server) {
+		wchar_t *slash_after_share = next_slash(slash_after_server + 1);
+		if (!(*slash_after_share)) {
+			slash_after_share[0] = L'\\';
+			slash_after_share[1] = L'\0';
+		}
+	}
+}
+
+static void BLI_path_unc_to_short(wchar_t *unc)
+{
+	wchar_t tmp[PATH_MAX];
+
+	int len = wcslen(unc);
+	int copy_start = 0;
+	/* convert:
+	 *    \\?\UNC\server\share\folder\... to \\server\share\folder\...
+	 *    \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
+	 */
+	if ((len > 3) &&
+	    (unc[0] ==  L'\\') &&
+	    (unc[1] ==  L'\\') &&
+	    (unc[2] ==  L'?') &&
+	    ((unc[3] ==  L'\\') || (unc[3] ==  L'/')))
+	{
+		if ((len > 5) && (unc[5] ==  L':')) {
+			wcsncpy(tmp, unc + 4, len - 4);
+			tmp[len - 4] = L'\0';
+			wcscpy(unc, tmp);
+		}
+		else if ((len > 7) && (wcsncmp(&unc[4], L"UNC", 3) == 0) &&
+		         ((unc[7] ==  L'\\') || (unc[7] ==  L'/')))
+		{
+			tmp[0] = L'\\';
+			tmp[1] = L'\\';
+			wcsncpy(tmp + 2, unc + 8, len - 8);
+			tmp[len - 6] = L'\0';
+			wcscpy(unc, tmp);
+		}
+	}
+}
+
+void BLI_cleanup_unc(char *path, int maxlen)
+{
+	wchar_t *tmp_16 = alloc_utf16_from_8(path, 1);
+	BLI_cleanup_unc_16(tmp_16);
+	conv_utf_16_to_8(tmp_16, path, maxlen);
+}
+
+void BLI_cleanup_unc_16(wchar_t *path_16)
+{
+	BLI_path_unc_to_short(path_16);
+	BLI_path_add_slash_to_share(path_16);
+}
+#endif
+
 /**
  * Replaces *file with a relative version (prefixed by "//") such that BLI_path_abs, given
  * the same *relfile, will convert it back to its original value.
@@ -484,7 +590,7 @@ void BLI_path_rel(char *file, const char *relfile)
 	}
 
 #ifdef WIN32
-	if (BLI_strnlen(relfile, 3) > 2 && relfile[1] != ':') {
+	if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
 		char *ptemp;
 		/* fix missing volume name in relative base,
 		 * can happen with old recent-files.txt files */
@@ -500,15 +606,35 @@ void BLI_path_rel(char *file, const char *relfile)
 	}
 
 	if (BLI_strnlen(file, 3) > 2) {
-		if (temp[1] == ':' && file[1] == ':' && temp[0] != file[0])
+		bool is_unc = BLI_path_is_unc(file);
+
+		/* Ensure paths are both UNC paths or are both drives */
+		if (BLI_path_is_unc(temp) != is_unc) {
+			return;
+		}
+
+		/* Ensure both UNC paths are on the same share */
+		if (is_unc) {
+			int off;
+			int slash = 0;
+			for (off = 0; temp[off] && slash < 4; off++) {
+				if (temp[off] != file[off])
+					return;
+
+				if (temp[off] == '\\')
+					slash++;
+			}
+		}
+		else if (temp[1] == ':' && file[1] == ':' && temp[0] != file[0]) {
 			return;
+		}
 	}
 #else
 	BLI_strncpy(temp, relfile, FILE_MAX);
 #endif
 
-	BLI_char_switch(temp, '\\', '/');
-	BLI_char_switch(file, '\\', '/');
+	BLI_char_switch(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
+	BLI_char_switch(file + BLI_path_unc_prefix_len(file), '\\', '/');
 	
 	/* remove /./ which confuse the following slash counting... */
 	BLI_cleanup_path(NULL, file);
@@ -727,7 +853,7 @@ bool BLI_path_abs(char *path, const char *basepath)
 	 * blend file as a lib main - we are basically checking for the case that a 
 	 * UNIX root '/' is passed.
 	 */
-	if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
+	if (!wasrelative && !BLI_path_is_abs(path)) {
 		char *p = path;
 		get_default_root(tmp);
 		// get rid of the slashes at the beginning of the path
@@ -757,24 +883,28 @@ bool BLI_path_abs(char *path, const char *basepath)
 	
 #endif
 
-	BLI_strncpy(base, basepath, sizeof(base));
-
-	/* file component is ignored, so don't bother with the trailing slash */
-	BLI_cleanup_path(NULL, base);
-	
 	/* push slashes into unix mode - strings entering this part are
 	 * potentially messed up: having both back- and forward slashes.
 	 * Here we push into one conform direction, and at the end we
 	 * push them into the system specific dir. This ensures uniformity
 	 * of paths and solving some problems (and prevent potential future
-	 * ones) -jesterKing. */
-	BLI_char_switch(tmp, '\\', '/');
-	BLI_char_switch(base, '\\', '/');
+	 * ones) -jesterKing.
+	 * For UNC paths the first characters containing the UNC prefix
+	 * shouldn't be switched as we need to distinguish them from
+	 * paths relative to the .blend file -elubie */
+	BLI_char_switch(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/');
 
 	/* Paths starting with // will get the blend file as their base,
 	 * this isn't standard in any os but is used in blender all over the place */
 	if (wasrelative) {
-		const char * const lslash = BLI_last_slash(base);
+		const char *lslash;
+		BLI_strncpy(base, basepath, sizeof(base));
+
+		/* file component is ignored, so don't bother with the trailing slash */
+		BLI_cleanup_path(NULL, base);
+		lslash = BLI_last_slash(base);
+		BLI_char_switch(base + BLI_path_unc_prefix_len(base), '\\', '/');
+
 		if (lslash) {
 			const int baselen = (int) (lslash - base) + 1;  /* length up to and including last "/" */
 			/* use path for temp storage here, we copy back over it right away */
@@ -823,7 +953,7 @@ bool BLI_path_cwd(char *path)
 	const int filelen = strlen(path);
 	
 #ifdef WIN32
-	if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/'))
+	if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path))
 		wasrelative = false;
 #else
 	if (filelen >= 2 && path[0] == '/')
@@ -1369,7 +1499,7 @@ void BLI_clean(char *path)
 		BLI_char_switch(path + 2, '/', '\\');
 	}
 #else
-	BLI_char_switch(path, '\\', '/');
+	BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/');
 #endif
 }
 
@@ -1486,9 +1616,12 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c
 			BLI_strncpy(string, dir, 3);
 			dir += 2;
 		}
+		else if (BLI_strnlen(dir, 3) >= 2 && BLI_path_is_unc(dir)) {
+			string[0] = 0;
+		}
 		else { /* no drive specified */
 			   /* first option: get the drive from the relabase if it has one */
-			if (relabase && strlen(relabase) >= 2 && relabase[1] == ':') {
+			if (relabase && BLI_strnlen(relabase, 3) >= 2 && relabase[1] == ':') {
 				BLI_strncpy(string, relabase, 3);
 				string[2] = '\\';
 				string[

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list