#At file:///C:/w/repo/mysql-5.1-telco-7.0-bug45402/ based on revid:jack@stripped
2937 jack andrews 2009-06-29
Bug #45402 Win32AsyncFile::rmrfReq can run an infinite loop
- implemented and tested win32 implementation
- need to check interface is OK
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-06-29 14:02:59 +0000
@@ -16,14 +16,71 @@
#ifndef DirIterator_HPP
#define DirIterator_HPP
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+// ndbrequire is in src/kernel -- maybe put this somewhere else?
+#define require(x) do {\
+ long x_=(x);if(!x_) {\
+ fprintf(stderr,"required %s, got %ld\n%s:%d\n",#x,x_,__FILE__,__LINE__);\
+ perror("perror: ");\
+ assert(0); exit(1); }\
+} while(0)
+
+typedef enum {UNDEFINED, ISFILE, ISDIR} Entry ;
+const int CHECKERRNO = -1;
+
class DirIterator {
- class DirIteratorImpl& m_impl;
+ class DirIteratorImpl* m_impl; //must be a pointer for private cons
+ DirIterator(const DirIterator&){} // don't copy these objects
+ DirIterator& operator=(const DirIterator&){return *this;}
public:
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 != ISFILE);
+ return s;
+ }
+};
+
+struct DirIteratorWalk
+{
+ virtual int on_dir(const char *) = 0;
+ virtual int on_file(const char *) = 0;
+ virtual ~DirIteratorWalk(){}
+ int walk(const char *dir);
+};
+
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
+struct RM_RF : DirIteratorWalk
+{
+ int on_dir(const char *name)
+ {
+ int rv = rmdir(name);
+ if (rv)
+ perror("rmdir: ");
+ return rv;
+ }
+ int on_file(const char *name)
+ {
+ int rv = unlink(name);
+ if (rv)
+ perror("unlink: ");
+ return rv;
+ }
};
#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-06-29 14:02:59 +0000
@@ -15,8 +15,10 @@
#include "DirIterator.hpp"
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
-#ifndef __WIN__
+#ifndef _WIN32
#include <dirent.h>
@@ -28,7 +30,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 +45,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,7 +67,7 @@ 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))
@@ -77,29 +79,54 @@ public:
#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);
+ Entry to_entry(const WIN32_FIND_DATA find_data) const {
+ DWORD atts = find_data.dwFileAttributes;
+ if (atts & FILE_ATTRIBUTE_DIRECTORY)
+ return ISDIR;
+ if ((atts & FILE_ATTRIBUTE_NORMAL) || (atts & FILE_ATTRIBUTE_TEMPORARY))
+ return ISFILE;
+ return UNDEFINED;
+ }
+
+ 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)
+ FindClose(m_find_handle);
+ 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,40 +137,122 @@ public:
return 0;
}
- const char* next_file(void){
- while(m_first || FindNextFile(m_find_handle, &m_find_data))
+ const char* next_entry(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;
+ entry = to_entry(m_find_data);
+ return s;
}
return NULL;
}
+ const char* path() {
+ return m_path.c_str();
+ }
+
};
#endif
-
DirIterator::DirIterator() :
- m_impl(*new DirIteratorImpl())
+ m_impl(new DirIteratorImpl()) // new used in kernel?
{
}
DirIterator::~DirIterator()
{
- delete &m_impl;
+ delete m_impl;
}
int DirIterator::open(const char* path)
{
- return m_impl.open(path);
+ return m_impl->open(path);
+}
+
+int DirIterator::close()
+{
+ return m_impl->close();
+}
+
+const char *DirIterator::path()
+{
+ return m_impl->path();
}
-const char* DirIterator::next_file(void)
+const char* DirIterator::next_entry(Entry &entry)
{
- return m_impl.next_file();
+ return m_impl->next_entry(entry);
}
+int DirIteratorWalk::walk(const char *dir) {
+ struct stat statbuf;
+ if(stat(dir,&statbuf)==-1 && errno==ENOENT)
+ return CHECKERRNO;
+ Vector<BaseString> bss;
+ bss.push(dir,0);
+ for (;bss.size();) {
+ DirIterator di;
+ Entry entry;
+ const char *name;
+ int has_entries;
+ int rv = di.open(bss[0].c_str());
+ has_entries = (int)di.next_entry(entry);
+ if (!has_entries) {
+ require(!on_dir(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!=ISDIR) {
+ require(!on_file(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;
+ RM_RF rm_rf;
+ rm_rf.walk(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"));
+
+ OK(!rm_rf.walk(TMP));
+ OK(stat(TMP,&statbuf)==-1 && errno==ENOENT);
+ return 1;
+}
+#endif
Attachment: [text/bzr-bundle] bzr/jack@sun.com-20090629140259-6rg661v9t3uw1q2c.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.0 branch (jack:2937) Bug#45402 | jack andrews | 29 Jun |