Commit db8fb408 authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.4 into 10.5

parents 895c126a 08b6fd93
......@@ -200,9 +200,9 @@ datadir_iter_new(const char *path, bool skip_first_level = true)
pthread_mutex_init(&it->mutex, NULL);
it->datadir_path = strdup(path);
it->dir = os_file_opendir(it->datadir_path, TRUE);
it->dir = os_file_opendir(it->datadir_path);
if (it->dir == NULL) {
if (it->dir == IF_WIN(INVALID_HANDLE_VALUE, nullptr)) {
goto error;
}
......@@ -233,11 +233,9 @@ bool
datadir_iter_next_database(datadir_iter_t *it)
{
if (it->dbdir != NULL) {
if (os_file_closedir(it->dbdir) != 0) {
if (os_file_closedir_failed(it->dbdir)) {
msg("Warning: could not"
" close database directory %s", it->dbpath);
it->err = DB_ERROR;
}
......@@ -283,10 +281,9 @@ datadir_iter_next_database(datadir_iter_t *it)
/* We want wrong directory permissions to be a fatal error for
XtraBackup. */
it->dbdir = os_file_opendir(it->dbpath, TRUE);
if (it->dbdir != NULL) {
it->dbdir = os_file_opendir(it->dbpath);
if (it->dir != IF_WIN(INVALID_HANDLE_VALUE, nullptr)) {
it->is_file = false;
return(true);
}
......@@ -726,9 +723,9 @@ directory_exists(const char *dir, bool create)
}
/* could be symlink */
os_dir = os_file_opendir(dir, FALSE);
os_dir = os_file_opendir(dir);
if (os_dir == NULL) {
if (os_dir == IF_WIN(INVALID_HANDLE_VALUE, nullptr)) {
my_strerror(errbuf, sizeof(errbuf), my_errno);
msg("Can not open directory %s: %s", dir,
errbuf);
......@@ -756,9 +753,9 @@ directory_exists_and_empty(const char *dir, const char *comment)
return(false);
}
os_dir = os_file_opendir(dir, FALSE);
os_dir = os_file_opendir(dir);
if (os_dir == NULL) {
if (os_dir == IF_WIN(INVALID_HANDLE_VALUE, nullptr)) {
msg("%s can not open directory %s", comment, dir);
return(false);
}
......@@ -2178,7 +2175,9 @@ decrypt_decompress()
*/
static bool backup_files_from_datadir(const char *dir_path)
{
os_file_dir_t dir = os_file_opendir(dir_path, TRUE);
os_file_dir_t dir = os_file_opendir(dir_path);
if (dir == IF_WIN(INVALID_HANDLE_VALUE, nullptr)) return false;
os_file_stat_t info;
bool ret = true;
while (os_file_readdir_next_file(dir_path, dir, &info) == 0) {
......
......@@ -279,9 +279,8 @@ log_online_setup_bitmap_file_range(
/* 1st pass: size the info array */
bitmap_dir = os_file_opendir(srv_data_home, FALSE);
if (UNIV_UNLIKELY(!bitmap_dir)) {
bitmap_dir = os_file_opendir(srv_data_home);
if (UNIV_UNLIKELY(bitmap_dir == IF_WIN(INVALID_HANDLE_VALUE, NULL))) {
msg("InnoDB: Error: failed to open bitmap directory \'%s\'",
srv_data_home);
return FALSE;
......@@ -329,8 +328,7 @@ log_online_setup_bitmap_file_range(
}
}
if (UNIV_UNLIKELY(os_file_closedir(bitmap_dir))) {
if (UNIV_UNLIKELY(os_file_closedir_failed(bitmap_dir))) {
os_file_get_last_error(TRUE);
msg("InnoDB: Error: cannot close \'%s\'",srv_data_home);
return FALSE;
......@@ -346,9 +344,8 @@ log_online_setup_bitmap_file_range(
/* 2nd pass: get the file names in the file_seq_num order */
bitmap_dir = os_file_opendir(srv_data_home, FALSE);
if (UNIV_UNLIKELY(!bitmap_dir)) {
bitmap_dir = os_file_opendir(srv_data_home);
if (UNIV_UNLIKELY(bitmap_dir == IF_WIN(INVALID_HANDLE_VALUE, NULL))) {
msg("InnoDB: Error: failed to open bitmap directory \'%s\'",
srv_data_home);
return FALSE;
......@@ -398,8 +395,7 @@ log_online_setup_bitmap_file_range(
}
}
if (UNIV_UNLIKELY(os_file_closedir(bitmap_dir))) {
if (UNIV_UNLIKELY(os_file_closedir_failed(bitmap_dir))) {
os_file_get_last_error(TRUE);
msg("InnoDB: Error: cannot close \'%s\'", srv_data_home);
free(bitmap_files->files);
......
......@@ -3442,6 +3442,225 @@ static void xb_load_single_table_tablespace(const std::string &space_name,
skip_node_page0);
}
#ifdef _WIN32
/**
The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
at the first entry. In both Unix and Windows we automatically skip the '.'
and '..' items at the start of the directory listing.
@param[in] dirname directory name; it must not contain a trailing
'\' or '/'
@return directory stream, NULL if error */
os_file_dir_t os_file_opendir(const char *dirname)
{
char path[OS_FILE_MAX_PATH + 3];
ut_a(strlen(dirname) < OS_FILE_MAX_PATH);
strcpy(path, dirname);
strcpy(path + strlen(path), "\\*");
/* Note that in Windows opening the 'directory stream' also retrieves
the first entry in the directory. Since it is '.', that is no problem,
as we will skip over the '.' and '..' entries anyway. */
LPWIN32_FIND_DATA lpFindFileData= static_cast<LPWIN32_FIND_DATA>
(ut_malloc_nokey(sizeof(WIN32_FIND_DATA)));
os_file_dir_t dir= FindFirstFile((LPCTSTR) path, lpFindFileData);
ut_free(lpFindFileData);
return dir;
}
#endif
/** This function returns information of the next file in the directory. We jump
over the '.' and '..' entries in the directory.
@param[in] dirname directory name or path
@param[in] dir directory stream
@param[out] info buffer where the info is returned
@return 0 if ok, -1 if error, 1 if at the end of the directory */
int
os_file_readdir_next_file(
const char* dirname,
os_file_dir_t dir,
os_file_stat_t* info)
{
#ifdef _WIN32
BOOL ret;
int status;
WIN32_FIND_DATA find_data;
next_file:
ret = FindNextFile(dir, &find_data);
if (ret > 0) {
const char* name;
name = static_cast<const char*>(find_data.cFileName);
ut_a(strlen(name) < OS_FILE_MAX_PATH);
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
goto next_file;
}
strcpy(info->name, name);
info->size = find_data.nFileSizeHigh;
info->size <<= 32;
info->size |= find_data.nFileSizeLow;
if (find_data.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT) {
/* TODO: test Windows symlinks */
/* TODO: MySQL has apparently its own symlink
implementation in Windows, dbname.sym can
redirect a database directory:
REFMAN "windows-symbolic-links.html" */
info->type = OS_FILE_TYPE_LINK;
} else if (find_data.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY) {
info->type = OS_FILE_TYPE_DIR;
} else {
/* It is probably safest to assume that all other
file types are normal. Better to check them rather
than blindly skip them. */
info->type = OS_FILE_TYPE_FILE;
}
status = 0;
} else {
DWORD err = GetLastError();
if (err == ERROR_NO_MORE_FILES) {
status = 1;
} else {
msg("readdir_next_file in %s returned %lu", dir, err);
status = -1;
}
}
return(status);
#else
struct dirent* ent;
char* full_path;
int ret;
struct stat statinfo;
next_file:
ent = readdir(dir);
if (ent == NULL) {
return(1);
}
ut_a(strlen(ent->d_name) < OS_FILE_MAX_PATH);
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
goto next_file;
}
strcpy(info->name, ent->d_name);
full_path = static_cast<char*>(
ut_malloc_nokey(strlen(dirname) + strlen(ent->d_name) + 10));
if (!full_path) {
return -1;
}
sprintf(full_path, "%s/%s", dirname, ent->d_name);
ret = stat(full_path, &statinfo);
if (ret) {
if (errno == ENOENT) {
/* readdir() returned a file that does not exist,
it must have been deleted in the meantime. Do what
would have happened if the file was deleted before
readdir() - ignore and go to the next entry.
If this is the last entry then info->name will still
contain the name of the deleted file when this
function returns, but this is not an issue since the
caller shouldn't be looking at info when end of
directory is returned. */
ut_free(full_path);
goto next_file;
}
msg("stat %s: Got error %d", full_path, errno);
ut_free(full_path);
return(-1);
}
info->size = statinfo.st_size;
if (S_ISDIR(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_DIR;
} else if (S_ISLNK(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_LINK;
} else if (S_ISREG(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_FILE;
} else {
info->type = OS_FILE_TYPE_UNKNOWN;
}
ut_free(full_path);
return(0);
#endif
}
/***********************************************************************//**
A fault-tolerant function that tries to read the next file name in the
directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
idea is to read as much good data as we can and jump over bad data.
@return 0 if ok, -1 if error even after the retries, 1 if at the end
of the directory */
int
fil_file_readdir_next_file(
/*=======================*/
dberr_t* err, /*!< out: this is set to DB_ERROR if an error
was encountered, otherwise not changed */
const char* dirname,/*!< in: directory name or path */
os_file_dir_t dir, /*!< in: directory stream */
os_file_stat_t* info) /*!< in/out: buffer where the
info is returned */
{
for (ulint i = 0; i < 100; i++) {
int ret = os_file_readdir_next_file(dirname, dir, info);
if (ret != -1) {
return(ret);
}
ib::error() << "os_file_readdir_next_file() returned -1 in"
" directory " << dirname
<< ", crash recovery may have failed"
" for some .ibd files!";
*err = DB_ERROR;
}
return(-1);
}
/** Scan the database directories under the MySQL datadir, looking for
.ibd files and determining the space id in each of them.
@return DB_SUCCESS or error number */
......@@ -3460,10 +3679,10 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
/* The datadir of MySQL is always the default directory of mysqld */
dir = os_file_opendir(fil_path_to_mysql_datadir, true);
if (dir == NULL) {
dir = os_file_opendir(fil_path_to_mysql_datadir);
if (UNIV_UNLIKELY(dir == IF_WIN(INVALID_HANDLE_VALUE, nullptr))) {
msg("cannot open dir %s", fil_path_to_mysql_datadir);
return(DB_ERROR);
}
......@@ -3516,12 +3735,9 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
goto next_datadir_item;
}
/* We want wrong directory permissions to be a fatal error for
XtraBackup. */
dbdir = os_file_opendir(dbpath, true);
if (dbdir != NULL) {
dbdir = os_file_opendir(dbpath);
if (UNIV_UNLIKELY(dbdir != IF_WIN(INVALID_HANDLE_VALUE,NULL))){
/* We found a database directory; loop through it,
looking for possible .ibd files in it */
......@@ -3544,7 +3760,7 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
}
}
if (0 != os_file_closedir(dbdir)) {
if (os_file_closedir_failed(dbdir)) {
fprintf(stderr, "InnoDB: Warning: could not"
" close database directory %s\n",
dbpath);
......@@ -3553,7 +3769,7 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
}
} else {
msg("Can't open dir %s", dbpath);
err = DB_ERROR;
break;
......@@ -3567,10 +3783,9 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
ut_free(dbpath);
if (0 != os_file_closedir(dir)) {
if (os_file_closedir_failed(dir)) {
fprintf(stderr,
"InnoDB: Error: could not close MySQL datadir\n");
return(DB_ERROR);
}
......@@ -5435,11 +5650,9 @@ static ibool xb_process_datadir(const char *path, const char *suffix,
suffix_len = strlen(suffix);
/* datafile */
dbdir = os_file_opendir(path, FALSE);
if (dbdir != NULL) {
ret = fil_file_readdir_next_file(&err, path, dbdir,
&fileinfo);
dbdir = os_file_opendir(path);
if (UNIV_UNLIKELY(dbdir != IF_WIN(INVALID_HANDLE_VALUE, nullptr))) {
ret = fil_file_readdir_next_file(&err, path, dbdir, &fileinfo);
while (ret == 0) {
if (fileinfo.type == OS_FILE_TYPE_DIR) {
goto next_file_item_1;
......@@ -5469,14 +5682,14 @@ static ibool xb_process_datadir(const char *path, const char *suffix,
}
/* single table tablespaces */
dir = os_file_opendir(path, FALSE);
dir = os_file_opendir(path);
if (dir == NULL) {
if (UNIV_UNLIKELY(dbdir == IF_WIN(INVALID_HANDLE_VALUE, nullptr))) {
msg("Can't open dir %s", path);
return TRUE;
}
ret = fil_file_readdir_next_file(&err, path, dir,
&dbinfo);
ret = fil_file_readdir_next_file(&err, path, dir, &dbinfo);
while (ret == 0) {
if (dbinfo.type == OS_FILE_TYPE_FILE
|| dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
......@@ -5492,10 +5705,9 @@ static ibool xb_process_datadir(const char *path, const char *suffix,
os_normalize_path(dbpath);
dbdir = os_file_opendir(dbpath, FALSE);
if (dbdir != NULL) {
dbdir = os_file_opendir(dbpath);
if (dbdir != IF_WIN(INVALID_HANDLE_VALUE, nullptr)) {
ret = fil_file_readdir_next_file(&err, dbpath, dbdir,
&fileinfo);
while (ret == 0) {
......
......@@ -235,4 +235,53 @@ typedef void (*insert_entry_func_t)(const char*);
void xb_load_list_string(char *list, const char *delimiters,
insert_entry_func_t ins);
void register_ignore_db_dirs_filter(const char *name);
#ifdef _WIN32
typedef HANDLE os_file_dir_t; /*!< directory stream */
/** The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
at the first entry. In both Unix and Windows we automatically skip the '.'
and '..' items at the start of the directory listing.
@param[in] dirname directory name; it must not contain a trailing
'\' or '/'
@return directory stream
@retval INVALID_HANDLE_VALUE on error */
HANDLE os_file_opendir(const char *dirname);
# define os_file_closedir(dir) static_cast<void>(FindClose(dir))
# define os_file_closedir_failed(dir) !FindClose(dir)
#else
typedef DIR* os_file_dir_t;
# define os_file_opendir(dirname) opendir(dirname)
# define os_file_closedir(dir) static_cast<void>(closedir(dir))
# define os_file_closedir_failed(dir) closedir(dir)
#endif
/** This function returns information of the next file in the directory. We jump
over the '.' and '..' entries in the directory.
@param[in] dirname directory name or path
@param[in] dir directory stream
@param[out] info buffer where the info is returned
@return 0 if ok, -1 if error, 1 if at the end of the directory */
int
os_file_readdir_next_file(
const char* dirname,
os_file_dir_t dir,
os_file_stat_t* info);
/***********************************************************************//**
A fault-tolerant function that tries to read the next file name in the
directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
idea is to read as much good data as we can and jump over bad data.
@return 0 if ok, -1 if error even after the retries, 1 if at the end
of the directory */
int
fil_file_readdir_next_file(
/*=======================*/
dberr_t* err, /*!< out: this is set to DB_ERROR if an error
was encountered, otherwise not changed */
const char* dirname,/*!< in: directory name or path */
os_file_dir_t dir, /*!< in: directory stream */
os_file_stat_t* info); /*!< in/out: buffer where the
info is returned */
#endif /* XB_XTRABACKUP_H */
......@@ -3109,41 +3109,6 @@ fil_ibd_load(
return(FIL_LOAD_OK);
}
/***********************************************************************//**
A fault-tolerant function that tries to read the next file name in the
directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
idea is to read as much good data as we can and jump over bad data.
@return 0 if ok, -1 if error even after the retries, 1 if at the end
of the directory */
int
fil_file_readdir_next_file(
/*=======================*/
dberr_t* err, /*!< out: this is set to DB_ERROR if an error
was encountered, otherwise not changed */
const char* dirname,/*!< in: directory name or path */
os_file_dir_t dir, /*!< in: directory stream */
os_file_stat_t* info) /*!< in/out: buffer where the
info is returned */
{
for (ulint i = 0; i < 100; i++) {
int ret = os_file_readdir_next_file(dirname, dir, info);
if (ret != -1) {
return(ret);
}
ib::error() << "os_file_readdir_next_file() returned -1 in"
" directory " << dirname
<< ", crash recovery may have failed"
" for some .ibd files!";
*err = DB_ERROR;
}
return(-1);
}
/** Try to adjust FSP_SPACE_FLAGS if they differ from the expectations.
(Typically when upgrading from MariaDB 10.1.0..10.1.20.)
@param[in,out] space tablespace
......
......@@ -1656,21 +1656,6 @@ fil_ibd_load(
MY_ATTRIBUTE((warn_unused_result));
/***********************************************************************//**
A fault-tolerant function that tries to read the next file name in the
directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
idea is to read as much good data as we can and jump over bad data.
@return 0 if ok, -1 if error even after the retries, 1 if at the end
of the directory */
int
fil_file_readdir_next_file(
/*=======================*/
dberr_t* err, /*!< out: this is set to DB_ERROR if an error
was encountered, otherwise not changed */
const char* dirname,/*!< in: directory name or path */
os_file_dir_t dir, /*!< in: directory stream */
os_file_stat_t* info); /*!< in/out: buffer where the
info is returned */
/** Determine if a matching tablespace exists in the InnoDB tablespace
memory cache. Note that if we have not done a crash recovery at the database
startup, there may be many tablespaces which are not yet in the memory cache.
......
......@@ -53,8 +53,6 @@ typedef ib_uint64_t os_offset_t;
#ifdef _WIN32
typedef HANDLE os_file_dir_t; /*!< directory stream */
/** We define always WIN_ASYNC_IO, and check at run-time whether
the OS actually supports it: Win 95 does not, NT does. */
# define WIN_ASYNC_IO
......@@ -68,8 +66,6 @@ typedef native_file_handle os_file_t;
#else /* _WIN32 */
typedef DIR* os_file_dir_t; /*!< directory stream */
/** File handle */
typedef int os_file_t;
......@@ -320,43 +316,6 @@ parameter (--tmpdir).
FILE*
os_file_create_tmpfile();
/** The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
at the first entry. In both Unix and Windows we automatically skip the '.'
and '..' items at the start of the directory listing.
@param[in] dirname directory name; it must not contain a trailing
'\' or '/'
@param[in] is_fatal true if we should treat an error as a fatal
error; if we try to open symlinks then we do
not wish a fatal error if it happens not to be
a directory
@return directory stream, NULL if error */
os_file_dir_t
os_file_opendir(
const char* dirname,
bool is_fatal);
/**
Closes a directory stream.
@param[in] dir directory stream
@return 0 if success, -1 if failure */
int
os_file_closedir(
os_file_dir_t dir);
/** This function returns information of the next file in the directory. We jump
over the '.' and '..' entries in the directory.
@param[in] dirname directory name or path
@param[in] dir directory stream
@param[out] info buffer where the info is returned
@return 0 if ok, -1 if error, 1 if at the end of the directory */
int
os_file_readdir_next_file(
const char* dirname,
os_file_dir_t dir,
os_file_stat_t* info);
/**
This function attempts to create a directory named pathname. The new directory
gets default permissions. On Unix, the permissions are (0770 & ~umask). If the
......
......@@ -1172,136 +1172,6 @@ os_file_create_directory(
return(true);
}
/**
The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
at the first entry. In both Unix and Windows we automatically skip the '.'
and '..' items at the start of the directory listing.
@param[in] dirname directory name; it must not contain a trailing
'\' or '/'
@param[in] is_fatal true if we should treat an error as a fatal
error; if we try to open symlinks then we do
not wish a fatal error if it happens not to be
a directory
@return directory stream, NULL if error */
os_file_dir_t
os_file_opendir(
const char* dirname,
bool error_is_fatal)
{
os_file_dir_t dir;
dir = opendir(dirname);
if (dir == NULL && error_is_fatal) {
os_file_handle_error(dirname, "opendir");
}
return(dir);
}
/** Closes a directory stream.
@param[in] dir directory stream
@return 0 if success, -1 if failure */
int
os_file_closedir(
os_file_dir_t dir)
{
int ret = closedir(dir);
if (ret != 0) {
os_file_handle_error_no_exit(NULL, "closedir", false);
}
return(ret);
}
/** This function returns information of the next file in the directory. We jump
over the '.' and '..' entries in the directory.
@param[in] dirname directory name or path
@param[in] dir directory stream
@param[out] info buffer where the info is returned
@return 0 if ok, -1 if error, 1 if at the end of the directory */
int
os_file_readdir_next_file(
const char* dirname,
os_file_dir_t dir,
os_file_stat_t* info)
{
struct dirent* ent;
char* full_path;
int ret;
struct stat statinfo;
next_file:
ent = readdir(dir);
if (ent == NULL) {
return(1);
}
ut_a(strlen(ent->d_name) < OS_FILE_MAX_PATH);
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
goto next_file;
}
strcpy(info->name, ent->d_name);
full_path = static_cast<char*>(
ut_malloc_nokey(strlen(dirname) + strlen(ent->d_name) + 10));
if (!full_path) {
return -1;
}
sprintf(full_path, "%s/%s", dirname, ent->d_name);
ret = stat(full_path, &statinfo);
if (ret) {
if (errno == ENOENT) {
/* readdir() returned a file that does not exist,
it must have been deleted in the meantime. Do what
would have happened if the file was deleted before
readdir() - ignore and go to the next entry.
If this is the last entry then info->name will still
contain the name of the deleted file when this
function returns, but this is not an issue since the
caller shouldn't be looking at info when end of
directory is returned. */
ut_free(full_path);
goto next_file;
}
os_file_handle_error_no_exit(full_path, "stat", false);
ut_free(full_path);
return(-1);
}
info->size = statinfo.st_size;
if (S_ISDIR(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_DIR;
} else if (S_ISLNK(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_LINK;
} else if (S_ISREG(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_FILE;
} else {
info->type = OS_FILE_TYPE_UNKNOWN;
}
ut_free(full_path);
return(0);
}
/** NOTE! Use the corresponding macro os_file_create(), not directly
this function!
Opens an existing file or creates a new.
......@@ -2206,154 +2076,6 @@ os_file_create_directory(
return(true);
}
/** The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
at the first entry. In both Unix and Windows we automatically skip the '.'
and '..' items at the start of the directory listing.
@param[in] dirname directory name; it must not contain a trailing
'\' or '/'
@param[in] is_fatal true if we should treat an error as a fatal
error; if we try to open symlinks then we do
not wish a fatal error if it happens not to
be a directory
@return directory stream, NULL if error */
os_file_dir_t
os_file_opendir(
const char* dirname,
bool error_is_fatal)
{
os_file_dir_t dir;
LPWIN32_FIND_DATA lpFindFileData;
char path[OS_FILE_MAX_PATH + 3];
ut_a(strlen(dirname) < OS_FILE_MAX_PATH);
strcpy(path, dirname);
strcpy(path + strlen(path), "\\*");
/* Note that in Windows opening the 'directory stream' also retrieves
the first entry in the directory. Since it is '.', that is no problem,
as we will skip over the '.' and '..' entries anyway. */
lpFindFileData = static_cast<LPWIN32_FIND_DATA>(
ut_malloc_nokey(sizeof(WIN32_FIND_DATA)));
dir = FindFirstFile((LPCTSTR) path, lpFindFileData);
ut_free(lpFindFileData);
if (dir == INVALID_HANDLE_VALUE) {
if (error_is_fatal) {
os_file_handle_error(dirname, "opendir");
}
return(NULL);
}
return(dir);
}
/** Closes a directory stream.
@param[in] dir directory stream
@return 0 if success, -1 if failure */
int
os_file_closedir(
os_file_dir_t dir)
{
BOOL ret;
ret = FindClose(dir);
if (!ret) {
os_file_handle_error_no_exit(NULL, "closedir", false);
return(-1);
}
return(0);
}
/** This function returns information of the next file in the directory. We
jump over the '.' and '..' entries in the directory.
@param[in] dirname directory name or path
@param[in] dir directory stream
@param[out] info buffer where the info is returned
@return 0 if ok, -1 if error, 1 if at the end of the directory */
int
os_file_readdir_next_file(
const char* dirname,
os_file_dir_t dir,
os_file_stat_t* info)
{
BOOL ret;
int status;
WIN32_FIND_DATA find_data;
next_file:
ret = FindNextFile(dir, &find_data);
if (ret > 0) {
const char* name;
name = static_cast<const char*>(find_data.cFileName);
ut_a(strlen(name) < OS_FILE_MAX_PATH);
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
goto next_file;
}
strcpy(info->name, name);
info->size = find_data.nFileSizeHigh;
info->size <<= 32;
info->size |= find_data.nFileSizeLow;
if (find_data.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT) {
/* TODO: test Windows symlinks */
/* TODO: MySQL has apparently its own symlink
implementation in Windows, dbname.sym can
redirect a database directory:
REFMAN "windows-symbolic-links.html" */
info->type = OS_FILE_TYPE_LINK;
} else if (find_data.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY) {
info->type = OS_FILE_TYPE_DIR;
} else {
/* It is probably safest to assume that all other
file types are normal. Better to check them rather
than blindly skip them. */
info->type = OS_FILE_TYPE_FILE;
}
status = 0;
} else if (GetLastError() == ERROR_NO_MORE_FILES) {
status = 1;
} else {
os_file_handle_error_no_exit(NULL, "readdir_next_file", false);
status = -1;
}
return(status);
}
/** Check that IO of specific size is possible for the file
opened with FILE_FLAG_NO_BUFFERING.
......
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