#At file:///C:/w/repo/mysql-5.1-telco-7.0-bug45402/ based on revid:jack@stripped
2936 jack andrews 2009-06-25
Bug #45402 Win32AsyncFile::rmrfReq can run an infinite loop
. supporting code with test
. test code does a rm -rf
added:
storage/ndb/include/util/DirIterator.hpp
storage/ndb/src/common/util/DirIterator.cpp
modified:
storage/ndb/src/common/util/CMakeLists.txt
storage/ndb/src/common/util/Makefile.am
=== added file 'storage/ndb/include/util/DirIterator.hpp'
--- a/storage/ndb/include/util/DirIterator.hpp 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/include/util/DirIterator.hpp 2009-06-25 18:40:13 +0000
@@ -0,0 +1,102 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef DirIterator_HPP
+#define DirIterator_HPP
+#include <util/BaseString.hpp>
+#include <stdio.h>
+
+enum fileinfo_e {ISDIR=1,ISFILE=2} ;
+typedef struct fileinfo {
+ char *name;
+ enum fileinfo_e type;
+} *FILEINFO;
+enum return_codes_e {NOTADIR=8,DIREMPTY,NOMORE,CHECKERRNO=128};
+
+typedef struct di *DI;
+
+int di_open(DI *di, const char *path);
+int di_next(DI di, FILEINFO fi);
+const char *di_path(DI di);
+int di_close(DI *pdi);
+typedef int (*di_callback_t)(void *self, const char *name);
+int di_walk(const char *dir, void *self, di_callback_t on_dir, di_callback_t on_file);
+
+class DirIterator {
+ DI impl;
+ DirIterator(const DirIterator&){} // don't copy these objects
+ DirIterator& operator=(const DirIterator&){return *this;}
+public:
+ DirIterator() : impl(0) {};
+ ~DirIterator() { close(); }
+
+ int open(const BaseString &path)
+ {
+ int rv_, rv = di_open(&impl,path.c_str());
+ if (rv)
+ return rv;
+ struct fileinfo fi;
+ rv = di_next(impl,&fi);
+ di_close(&impl);
+ rv_ = di_open(&impl,path.c_str());
+ return rv ? DIREMPTY : rv_;
+ }
+
+ const char *get_path()
+ {
+ return di_path(impl);
+ }
+
+ int close()
+ {
+ return impl ? di_close(&impl) : 0;
+ }
+
+
+ // 0 - no more. otherwise return next filename not a dir
+ // return val is valid until another next_XXX() call
+ const char* next_entry(bool& is_dir)
+ {
+ int rv;
+ struct fileinfo fi;
+
+ rv = di_next(impl, &fi);
+ is_dir = fi.type & ISDIR;
+ return rv ? 0 : fi.name;
+ }
+
+ const char* next_file(void)
+ {
+ bool is_dir;
+ const char *rv;
+ while ((rv=next_entry(is_dir)) && !is_dir)
+ ;
+ return rv ? 0 : rv;
+ }
+};
+
+int di_on_dir(void *self, const char *name);
+int di_on_file(void *self, const char *name);
+struct DirIteratorWalk
+{
+ virtual int on_dir(const BaseString&) = 0;
+ virtual int on_file(const BaseString&) = 0;
+ virtual ~DirIteratorWalk(){}
+ int walk(const BaseString &dir)
+ {
+ return di_walk(dir.c_str(), this, di_on_dir, di_on_file);
+ }
+};
+#endif
=== modified file 'storage/ndb/src/common/util/CMakeLists.txt'
--- a/storage/ndb/src/common/util/CMakeLists.txt 2009-06-02 14:00:06 +0000
+++ b/storage/ndb/src/common/util/CMakeLists.txt 2009-06-25 18:40:13 +0000
@@ -54,6 +54,7 @@ ADD_LIBRARY(ndbgeneral STATIC
basestring_vsnprintf.c
Bitmask.cpp
ndbinfo.c
+ DirIterator.cpp
)
TARGET_LINK_LIBRARIES(ndbgeneral zlib)
@@ -67,3 +68,8 @@ SET_TARGET_PROPERTIES(Bitmask-t
PROPERTIES COMPILE_FLAGS "-DTEST_BITMASK")
TARGET_LINK_LIBRARIES(Bitmask-t ndbgeneral)
+ADD_EXECUTABLE(DirIterator-t DirIterator.cpp)
+SET_TARGET_PROPERTIES(DirIterator-t
+ PROPERTIES COMPILE_FLAGS "-DTAP_TEST")
+TARGET_LINK_LIBRARIES(DirIterator-t ndbgeneral mysys wsock32)
+
=== added file 'storage/ndb/src/common/util/DirIterator.cpp'
--- a/storage/ndb/src/common/util/DirIterator.cpp 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/common/util/DirIterator.cpp 2009-06-25 18:40:13 +0000
@@ -0,0 +1,305 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <DirIterator.hpp>
+#ifdef _WIN32
+#include <direct.h>
+#include <sys/types.h>
+#else
+#include <dirent.h>
+#endif
+#include <sys/stat.h>
+
+struct di {
+ char *path;
+#ifdef _WIN32
+ char *pat;
+ struct _finddata_t finddata;
+ intptr_t handle;
+ int first, end;
+#else
+ DIR *dir;
+#endif
+};
+
+static int di_normalize_path(const char *path, char **norm_path)
+{
+ *norm_path = strdup(path);
+ if (!*norm_path)
+ return CHECKERRNO;
+ int len = strlen(*norm_path);
+ if ((*norm_path)[len-1] == DIR_SEPARATOR[0])
+ (*norm_path)[len-1] = 0;
+ return 0;
+}
+
+const char *di_path(DI di)
+{
+ return di->path;
+}
+
+#ifdef _WIN32
+#define stat _stat
+#define S_IFDIR _S_IFDIR
+#endif
+
+int di_open(DI *di, const char *path) {
+ struct stat statbuf;
+ int rv, pathlen;
+ DI d;
+ char *norm_path = 0;
+
+ *di = (DI)malloc(sizeof(struct di));
+ d=*di;
+ memset(d,0,sizeof(struct di));
+ if(!d)
+ return CHECKERRNO;
+ if ((rv = di_normalize_path(path, &norm_path))) {
+ int err = errno;
+ if (norm_path)
+ free(norm_path);
+ errno = err;
+ return rv;
+ }
+ d->path = (char*)malloc(strlen(norm_path) + 8);
+ if (!d->path)
+ return CHECKERRNO;
+ strcpy(d->path,norm_path);
+ free(norm_path);
+ pathlen = strlen(d->path);
+ assert(d->path[pathlen-1]!='\\');
+ rv = stat(d->path, &statbuf);
+ if (rv || !(statbuf.st_mode & S_IFDIR))
+ return NOTADIR;
+#ifdef _WIN32
+ d->pat = (char*)malloc(strlen(d->path) + 8);
+ if (!d->pat)
+ return CHECKERRNO;
+ sprintf(d->pat, "%s\\*", d->path);
+ d->first = 1;
+ d->end = 0;
+ d->handle = -1;
+#else
+ d->dir = opendir(path);
+ if(!d->dir)
+ return CHECKERRNO;
+#endif
+ return 0;
+}
+
+int di_close(DI *pdi)
+{
+ DI di=*pdi;
+#ifdef _WIN32
+ if (di->handle != -1) {
+ _findclose(di->handle);
+ di->handle = -1;
+ }
+#else
+ if (di->dir) {
+ closedir(di->dir);
+ di->dir = 0;
+ }
+#endif
+ if (di->path) {
+ free(di->path);
+ di->path = 0;
+ }
+ free(di);
+ *pdi=0;
+ return 0;
+}
+
+int di_next(DI di, FILEINFO fi)
+{
+#ifdef _WIN32
+ if (di->end)
+ return NOMORE;
+ if (di->first) {
+ if ((di->handle = _findfirst(di->pat, &di->finddata)) == -1L) {
+ di->end = 1;
+ DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
+ return CHECKERRNO;
+ }
+ }
+ while ( di->first || !(di->end = !!_findnext(di->handle,&di->finddata)) ) {
+ di->first = 0;
+ char *s=di->finddata.name;
+ if (di->finddata.attrib & (_A_HIDDEN | _A_SYSTEM))
+ continue;
+ if(!strcmp(s,".") || !strcmp(s,".."))
+ continue;
+ fi->name = s;
+ fi->type = (di->finddata.attrib&_A_SUBDIR)?ISDIR:ISFILE;
+ return 0;
+ }
+ _findclose(di->handle);
+ di->handle = -1;
+#else
+ struct dirent *ent;
+ struct stat statbuf;
+ while ((ent = readdir(di->dir)))
+ { char *s=ent->d_name,*pathname;
+ int mode=0,size;
+ if(!strcmp(s,".") || !strcmp(s,".."))
+ continue;
+ pathname = (char*)malloc(strlen(s)+strlen(di->path)+4);
+ sprintf(pathname,"%s/%s",di->path,s);
+ if (stat(pathname, &statbuf) == -1) {
+ free(pathname);
+ return CHECKERRNO;
+ }
+ free(pathname);
+ mode = statbuf.st_mode;
+ fi->name = s;
+ fi->type = S_ISDIR(mode)?ISDIR:ISFILE;
+ return 0;
+ }
+ (void)closedir(di->dir);
+ di->dir = 0;
+#endif
+ return NOMORE;
+}
+
+typedef Vector<BaseString> BSS;
+int di_walk(const char *dir, void *self, di_callback_t on_dir, di_callback_t on_file)
+{
+ struct stat statbuf;
+ if(stat(dir,&statbuf)==-1 && errno==ENOENT)
+ return CHECKERRNO;
+ BSS bss;
+ bss.push(dir,0);
+ for (;bss.size();) {
+ DirIterator di;
+ const char *name;
+ bool is_dir;
+ int rv = di.open(bss[0].c_str());
+ assert(rv != NOTADIR && rv != CHECKERRNO);
+ if (rv == DIREMPTY) {
+ assert(!on_dir(self, di.get_path()));
+ bss.erase(0); //pop
+ continue;
+ }
+ while ((name = di.next_entry(is_dir))) {
+ BaseString bs;
+ bs.assfmt("%s%s%s", di.get_path(), DIR_SEPARATOR, name);
+ if (!is_dir) {
+ assert(!on_file(self, bs.c_str()));
+ } else {
+ bss.push(bs,0);
+ }
+ }
+ }
+ return 0;
+}
+
+int di_on_dir(void *self, const char *name)
+{
+ return ((DirIteratorWalk*)self)->on_dir(name);
+}
+
+int di_on_file(void *self, const char *name)
+{
+ return ((DirIteratorWalk*)self)->on_file(name);
+}
+
+
+#ifdef TAP_TEST
+#include <NdbTap.hpp>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _WIN32
+#define unlink _unlink
+#define rmdir _rmdir
+#endif
+
+int deltree(char *dir)
+{
+ struct stat statbuf;
+ if(stat(dir,&statbuf)==-1 && errno==ENOENT)
+ return CHECKERRNO;
+ BSS bss;
+ bss.push(dir,0);
+ for (;bss.size();) {
+ DirIterator di;
+ const char *name;
+ bool is_dir;
+ int rv = di.open(bss[0].c_str());
+ OK(rv != NOTADIR && rv != CHECKERRNO);
+ if (rv == DIREMPTY) {
+ OK(!rmdir(di.get_path()));
+ bss.erase(0); //pop
+ continue;
+ }
+ while ((name = di.next_entry(is_dir))) {
+ BaseString bs;
+ bs.assfmt("%s%s%s", di.get_path(), DIR_SEPARATOR, name);
+ if (!is_dir) {
+ OK(!unlink(bs.c_str()));
+ } else {
+ bss.push(bs,0);
+ }
+ }
+ }
+ return 0;
+}
+
+struct RM_RF : DirIteratorWalk
+{
+ int on_dir(const BaseString &name)
+ {
+ int rv = rmdir(name.c_str());
+ if (rv)
+ perror("rmdir: ");
+ return rv;
+ }
+ int on_file(const BaseString &name)
+ {
+ int rv = unlink(name.c_str());
+ if (rv)
+ perror("unlink: ");
+ return rv;
+ }
+};
+
+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
+
=== modified file 'storage/ndb/src/common/util/Makefile.am'
--- a/storage/ndb/src/common/util/Makefile.am 2009-06-03 16:04:23 +0000
+++ b/storage/ndb/src/common/util/Makefile.am 2009-06-25 18:40:13 +0000
@@ -29,14 +29,20 @@ libgeneral_la_SOURCES = \
ConfigValues.cpp ndb_init.cpp basestring_vsnprintf.c \
Bitmask.cpp \
ndb_rand.c \
- ndbinfo.c
+ ndbinfo.c DirIterator.cpp
INCLUDES_LOC = @ZLIB_INCLUDES@
libndbazio_la_SOURCES = azio.c
libndbazio_la_LIBADD = @ZLIB_LIBS@
-noinst_PROGRAMS = BaseString-t HashMap-t Bitmask-t
+noinst_PROGRAMS = BaseString-t HashMap-t Bitmask-t DirIterator-t
+
+DirIterator_t_SOURCES = DirIterator.cpp
+DirIterator_t_CXXFLAGS = -DTAP_TEST
+DirIterator_t_LDADD = \
+ libgeneral.la \
+ $(top_builddir)/mysys/libmysyslt.la
BaseString_t_SOURCES = BaseString.cpp
BaseString_t_CXXFLAGS = -DTEST_BASE_STRING
Attachment: [text/bzr-bundle] bzr/jack@sun.com-20090625184013-0hvr1oqxggfcxt85.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.0 branch (jack:2936) Bug#45402 | jack andrews | 25 Jun |