Hi all,
I am attaching the test program to reproduce a bug in the NTFS 2000 (Memory manager? CopyFile API?).
- Build the test code.
- Create temp dir on a NTFS 2000 disk, copy the test executable to this
directory (it uses current dir to work). - Run the test (under Windows 2000 Professional or Server) giving your NTDDK tree path as an argument (this is for instance, any 3-4 levels deep directory tree with ~20MB of files is ok) .
Like this: test e:\NTDDK
The test program will copy all files from the tree to .\backup directory, then rename the .\backup directory to some unique name and try to copy the tree second time. Test will fail during second copy and print error mesages.
What is strange the test code works ok on FAT and FAT32 disks and on NTFS in Windows NT 4.0.
I suspect the problem is inside memory manager code which doesn’t dereference directories during rename.
May be YOU have time to look on the problem and explain it for all NTFSD readers?
Thanks in advance.
Oleg
… and the test code (it is originnaly called ntfsbugq.c)
#include <windows.h>
#include <direct.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
int _makedir(char* dir)
{
int rv = _mkdir(dir);
if(0 != rv && ENOENT == errno)
{
char _dir[_MAX_PATH];
char* last_5c;
strcpy(_dir, dir);
if(NULL != (last_5c = strrchr(_dir, ‘\’)))
{
last_5c = 0;
rv = _makedir(_dir);
if(0 == rv)
rv = _mkdir(dir);
}
}
return rv;
}
static char cwd[_MAX_PATH];
int makedir(char dir)
{
char _dir[_MAX_PATH];
strcpy(_dir, cwd);
strcat(_dir, dir);
return _makedir(_dir);
}
void copyfile(char* from, char* to, char* newname) // from is full path!
{
char _to[_MAX_PATH];
char fname[_MAX_FNAME];
strcpy(_to, cwd); strcat(_to, to);
if(NULL == newname)
{
char ext[_MAX_PATH];
_splitpath(from, NULL, NULL, fname, ext);
strcat(fname, ext);
}
else
strcpy(fname, newname);
strcat(_to, “\”); strcat(_to, fname);
if(!CopyFile(from, _to, FALSE))
{
DWORD gle = GetLastError();
printf(“CopyFile failed, from '%s' to '%s', gle=0x%08lx\n”, from, _to, gle);
}
}
void _enumdir(char* from, char* to) // from is full path!
{
BOOL todircreated = FALSE;
char filespec[_MAX_PATH];
struct _finddata_t fileinfo;
long find;
strcpy(filespec, from); strcat(filespec, “\.”);
memset(&fileinfo, 0, sizeof fileinfo);
find = _findfirst(filespec, &fileinfo);
if(-1 != find)
{
do
{
char _from[_MAX_PATH], _to[_MAX_PATH];
if(!(0 == strcmp(fileinfo.name, “.”) || 0 == strcmp(fileinfo.name, “…”)))
{
strcpy(_from, from); strcat(_from, “\”); strcat(_from, fileinfo.name);
if(fileinfo.attrib & _A_SUBDIR)
{
strcpy(_to, to); strcat(_to, “\”); strcat(_to, fileinfo.name);
_enumdir(_from, _to);
}
else
{
if(!todircreated)
{
makedir(to);
todircreated = TRUE;
}
copyfile(_from, to, NULL);
}
}
} while(0 == _findnext(find, &fileinfo));
_findclose(find);
}
}
void copytree(char* from, char* to) // from is full path
{
_enumdir(from, to);
}
void renamedir(char* old, char* new)
{
char _o[_MAX_PATH], _n[MAX_PATH];
strcpy(_o, cwd); strcat(_o, old);
strcpy(_n, cwd); strcat(_n, new);
rename(_o, _n);
}
void struct_tm_to_ext(struct tm* _tm, char ext[_MAX_EXT])
{
strftime(ext, _MAX_EXT, “.%Y%m%d%H%M%S”, _tm);
}
void renamedir_time(char* dir)
{
char dot_date_time_ext[_MAX_EXT];
char _dir[_MAX_PATH];
struct tm ltime;
time_t long_time;
time(&long_time);
ltime = localtime(&long_time);
struct_tm_to_ext(ltime, dot_date_time_ext);
strcpy(_dir, dir); strcat(_dir, dot_date_time_ext);
renamedir(dir, _dir);
}
void test(char srctreeroot)
{
char* backup = “\backup”;
char* backup_temp = “\backup.tmp”;
copytree(srctreeroot, backup_temp);
renamedir_time(backup);
renamedir(backup_temp, backup);
copytree(srctreeroot, backup_temp);
renamedir_time(backup);
renamedir(backup_temp, backup);
}
int __cdecl main(int argc, char* argv)
{
if(argc > 1)
if(NULL != _getcwd(cwd, _MAX_PATH))
test(argv[1]);
return argc;
}
/* ntfsbugq.c */</errno.h></time.h></stdio.h></io.h></stdlib.h></string.h></direct.h></windows.h>