Commit 6d503245 authored by Sergei Golubchik's avatar Sergei Golubchik

support MY_NOSYMLINKS in my_delete()

parent f2d24ea6
......@@ -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)
......
......@@ -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
}
......@@ -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
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment