6

NTFS supports all kinds of links including junctions, hard links, soft links, etc. so here's a problem.

Let's say you're recursively deleting a directory which actually contains the above things. It's easy to imagine that your application, whatever that is, instead of deleting all the junctions, soft links which could lead outside of the directory you're interested in, etc. instead traverses them and first deletes all the files within instead.

This could easily lead to a major data loss.

Here's a simple example. You mount a hard disk drive which has another Windows installation.

Let's check the contents of D:\ProgramData:

D:\ProgramData>dir /a
 Volume in drive D has no label.
 Volume Serial Number is 1234-4321

 Directory of D:\ProgramData

12/06/2021  12:56 PM    <DIR>          .
12/06/2021  12:56 PM    <DIR>          ..
07/14/2009  10:08 AM    <JUNCTION>     Application Data [C:\ProgramData]
07/14/2009  10:08 AM    <JUNCTION>     Desktop [C:\Users\Public\Desktop]
07/14/2009  10:08 AM    <JUNCTION>     Documents [C:\Users\Public\Documents]
07/14/2009  10:08 AM    <JUNCTION>     Favorites [C:\Users\Public\Favorites]
02/11/2016  03:51 PM    <DIR>          Microsoft
07/10/2019  03:00 AM    <DIR>          Microsoft Help
12/23/2019  04:04 PM    <DIR>          Package Cache
07/14/2009  10:08 AM    <JUNCTION>     Start Menu [C:\ProgramData\Microsoft\Windows\Start Menu]
07/14/2009  10:08 AM    <JUNCTION>     Templates [C:\ProgramData\Microsoft\Windows\Templates]

Now what if you try to recursively delete D:\ProgramData? I won't even attempt to do that because I'm afraid C:\ProgramData will be deleted first.

In Linux rm -rf handles this perfectly - it sees symbolic links (to directories) and deletes symbolic links as files, without trying to traverse them.

What's the safe way to recursively delete such directories in Windows?

rmdir /q /s? Something else?

3 Answers 3

0

Tried with rmdir /s from command prompt

I created a directory c:\abc1 with a text file in it.

And I created a directory c:\test1 with a subdirectory c:\test1\blah

Within c:\test1\blah I tried creating links to c:\abc1 , a symbolic link or a junction link..

Then when I did rmdir /s on blah, I checked c:\abc1 and it's still there with its contents.

So rmdir /s from cmd prompt, tested in Windows 7, is safe.

C:\>dir c:\abc1
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of c:\abc1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,425,338,368 bytes free

C:\>cd test
The system cannot find the path specified.

C:\>cd test1

C:\test1>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:46    <DIR>          blah
               0 File(s)              0 bytes
               3 Dir(s)  137,425,338,368 bytes free

C:\test1>cd blah

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:46    <DIR>          .
28/12/2021  19:46    <DIR>          ..
               0 File(s)              0 bytes
               2 Dir(s)  137,425,338,368 bytes free

C:\test1\blah>mklink /?
Creates a symbolic link.

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      Creates a directory symbolic link.  Default is a file
                symbolic link.
        /H      Creates a hard link instead of a symbolic link.
        /J      Creates a Directory Junction.
        Link    specifies the new symbolic link name.
        Target  specifies the path (relative or absolute) that the new link
                refers to.

C:\test1\blah>mklink /d c:\abc1
The syntax of the command is incorrect.
Creates a symbolic link.

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      Creates a directory symbolic link.  Default is a file
                symbolic link.
        /H      Creates a hard link instead of a symbolic link.
        /J      Creates a Directory Junction.
        Link    specifies the new symbolic link name.
        Target  specifies the path (relative or absolute) that the new link
                refers to.

C:\test1\blah>mklink /d qq c:\abc1
symbolic link created for qq <<===>> c:\abc1

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:47    <DIR>          .
28/12/2021  19:47    <DIR>          ..
28/12/2021  19:47    <SYMLINKD>     qq [c:\abc1]
               0 File(s)              0 bytes
               3 Dir(s)  137,425,469,440 bytes free

C:\test1\blah>dir qq
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah\qq

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,425,469,440 bytes free

C:\test1\blah>cd ..

C:\test1>rmdir /s blah
blah, Are you sure (Y/N)? y

C:\test1>dir c:\abc1
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of c:\abc1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,425,379,328 bytes free

C:\test1>cd blah
The system cannot find the path specified.

C:\test1>md blah

C:\test1>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1

28/12/2021  19:47    <DIR>          .
28/12/2021  19:47    <DIR>          ..
28/12/2021  19:47    <DIR>          blah
               0 File(s)              0 bytes
               3 Dir(s)  137,424,666,624 bytes free

C:\test1>cd blah

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:47    <DIR>          .
28/12/2021  19:47    <DIR>          ..
               0 File(s)              0 bytes
               2 Dir(s)  137,424,666,624 bytes free

C:\test1\blah>mklink /?
Creates a symbolic link.

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      Creates a directory symbolic link.  Default is a file
                symbolic link.
        /H      Creates a hard link instead of a symbolic link.
        /J      Creates a Directory Junction.
        Link    specifies the new symbolic link name.
        Target  specifies the path (relative or absolute) that the new link
                refers to.

C:\test1\blah>mklink /J ww c:\abc1
Junction created for ww <<===>> c:\abc1

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:48    <DIR>          .
28/12/2021  19:48    <DIR>          ..
28/12/2021  19:48    <JUNCTION>     ww [c:\abc1]
               0 File(s)              0 bytes
               3 Dir(s)  137,424,715,776 bytes free

C:\test1\blah>dir ww
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah\ww

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,424,715,776 bytes free

C:\test1\blah>cd ..

C:\test1>rmdir /s blah
blah, Are you sure (Y/N)? y

C:\test1>dir c:\abc1
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of c:\abc1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,424,740,352 bytes free

C:\test1>

Really you should be able to do the test yourself very easily.

One comment mentions that powershell rmdir is different.. I can't comment much re powershell, I don't use it that much. I see that powershell's rmdir does give different output e.g. rmdir says "cmdlet Remove-Item at command pipeline..." so seems to be very different to the cmd one, i'm not familiar with it.

2

For deleting all files which are not a junction, this command should do it:

del /s /a:-l

Where:

  • /s : recurse
  • /a:-l : only files which are not reparse points

NTFS reparse points include Directory junctions, Symbolic links and Volume mount points.

A small test of what will be deleted can be done using the command:

dir /s /a:-l

(I would still take a backup of the folder if it's important.)

2
  • Note: This will delete files, not folders.
    – harrymc
    Dec 20, 2021 at 17:49
  • @ArtemS.Tashkinov: Any comment?
    – harrymc
    Dec 27, 2021 at 8:02
2
+25

rmdir will delete the symbolic link.

del will delete the links destination but not the link.

rmdir /S /Q will delete the directory recursively and won't follow symlinks.

I have tested and confirmed the behaviour with cmd in Windows 10:

#create directory structure
C:\Users\username\test>mkdir 1 2 3

C:\Users\username\test>mkdir 1\testdir

C:\Users\username\test>mkdir 1\testdir\1

#create symbolic link to directory

C:\Users\username\test>mklink /D testlink 1\testdir\1
symbolische Verknüpfung erstellt für testlink <<===>> 1\testdir\1


C:\Users\username\test>dir

 Verzeichnis von C:\Users\username\test

28.12.2021  20:24    <DIR>          .
28.12.2021  20:24    <DIR>          ..
28.12.2021  20:23    <DIR>          1
28.12.2021  20:23    <DIR>          2
28.12.2021  20:23    <DIR>          3
28.12.2021  20:24    <SYMLINKD>     testlink [1\testdir\1]
               0 Datei(en),              0 Bytes
               6 Verzeichnis(se), 22.185.267.200 Bytes frei

#test rmdir with the named parameters
C:\Users\username\test>rmdir /s /q testlink

C:\Users\username\test>dir

 Verzeichnis von C:\Users\username\test

28.12.2021  20:25    <DIR>          .
28.12.2021  20:25    <DIR>          ..
28.12.2021  20:23    <DIR>          1
28.12.2021  20:23    <DIR>          2
28.12.2021  20:23    <DIR>          3
               0 Datei(en),              0 Bytes
               5 Verzeichnis(se), 22.185.267.200 Bytes frei



C:\Users\username\test>cd 1\testdir\

#obviously the subdirectory in the linked-to directory is still there
C:\Users\username\test\1\testdir>dir


 Verzeichnis von C:\Users\username\test\1\testdir

28.12.2021  20:23    <DIR>          .
28.12.2021  20:23    <DIR>          ..
28.12.2021  20:24    <DIR>          1
               0 Datei(en),              0 Bytes
               3 Verzeichnis(se), 22.184.206.336 Bytes frei

According to this comment rmdir will behave different if invoked from powershell than from cmd, I have however not tested it with powershell.

7
  • The question is about recursively deleting a directory. I don't want to go look for all junctions/links within and delete them one by one first. I've already once used WinRAR for that and accidentally deleted tons of files. Luckily I had backups. Dec 20, 2021 at 15:49
  • Then just use the arguments /Q and /S as you've already stated in your opening question. Dec 21, 2021 at 0:46
  • have you personally tested it? Dec 22, 2021 at 19:24
  • According to this post: "If the pathname is a Junction Point, then RD without /S will remove the Junction point itself, not the Junction’s destination directory". So it seems to me that /S will actually follow the junction and delete its target - just the opposite of your answer.
    – harrymc
    Dec 28, 2021 at 8:57
  • According to this comment rmdir seems to behave differently if invoked from powershell. This seriously is a dangerous implementation change! Dec 28, 2021 at 9:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.