Re: Path separator - Mailing list pgsql-hackers
| From | Magnus Hagander |
|---|---|
| Subject | Re: Path separator |
| Date | |
| Msg-id | 49DB5D2E.6040503@hagander.net Whole thread Raw |
| In response to | Re: Path separator (Magnus Hagander <magnus@hagander.net>) |
| Responses |
Re: Path separator
|
| List | pgsql-hackers |
Magnus Hagander wrote:
> Magnus Hagander wrote:
>>> The major stumbling block to doing either thing is not wishing to import
>>> path.c into libpq. I think that the objection was partially code size
>>> and partially namespace pollution (path.c doesn't use pg_ or similar
>>> prefixes on its exported names). The latter is no longer a problem on
>>> platforms that support exported-name filtering, but that isn't all of
>>> them. Could we consider splitting path.c into two parts, that which we
>>> want in libpq and that which we don't?
>> On my system (linux), path.o is 5k. libpq.so is 157k. Is adding that
>> size *really* a problem?
>>
>> Also, is there a chance that the linker is smart enough to actually
>> remove the parts of path.o that aren't used in libpq completely, if it's
>> not exported at all? (if the size does matter)
>>
>> If it is, sure, we could split it apart. But fairly large parts of it
>> would be required by both. But I guess the number of symbols would be
>> quite a bit smaller.
>
> Answering myself here: the filesize for the "frontend only" part is
> about 2k on this system.
Long meeting, time for coding.. :-) Here's a rough patch. Is this about
what you had in mind?
//Magnus
diff --git a/src/include/port.h b/src/include/port.h
index 0557dd2..c84f0d6 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -28,8 +28,15 @@ extern char *last_dir_separator(const char *filename);
extern char *first_path_separator(const char *pathlist);
extern void join_path_components(char *ret_path,
const char *head, const char *tail);
+extern void trim_directory(char *path);
+extern void trim_trailing_separator(char *path);
extern void canonicalize_path(char *path);
extern void make_native_path(char *path);
+#ifdef WIN32
+extern char *skip_drive(const char *path);
+#else
+#define skip_drive(path) (path)
+#endif
extern bool path_contains_parent_reference(const char *path);
extern bool path_is_prefix_of_path(const char *path1, const char *path2);
extern const char *get_progname(const char *argv0);
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 3b9df76..02a240d 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -34,6 +34,7 @@ OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
libpq-events.o \
md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
+ path_fe.o \
$(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
ifeq ($(PORTNAME), cygwin)
@@ -80,7 +81,7 @@ backend_src = $(top_srcdir)/src/backend
# For port modules, this only happens if configure decides the module
# is needed (see filter hack in OBJS, above).
-crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c
win32error.cpgsleep.c: % : $(top_srcdir)/src/port/%
+crypt.c getaddrinfo.c inet_aton.c noblock.c open.c path_fe.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c
win32error.cpgsleep.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
md5.c ip.c: % : $(backend_src)/libpq/%
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 8383f2a..a68baee 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -600,6 +600,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
strncpy(fnbuf, conn->sslcert, sizeof(fnbuf));
else
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
+ canonicalize_path(fnbuf);
/*
* OpenSSL <= 0.9.8 lacks error stack handling, which means it's likely to
@@ -716,6 +717,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
/* No PGSSLKEY specified, load default file */
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
}
+ canonicalize_path(fnbuf);
if (fnbuf[0] != '\0')
{
@@ -1016,6 +1018,7 @@ initialize_SSL(PGconn *conn)
strncpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
else
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE);
+ canonicalize_path(fnbuf);
if (stat(fnbuf, &buf) == 0)
{
@@ -1038,6 +1041,7 @@ initialize_SSL(PGconn *conn)
strncpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
else
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE);
+ canonicalize_path(fnbuf);
/* setting the flags to check against the complete CRL chain */
if (X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
diff --git a/src/port/Makefile b/src/port/Makefile
index f03a17a..f515847 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -31,7 +31,7 @@ override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS)
OBJS = $(LIBOBJS) chklocale.o copydir.o dirmod.o exec.o noblock.o path.o \
- pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
+ path_fe.o pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
ifneq (,$(filter $(PORTNAME),cygwin win32))
OBJS += pipe.o
endif
diff --git a/src/port/path.c b/src/port/path.c
index a841ef4..bfc0be3 100644
--- a/src/port/path.c
+++ b/src/port/path.c
@@ -46,94 +46,6 @@
#define IS_PATH_SEP(ch) ((ch) == ';')
#endif
-static void make_relative_path(char *ret_path, const char *target_path,
- const char *bin_path, const char *my_exec_path);
-static void trim_directory(char *path);
-static void trim_trailing_separator(char *path);
-
-
-/*
- * skip_drive
- *
- * On Windows, a path may begin with "C:" or "//network/". Advance over
- * this and point to the effective start of the path.
- */
-#ifdef WIN32
-
-static char *
-skip_drive(const char *path)
-{
- if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
- {
- path += 2;
- while (*path && !IS_DIR_SEP(*path))
- path++;
- }
- else if (isalpha((unsigned char) path[0]) && path[1] == ':')
- {
- path += 2;
- }
- return (char *) path;
-}
-#else
-
-#define skip_drive(path) (path)
-#endif
-
-/*
- * first_dir_separator
- *
- * Find the location of the first directory separator, return
- * NULL if not found.
- */
-char *
-first_dir_separator(const char *filename)
-{
- const char *p;
-
- for (p = skip_drive(filename); *p; p++)
- if (IS_DIR_SEP(*p))
- return (char *) p;
- return NULL;
-}
-
-/*
- * first_path_separator
- *
- * Find the location of the first path separator (i.e. ':' on
- * Unix, ';' on Windows), return NULL if not found.
- */
-char *
-first_path_separator(const char *pathlist)
-{
- const char *p;
-
- /* skip_drive is not needed */
- for (p = pathlist; *p; p++)
- if (IS_PATH_SEP(*p))
- return (char *) p;
- return NULL;
-}
-
-/*
- * last_dir_separator
- *
- * Find the location of the last directory separator, return
- * NULL if not found.
- */
-char *
-last_dir_separator(const char *filename)
-{
- const char *p,
- *ret = NULL;
-
- for (p = skip_drive(filename); *p; p++)
- if (IS_DIR_SEP(*p))
- ret = p;
- return (char *) ret;
-}
-
-
/*
* make_native_path - on WIN32, change / to \ in the path
*
@@ -210,130 +122,6 @@ join_path_components(char *ret_path,
"/%s", tail);
}
-
-/*
- * Clean up path by:
- * o make Win32 path use Unix slashes
- * o remove trailing quote on Win32
- * o remove trailing slash
- * o remove duplicate adjacent separators
- * o remove trailing '.'
- * o process trailing '..' ourselves
- */
-void
-canonicalize_path(char *path)
-{
- char *p,
- *to_p;
- char *spath;
- bool was_sep = false;
- int pending_strips;
-
-#ifdef WIN32
-
- /*
- * The Windows command processor will accept suitably quoted paths with
- * forward slashes, but barfs badly with mixed forward and back slashes.
- */
- for (p = path; *p; p++)
- {
- if (*p == '\\')
- *p = '/';
- }
-
- /*
- * In Win32, if you do: prog.exe "a b" "\c\d\" the system will pass \c\d"
- * as argv[2], so trim off trailing quote.
- */
- if (p > path && *(p - 1) == '"')
- *(p - 1) = '/';
-#endif
-
- /*
- * Removing the trailing slash on a path means we never get ugly double
- * trailing slashes. Also, Win32 can't stat() a directory with a trailing
- * slash. Don't remove a leading slash, though.
- */
- trim_trailing_separator(path);
-
- /*
- * Remove duplicate adjacent separators
- */
- p = path;
-#ifdef WIN32
- /* Don't remove leading double-slash on Win32 */
- if (*p)
- p++;
-#endif
- to_p = p;
- for (; *p; p++, to_p++)
- {
- /* Handle many adjacent slashes, like "/a///b" */
- while (*p == '/' && was_sep)
- p++;
- if (to_p != p)
- *to_p = *p;
- was_sep = (*p == '/');
- }
- *to_p = '\0';
-
- /*
- * Remove any trailing uses of "." and process ".." ourselves
- *
- * Note that "/../.." should reduce to just "/", while "../.." has to be
- * kept as-is. In the latter case we put back mistakenly trimmed ".."
- * components below. Also note that we want a Windows drive spec to be
- * visible to trim_directory(), but it's not part of the logic that's
- * looking at the name components; hence distinction between path and
- * spath.
- */
- spath = skip_drive(path);
- pending_strips = 0;
- for (;;)
- {
- int len = strlen(spath);
-
- if (len >= 2 && strcmp(spath + len - 2, "/.") == 0)
- trim_directory(path);
- else if (strcmp(spath, ".") == 0)
- {
- /* Want to leave "." alone, but "./.." has to become ".." */
- if (pending_strips > 0)
- *spath = '\0';
- break;
- }
- else if ((len >= 3 && strcmp(spath + len - 3, "/..") == 0) ||
- strcmp(spath, "..") == 0)
- {
- trim_directory(path);
- pending_strips++;
- }
- else if (pending_strips > 0 && *spath != '\0')
- {
- /* trim a regular directory name cancelled by ".." */
- trim_directory(path);
- pending_strips--;
- /* foo/.. should become ".", not empty */
- if (*spath == '\0')
- strcpy(spath, ".");
- }
- else
- break;
- }
-
- if (pending_strips > 0)
- {
- /*
- * We could only get here if path is now totally empty (other than a
- * possible drive specifier on Windows). We have to put back one or
- * more ".."'s that we took off.
- */
- while (--pending_strips > 0)
- strcat(path, "../");
- strcat(path, "..");
- }
-}
-
/*
* Detect whether a path contains any parent-directory references ("..")
*
@@ -672,53 +460,3 @@ get_parent_directory(char *path)
trim_directory(path);
}
-
-/*
- * trim_directory
- *
- * Trim trailing directory from path, that is, remove any trailing slashes,
- * the last pathname component, and the slash just ahead of it --- but never
- * remove a leading slash.
- */
-static void
-trim_directory(char *path)
-{
- char *p;
-
- path = skip_drive(path);
-
- if (path[0] == '\0')
- return;
-
- /* back up over trailing slash(es) */
- for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--)
- ;
- /* back up over directory name */
- for (; !IS_DIR_SEP(*p) && p > path; p--)
- ;
- /* if multiple slashes before directory name, remove 'em all */
- for (; p > path && IS_DIR_SEP(*(p - 1)); p--)
- ;
- /* don't erase a leading slash */
- if (p == path && IS_DIR_SEP(*p))
- p++;
- *p = '\0';
-}
-
-
-/*
- * trim_trailing_separator
- *
- * trim off trailing slashes, but not a leading slash
- */
-static void
-trim_trailing_separator(char *path)
-{
- char *p;
-
- path = skip_drive(path);
- p = path + strlen(path);
- if (p > path)
- for (p--; p > path && IS_DIR_SEP(*p); p--)
- *p = '\0';
-}
diff --git a/src/port/path_fe.c b/src/port/path_fe.c
new file mode 100644
index 0000000..e8ec271
--- /dev/null
+++ b/src/port/path_fe.c
@@ -0,0 +1,300 @@
+/*-------------------------------------------------------------------------
+ *
+ * path.c
+ * portable path handling routines
+ *
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL$
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#include <ctype.h>
+#include <sys/stat.h>
+#ifdef WIN32
+#ifdef _WIN32_IE
+#undef _WIN32_IE
+#endif
+#define _WIN32_IE 0x0500
+#ifdef near
+#undef near
+#endif
+#define near
+#include <shlobj.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "pg_config_paths.h"
+
+
+#ifndef WIN32
+#define IS_DIR_SEP(ch) ((ch) == '/')
+#else
+#define IS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\')
+#endif
+
+#ifndef WIN32
+#define IS_PATH_SEP(ch) ((ch) == ':')
+#else
+#define IS_PATH_SEP(ch) ((ch) == ';')
+#endif
+
+
+/*
+ * skip_drive
+ *
+ * On Windows, a path may begin with "C:" or "//network/". Advance over
+ * this and point to the effective start of the path.
+ */
+#ifdef WIN32
+
+static char *
+skip_drive(const char *path)
+{
+ if (IS_DIR_SEP(path[0]) && IS_DIR_SEP(path[1]))
+ {
+ path += 2;
+ while (*path && !IS_DIR_SEP(*path))
+ path++;
+ }
+ else if (isalpha((unsigned char) path[0]) && path[1] == ':')
+ {
+ path += 2;
+ }
+ return (char *) path;
+}
+#endif
+
+/*
+ * first_dir_separator
+ *
+ * Find the location of the first directory separator, return
+ * NULL if not found.
+ */
+char *
+first_dir_separator(const char *filename)
+{
+ const char *p;
+
+ for (p = skip_drive(filename); *p; p++)
+ if (IS_DIR_SEP(*p))
+ return (char *) p;
+ return NULL;
+}
+
+/*
+ * first_path_separator
+ *
+ * Find the location of the first path separator (i.e. ':' on
+ * Unix, ';' on Windows), return NULL if not found.
+ */
+char *
+first_path_separator(const char *pathlist)
+{
+ const char *p;
+
+ /* skip_drive is not needed */
+ for (p = pathlist; *p; p++)
+ if (IS_PATH_SEP(*p))
+ return (char *) p;
+ return NULL;
+}
+
+/*
+ * last_dir_separator
+ *
+ * Find the location of the last directory separator, return
+ * NULL if not found.
+ */
+char *
+last_dir_separator(const char *filename)
+{
+ const char *p,
+ *ret = NULL;
+
+ for (p = skip_drive(filename); *p; p++)
+ if (IS_DIR_SEP(*p))
+ ret = p;
+ return (char *) ret;
+}
+
+
+/*
+ * Clean up path by:
+ * o make Win32 path use Unix slashes
+ * o remove trailing quote on Win32
+ * o remove trailing slash
+ * o remove duplicate adjacent separators
+ * o remove trailing '.'
+ * o process trailing '..' ourselves
+ */
+void
+canonicalize_path(char *path)
+{
+ char *p,
+ *to_p;
+ char *spath;
+ bool was_sep = false;
+ int pending_strips;
+
+#ifdef WIN32
+
+ /*
+ * The Windows command processor will accept suitably quoted paths with
+ * forward slashes, but barfs badly with mixed forward and back slashes.
+ */
+ for (p = path; *p; p++)
+ {
+ if (*p == '\\')
+ *p = '/';
+ }
+
+ /*
+ * In Win32, if you do: prog.exe "a b" "\c\d\" the system will pass \c\d"
+ * as argv[2], so trim off trailing quote.
+ */
+ if (p > path && *(p - 1) == '"')
+ *(p - 1) = '/';
+#endif
+
+ /*
+ * Removing the trailing slash on a path means we never get ugly double
+ * trailing slashes. Also, Win32 can't stat() a directory with a trailing
+ * slash. Don't remove a leading slash, though.
+ */
+ trim_trailing_separator(path);
+
+ /*
+ * Remove duplicate adjacent separators
+ */
+ p = path;
+#ifdef WIN32
+ /* Don't remove leading double-slash on Win32 */
+ if (*p)
+ p++;
+#endif
+ to_p = p;
+ for (; *p; p++, to_p++)
+ {
+ /* Handle many adjacent slashes, like "/a///b" */
+ while (*p == '/' && was_sep)
+ p++;
+ if (to_p != p)
+ *to_p = *p;
+ was_sep = (*p == '/');
+ }
+ *to_p = '\0';
+
+ /*
+ * Remove any trailing uses of "." and process ".." ourselves
+ *
+ * Note that "/../.." should reduce to just "/", while "../.." has to be
+ * kept as-is. In the latter case we put back mistakenly trimmed ".."
+ * components below. Also note that we want a Windows drive spec to be
+ * visible to trim_directory(), but it's not part of the logic that's
+ * looking at the name components; hence distinction between path and
+ * spath.
+ */
+ spath = skip_drive(path);
+ pending_strips = 0;
+ for (;;)
+ {
+ int len = strlen(spath);
+
+ if (len >= 2 && strcmp(spath + len - 2, "/.") == 0)
+ trim_directory(path);
+ else if (strcmp(spath, ".") == 0)
+ {
+ /* Want to leave "." alone, but "./.." has to become ".." */
+ if (pending_strips > 0)
+ *spath = '\0';
+ break;
+ }
+ else if ((len >= 3 && strcmp(spath + len - 3, "/..") == 0) ||
+ strcmp(spath, "..") == 0)
+ {
+ trim_directory(path);
+ pending_strips++;
+ }
+ else if (pending_strips > 0 && *spath != '\0')
+ {
+ /* trim a regular directory name cancelled by ".." */
+ trim_directory(path);
+ pending_strips--;
+ /* foo/.. should become ".", not empty */
+ if (*spath == '\0')
+ strcpy(spath, ".");
+ }
+ else
+ break;
+ }
+
+ if (pending_strips > 0)
+ {
+ /*
+ * We could only get here if path is now totally empty (other than a
+ * possible drive specifier on Windows). We have to put back one or
+ * more ".."'s that we took off.
+ */
+ while (--pending_strips > 0)
+ strcat(path, "../");
+ strcat(path, "..");
+ }
+}
+
+/*
+ * trim_directory
+ *
+ * Trim trailing directory from path, that is, remove any trailing slashes,
+ * the last pathname component, and the slash just ahead of it --- but never
+ * remove a leading slash.
+ */
+void
+trim_directory(char *path)
+{
+ char *p;
+
+ path = skip_drive(path);
+
+ if (path[0] == '\0')
+ return;
+
+ /* back up over trailing slash(es) */
+ for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--)
+ ;
+ /* back up over directory name */
+ for (; !IS_DIR_SEP(*p) && p > path; p--)
+ ;
+ /* if multiple slashes before directory name, remove 'em all */
+ for (; p > path && IS_DIR_SEP(*(p - 1)); p--)
+ ;
+ /* don't erase a leading slash */
+ if (p == path && IS_DIR_SEP(*p))
+ p++;
+ *p = '\0';
+}
+
+
+/*
+ * trim_trailing_separator
+ *
+ * trim off trailing slashes, but not a leading slash
+ */
+void
+trim_trailing_separator(char *path)
+{
+ char *p;
+
+ path = skip_drive(path);
+ p = path + strlen(path);
+ if (p > path)
+ for (p--; p > path && IS_DIR_SEP(*p); p--)
+ *p = '\0';
+}
pgsql-hackers by date: