2003-11-12 00:52:45 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* path.c
|
|
|
|
* portable path handling routines
|
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2003-11-12 00:52:45 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/port/path.c
|
2003-11-12 00:52:45 +01:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2003-04-04 22:42:13 +02:00
|
|
|
|
2014-04-05 00:42:13 +02:00
|
|
|
#ifndef FRONTEND
|
|
|
|
#include "postgres.h"
|
|
|
|
#else
|
|
|
|
#include "postgres_fe.h"
|
|
|
|
#endif
|
2004-05-21 22:56:50 +02:00
|
|
|
|
2003-04-04 22:42:13 +02:00
|
|
|
#include <ctype.h>
|
2005-01-06 02:00:12 +01:00
|
|
|
#include <sys/stat.h>
|
2005-01-06 19:29:11 +01:00
|
|
|
#ifdef WIN32
|
2005-01-10 01:19:51 +01:00
|
|
|
#ifdef _WIN32_IE
|
|
|
|
#undef _WIN32_IE
|
|
|
|
#endif
|
2005-01-26 20:24:03 +01:00
|
|
|
#define _WIN32_IE 0x0500
|
2005-01-10 01:19:51 +01:00
|
|
|
#ifdef near
|
|
|
|
#undef near
|
|
|
|
#endif
|
|
|
|
#define near
|
2005-01-06 19:29:11 +01:00
|
|
|
#include <shlobj.h>
|
|
|
|
#else
|
2005-01-06 02:00:12 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2003-04-04 22:42:13 +02:00
|
|
|
|
2004-05-21 22:56:50 +02:00
|
|
|
#include "pg_config_paths.h"
|
|
|
|
|
|
|
|
|
2004-06-11 00:26:24 +02:00
|
|
|
#ifndef WIN32
|
2011-02-03 04:28:14 +01:00
|
|
|
#define IS_PATH_VAR_SEP(ch) ((ch) == ':')
|
2004-06-11 00:26:24 +02:00
|
|
|
#else
|
2011-02-03 04:28:14 +01:00
|
|
|
#define IS_PATH_VAR_SEP(ch) ((ch) == ';')
|
2004-05-17 16:35:34 +02:00
|
|
|
#endif
|
|
|
|
|
2004-11-06 22:39:45 +01:00
|
|
|
static void make_relative_path(char *ret_path, const char *target_path,
|
|
|
|
const char *bin_path, const char *my_exec_path);
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
static char *trim_directory(char *path);
|
2004-05-17 16:35:34 +02:00
|
|
|
static void trim_trailing_separator(char *path);
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
static char *append_subdir_to_path(char *path, char *subdir);
|
2004-05-17 16:35:34 +02:00
|
|
|
|
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
/*
|
|
|
|
* 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++;
|
|
|
|
}
|
2006-09-22 23:39:58 +02:00
|
|
|
else if (isalpha((unsigned char) path[0]) && path[1] == ':')
|
2004-11-06 02:16:22 +01:00
|
|
|
{
|
|
|
|
path += 2;
|
|
|
|
}
|
|
|
|
return (char *) path;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
|
|
#define skip_drive(path) (path)
|
|
|
|
#endif
|
|
|
|
|
2011-07-06 17:45:13 +02:00
|
|
|
/*
|
|
|
|
* has_drive_prefix
|
|
|
|
*
|
|
|
|
* Return true if the given pathname has a drive prefix.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
has_drive_prefix(const char *path)
|
|
|
|
{
|
2016-02-20 05:07:46 +01:00
|
|
|
#ifdef WIN32
|
2011-07-06 17:45:13 +02:00
|
|
|
return skip_drive(path) != path;
|
2016-02-20 05:07:46 +01:00
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
2011-07-06 17:45:13 +02:00
|
|
|
}
|
|
|
|
|
2004-06-11 00:26:24 +02:00
|
|
|
/*
|
|
|
|
* first_dir_separator
|
2004-11-06 02:16:22 +01:00
|
|
|
*
|
|
|
|
* Find the location of the first directory separator, return
|
|
|
|
* NULL if not found.
|
2004-06-11 00:26:24 +02:00
|
|
|
*/
|
|
|
|
char *
|
|
|
|
first_dir_separator(const char *filename)
|
|
|
|
{
|
2004-11-06 02:16:22 +01:00
|
|
|
const char *p;
|
2004-06-11 00:26:24 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
for (p = skip_drive(filename); *p; p++)
|
2004-06-11 00:26:24 +02:00
|
|
|
if (IS_DIR_SEP(*p))
|
2019-01-29 01:16:24 +01:00
|
|
|
return unconstify(char *, p);
|
2004-06-11 00:26:24 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-04-04 22:42:13 +02:00
|
|
|
/*
|
2011-02-03 04:49:54 +01:00
|
|
|
* first_path_var_separator
|
2004-11-06 02:16:22 +01:00
|
|
|
*
|
|
|
|
* Find the location of the first path separator (i.e. ':' on
|
|
|
|
* Unix, ';' on Windows), return NULL if not found.
|
2003-04-04 22:42:13 +02:00
|
|
|
*/
|
|
|
|
char *
|
2011-02-03 04:49:54 +01:00
|
|
|
first_path_var_separator(const char *pathlist)
|
2003-04-04 22:42:13 +02:00
|
|
|
{
|
2004-11-06 02:16:22 +01:00
|
|
|
const char *p;
|
2004-05-17 16:35:34 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
/* skip_drive is not needed */
|
|
|
|
for (p = pathlist; *p; p++)
|
2011-02-03 04:28:14 +01:00
|
|
|
if (IS_PATH_VAR_SEP(*p))
|
2019-01-29 01:16:24 +01:00
|
|
|
return unconstify(char *, p);
|
2004-05-17 16:35:34 +02:00
|
|
|
return NULL;
|
2003-04-04 22:42:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-06-11 00:26:24 +02:00
|
|
|
* last_dir_separator
|
2004-11-06 02:16:22 +01:00
|
|
|
*
|
|
|
|
* Find the location of the last directory separator, return
|
|
|
|
* NULL if not found.
|
2003-04-04 22:42:13 +02:00
|
|
|
*/
|
|
|
|
char *
|
2004-06-11 00:26:24 +02:00
|
|
|
last_dir_separator(const char *filename)
|
2003-04-04 22:42:13 +02:00
|
|
|
{
|
2004-11-06 02:16:22 +01:00
|
|
|
const char *p,
|
2004-05-17 16:35:34 +02:00
|
|
|
*ret = NULL;
|
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
for (p = skip_drive(filename); *p; p++)
|
2004-06-11 00:26:24 +02:00
|
|
|
if (IS_DIR_SEP(*p))
|
2004-05-17 16:35:34 +02:00
|
|
|
ret = p;
|
2019-01-29 01:16:24 +01:00
|
|
|
return unconstify(char *, ret);
|
2003-04-04 22:42:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-12 20:32:52 +02:00
|
|
|
/*
|
2004-08-12 21:03:44 +02:00
|
|
|
* make_native_path - on WIN32, change / to \ in the path
|
|
|
|
*
|
2004-11-06 02:16:22 +01:00
|
|
|
* This effectively undoes canonicalize_path.
|
|
|
|
*
|
2004-08-12 21:03:44 +02:00
|
|
|
* This is required because WIN32 COPY is an internal CMD.EXE
|
|
|
|
* command and doesn't process forward slashes in the same way
|
|
|
|
* as external commands. Quoting the first argument to COPY
|
|
|
|
* does not convert forward to backward slashes, but COPY does
|
|
|
|
* properly process quoted forward slashes in the second argument.
|
|
|
|
*
|
|
|
|
* COPY works with quoted forward slashes in the first argument
|
|
|
|
* only if the current directory is the same as the directory
|
|
|
|
* of the first argument.
|
2004-08-12 20:32:52 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
make_native_path(char *filename)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
char *p;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-08-12 20:32:52 +02:00
|
|
|
for (p = filename; *p; p++)
|
|
|
|
if (*p == '/')
|
|
|
|
*p = '\\';
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-17 18:12:06 +01:00
|
|
|
/*
|
|
|
|
* This function cleans up the paths for use with either cmd.exe or Msys
|
|
|
|
* on Windows. We need them to use filenames without spaces, for which a
|
|
|
|
* short filename is the safest equivalent, eg:
|
|
|
|
* C:/Progra~1/
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
cleanup_path(char *path)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GetShortPathName() will fail if the path does not exist, or short names
|
|
|
|
* are disabled on this file system. In both cases, we just return the
|
|
|
|
* original path. This is particularly useful for --sysconfdir, which
|
|
|
|
* might not exist.
|
|
|
|
*/
|
|
|
|
GetShortPathName(path, path, MAXPGPATH - 1);
|
|
|
|
|
|
|
|
/* Replace '\' with '/' */
|
|
|
|
for (ptr = path; *ptr; ptr++)
|
|
|
|
{
|
|
|
|
if (*ptr == '\\')
|
|
|
|
*ptr = '/';
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
/*
|
|
|
|
* join_path_components - join two path components, inserting a slash
|
|
|
|
*
|
2012-07-05 23:15:05 +02:00
|
|
|
* We omit the slash if either given component is empty.
|
|
|
|
*
|
2004-11-06 02:16:22 +01:00
|
|
|
* ret_path is the output area (must be of size MAXPGPATH)
|
|
|
|
*
|
|
|
|
* ret_path can be the same as head, but not the same as tail.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
join_path_components(char *ret_path,
|
|
|
|
const char *head, const char *tail)
|
|
|
|
{
|
|
|
|
if (ret_path != head)
|
2006-09-27 20:40:10 +02:00
|
|
|
strlcpy(ret_path, head, MAXPGPATH);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
/*
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
* We used to try to simplify some cases involving "." and "..", but now
|
|
|
|
* we just leave that to be done by canonicalize_path() later.
|
2004-11-06 02:16:22 +01:00
|
|
|
*/
|
2012-07-05 23:15:05 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
if (*tail)
|
2012-07-05 23:15:05 +02:00
|
|
|
{
|
|
|
|
/* only separate with slash if head wasn't empty */
|
2004-11-06 02:16:22 +01:00
|
|
|
snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path),
|
2012-07-05 23:15:05 +02:00
|
|
|
"%s%s",
|
|
|
|
(*(skip_drive(head)) != '\0') ? "/" : "",
|
|
|
|
tail);
|
|
|
|
}
|
2004-11-06 02:16:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
/* State-machine states for canonicalize_path */
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
ABSOLUTE_PATH_INIT, /* Just past the leading '/' (and Windows
|
|
|
|
* drive name if any) of an absolute path */
|
|
|
|
ABSOLUTE_WITH_N_DEPTH, /* We collected 'pathdepth' directories in an
|
|
|
|
* absolute path */
|
|
|
|
RELATIVE_PATH_INIT, /* At start of a relative path */
|
|
|
|
RELATIVE_WITH_N_DEPTH, /* We collected 'pathdepth' directories in a
|
|
|
|
* relative path */
|
|
|
|
RELATIVE_WITH_PARENT_REF /* Relative path containing only double-dots */
|
|
|
|
} canonicalize_state;
|
|
|
|
|
2004-03-09 05:49:02 +01:00
|
|
|
/*
|
2004-10-27 19:17:09 +02:00
|
|
|
* Clean up path by:
|
|
|
|
* o make Win32 path use Unix slashes
|
2004-11-06 02:16:22 +01:00
|
|
|
* o remove trailing quote on Win32
|
|
|
|
* o remove trailing slash
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
* o remove duplicate (adjacent) separators
|
|
|
|
* o remove '.' (unless path reduces to only '.')
|
|
|
|
* o process '..' ourselves, removing it if possible
|
2004-03-09 05:49:02 +01:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
canonicalize_path(char *path)
|
|
|
|
{
|
2004-11-07 03:12:17 +01:00
|
|
|
char *p,
|
|
|
|
*to_p;
|
2005-08-12 23:07:53 +02:00
|
|
|
char *spath;
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
char *parsed;
|
|
|
|
char *unparse;
|
2004-11-07 03:12:17 +01:00
|
|
|
bool was_sep = false;
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
canonicalize_state state;
|
|
|
|
int pathdepth = 0; /* counts collected regular directory names */
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-11-07 03:12:17 +01:00
|
|
|
#ifdef WIN32
|
2014-05-06 18:12:18 +02:00
|
|
|
|
2004-07-12 21:15:14 +02:00
|
|
|
/*
|
|
|
|
* The Windows command processor will accept suitably quoted paths with
|
|
|
|
* forward slashes, but barfs badly with mixed forward and back slashes.
|
|
|
|
*/
|
2004-03-09 05:49:02 +01:00
|
|
|
for (p = path; *p; p++)
|
|
|
|
{
|
|
|
|
if (*p == '\\')
|
|
|
|
*p = '/';
|
|
|
|
}
|
2004-07-12 21:27:31 +02:00
|
|
|
|
2004-07-12 21:15:14 +02:00
|
|
|
/*
|
|
|
|
* In Win32, if you do: prog.exe "a b" "\c\d\" the system will pass \c\d"
|
2004-11-07 03:12:17 +01:00
|
|
|
* as argv[2], so trim off trailing quote.
|
2004-07-12 21:15:14 +02:00
|
|
|
*/
|
|
|
|
if (p > path && *(p - 1) == '"')
|
|
|
|
*(p - 1) = '/';
|
2004-05-17 16:35:34 +02:00
|
|
|
#endif
|
|
|
|
|
2004-07-12 21:15:14 +02:00
|
|
|
/*
|
2004-08-09 22:20:47 +02:00
|
|
|
* Removing the trailing slash on a path means we never get ugly double
|
2004-10-27 19:17:09 +02:00
|
|
|
* trailing slashes. Also, Win32 can't stat() a directory with a trailing
|
|
|
|
* slash. Don't remove a leading slash, though.
|
2004-07-12 21:15:14 +02:00
|
|
|
*/
|
2004-05-17 16:35:34 +02:00
|
|
|
trim_trailing_separator(path);
|
2004-08-09 22:20:47 +02:00
|
|
|
|
2004-11-07 03:12:17 +01:00
|
|
|
/*
|
|
|
|
* 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';
|
|
|
|
|
2004-08-09 22:20:47 +02:00
|
|
|
/*
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
* Remove any uses of "." and process ".." ourselves
|
2005-08-12 23:07:53 +02:00
|
|
|
*
|
|
|
|
* Note that "/../.." should reduce to just "/", while "../.." has to be
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
* kept as-is. 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.
|
|
|
|
*
|
|
|
|
* This loop overwrites the path in-place. This is safe since we'll never
|
|
|
|
* make the path longer. "unparse" points to where we are reading the
|
|
|
|
* path, "parse" to where we are writing.
|
2004-08-09 22:20:47 +02:00
|
|
|
*/
|
2005-08-12 23:07:53 +02:00
|
|
|
spath = skip_drive(path);
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
if (*spath == '\0')
|
|
|
|
return; /* empty path is returned as-is */
|
|
|
|
|
|
|
|
if (*spath == '/')
|
2004-08-09 22:20:47 +02:00
|
|
|
{
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
state = ABSOLUTE_PATH_INIT;
|
|
|
|
/* Skip the leading slash for absolute path */
|
|
|
|
parsed = unparse = (spath + 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
state = RELATIVE_PATH_INIT;
|
|
|
|
parsed = unparse = spath;
|
|
|
|
}
|
2004-08-09 22:20:47 +02:00
|
|
|
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
while (*unparse != '\0')
|
|
|
|
{
|
|
|
|
char *unparse_next;
|
|
|
|
bool is_double_dot;
|
|
|
|
|
|
|
|
/* Split off this dir name, and set unparse_next to the next one */
|
|
|
|
unparse_next = unparse;
|
|
|
|
while (*unparse_next && *unparse_next != '/')
|
|
|
|
unparse_next++;
|
|
|
|
if (*unparse_next != '\0')
|
|
|
|
*unparse_next++ = '\0';
|
|
|
|
|
|
|
|
/* Identify type of this dir name */
|
|
|
|
if (strcmp(unparse, ".") == 0)
|
2005-08-12 23:07:53 +02:00
|
|
|
{
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
/* We can ignore "." components in all cases */
|
|
|
|
unparse = unparse_next;
|
|
|
|
continue;
|
2005-08-12 23:07:53 +02:00
|
|
|
}
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
|
|
|
|
if (strcmp(unparse, "..") == 0)
|
|
|
|
is_double_dot = true;
|
|
|
|
else
|
2004-08-09 22:20:47 +02:00
|
|
|
{
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
/* adjacent separators were eliminated above */
|
|
|
|
Assert(*unparse != '\0');
|
|
|
|
is_double_dot = false;
|
2005-08-12 23:07:53 +02:00
|
|
|
}
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
|
|
|
|
switch (state)
|
2005-08-12 23:07:53 +02:00
|
|
|
{
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
case ABSOLUTE_PATH_INIT:
|
|
|
|
/* We can ignore ".." immediately after / */
|
|
|
|
if (!is_double_dot)
|
|
|
|
{
|
|
|
|
/* Append first dir name (we already have leading slash) */
|
|
|
|
parsed = append_subdir_to_path(parsed, unparse);
|
|
|
|
state = ABSOLUTE_WITH_N_DEPTH;
|
|
|
|
pathdepth++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ABSOLUTE_WITH_N_DEPTH:
|
|
|
|
if (is_double_dot)
|
|
|
|
{
|
|
|
|
/* Remove last parsed dir */
|
|
|
|
/* (trim_directory won't remove the leading slash) */
|
|
|
|
*parsed = '\0';
|
|
|
|
parsed = trim_directory(path);
|
|
|
|
if (--pathdepth == 0)
|
|
|
|
state = ABSOLUTE_PATH_INIT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Append normal dir */
|
|
|
|
*parsed++ = '/';
|
|
|
|
parsed = append_subdir_to_path(parsed, unparse);
|
|
|
|
pathdepth++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RELATIVE_PATH_INIT:
|
|
|
|
if (is_double_dot)
|
|
|
|
{
|
|
|
|
/* Append irreducible double-dot (..) */
|
|
|
|
parsed = append_subdir_to_path(parsed, unparse);
|
|
|
|
state = RELATIVE_WITH_PARENT_REF;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Append normal dir */
|
|
|
|
parsed = append_subdir_to_path(parsed, unparse);
|
|
|
|
state = RELATIVE_WITH_N_DEPTH;
|
|
|
|
pathdepth++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RELATIVE_WITH_N_DEPTH:
|
|
|
|
if (is_double_dot)
|
|
|
|
{
|
|
|
|
/* Remove last parsed dir */
|
|
|
|
*parsed = '\0';
|
|
|
|
parsed = trim_directory(path);
|
|
|
|
if (--pathdepth == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the output path is now empty, we're back to the
|
|
|
|
* INIT state. However, we could have processed a
|
|
|
|
* path like "../dir/.." and now be down to "..", in
|
|
|
|
* which case enter the correct state for that.
|
|
|
|
*/
|
|
|
|
if (parsed == spath)
|
|
|
|
state = RELATIVE_PATH_INIT;
|
|
|
|
else
|
|
|
|
state = RELATIVE_WITH_PARENT_REF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Append normal dir */
|
|
|
|
*parsed++ = '/';
|
|
|
|
parsed = append_subdir_to_path(parsed, unparse);
|
|
|
|
pathdepth++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RELATIVE_WITH_PARENT_REF:
|
|
|
|
if (is_double_dot)
|
|
|
|
{
|
|
|
|
/* Append next irreducible double-dot (..) */
|
|
|
|
*parsed++ = '/';
|
|
|
|
parsed = append_subdir_to_path(parsed, unparse);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Append normal dir */
|
|
|
|
*parsed++ = '/';
|
|
|
|
parsed = append_subdir_to_path(parsed, unparse);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can now start counting normal dirs. But if later
|
|
|
|
* double-dots make us remove this dir again, we'd better
|
|
|
|
* revert to RELATIVE_WITH_PARENT_REF not INIT state.
|
|
|
|
*/
|
|
|
|
state = RELATIVE_WITH_N_DEPTH;
|
|
|
|
pathdepth = 1;
|
|
|
|
}
|
|
|
|
break;
|
2004-08-09 22:20:47 +02:00
|
|
|
}
|
2005-08-12 23:07:53 +02:00
|
|
|
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
unparse = unparse_next;
|
2005-08-12 23:07:53 +02:00
|
|
|
}
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If our output path is empty at this point, insert ".". We don't want
|
|
|
|
* to do this any earlier because it'd result in an extra dot in corner
|
|
|
|
* cases such as "../dir/..". Since we rejected the wholly-empty-path
|
|
|
|
* case above, there is certainly room.
|
|
|
|
*/
|
|
|
|
if (parsed == spath)
|
|
|
|
*parsed++ = '.';
|
|
|
|
|
|
|
|
/* And finally, ensure the output path is nul-terminated. */
|
|
|
|
*parsed = '\0';
|
2005-08-12 23:07:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Detect whether a path contains any parent-directory references ("..")
|
|
|
|
*
|
|
|
|
* The input *must* have been put through canonicalize_path previously.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
path_contains_parent_reference(const char *path)
|
|
|
|
{
|
|
|
|
/*
|
2022-01-31 19:53:38 +01:00
|
|
|
* Once canonicalized, an absolute path cannot contain any ".." at all,
|
|
|
|
* while a relative path could contain ".."(s) only at the start. So it
|
|
|
|
* is sufficient to check the start of the path, after skipping any
|
|
|
|
* Windows drive/network specifier.
|
2005-08-12 23:07:53 +02:00
|
|
|
*/
|
2022-01-31 19:53:38 +01:00
|
|
|
path = skip_drive(path); /* C: shouldn't affect our conclusion */
|
|
|
|
|
|
|
|
if (path[0] == '.' &&
|
|
|
|
path[1] == '.' &&
|
|
|
|
(path[2] == '\0' || path[2] == '/'))
|
2005-08-12 23:07:53 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
2004-03-09 05:49:02 +01:00
|
|
|
}
|
|
|
|
|
2011-02-12 15:47:51 +01:00
|
|
|
/*
|
|
|
|
* Detect whether a path is only in or below the current working directory.
|
2022-01-31 19:53:38 +01:00
|
|
|
*
|
|
|
|
* The input *must* have been put through canonicalize_path previously.
|
|
|
|
*
|
2011-02-12 15:47:51 +01:00
|
|
|
* An absolute path that matches the current working directory should
|
2022-01-31 19:53:38 +01:00
|
|
|
* return false (we only want relative to the cwd).
|
2011-02-12 15:47:51 +01:00
|
|
|
*/
|
|
|
|
bool
|
|
|
|
path_is_relative_and_below_cwd(const char *path)
|
|
|
|
{
|
2011-02-13 06:14:08 +01:00
|
|
|
if (is_absolute_path(path))
|
2011-02-12 15:47:51 +01:00
|
|
|
return false;
|
|
|
|
/* don't allow anything above the cwd */
|
|
|
|
else if (path_contains_parent_reference(path))
|
|
|
|
return false;
|
|
|
|
#ifdef WIN32
|
2014-05-06 18:12:18 +02:00
|
|
|
|
2011-02-12 15:47:51 +01:00
|
|
|
/*
|
|
|
|
* On Win32, a drive letter _not_ followed by a slash, e.g. 'E:abc', is
|
|
|
|
* relative to the cwd on that drive, or the drive's root directory if
|
|
|
|
* that drive has no cwd. Because the path itself cannot tell us which is
|
|
|
|
* the case, we have to assume the worst, i.e. that it is not below the
|
|
|
|
* cwd. We could use GetFullPathName() to find the full path but that
|
|
|
|
* could change if the current directory for the drive changes underneath
|
|
|
|
* us, so we just disallow it.
|
|
|
|
*/
|
|
|
|
else if (isalpha((unsigned char) path[0]) && path[1] == ':' &&
|
|
|
|
!IS_DIR_SEP(path[2]))
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-08-29 21:39:39 +02:00
|
|
|
/*
|
|
|
|
* Detect whether path1 is a prefix of path2 (including equality).
|
|
|
|
*
|
|
|
|
* This is pretty trivial, but it seems better to export a function than
|
|
|
|
* to export IS_DIR_SEP.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
path_is_prefix_of_path(const char *path1, const char *path2)
|
|
|
|
{
|
|
|
|
int path1_len = strlen(path1);
|
|
|
|
|
|
|
|
if (strncmp(path1, path2, path1_len) == 0 &&
|
|
|
|
(IS_DIR_SEP(path2[path1_len]) || path2[path1_len] == '\0'))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2004-03-09 05:49:02 +01:00
|
|
|
|
2003-04-04 22:42:13 +02:00
|
|
|
/*
|
2005-08-12 21:43:32 +02:00
|
|
|
* Extracts the actual name of the program as called -
|
|
|
|
* stripped of .exe suffix if any
|
2003-04-04 22:42:13 +02:00
|
|
|
*/
|
2004-05-12 15:38:49 +02:00
|
|
|
const char *
|
|
|
|
get_progname(const char *argv0)
|
2003-04-04 22:42:13 +02:00
|
|
|
{
|
2006-02-01 01:31:59 +01:00
|
|
|
const char *nodir_name;
|
2006-02-01 13:41:45 +01:00
|
|
|
char *progname;
|
2004-10-25 00:08:19 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
nodir_name = last_dir_separator(argv0);
|
|
|
|
if (nodir_name)
|
|
|
|
nodir_name++;
|
2003-04-04 22:42:13 +02:00
|
|
|
else
|
2004-11-06 02:16:22 +01:00
|
|
|
nodir_name = skip_drive(argv0);
|
2004-10-25 00:08:19 +02:00
|
|
|
|
2006-02-01 01:31:59 +01:00
|
|
|
/*
|
|
|
|
* Make a copy in case argv[0] is modified by ps_status. Leaks memory, but
|
|
|
|
* called only once.
|
|
|
|
*/
|
|
|
|
progname = strdup(nodir_name);
|
|
|
|
if (progname == NULL)
|
2004-10-25 00:08:19 +02:00
|
|
|
{
|
2006-02-01 01:31:59 +01:00
|
|
|
fprintf(stderr, "%s: out of memory\n", nodir_name);
|
2012-01-30 20:34:00 +01:00
|
|
|
abort(); /* This could exit the postmaster */
|
2006-02-01 01:31:59 +01:00
|
|
|
}
|
2004-10-25 00:08:19 +02:00
|
|
|
|
2006-02-01 01:31:59 +01:00
|
|
|
#if defined(__CYGWIN__) || defined(WIN32)
|
|
|
|
/* strip ".exe" suffix, regardless of case */
|
|
|
|
if (strlen(progname) > sizeof(EXE) - 1 &&
|
|
|
|
pg_strcasecmp(progname + strlen(progname) - (sizeof(EXE) - 1), EXE) == 0)
|
2004-11-06 05:24:14 +01:00
|
|
|
progname[strlen(progname) - (sizeof(EXE) - 1)] = '\0';
|
2004-10-25 00:08:19 +02:00
|
|
|
#endif
|
|
|
|
|
2006-02-01 01:31:59 +01:00
|
|
|
return progname;
|
2003-04-04 22:42:13 +02:00
|
|
|
}
|
2004-05-11 23:57:15 +02:00
|
|
|
|
2004-05-17 16:35:34 +02:00
|
|
|
|
2005-12-23 23:34:22 +01:00
|
|
|
/*
|
2009-04-04 01:27:17 +02:00
|
|
|
* dir_strcmp: strcmp except any two DIR_SEP characters are considered equal,
|
|
|
|
* and we honor filesystem case insensitivity if known
|
2005-12-23 23:34:22 +01:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
dir_strcmp(const char *s1, const char *s2)
|
|
|
|
{
|
|
|
|
while (*s1 && *s2)
|
|
|
|
{
|
2009-04-04 01:27:17 +02:00
|
|
|
if (
|
2009-04-03 13:52:08 +02:00
|
|
|
#ifndef WIN32
|
2009-04-04 01:27:17 +02:00
|
|
|
*s1 != *s2
|
2009-04-03 13:52:08 +02:00
|
|
|
#else
|
|
|
|
/* On windows, paths are case-insensitive */
|
2009-04-04 01:27:17 +02:00
|
|
|
pg_tolower((unsigned char) *s1) != pg_tolower((unsigned char) *s2)
|
2009-04-03 13:52:08 +02:00
|
|
|
#endif
|
2009-04-04 01:27:17 +02:00
|
|
|
&& !(IS_DIR_SEP(*s1) && IS_DIR_SEP(*s2)))
|
2005-12-23 23:34:22 +01:00
|
|
|
return (int) *s1 - (int) *s2;
|
|
|
|
s1++, s2++;
|
|
|
|
}
|
|
|
|
if (*s1)
|
|
|
|
return 1; /* s1 longer */
|
|
|
|
if (*s2)
|
|
|
|
return -1; /* s2 longer */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-17 16:35:34 +02:00
|
|
|
/*
|
2004-11-06 22:39:45 +01:00
|
|
|
* make_relative_path - make a path relative to the actual binary location
|
|
|
|
*
|
|
|
|
* This function exists to support relocation of installation trees.
|
|
|
|
*
|
|
|
|
* ret_path is the output area (must be of size MAXPGPATH)
|
|
|
|
* target_path is the compiled-in path to the directory we want to find
|
|
|
|
* bin_path is the compiled-in path to the directory of executables
|
|
|
|
* my_exec_path is the actual location of my executable
|
|
|
|
*
|
2005-12-23 23:34:22 +01:00
|
|
|
* We determine the common prefix of target_path and bin_path, then compare
|
|
|
|
* the remainder of bin_path to the last directory component(s) of
|
|
|
|
* my_exec_path. If they match, build the result as the part of my_exec_path
|
|
|
|
* preceding the match, joined to the remainder of target_path. If no match,
|
|
|
|
* return target_path as-is.
|
2004-11-06 22:39:45 +01:00
|
|
|
*
|
|
|
|
* For example:
|
|
|
|
* target_path = '/usr/local/share/postgresql'
|
|
|
|
* bin_path = '/usr/local/bin'
|
2023-01-26 10:48:32 +01:00
|
|
|
* my_exec_path = '/opt/pgsql/bin/postgres'
|
2005-12-23 23:34:22 +01:00
|
|
|
* Given these inputs, the common prefix is '/usr/local/', the tail of
|
|
|
|
* bin_path is 'bin' which does match the last directory component of
|
|
|
|
* my_exec_path, so we would return '/opt/pgsql/share/postgresql'
|
2004-05-17 16:35:34 +02:00
|
|
|
*/
|
2004-11-06 22:39:45 +01:00
|
|
|
static void
|
|
|
|
make_relative_path(char *ret_path, const char *target_path,
|
|
|
|
const char *bin_path, const char *my_exec_path)
|
2004-05-17 16:35:34 +02:00
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
int prefix_len;
|
2005-12-23 23:34:22 +01:00
|
|
|
int tail_start;
|
|
|
|
int tail_len;
|
|
|
|
int i;
|
2004-11-06 22:39:45 +01:00
|
|
|
|
2005-12-23 23:34:22 +01:00
|
|
|
/*
|
|
|
|
* Determine the common prefix --- note we require it to end on a
|
|
|
|
* directory separator, consider eg '/usr/lib' and '/usr/libexec'.
|
|
|
|
*/
|
|
|
|
prefix_len = 0;
|
|
|
|
for (i = 0; target_path[i] && bin_path[i]; i++)
|
|
|
|
{
|
|
|
|
if (IS_DIR_SEP(target_path[i]) && IS_DIR_SEP(bin_path[i]))
|
|
|
|
prefix_len = i + 1;
|
|
|
|
else if (target_path[i] != bin_path[i])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (prefix_len == 0)
|
|
|
|
goto no_match; /* no common prefix? */
|
|
|
|
tail_len = strlen(bin_path) - prefix_len;
|
2004-11-06 22:39:45 +01:00
|
|
|
|
2005-12-23 23:34:22 +01:00
|
|
|
/*
|
|
|
|
* Set up my_exec_path without the actual executable name, and
|
|
|
|
* canonicalize to simplify comparison to bin_path.
|
|
|
|
*/
|
2006-09-27 20:40:10 +02:00
|
|
|
strlcpy(ret_path, my_exec_path, MAXPGPATH);
|
2004-11-06 22:39:45 +01:00
|
|
|
trim_directory(ret_path); /* remove my executable name */
|
|
|
|
canonicalize_path(ret_path);
|
2005-12-23 23:34:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Tail match?
|
|
|
|
*/
|
|
|
|
tail_start = (int) strlen(ret_path) - tail_len;
|
|
|
|
if (tail_start > 0 &&
|
|
|
|
IS_DIR_SEP(ret_path[tail_start - 1]) &&
|
|
|
|
dir_strcmp(ret_path + tail_start, bin_path + prefix_len) == 0)
|
|
|
|
{
|
|
|
|
ret_path[tail_start] = '\0';
|
|
|
|
trim_trailing_separator(ret_path);
|
|
|
|
join_path_components(ret_path, ret_path, target_path + prefix_len);
|
|
|
|
canonicalize_path(ret_path);
|
|
|
|
return;
|
|
|
|
}
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-11-06 22:39:45 +01:00
|
|
|
no_match:
|
2006-09-27 20:40:10 +02:00
|
|
|
strlcpy(ret_path, target_path, MAXPGPATH);
|
2004-07-11 23:34:04 +02:00
|
|
|
canonicalize_path(ret_path);
|
2004-05-17 16:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-05 00:42:13 +02:00
|
|
|
/*
|
|
|
|
* make_absolute_path
|
|
|
|
*
|
|
|
|
* If the given pathname isn't already absolute, make it so, interpreting
|
|
|
|
* it relative to the current working directory.
|
|
|
|
*
|
|
|
|
* Also canonicalizes the path. The result is always a malloc'd copy.
|
|
|
|
*
|
|
|
|
* In backend, failure cases result in ereport(ERROR); in frontend,
|
|
|
|
* we write a complaint on stderr and return NULL.
|
|
|
|
*
|
|
|
|
* Note: interpretation of relative-path arguments during postmaster startup
|
|
|
|
* should happen before doing ChangeToDataDir(), else the user will probably
|
|
|
|
* not like the results.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
make_absolute_path(const char *path)
|
|
|
|
{
|
|
|
|
char *new;
|
|
|
|
|
|
|
|
/* Returning null for null input is convenient for some callers */
|
|
|
|
if (path == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!is_absolute_path(path))
|
|
|
|
{
|
|
|
|
char *buf;
|
|
|
|
size_t buflen;
|
|
|
|
|
|
|
|
buflen = MAXPGPATH;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
buf = malloc(buflen);
|
|
|
|
if (!buf)
|
|
|
|
{
|
|
|
|
#ifndef FRONTEND
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
|
|
|
errmsg("out of memory")));
|
|
|
|
#else
|
|
|
|
fprintf(stderr, _("out of memory\n"));
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getcwd(buf, buflen))
|
|
|
|
break;
|
|
|
|
else if (errno == ERANGE)
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
buflen *= 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-04-05 01:07:37 +02:00
|
|
|
int save_errno = errno;
|
|
|
|
|
2014-04-05 00:42:13 +02:00
|
|
|
free(buf);
|
2014-04-05 01:07:37 +02:00
|
|
|
errno = save_errno;
|
2014-04-05 00:42:13 +02:00
|
|
|
#ifndef FRONTEND
|
|
|
|
elog(ERROR, "could not get current working directory: %m");
|
|
|
|
#else
|
|
|
|
fprintf(stderr, _("could not get current working directory: %s\n"),
|
|
|
|
strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
new = malloc(strlen(buf) + strlen(path) + 2);
|
|
|
|
if (!new)
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
#ifndef FRONTEND
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
|
|
|
errmsg("out of memory")));
|
|
|
|
#else
|
|
|
|
fprintf(stderr, _("out of memory\n"));
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
sprintf(new, "%s/%s", buf, path);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new = strdup(path);
|
|
|
|
if (!new)
|
|
|
|
{
|
|
|
|
#ifndef FRONTEND
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
|
|
|
errmsg("out of memory")));
|
|
|
|
#else
|
|
|
|
fprintf(stderr, _("out of memory\n"));
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure punctuation is canonical, too */
|
|
|
|
canonicalize_path(new);
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-11-06 22:39:45 +01:00
|
|
|
/*
|
|
|
|
* get_share_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_share_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
|
|
|
make_relative_path(ret_path, PGSHAREDIR, PGBINDIR, my_exec_path);
|
|
|
|
}
|
|
|
|
|
2004-05-17 16:35:34 +02:00
|
|
|
/*
|
|
|
|
* get_etc_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_etc_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
make_relative_path(ret_path, SYSCONFDIR, PGBINDIR, my_exec_path);
|
2004-05-17 16:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_include_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_include_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
make_relative_path(ret_path, INCLUDEDIR, PGBINDIR, my_exec_path);
|
2004-05-17 16:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_pkginclude_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_pkginclude_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
make_relative_path(ret_path, PKGINCLUDEDIR, PGBINDIR, my_exec_path);
|
2004-05-17 16:35:34 +02:00
|
|
|
}
|
|
|
|
|
2004-08-01 08:56:39 +02:00
|
|
|
/*
|
|
|
|
* get_includeserver_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_includeserver_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
make_relative_path(ret_path, INCLUDEDIRSERVER, PGBINDIR, my_exec_path);
|
2004-08-01 08:56:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_lib_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_lib_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
make_relative_path(ret_path, LIBDIR, PGBINDIR, my_exec_path);
|
2004-08-01 08:56:39 +02:00
|
|
|
}
|
|
|
|
|
2004-05-17 16:35:34 +02:00
|
|
|
/*
|
|
|
|
* get_pkglib_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_pkglib_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
make_relative_path(ret_path, PKGLIBDIR, PGBINDIR, my_exec_path);
|
2004-05-17 16:35:34 +02:00
|
|
|
}
|
|
|
|
|
2004-05-25 03:00:30 +02:00
|
|
|
/*
|
|
|
|
* get_locale_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_locale_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
2004-11-06 22:39:45 +01:00
|
|
|
make_relative_path(ret_path, LOCALEDIR, PGBINDIR, my_exec_path);
|
2004-05-25 03:00:30 +02:00
|
|
|
}
|
|
|
|
|
2005-09-27 19:39:35 +02:00
|
|
|
/*
|
|
|
|
* get_doc_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_doc_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
|
|
|
make_relative_path(ret_path, DOCDIR, PGBINDIR, my_exec_path);
|
|
|
|
}
|
|
|
|
|
2008-02-18 15:51:48 +01:00
|
|
|
/*
|
|
|
|
* get_html_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_html_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
|
|
|
make_relative_path(ret_path, HTMLDIR, PGBINDIR, my_exec_path);
|
|
|
|
}
|
|
|
|
|
2005-09-27 19:39:35 +02:00
|
|
|
/*
|
|
|
|
* get_man_path
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_man_path(const char *my_exec_path, char *ret_path)
|
|
|
|
{
|
|
|
|
make_relative_path(ret_path, MANDIR, PGBINDIR, my_exec_path);
|
|
|
|
}
|
|
|
|
|
2004-05-25 03:00:30 +02:00
|
|
|
|
2004-08-29 23:08:48 +02:00
|
|
|
/*
|
|
|
|
* get_home_path
|
2005-01-06 19:29:11 +01:00
|
|
|
*
|
|
|
|
* On Unix, this actually returns the user's home directory. On Windows
|
|
|
|
* it returns the PostgreSQL-specific application data folder.
|
2004-08-29 23:08:48 +02:00
|
|
|
*/
|
|
|
|
bool
|
|
|
|
get_home_path(char *ret_path)
|
|
|
|
{
|
2005-01-06 02:00:12 +01:00
|
|
|
#ifndef WIN32
|
2022-01-10 01:19:02 +01:00
|
|
|
/*
|
|
|
|
* We first consult $HOME. If that's unset, try to get the info from
|
|
|
|
* <pwd.h>.
|
|
|
|
*/
|
|
|
|
const char *home;
|
2005-01-06 02:00:12 +01:00
|
|
|
|
2022-01-10 01:19:02 +01:00
|
|
|
home = getenv("HOME");
|
|
|
|
if (home == NULL || home[0] == '\0')
|
2022-01-11 19:46:12 +01:00
|
|
|
return pg_get_user_home_dir(geteuid(), ret_path, MAXPGPATH);
|
2022-01-10 01:19:02 +01:00
|
|
|
strlcpy(ret_path, home, MAXPGPATH);
|
2005-01-06 02:00:12 +01:00
|
|
|
return true;
|
|
|
|
#else
|
2007-10-23 19:58:01 +02:00
|
|
|
char *tmppath;
|
|
|
|
|
|
|
|
/*
|
2014-10-22 04:55:43 +02:00
|
|
|
* Note: We use getenv() here because the more modern SHGetFolderPath()
|
|
|
|
* would force the backend to link with shell32.lib, which eats valuable
|
|
|
|
* desktop heap. XXX This function is used only in psql, which already
|
|
|
|
* brings in shell32 via libpq. Moving this function to its own file
|
|
|
|
* would keep it out of the backend, freeing it from this concern.
|
2007-10-23 19:58:01 +02:00
|
|
|
*/
|
|
|
|
tmppath = getenv("APPDATA");
|
|
|
|
if (!tmppath)
|
2004-08-29 23:08:48 +02:00
|
|
|
return false;
|
2005-01-06 19:29:11 +01:00
|
|
|
snprintf(ret_path, MAXPGPATH, "%s/postgresql", tmppath);
|
2005-01-06 02:00:12 +01:00
|
|
|
return true;
|
|
|
|
#endif
|
2004-08-29 23:08:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_parent_directory
|
|
|
|
*
|
|
|
|
* Modify the given string in-place to name the parent directory of the
|
|
|
|
* named file.
|
2012-07-05 23:15:05 +02:00
|
|
|
*
|
|
|
|
* If the input is just a file name with no directory part, the result is
|
|
|
|
* an empty string, not ".". This is appropriate when the next step is
|
|
|
|
* join_path_components(), but might need special handling otherwise.
|
|
|
|
*
|
|
|
|
* Caution: this will not produce desirable results if the string ends
|
|
|
|
* with "..". For most callers this is not a problem since the string
|
|
|
|
* is already known to name a regular file. If in doubt, apply
|
|
|
|
* canonicalize_path() first.
|
2004-08-29 23:08:48 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_parent_directory(char *path)
|
|
|
|
{
|
|
|
|
trim_directory(path);
|
|
|
|
}
|
|
|
|
|
2004-05-25 03:00:30 +02:00
|
|
|
|
2004-05-17 16:35:34 +02:00
|
|
|
/*
|
|
|
|
* trim_directory
|
|
|
|
*
|
2004-11-06 02:16:22 +01:00
|
|
|
* 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.
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
*
|
|
|
|
* For the convenience of canonicalize_path, the path's new end location
|
|
|
|
* is returned.
|
2004-05-17 16:35:34 +02:00
|
|
|
*/
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
static char *
|
2004-05-17 16:35:34 +02:00
|
|
|
trim_directory(char *path)
|
|
|
|
{
|
|
|
|
char *p;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
path = skip_drive(path);
|
|
|
|
|
2004-05-17 16:35:34 +02:00
|
|
|
if (path[0] == '\0')
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
return path;
|
2004-05-17 16:35:34 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
/* back up over trailing slash(es) */
|
2004-06-11 00:26:24 +02:00
|
|
|
for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--)
|
2004-05-17 16:35:34 +02:00
|
|
|
;
|
2004-11-06 02:16:22 +01:00
|
|
|
/* back up over directory name */
|
2004-06-11 00:26:24 +02:00
|
|
|
for (; !IS_DIR_SEP(*p) && p > path; p--)
|
2004-05-17 16:35:34 +02:00
|
|
|
;
|
2004-11-06 02:16:22 +01:00
|
|
|
/* 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++;
|
2004-05-17 16:35:34 +02:00
|
|
|
*p = '\0';
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
return p;
|
2004-05-17 16:35:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* trim_trailing_separator
|
2004-11-06 02:16:22 +01:00
|
|
|
*
|
|
|
|
* trim off trailing slashes, but not a leading slash
|
2004-05-17 16:35:34 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
trim_trailing_separator(char *path)
|
|
|
|
{
|
2004-11-06 02:16:22 +01:00
|
|
|
char *p;
|
2004-07-11 04:59:42 +02:00
|
|
|
|
2004-11-06 02:16:22 +01:00
|
|
|
path = skip_drive(path);
|
|
|
|
p = path + strlen(path);
|
2004-05-17 16:35:34 +02:00
|
|
|
if (p > path)
|
2004-07-11 00:58:42 +02:00
|
|
|
for (p--; p > path && IS_DIR_SEP(*p); p--)
|
2004-05-17 16:35:34 +02:00
|
|
|
*p = '\0';
|
|
|
|
}
|
Make canonicalize_path() more canonical.
Teach canonicalize_path() how to strip all unnecessary uses of "."
and "..", replacing the previous ad-hoc code that got rid of only
some such cases. In particular, we can always remove all such
uses from absolute paths.
The proximate reason to do this is that Windows rejects paths
involving ".." in some cases (in particular, you can't put one in a
symlink), so we ought to be sure we don't use ".." unnecessarily.
Moreover, it seems like good cleanup on general principles.
There is other path-munging code that could be simplified now, but
we'll leave that for followup work.
It is tempting to call this a bug fix and back-patch it. On the other
hand, the misbehavior can only be reached if a highly privileged user
does something dubious, so it's not unreasonable to say "so don't do
that". And this patch could result in unexpected behavioral changes,
in case anybody was expecting uses of ".." to stay put. So at least
for now, just put it in HEAD.
Shenhao Wang, editorialized a bit by me
Discussion: https://postgr.es/m/OSBPR01MB4214FA221FFE046F11F2AD74F2D49@OSBPR01MB4214.jpnprd01.prod.outlook.com
2022-01-31 18:05:37 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* append_subdir_to_path
|
|
|
|
*
|
|
|
|
* Append the currently-considered subdirectory name to the output
|
|
|
|
* path in canonicalize_path. Return the new end location of the
|
|
|
|
* output path.
|
|
|
|
*
|
|
|
|
* Since canonicalize_path updates the path in-place, we must use
|
|
|
|
* memmove not memcpy, and we don't yet terminate the path with '\0'.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
append_subdir_to_path(char *path, char *subdir)
|
|
|
|
{
|
|
|
|
size_t len = strlen(subdir);
|
|
|
|
|
|
|
|
/* No need to copy data if path and subdir are the same. */
|
|
|
|
if (path != subdir)
|
|
|
|
memmove(path, subdir, len);
|
|
|
|
|
|
|
|
return path + len;
|
|
|
|
}
|