NTFS 2000 bug ???

Hi all,

I am attaching the test program to reproduce a bug in the NTFS 2000 (Memory manager? CopyFile API?).

  1. Build the test code.
  2. Create temp dir on a NTFS 2000 disk, copy the test executable to this
    directory (it uses current dir to work).
  3. 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>

To the original author of this post.

I am curious; what version of Win2k are you experiencing this problem on.
Win2k professional or Win2k Server.

My reasons are that we are experiencing some similar issues except it is
with an Installable file system that we have created. Basically from a user
mode perspective we simply create a node, populate it with some “file”
objects. Then we rename the node or at least try and we get an illegal
command message back to the user mode code. This scenario works with 2K
professional but fails with 2K server.

Thought your issues sounded similar so I thought I’d plant the 2K
professional versus 2K server.

Ken Crismon
Riolabs Inc
xxxxx@riolabs.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of
xxxxx@tarzan.cr.cyco.com
Sent: Friday, August 04, 2000 12:00 AM
To: File Systems Developers
Subject: [ntfsd] NTFS 2000 bug ???

Hi all,

I am attaching the test program to reproduce a bug in the NTFS 2000 (Memory
manager? CopyFile API?).

  1. Build the test code.
  2. Create temp dir on a NTFS 2000 disk, copy the test executable to this
    directory (it uses current dir to work).
  3. 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 */


You are currently subscribed to ntfsd as: xxxxx@riolabs.com
To unsubscribe send a blank email to $subst(‘Email.Unsub’)</errno.h></time.h></stdio.h></io.h></stdlib.h></string.h></direct.h></windows.h>