summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysys/my_delete.c11
-rw-r--r--mysys/my_open.c88
-rw-r--r--mysys/my_symlink.c75
-rw-r--r--mysys/mysys_priv.h28
4 files changed, 118 insertions, 84 deletions
diff --git a/mysys/my_delete.c b/mysys/my_delete.c
index 155e925e9ba..8487f1d2e5a 100644
--- a/mysys/my_delete.c
+++ b/mysys/my_delete.c
@@ -21,6 +21,12 @@
static int my_win_unlink(const char *name);
#endif
+CREATE_NOSYMLINK_FUNCTION(
+ unlink_nosymlinks(const char *pathname),
+ unlinkat(dfd, filename, 0),
+ unlink(pathname)
+);
+
int my_delete(const char *name, myf MyFlags)
{
int err;
@@ -30,7 +36,10 @@ int my_delete(const char *name, myf MyFlags)
#ifdef _WIN32
err = my_win_unlink(name);
#else
- err = unlink(name);
+ if (MyFlags & MY_NOSYMLINKS)
+ err= unlink_nosymlinks(name);
+ else
+ err= unlink(name);
#endif
if(err)
diff --git a/mysys/my_open.c b/mysys/my_open.c
index 0effc4bedda..cafb94ef558 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -18,11 +18,11 @@
#include <m_string.h>
#include <errno.h>
-#if !defined(O_PATH) && defined(O_EXEC) /* FreeBSD */
-#define O_PATH O_EXEC
-#endif
-
-static int open_nosymlinks(const char *pathname, int flags, int mode);
+CREATE_NOSYMLINK_FUNCTION(
+ open_nosymlinks(const char *pathname, int flags, int mode),
+ openat(dfd, filename, O_NOFOLLOW | flags, mode),
+ open(pathname, O_NOFOLLOW | flags, mode)
+);
/*
Open a file
@@ -182,81 +182,3 @@ void my_print_open_files(void)
}
#endif
-
-/**
- like open(), but with symlinks are not accepted anywhere in the path
-
- This is used for opening symlinked tables for DATA/INDEX DIRECTORY.
- The paths there have been realpath()-ed. So, we can assume here that
-
- * `pathname` is an absolute path
- * no '.', '..', and '//' in the path
- * file exists
-*/
-static int open_nosymlinks(const char *pathname, int flags, int mode)
-{
-#ifndef O_PATH
-#ifdef HAVE_REALPATH
- char buf[PATH_MAX+1];
- if (realpath(pathname, buf) == NULL)
- return -1;
- if (strcmp(pathname, buf))
- {
- errno= ENOTDIR;
- return -1;
- }
-#endif
- return open(pathname, flags, mode | O_NOFOLLOW);
-#else
-
- char buf[PATH_MAX+1];
- char *s= buf, *e= buf+1, *end= strnmov(buf, pathname, sizeof(buf));
- int fd, dfd= -1;
-
- if (*end)
- {
- errno= ENAMETOOLONG;
- return -1;
- }
-
- if (*s != '/') /* not an absolute path */
- {
- errno= ENOENT;
- return -1;
- }
-
- for (;;)
- {
- if (*e == '/') /* '//' in the path */
- {
- errno= ENOENT;
- goto err;
- }
- while (*e && *e != '/')
- e++;
- *e= 0;
- if (!memcmp(s, ".", 2) || !memcmp(s, "..", 3))
- {
- errno= ENOENT;
- goto err;
- }
-
- fd = openat(dfd, s, O_NOFOLLOW | (e < end ? O_PATH : flags), mode);
- if (fd < 0)
- goto err;
-
- if (dfd >= 0)
- close(dfd);
-
- dfd= fd;
- s= ++e;
-
- if (e >= end)
- return fd;
- }
-err:
- if (dfd >= 0)
- close(dfd);
- return -1;
-#endif
-}
diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c
index bc01a68263d..ed35fff41e9 100644
--- a/mysys/my_symlink.c
+++ b/mysys/my_symlink.c
@@ -177,3 +177,78 @@ int my_realpath(char *to, const char *filename, myf MyFlags)
#endif
return 0;
}
+
+#ifdef HAVE_OPEN_PARENT_DIR_NOSYMLINKS
+/** opens the parent dir. walks the path, and does not resolve symlinks
+
+ returns the pointer to the file name (basename) within the pathname
+ or NULL in case of an error
+
+ stores the parent dir (dirname) file descriptor in pdfd.
+ It can be -1 even if there was no error!
+
+ This is used for symlinked tables for DATA/INDEX DIRECTORY.
+ The paths there have been realpath()-ed. So, we can assume here that
+
+ * `pathname` is an absolute path
+ * no '.', '..', and '//' in the path
+ * file exists
+*/
+
+const char *my_open_parent_dir_nosymlinks(const char *pathname, int *pdfd)
+{
+ char buf[PATH_MAX+1];
+ char *s= buf, *e= buf+1, *end= strnmov(buf, pathname, sizeof(buf));
+ int fd, dfd= -1;
+
+ if (*end)
+ {
+ errno= ENAMETOOLONG;
+ return NULL;
+ }
+
+ if (*s != '/') /* not an absolute path */
+ {
+ errno= ENOENT;
+ return NULL;
+ }
+
+ for (;;)
+ {
+ if (*e == '/') /* '//' in the path */
+ {
+ errno= ENOENT;
+ goto err;
+ }
+ while (*e && *e != '/')
+ e++;
+ *e= 0;
+
+ if (!memcmp(s, ".", 2) || !memcmp(s, "..", 3))
+ {
+ errno= ENOENT;
+ goto err;
+ }
+
+ if (++e >= end)
+ {
+ *pdfd= dfd;
+ return pathname + (s - buf);
+ }
+
+ fd = openat(dfd, s, O_NOFOLLOW | O_PATH);
+ if (fd < 0)
+ goto err;
+
+ if (dfd >= 0)
+ close(dfd);
+
+ dfd= fd;
+ s= e;
+ }
+err:
+ if (dfd >= 0)
+ close(dfd);
+ return NULL;
+}
+#endif
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index f5d2f301837..4b489504c26 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -89,6 +89,34 @@ void sf_free(void *ptr);
void my_error_unregister_all(void);
+#if !defined(O_PATH) && defined(O_EXEC) /* FreeBSD */
+#define O_PATH O_EXEC
+#endif
+
+#ifdef O_PATH
+#define HAVE_OPEN_PARENT_DIR_NOSYMLINKS
+const char *my_open_parent_dir_nosymlinks(const char *pathname, int *pdfd);
+#define NOSYMLINK_FUNCTION_BODY(AT,NOAT) \
+ int dfd, res; \
+ const char *filename= my_open_parent_dir_nosymlinks(pathname, &dfd); \
+ if (filename == NULL) return -1; \
+ res= AT; \
+ if (dfd >= 0) close(dfd); \
+ return res;
+#elif defined(HAVE_REALPATH)
+#define NOSYMLINK_FUNCTION_BODY(AT,NOAT) \
+ char buf[PATH_MAX+1]; \
+ if (realpath(pathname, buf) == NULL) return -1; \
+ if (strcmp(pathname, buf)) { errno= ENOTDIR; return -1; } \
+ return NOAT;
+#else
+#define NOSYMLINK_FUNCTION_BODY(AT,NOAT) \
+ return NOAT;
+#endif
+
+#define CREATE_NOSYMLINK_FUNCTION(PROTO,AT,NOAT) \
+static int PROTO { NOSYMLINK_FUNCTION_BODY(AT,NOAT) }
+
#ifdef _WIN32
#include <sys/stat.h>
/* my_winfile.c exports, should not be used outside mysys */