I see Squashman beat me to it while I've been playing with long path names, but here's my take on the :EOF
:EOF is a predefined label that is always at the end of the file.
So this exits the current script, same as using
Exit /B
If you are familiar with BASIC,
Goto :EOF is equivalent to
RETURN
The /C switch will continue on copy errors like Access Denied, Sharing Violations (file in use), or File not found (deleted/moved/renamed before xcopy got to it).
It will not continue when it hits a long path. You get an Insufficient memory error and Xcopy quits. So you can't use it to find long paths.
Easiest solution is to use Robocopy as I mentioned in
post 9 in the
previous thread, which doesn't have that path length limitation. It's included with Vista, and can be downloaded for XP/Win2K as part of the
Win2K3 Resource Kit. (This Vista version won't work on XP)
The Resource kit is an 11.8 MiB download, but you only need to download it once. If you have multiple PCs, you can have the batch file check to see if robocopy.exe exists on the system, and if not copy it to the Windows\system32 folder from a network share, robocopy.exe is only 78 KiB. Or copy it at the same time as the batch file is copied to the system
If you have to use xcopy, there's a couple of options. All depends on if you have multiple nested folders, or just a couple levels of folders, and a few files with a very long name.
You can use Dir to do a directory list. It will send this error message to STDERR when it finds a long path:
The directory name <path listed> is too long.
You can run a DIR command and check for that error message.
Dir /B /S "C:\Path\*.*" >Dirlist.txt 2>LongPath.txt
You can then create an exclude file to exclude that path. However, this may not find some long paths.
I created a group of nested folders, then renamed the top level folder to make the path too long. With just the right length, Dir will not give an error, nor will it list all the files/folders. In my test, it will list the 2nd to last folder, but not the files it contains, or the folder. And Xcopy doesn't cause an error, but the files in that 2nd to last folder and it's subfolder are not copied.
Added a couple more characters, and Dir now gives an error, but Xcopy still runs, but again doesn't copy the last two folders.
I then created the longest filename I could in the root of the drive, which is 256 characters (260 counting the C:\ at the front, and the <NULL> at the end)
Created a folder named New Folder, used Robocopy to move the file.
Dir will list the file, and Xcopy gives an error.
Moved it to C:\Test Dir\New Folder, and Dir will list it. Xcopy won't copy, nor does it give an error. Tried copying using the short file name, and xcopy doesn't give an error, but still won't copy the file.
You can't exclude the filename. Even trying a partial match of the first few characters fails, because Xcopy has to read the filename before it can try to match it to what is in the exclude file.
Renaming using the short name also fails with this error:
The system cannot find the path specified.
Then the Command Prompt generates an error and closes. The dump file indicates this:
Stack buffer overflow - code c0000409
So, you can check to make sure Xcopy won't fail, but you can't guarantee that you haven't missed some files.
You use Dir to find any long paths, then exclude the path so Xcopy won't cause an error.
You then check the total length of the files Dir finds, and exclude those paths.
Then process the list to create a list of files in the excluded folders that you can copy.
You then individually copy everything in the excluded folders that is not too long, or create a share at the lowest level folder and then repeat all the above starting from that share.
But, if the filename itself is over 256 characters, there is nothing you can do with it with a batch file. I'm not even sure if Dir would be able to list it if it's too long.
You can't create a name longer than 256 characters using the Command Prompt or Explorer, but any program can by using the Windows API, which allows up to 32,767 characters in the path.
Much much easier to just copy Robocopy to each system.
This is what I've got so far. Still need to go through the Will Copy list and remove any files that are in excluded paths and add them to the Excludedlist file, then decide how to copy them.
Code:
@Echo Off
SetLocal EnableDelayedExpansion
Set _SrcFld=C:\Test Dir
Set _DstFld=D:\Test Dir
PushD %_SrcFld%
Set _TPath=C:\Test1\
If Exist "%Temp%\*.}x{" Del /F "%Temp%\*.}x{"
Dir /B /S /A-D >"%Temp%\Dirlist.}x{" 2>"%Temp%\LongPath.}x{"
For %%I In ("%Temp%\LongPath.}x{") Do If %%~zI==0 Goto _NoLong
For /F "Usebackq Delims=" %%I In ("%Temp%\LongPath.}x{") Do (
Set _Dir=%%I
>>"%Temp%\Exclude.}x{" Echo !_Dir:~19,-13!
)
:_NoLong
:: Now check dirlist for names/paths over 256 characters
For /F "Usebackq Delims=" %%I In ("%Temp%\Dirlist.}x{") Do (
Call :_StrLen "%%I"
If !_Result! LSS 256 (
>>"%Temp%\WillCopy.}x{" Echo %%I
) Else (
>>"%Temp%\Exclude.}x{" Echo %%~dpI
>>"%Temp%\excludedlist.}x{" Echo %%I
)
)
Copy "%Temp%\Exclude.}x{" C:\Exclude.}x{>Nul
Xcopy /CEHIRYL "%_SrcFld%" "%_DstFld%" /Exclude:C:\Exclude.}x{
Del /F C:\Exclude.}x{
:_End
PopD
::If Exist "%Temp%\*.}x{" Del /F "%Temp%\*.}x{"
EndLocal
Goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: This routine does a divide by 2 type check.
:: Faster than counting each character for strings longer than 16
:: Returns the string length.
:: PARAM
:: 1 String to get length of
:: RETURN Integer string length in _Result
:_StrLen
SetLocal EnableExtensions EnableDelayedExpansion
Set _Str="%~1"& Set _Str=!_Str:~1,-1!
Set _Len=0
:: Max string length is 8191, see http://support.microsoft.com/kb/830473
Set _Pos=8192
:_StrLenLoop
Set /A _Pos /= 2
If NOT "!_Str!" == "" (
If NOT "!_Str:~%_Pos%,1!" == "" (
Set /A _Len += %_Pos% + 1
:: work on rest, that is after _Pos+1
Set _Str=!_Str:~%_Pos%!
Set _Str=!_Str:~1!
)
Goto :_StrLenLoop
)
EndLocal & Set _Result=%_Len%
Goto :EOF
Jerry