#At file:///C:/w/repo/mysql-5.1-telco-7.0-bug45402/ based on revid:jack@stripped
2937 jack andrews 2009-07-01
Bug #45402 Win32AsyncFile::rmrfReq can run an infinite loop
- implemented and tested win32 implementation
modified:
storage/ndb/include/util/DirIterator.hpp
storage/ndb/src/common/util/DirIterator.cpp
=== modified file 'storage/ndb/include/util/DirIterator.hpp'
--- a/storage/ndb/include/util/DirIterator.hpp 2009-06-29 10:15:39 +0000
+++ b/storage/ndb/include/util/DirIterator.hpp 2009-07-01 10:53:50 +0000
@@ -16,14 +16,47 @@
#ifndef DirIterator_HPP
#define DirIterator_HPP
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
class DirIterator {
class DirIteratorImpl& m_impl;
+ DirIterator(const DirIterator&); // not impl
+ DirIterator& operator=(const DirIterator&); // not impl
public:
+
+ struct Entry {
+ enum { UNKNOWN, ISFILE, ISDIR } type;
+ const char* name;
+ Entry() :
+ type(UNKNOWN), name(0) {};
+ };
DirIterator();
~DirIterator();
- int open(const char* path);
- const char* next_file(void);
+ // 0: success
+ int open(const char *path);
+ int close();
+ const char* path();
+ const char* next_entry(Entry &);
+
+ // 0 - no more files, char* otherwise
+ const char* next_file() {
+ const char*s;
+ Entry entry;
+ do {
+ s = next_entry(entry);
+ } while (s && entry.type != Entry::ISFILE);
+ return s;
+ }
};
+
+/*
+ Remove a directory and all it's subdirecrories
+*/
+
+int remove_dir_recursive(const char* name);
+
#endif
=== modified file 'storage/ndb/src/common/util/DirIterator.cpp'
--- a/storage/ndb/src/common/util/DirIterator.cpp 2009-06-29 10:15:39 +0000
+++ b/storage/ndb/src/common/util/DirIterator.cpp 2009-07-01 10:53:50 +0000
@@ -15,8 +15,18 @@
#include "DirIterator.hpp"
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define require(x) do {\
+ long x_,e=errno=0;x_=(x);e=errno;if(!x_) {\
+ fprintf(stderr,"required %s, got %ld\n%s:%d\n",#x,x_,__FILE__,__LINE__);\
+ errno=e;\
+ perror("perror: ");\
+ assert(0); exit(1); }\
+} while(0)
-#ifndef __WIN__
+#ifndef _WIN32
#include <dirent.h>
@@ -28,7 +38,7 @@ class DirIteratorImpl {
DIR* m_dirp;
const char *m_path;
- bool is_regular_file(struct dirent* dp) const {
+ Entry to_entry(struct dirent* dp) const {
#ifdef _DIRENT_HAVE_D_TYPE
/*
Using dirent's d_type field to determine if
@@ -43,9 +53,9 @@ class DirIteratorImpl {
struct stat buf;
if (stat(fullpath.c_str(), &buf))
- return false; // 'stat' failed
+ return UNDEFINED; // 'stat' failed
- return S_ISREG(buf.st_mode);
+ return ... S_ISREG(buf.st_mode);
}
@@ -65,41 +75,69 @@ public:
return 0;
}
- const char* next_file(void){
+ const char* next_file(const Entry &entry){
struct dirent* dp;
while ((dp = readdir(m_dirp)) != NULL &&
!is_regular_file(dp))
;
- return dp ? dp->d_name : NULL;
+ return dp ? dp->d_name : NULL;
}
};
#else
#include <BaseString.hpp>
+#include <direct.h>
class DirIteratorImpl {
- bool m_first;
+ bool m_first, m_end;
WIN32_FIND_DATA m_find_data;
HANDLE m_find_handle;
+ intptr_t m_handle;
+ BaseString m_path;
- bool is_dir(const WIN32_FIND_DATA find_data) const {
- return (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+ bool to_entry(DirIterator::Entry &e, const WIN32_FIND_DATA find_data) const {
+ DWORD atts = find_data.dwFileAttributes;
+ e.name = m_find_data.cFileName;
+ e.type = DirIterator::Entry::UNKNOWN;
+ if (atts & FILE_ATTRIBUTE_DIRECTORY)
+ e.type = DirIterator::Entry::ISDIR;
+ if ((atts & FILE_ATTRIBUTE_NORMAL) || (atts & FILE_ATTRIBUTE_TEMPORARY))
+ e.type = DirIterator::Entry::ISFILE;
+ return true;
+ }
+
+ BaseString normalize_path(const char *path)
+ { BaseString rv = path;
+ int len = rv.length();
+ if (rv.c_str()[len-1] == DIR_SEPARATOR[0])
+ rv.substr(0,len-1);
+ return rv;
}
public:
DirIteratorImpl():
+ m_path(),
m_first(true),
+ m_end(false),
m_find_handle(INVALID_HANDLE_VALUE) {};
~DirIteratorImpl() {
- FindClose(m_find_handle);
+ close();
+ }
+
+ int close() {
+ if(m_find_handle != INVALID_HANDLE_VALUE)
+ if(!FindClose(m_find_handle))
+ return -1;
+ return 0;
}
int open(const char* path){
- BaseString path_buf;
- path_buf.assfmt("%s\\*", path);
- m_find_handle = FindFirstFile(path_buf.c_str(), &m_find_data);
+ m_path = normalize_path(path);
+ BaseString pattern;
+ pattern.assfmt("%s\\*", m_path);
+ m_find_handle = FindFirstFile(pattern.c_str(), &m_find_data);
if(m_find_handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
@@ -110,22 +148,30 @@ public:
return 0;
}
- const char* next_file(void){
- while(m_first || FindNextFile(m_find_handle, &m_find_data))
+ const char* next_entry(DirIterator::Entry &entry){
+ const char *s;
+ while(m_first || FindNextFile(m_find_handle, &m_find_data))
{
- m_first= false;
-
- if (!is_dir(m_find_data))
- return m_find_data.cFileName;
+ s = m_find_data.cFileName;
+ m_first = false;
+ if(!strcmp(s,".") || !strcmp(s,".."))
+ continue;
+ bool result = to_entry(entry,m_find_data);
+ if (!result)
+ return 0;
+ return s;
}
return NULL;
}
+ const char* path() {
+ return m_path.c_str();
+ }
+
};
#endif
-
DirIterator::DirIterator() :
m_impl(*new DirIteratorImpl())
{
@@ -142,8 +188,98 @@ int DirIterator::open(const char* path)
return m_impl.open(path);
}
-const char* DirIterator::next_file(void)
+int DirIterator::close()
{
- return m_impl.next_file();
+ return m_impl.close();
}
+const char *DirIterator::path()
+{
+ return m_impl.path();
+}
+
+const char* DirIterator::next_entry(Entry &entry)
+{
+ return m_impl.next_entry(entry);
+}
+
+#ifdef _WIN32
+static inline int unlink(const char *s)
+{
+ return _unlink(s);
+}
+static inline int rmdir(const char *s)
+{
+ return _rmdir(s);
+}
+#endif
+
+static inline int remove_dir_recursive(const char* dir) {
+ struct stat statbuf;
+ if(stat(dir,&statbuf)==-1 && errno==ENOENT)
+ return -1;
+ Vector<BaseString> bss;
+ bss.push(dir,0);
+ for (;bss.size();) {
+ DirIterator di;
+ DirIterator::Entry entry;
+ const char *name;
+ int has_entries;
+ int rv;
+ require(!(rv = di.open(bss[0].c_str())));
+ has_entries = (int)di.next_entry(entry);
+ if (!has_entries) {
+ require(!rmdir(di.path()));
+ bss.erase(0); //pop
+ di.close();
+ continue;
+ }
+ di.close();
+ require(!di.open(bss[0].c_str()));
+ while ((name = di.next_entry(entry))) {
+ BaseString bs;
+ bs.assfmt("%s%s%s", di.path(), DIR_SEPARATOR, name);
+ if (entry.type!=DirIterator::Entry::ISDIR) {
+ require(!unlink(bs.c_str()));
+ } else {
+ bss.push(bs,0);
+ }
+ }
+ }
+ return 0;
+}
+
+#ifdef TAP_TEST
+#include <NdbTap.hpp>
+
+inline int mkdirectory(const char *path) {
+#ifdef _WIN32
+ return mkdir(path);
+#else
+ return mkdir(path,0777);
+#endif
+}
+
+#define TMP "tmp_dir_iterator"
+TAPTEST(DirIterator)
+{
+ struct stat statbuf;
+ remove_dir_recursive(TMP);
+ OK(stat(TMP,&statbuf)==-1 && errno==ENOENT);
+ OK(!mkdirectory(TMP));
+ fclose(fopen(TMP DIR_SEPARATOR "a","w"));
+ OK(!mkdirectory(TMP DIR_SEPARATOR "d"));
+ OK(!mkdirectory(TMP DIR_SEPARATOR "e"));
+ fclose(fopen(TMP DIR_SEPARATOR "d" DIR_SEPARATOR "a","w"));
+ fclose(fopen(TMP DIR_SEPARATOR "d" DIR_SEPARATOR "b","w"));
+ fclose(fopen(TMP DIR_SEPARATOR "d" DIR_SEPARATOR "c","w"));
+ fclose(fopen(TMP DIR_SEPARATOR "d" DIR_SEPARATOR "c.x","w"));
+#ifndef _WIN32
+ create symlink to test that, too.
+#endif
+
+ OK(!remove_dir_recursive(TMP));
+ OK(stat(TMP,&statbuf)==-1 && errno==ENOENT);
+ return 1;
+}
+#endif
Attachment: [text/bzr-bundle] bzr/jack@sun.com-20090701105350-cb9w6ccfggwx8i3l.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.0 branch (jack:2937) Bug#45402 | jack andrews | 1 Jul |