I support this request. I got no error message, but the limitation occures by subdirectories with a path length larger than 260 characters. This is often the case on network shares (e.g Sama export of UNIX volumes).
I have written a small program that demonstrates the problem. This program creates 20 subdirectories "a" and an file (filexx.txt) in each directory. Then the directories are renamed upwards to a 20 character long name. At the top level the program tries to open the file at the lowest level directory (file19.txt) with CreateFileW and with the \\?\ prefix.
With SS and Explorer you should not able to reach a directory lower then level 10 (file10.txt).
The program started with d renames the directories to the short names, so you can delete it.
Here is the code:
Code: Select all
/*
Demonstrates usage of CreateFile with paths longer than MAX_PATH
SS should implement this feature on W2K and newer Windows versions
The auhtor does not accept any WARRANTY for direct or indirect damages caused by this program.
Use it at your own risk!
see also http://msdn.microsoft.com/library/en-us/fileio/fs/createfile.asp
*/
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#define PATHLENGTH 20*20+30
void printErrorAndExit(const char *msg, DWORD err)
{
LPSTR lpMsgBuf;
if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPSTR) &lpMsgBuf,
0,
NULL ))
{
fprintf(stderr,"%s : %s\n",msg,lpMsgBuf);
LocalFree(lpMsgBuf);
}
else
{
fprintf(stderr,"Error at FormatMesage: %d\n",err=GetLastError());
}
//exit(err);
}
int main(int argc, char *argv[])
{
int i;
wchar_t tmp[100];
wchar_t *path;
wchar_t *upath;
wchar_t *curdir;
HANDLE f;
if(argc==1)
{
fprintf(stderr,"%s\nusage: c(reate)|d(delete)\n",argv[0]);
exit(1);
}
else
if(*argv[1]=='c')
{
for(i=0;i<20;i++)
{
DWORD written;
if(!CreateDirectoryW(L"a",NULL)) //create new dir a
printErrorAndExit("CreateDirectory",GetLastError());
if(!SetCurrentDirectoryW(L"a")) //change to a
printErrorAndExit("SetCurrentDirectory",GetLastError());
swprintf(tmp,L"file%2d.txt",i); //create file
f=CreateFileW(tmp,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
WriteFile(f,tmp,10*sizeof(wchar_t),&written,NULL);
CloseHandle(f);
}
for(i=0;i<20;i++) //rename Directories recursiv
{
SetCurrentDirectoryW(L"..");//go upwards
if(!MoveFileW(L"a",L"01234567890123456789")) /* rename Directory to 20 long name */
printErrorAndExit("MoveFile",GetLastError());
}
/* now 20*20+19*Backslash + Basedirectory >> MAX_PATH */
DWORD len=0;
len=GetCurrentDirectoryW(len,NULL); //get Basedirectory
curdir=new wchar_t[len+1];
path=new wchar_t[PATHLENGTH+len+10];
GetCurrentDirectoryW(len,curdir);
wprintf(L"%s\n",curdir);
//now the file10.txt exceeds MAX_PATH
for(i=0;i<20;i++)
{
if(i==0) //build the complete path to file19.txt
swprintf(path,L"%s\\01234567890123456789\\",curdir);
else
wcscat(path,L"01234567890123456789\\");
}
wcscat(path,L"file19.txt"); // add file name
wprintf(L"Try to open %s\n",path);
// try to open the normal way, should not work !!!
if(INVALID_HANDLE_VALUE==CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL))
printErrorAndExit("CreateFile 1",GetLastError());
upath=new wchar_t[wcslen(path)+4];
swprintf(upath,L"\\\\?\\%s",path); // use UNICODE path prefix, works also for networkshares
wprintf(L"Try to open %s\n",upath);
// open with unicode prefix, allows 32k path length
if(INVALID_HANDLE_VALUE==CreateFileW(upath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL))
printErrorAndExit("CreateFile 2",GetLastError());
// should work
delete curdir;
delete upath;
delete path;
}
else if(*argv[1]=='d') // rename the directories to short names
{ //rename to a
for(i=0;i<20;i++)
{
if(!MoveFileW(L"01234567890123456789",L"a"))
printErrorAndExit("MoveFile 1",GetLastError());
if(!SetCurrentDirectoryW(L"a"))
printErrorAndExit("SetCurrentDirectory 1",GetLastError());
}
//now you can delete the directories
}
return 0;
}