Frage Einen (anscheinend) unendlich rekursiven Ordner entfernen


Irgendwie hat eine unserer alten Server 2008 (nicht R2) Boxen einen scheinbar endlos wiederholenden Ordner entwickelt. Dies spielt bei unseren Backups eine Rolle, da der Backup-Agent versucht, in den Ordner zurückzuspringen und nie wieder zurückkehrt.

Die Ordnerstruktur sieht ungefähr so ​​aus:

C:\Storage\Folder1
C:\Storage\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1\Folder1

... und so weiter. Es ist wie einer von denen Mandelbrot-Sets Wir haben alle in den 90ern gespielt.

Ich habe es versucht:

  • Löschen aus dem Explorer. Ja, ich bin ein Optimist.
  • RMDIR C:\Storage\Folder1 /Q/S - Das kehrt zurück The directory is not empty
  • ROBOCOPY C:\temp\EmptyDirectory C:\Storage\Folder1 /PURGE - Dies durchläuft die Ordner für ein paar Minuten, bevor Robocopy.exe abstürzt.

Kann jemand vorschlagen, diesen Ordner für immer zu töten?


45
2018-02-12 11:12


Ursprung


Ich würde es versuchen /MIR stattdessen: ROBOCOPY /MIR C:\temp\EmptyDirectory C:\Storage\Folder1 kann auch einen Lauf wert sein chkdsk nur zum kichern. - jscott
/MIR schien länger zu dauern, aber schließlich ausgebombt ("robocopy hat aufgehört zu arbeiten"). Ich habe ein bisschen Angst, a zu machen chkdsk; Dies ist ein ziemlich alter Server und ich bin besorgt, dass dieses Problem auf größere Dateisystemprobleme hinweist ... - KenD
Versuchen Sie, von einer Linux (Ubuntu / Centos / Fedora / ...) Desktop-Test-CD zu booten und den Ordner von dort zu entfernen. - Guntram Blohm
@KenD Wenn Sie Probleme mit Dateisystemfehlern vermuten, sollten Sie zuerst versuchen, das Dateisystem zu reparieren. Versuchen Tricks zum Entfernen von Verzeichnissen könnten die Dinge verschlimmern. - jscott
Seit (von deiner Antwort unten) war das Verzeichnis nicht unendlich, nur sehr tief, wenn du es getan hättest CygWin oder UnxUtils installiert, könnten Sie verwenden find eine erste Entfernung des Tiefenverzeichnisses durchführen: find Storage/Folder1 -depth -exec rmdir {} \; - Johnny


Antworten:


Danke an alle für den nützlichen Rat.

In das StackOverflow-Gebiet eingedrungen, habe ich das Problem gelöst, indem ich dieses Code-Schnipsel hochgestoßen habe. Es nutzt die Delimon.Win32.IO Bibliothek, die speziell Probleme behandelt, die auf lange Dateipfade zugreifen.

Nur für den Fall, dass dies jemand anderem helfen kann, hier ist der Code - er hat die ~ 1600 Rekursionsstufe durchschritten, an der ich irgendwie festhielt und brauchte ungefähr 20 Minuten, um sie alle zu entfernen.

using System;
using Delimon.Win32.IO;

namespace ConsoleApplication1
{
    class Program
    {
        private static int level;
        static void Main(string[] args)
        {
            // Call the method to delete the directory structure
            RecursiveDelete(new DirectoryInfo(@"\\server\\c$\\storage\\folder1"));
        }

        // This deletes a particular folder, and recurses back to itself if it finds any subfolders
        public static void RecursiveDelete(DirectoryInfo Dir)
        {
            level++;
            Console.WriteLine("Now at level " +level);
            if (!Dir.Exists)
                return;

            // In any subdirectory ...
            foreach (var dir in Dir.GetDirectories())
            {
                // Call this method again, starting at the subdirectory
                RecursiveDelete(dir);
            }

            // Finally, delete the directory, and any files below it
            Dir.Delete(true);
            Console.WriteLine("Deleting directory at level " + level);
            level--;
        }
    }
}

45
2018-02-12 18:44



Ich habe versucht, sogar die Delimon Version von .Delete (statt der normalen System.IO Version), und obwohl es keine Ausnahme gab, schien es nichts zu tun. Sicher, die Rekursion mit der oben genannten Methode dauerte ewig, und .Delete nur für 5-10 Sekunden Dinge angeknabbert. Vielleicht hat es in ein paar Verzeichnissen abgebrochen und dann aufgegeben? - KenD
Hast du jemals herausgefunden, wie das anfing? Klingt wie ein wirklich schlecht geschriebenes Userland-Programm. - Parthian Shot
Wiederholt man 1600 mal in eine Funktion? Paketüberfluss Territorium in der Tat! - Aleksandr Dubinsky
Nur nebenbei, wurden die Ordner von irgendetwas gefüllt? Wenn Sie feststellen können, in welchen Intervallen die rekursiven Ordner erstellt wurden und multiplizieren Sie diese mit der Anzahl der Rekursionen, erhalten Sie (hoffentlich) einen ungefähren Zeitrahmen, wann dieses Problem begann ... - Get-HomeByFiveOClock
Wow, froh, dass du das gelöst hast. FYI, das offizielle von Microsoft unterstützte Update für diese Art von Situation ist "Formatieren des Volumes". Ja, ernsthaft. : / - HopelessN00b


Könnte ein rekursiver Verbindungspunkt sein. So etwas kann mit erstellt werden junction ein Datei- und Festplatten-Dienstprogramm von Sysinternals.

mkdir c:\Hello
junction c:\Hello\Hello c:\Hello

Und Sie können jetzt endlos nach unten c: \ Hallo \ Hallo \ Hallo .... (bis MAX_PATH erreicht ist, 260 Zeichen für die meisten Befehle, aber 32.767 Zeichen für einige Windows-API-Funktionen).

Eine Verzeichnisliste zeigt, dass es sich um eine Junction handelt:

C:\>dir c:\hello
 Volume in drive C is DR1
 Volume Serial Number is 993E-B99C

 Directory of c:\hello

12/02/2015  08:18 AM    <DIR>          .
12/02/2015  08:18 AM    <DIR>          ..
12/02/2015  08:18 AM    <JUNCTION>     hello [\??\c:\hello]
               0 File(s)              0 bytes
               3 Dir(s)  461,591,506,944 bytes free

C:\>

Um zu löschen, benutze das Junction Utility:

junction -d c:\Hello\Hello

25
2018-02-12 13:28



Leider, a DIR zeigt mir nur einfache Verzeichnisse - keine Anzeichen von Kreuzungen, fürchte ich - KenD
Kannst du einen kurzen Doppel-Check mit machen? junction -s C:\Storage\Folder1  ? - Brian
No reparse points found :( - KenD
Ich frage mich, was so ein Chaos der tatsächlichen Unterverzeichnisse erstellt hat. - Brian
Benutzen dir /a um <JUNCTION> zu sehen, ohne den spezifischen Namen anzugeben. - Chloe


Keine Antwort, aber ich habe nicht genügend Rep für einen Kommentar.

Ich habe dieses Problem einmal auf einer damals riesigen 500MB FAT16-Disk auf einem MS-DOS-System behoben. Ich benutzte DOS-Debugging, um die Verzeichnistabelle manuell zu sichern und zu analysieren. Ich blätterte dann ein Bit, um das rekursive Verzeichnis als gelöscht zu markieren. Meine Kopie von Dettman und Wyatt 'DOS Programmer's Reference' zeigte mir den Weg.

Ich bin immer noch außerordentlich stolz darauf. Ich wäre erstaunt und erschrocken, wenn es ein Allzweckwerkzeug gibt, das über FAT32- oder NTFS-Volumes verfügt. Das Leben war damals einfacher.


16
2018-02-13 14:06



Ich würde sagen, dass du es bist zu Recht stolz darauf. - mfinni
+1 habe einen Ruf bei mir. Nette Lösung. - Chris Thornton
Sie können jetzt den ersten Satz Ihrer Antwort löschen. - A.L
Dies ist keine Antwort. Es ist eine Geschichte über ein anderes Betriebssystem und ein anderes Dateisystem. Abgesehen davon, dass es für dieses (NT, NTFS) -Problem keine Hilfe ist, würde es auch jemandem mit dem gleichen Problem (DOS, FAT16) nicht helfen, da es eigentlich keine Details enthält. - Andrew Medico
Andrew Medico: Ich stimme dir zu, daher mein erster Satz. Aber ich sage Ihnen, wo Sie die Informationen finden, um das Problem zu lösen. - Richard


Java kann auch mit langen Dateipfaden umgehen. Und es kann es auch viel schneller machen. Dieser Code (den ich aus der Java-API-Dokumentation kopiert habe) löscht in etwa 1 Sekunde (unter Windows 7, Java 8.0) eine tiefe Verzeichnisstruktur mit 1600 Ebenen und ohne Risiko eines Stack-Überlaufs, da er keine Rekursion verwendet.

import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;

public class DeleteDir {

  static void deleteDirRecur(Path dir) throws IOException {
    Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
         @Override
         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
             throws IOException
         {
             Files.delete(file);
             return FileVisitResult.CONTINUE;
         }
         @Override
         public FileVisitResult postVisitDirectory(Path dir, IOException e)
             throws IOException
         {
             if (e == null) {
                 Files.delete(dir);
                 return FileVisitResult.CONTINUE;
             } else {
                 throw e;
             }
         }
     });
  }

  public static void main(String[] args) throws IOException {
    deleteDirRecur(Paths.get("C:/Storage/Folder1"));
  }
}

8
2018-02-14 17:35



Ich hasse dich. Du hast mich gezwungen, eine Antwort zu finden, die Java beinhaltet, und jetzt fühle ich mich total schmutzig. Ich brauche eine Dusche. - HopelessN00b
Entschuldigen Sie. Ich hoffe, dass Sie sich von Ihrem Trauma erholen werden. Aber ist eine von Microsoft entwickelte Sprache (c #) wirklich viel besser? - SpiderPig
Ich bin in diesen Tagen in erster Linie ein Windows-Typ, also ja, ja, ist es. Ich kann auch bitter und voreingenommen gegen Java seinen wegen 5 spezifische, verschiedene Versionen von JRE zu erhalten, die über fast 1.000 Kunden in Umgebung meines Arbeitgebers, von denen zurück bis 2009 datiert, wegen des Mists ... äh, Malware ... uh, "Enterprise-y" Software-Suites, die wir für geschäftskritische Anwendungen einsetzen. - HopelessN00b


Sie brauchen keine langen Pfadnamen chdir in das Verzeichnis und verwenden Sie nur relative Pfade zu rmdir.

Oder, wenn Sie eine POSIX-Shell installiert haben, oder portieren Sie diese auf die DOS-Entsprechung:

# untested code, didn't bother actually testing since the OP already solved the problem.

while [ -d Folder1 ]; do
    mv Folder1/Folder1/Folder1/Folder1  tmp # repeat more times to work in larger batches
    rm -r Folder1     # remove the first several levels remaining after moving the main tree out
    # then repeat to end up with the remaining big tree under the original name
    mv tmp/Folder1/Folder1/.../Folder1 Folder1 
    rm -r tmp
done

(Die Verwendung einer Shell-Variablen, um zu verfolgen, wo Sie sie für die Schleifenbedingung umbenannt haben, ist die andere Alternative zum Abwickeln der Schleife, wie ich es dort getan habe.)

Dies vermeidet den CPU-Overhead der Lösung von KenD, der das Betriebssystem zwingt, den Baum von oben nach unten zu durchqueren nth Ebene jedes Mal, wenn eine neue Ebene hinzugefügt wird, Berechtigungen usw. überprüft. So ist es sum(1, n) = n * (n-1) / 2 = O(n^2)Zeit Komplexität. Lösungen, die einen Brocken vom Anfang der Kette trennen, sollten sein O(n), es sei denn, Windows muss beim Umbenennen des übergeordneten Verzeichnisses eine Baumstruktur durchlaufen. (Linux / Unix nicht.) Lösungen, die chdir ganz nach unten bis zum Ende der Struktur und verwenden Sie relative Pfade von dort, Verzeichnisse wie sie entfernen chdir sichern, sollte auch sein O(n), vorausgesetzt, das Betriebssystem muss nicht alle Ihre übergeordneten Verzeichnisse bei jedem Systemaufruf überprüfen, wenn Sie Dinge während CDed irgendwo tun.

find Folder1 -depth -execdir rmdir {} + wird rmdir während CDed zum tiefsten Verzeichnis laufen lassen. Oder tatsächlich, finden -delete Option funktioniert für Verzeichnisse und impliziert -depth. So find Folder1 -delete sollte genau dasselbe tun, aber schneller. Yeah, GNU findet auf Linux nach unten, indem es ein Verzeichnis durchsucht, CDing in Unterverzeichnisse mit relativen Pfaden, dann rmdir mit einem relativen Pfad, dann chdir(".."). Es durchsucht die Verzeichnisse beim Aufsteigen nicht neu, also würde es verbrauchen O(n) RAM.

Das war wirklich eine Annäherung: strace zeigt es tatsächlich an unlinkat(AT_FDCWD, "tmp", AT_REMOVEDIR), open("..", O_DIRECTORY|...), und fchdir(the fd from opening the directory)mit einem Haufen fstat Anrufe sind auch reingekommen. Der Effekt ist jedoch derselbe, wenn die Verzeichnisstruktur nicht geändert wird, während die Suche ausgeführt wird.

edit: Ich probiere das nur für Kicks unter GNU / Linux (Ubuntu 14.10, auf einer 2,4GHz First-Gen Core2Duo CPU, auf einem XFS-Dateisystem auf einem WD 2.5TB Green Power Laufwerk (WD25EZRS)).

time mkdir -p $(perl -e 'print "annoyingfoldername/" x 2000, "\n"')

real    0m1.141s
user    0m0.005s
sys     0m0.052s

find annoyingfoldername/ | wc
   2000    2000 38019001  # 2k lines / 2k words / 38M characters of text


ll -R annoyingfoldername
... eventually
ls: cannot access ./annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername: File name too long
total 0
?????????? ? ? ? ?            ? annoyingfoldername

time find annoyingfoldername -delete

real    0m0.054s
user    0m0.004s
sys     0m0.049s

# about the same for normal rm -r,
# which also didn't fail due to long path names

(mkdir -p erstellt ein Verzeichnis und alle fehlenden Pfadkomponenten).

Ja, wirklich 0,05 Sekunden für 2k rmdir ops. xfs ist ziemlich gut darin, Metadaten-Operationen im Journal zusammen zu stapeln, da sie festlegten, dass Metadaten-Ops wie vor 10 Jahren langsam waren.

Auf ext4, create nahm 0m0.279s, löschen mit find noch 0m0.074s.


6
2018-02-15 05:40



bin neugierig geworden und habe es unter Linux versucht. Es stellt sich heraus, dass die Standard-GNU-Tools mit langen Pfaden allesamt in Ordnung sind, weil sie die Baumstruktur rekursieren, anstatt zu versuchen, Systemaufrufe mit riesigen langen Pfaden zu machen. Sogar mkdir ist in Ordnung, wenn Sie einen 38k-Pfad in der Befehlszeile übergeben! - Peter Cordes


Ich stieß auf das gleiche Problem mit einer 5000+ Verzeichnis-Deep-Ordner Chaos, die einige Java-Anwendung getan hat, und ich schrieb ein Programm, das Ihnen helfen wird, diesen Ordner zu entfernen. Der gesamte Quellcode ist in diesem Link:

https://imanolbarba.net/gitlab/imanol/DiREKT

Es hat nach einer Weile die ganze Sache entfernt, aber es hat es geschafft, die Arbeit zu erledigen, ich hoffe es hilft Leuten, die (wie ich) auf das gleiche frustrierende Problem stoßen


0
2017-08-08 18:35



Bitte posten Sie keine Link-Only-Antworten. Sie sollten die wichtigsten Informationen aus dem Link in der Post selbst eingeben und den Link als Referenz angeben. - Frederik Nielsen
Oh Entschuldigung, es ist ein Programm, und ich wollte wirklich nicht den ganzen Quellcode hier posten ... Ich denke, es ist ziemlich klar dass ich ein Programm, und ich bin Hosting es unter diesem Link, und die Motivation und alles ist in der Antwort, so sieht es ziemlich klar für mich, es ist kein Link-einzige Antwort, nontheless, schrieb werde ich angeben (deutlicher) dass es eine Software ist, die ausgeführt werden soll, um dieses Problem zu lösen - Imanol Barba Sabariego


Ich hatte dies auch in einem eigenständigen Windows 10-System. C: \ User \ Name \ Wiederholen \ Wiederholen \ Wiederholen \ Wiederholen \ Wiederholen \ Wiederholen \ Wiederholen bis unendlich.

Ich konnte mithilfe von Windows oder der Eingabeaufforderung über die 50. und nicht weiter navigieren. Ich konnte es nicht löschen oder auf es klicken usw.

C ist meine Sprache, also schrieb ich schließlich ein Programm mit einer Schleife von Systemaufrufen, die sich wiederholen, bis sie fehlschlagen. Sie könnten dies in jeder Sprache tun, sogar DOS-Batch. Ich habe ein Verzeichnis namens tmp erstellt und Repeat \ Repeat in das Verzeichnis verschoben, den jetzt leeren Repeat-Ordner gelöscht und tmp \ Repeat zurück in den aktuellen Ordner verschoben. Wieder und wieder!

 while (times<2000)
 {
  ChkSystem("move Repeat\\Repeat tmp");
  ChkSystem("rd Repeat");
  ChkSystem("move tmp\\Repeat Repeat");
  ++times;
  printf("Removed %d nested so far.\n", times);
 }

ChkSystem führt nur einen Aufruf von system () aus und überprüft den Rückgabewert, wobei er bei einem Fehler anhält.

Wichtig ist, dass es mehrmals fehlgeschlagen ist. Ich dachte, mein Programm würde vielleicht nicht funktionieren oder es wäre unendlich lang. Allerdings hatte ich dies zuvor mit Systemaufrufen, mit Dingen, die nicht synchronisiert, so dass ich nur das Programm erneut ausgeführt und es von dort fortgesetzt, wo es aufgehört hat, also nicht sofort denken, dass Ihr Programm nicht funktioniert. Insgesamt also, nachdem ich es etwa 20 Mal ausgeführt hatte, löschte es alle. Insgesamt waren es ursprünglich ungefähr 1280 Ordner. Keine Ahnung, was es verursacht hat. Verrückt.


0
2018-03-31 16:24