Vraag Een (blijkbaar) oneindig recursieve map verwijderen


Op de een of andere manier heeft een van onze oude Server 2008 (niet R2) -dozen een schijnbaar oneindig veel recursieve map ontwikkeld. Dit is havent met onze back-ups, omdat de back-upagent zich probeert terug te traceren in de map en nooit terugkeert.

De mappenstructuur ziet er ongeveer zo uit:

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

... enzovoorts. Het is als een van die Mandelbrot gaat zitten waar we vroeger allemaal mee speelden in de jaren 90.

Ik heb geprobeerd:

  • Verwijderen uit Verkenner. Ja, ik ben een optimist.
  • RMDIR C:\Storage\Folder1 /Q/S - dit komt terug The directory is not empty
  • ROBOCOPY C:\temp\EmptyDirectory C:\Storage\Folder1 /PURGE - dit draait een paar minuten door de mappen voordat robocopy.exe crasht.

Kan iemand een manier voorstellen om deze map voorgoed te vermoorden?


45
2018-02-12 11:12


oorsprong


Ik zou het proberen /MIR in plaats daarvan: ROBOCOPY /MIR C:\temp\EmptyDirectory C:\Storage\Folder1 het kan ook de moeite waard zijn om a te spelen chkdsk alleen voor giechelt. - jscott
/MIR leek langer te duren, maar uiteindelijk ook gebombardeerd ("robocopy is gestopt met werken"). Ik ben een beetje bang om een ​​te doen chkdsk; dit is een behoorlijk oude server en ik ben bang dat dit probleem wijst op grotere problemen met het bestandssysteem ... - KenD
Probeer op te starten vanaf een Linux (Ubuntu / Centos / Fedora / ...) desktop proef CD en verwijder de map van daar. - Guntram Blohm
@KenD Als u problemen met de corruptie van het bestandssysteem vermoedt, moet u zeker proberen eerst het bestandssysteem te repareren. Het proberen van trucjes om de directory te verwijderen kan de zaken alleen maar erger maken. - jscott
Omdat (van je antwoord hieronder), de directory niet oneindig was, gewoon heel diep, als je dat had gedaan cygwin of UnxUtils geïnstalleerd, zou je kunnen gebruiken find om een ​​diepte eerste directory verwijdering te doen: find Storage/Folder1 -depth -exec rmdir {} \; - Johnny


antwoorden:


Iedereen bedankt voor het nuttige advies.

Ik pas goed op StackOverflow-territorium en heb het probleem opgelost door dit codefragment van C # -code op te heffen. Het gebruikt de Delimon.Win32.IO bibliotheek die specifiek problemen aanpakt die toegang hebben tot lange bestandspaden.

Voor het geval dit iemand anders kan helpen, hier is de code - het kwam door de ~ 1600 niveaus van recursie die ik op de een of andere manier had volgehouden en nam ongeveer 20 minuten om ze allemaal te verwijderen.

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



Ik heb het geprobeerd, zelfs met de Delimon-versie van .Delete (in plaats van normaal System.IO versie), en hoewel het geen uitzondering gaf, leek het niets te doen. Zeker, de recursie met bovenstaande methode duurde eeuwen, en .Delete kauwde alleen op dingen gedurende 5-10 seconden. Misschien heeft het een paar mappen verwijderd en toen opgegeven? - KenD
Heb je ooit uitgevonden hoe dat is gebeurd om mee te beginnen? Klinkt als de fout van een aantal zeer slecht geschreven gebruikerslandprogramma's. - Parthian Shot
Herinneringen aan een functie 1600 keer? Stapel overloop grondgebied inderdaad! - Aleksandr Dubinsky
Even terzijde, werden de mappen door iets gevuld? Als u kunt bepalen met welke intervallen de recursieve mappen zijn gemaakt en vermenigvuldig dat met het aantal recursies, krijgt u (hopelijk) een ruw tijdsbestek waarin dit probleem begon ... - Get-HomeByFiveOClock
Wauw, leuk dat je dit hebt opgelost. Ter informatie, de officiële door Microsoft ondersteunde oplossing voor dit soort situaties is "het volume opnieuw formatteren". Ja, serieus. : / - HopelessN00b


Kan een recursief knooppunt zijn. Gemaakt met zoiets junction een bestand en schijfhulpprogramma van Sysinternals.

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

En je kunt nu eindeloos naar beneden gaan c: \ Hallo \ Hallo \ Hallo .... (goed totdat MAX_PATH is bereikt, 260 tekens voor de meeste opdrachten, maar 32.767 tekens voor sommige Windows API-functies).

Een mappenlijst laat zien dat het een knooppunt is:

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:\>

Om het junction-hulpprogramma te verwijderen:

junction -d c:\Hello\Hello

25
2018-02-12 13:28



Helaas, een DIR laat me gewoon ole-directory's zien - geen teken van kruispunten die ik vrees - KenD
Kunt u een snelle dubbele controle doen met junction -s C:\Storage\Folder1  ? - Brian
No reparse points found :( - KenD
Ik vraag me af wat zo'n puinhoop van werkelijke submappen heeft gemaakt. - Brian
Gebruik dir /a om '<JUNCTION>' te zien zonder de specifieke naam op te geven. - Chloe


Geen antwoord, maar ik heb niet voldoende rep voor een reactie.

Ik heb dit probleem ooit opgelost op een toenmalige enorme 500 MB FAT16-schijf op een MS-DOS-systeem. Ik gebruikte DOS-foutopsporing om handmatig te dumpen en te parseren via de maplijst. Vervolgens heb ik een bit omgedraaid om de recursieve map als verwijderd te markeren. Mijn exemplaar van Dettman en Wyatt 'DOS Programmers' Reference 'heeft me de weg gewezen.

Ik ben hier nog steeds buitengewoon trots op. Ik zou verbaasd en doodsbang zijn als er een tool voor algemene doeleinden is die zoveel macht heeft over FAT32- of NTFS-volumes. Het leven was toen eenvoudiger.


16
2018-02-13 14:06



Ik zou zeggen dat je dat bent terecht trots op dit. - mfinni
+1 heb een antwoord op mij. Leuke oplossing. - Chris Thornton
U kunt nu de eerste zin van uw antwoord verwijderen. - A.L
Dit is geen antwoord. Het is een verhaal over een ander besturingssysteem en een ander bestandssysteem. Naast dat het geen hulp biedt voor dit (NT, NTFS) probleem, zou het zelfs iemand met hetzelfde probleem (DOS, FAT16) niet helpen, omdat het feitelijk geen details bevat. - Andrew Medico
@Andrew Medico: ik ben het met je eens, vandaar mijn eerste zin. Maar ik vertel je wel waar je de info kunt vinden om het enigszins gerelateerde probleem op te lossen. - Richard


Java kan ook omgaan met lange bestandspaden. En het kan het ook een stuk sneller doen. Deze code (die ik heb gekopieerd uit de Java API-documentatie) verwijdert een 1600-niveau diepe directorystructuur in ongeveer 1 seconde (onder Windows 7, Java 8.0) en zonder risico van stackoverloop, omdat het geen recursie gebruikt.

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



Ik haat jou. Je hebt me gedwongen een antwoord te overtreffen dat Java gebruikt, en nu voel ik me helemaal smerig. Ik moet nodig douchen. - HopelessN00b
Mijn verontschuldigingen. Ik hoop dat je uiteindelijk zult herstellen van je trauma. Maar is een taal ontwikkeld door Microsoft (c #) echt veel beter? - SpiderPig
Ik ben tegenwoordig vooral een Windows-man, dus ja, ja dat is het. Ik kan ook verbitterd en bevooroordeeld zijn tegen Java vanwege het feit dat ik 5 specifieke, verschillende versies van JRE heb moeten onderhouden bij bijna 1.000 klanten in de omgeving van mijn werkgever, waarvan er een uit 2009 dateert, vanwege de onzin, malware ... zakelijke softwarepakketten die we gebruiken voor bedrijfskritieke applicaties. - HopelessN00b


Je hebt geen lange padnamen nodig als je chdir in de directory en gebruik gewoon relatieve paden naar rmdir.

Of, als u een POSIX-shell hebt geïnstalleerd, of port deze naar het DOS-equivalent:

# 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

(Het gebruik van een shell-variabele om bij te houden waar je de naam van de lus hebt gewijzigd, is het andere alternatief voor het uitrollen van de lus, zoals ik dat heb gedaan.)

Dit vermijdt de CPU-overhead van de oplossing van KenD, die het OS dwingt om de boom van de top naar de top te doorlopen nHet niveau elke keer dat een nieuw niveau wordt toegevoegd, controle van toestemmingen enz. Dat is zo sum(1, n) = n * (n-1) / 2 = O(n^2)tijd complexiteit. Oplossingen die een brok wegknallen vanaf het begin van de keten zouden moeten zijn O(n), tenzij Windows een tree moet doorlopen bij het hernoemen van de bovenliggende directory. (Linux / Unix doet dat niet.) Oplossingen die chdir helemaal tot aan de onderkant van de boom en gebruik relatieve paden vanaf daar, mappen verwijderen als ze chdir een back-up zou ook moeten zijn O(n), ervan uitgaande dat het besturingssysteem niet alle moederfolders hoeft te raadplegen bij elke systeemaanroep, als je dingen doet terwijl je ergens een CD hebt gemaakt.

find Folder1 -depth -execdir rmdir {} + zal rmdir uitvoeren terwijl het wordt CDed naar de diepste map. Of eigenlijk, vind's -delete optie werkt op mappen en houdt in -depth. Zo find Folder1 -delete zou precies hetzelfde moeten doen, maar dan sneller. Ja, GNU vind op Linux neerdaalt door een map te scannen, vervolgens naar submappen met relatieve paden te CD-en rmdir met een relatief pad, dan chdir(".."). Het nascan niet mappen opnieuw tijdens het opstijgen, dus het zou verbruiken O(n) RAM.

Dat was echt een benadering: strace laat zien dat het WERKELIJK gebruikt unlinkat(AT_FDCWD, "tmp", AT_REMOVEDIR), open("..", O_DIRECTORY|...), en fchdir(the fd from opening the directory), met een aantal fstat oproepen ook gemengd. Maar het effect is hetzelfde als de mappenstructuur niet wordt gewijzigd terwijl Zoeken actief is.

edit: alleen voor de kicks, probeerde ik dit op GNU / Linux (Ubuntu 14.10, op een 2,4 GHz first-gen Core2Duo CPU, op een XFS-bestandssysteem op een WD 2.5TB Green Power-drive (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 maakt een map en eventuele ontbrekende padcomponenten).

Ja, echt 0,05 seconden voor 2k rmdir ops. xfs is best goed in het samenstellen van metadata-bewerkingen in het journaal, omdat ze metadata-ops hebben gerepareerd die traag zijn zoals 10 jaar geleden.

Op ext4 nam create 0m0.279s, verwijderen met find nam nog steeds 0m0.074s.


6
2018-02-15 05:40



werd nieuwsgierig en probeerde het op Linux. Blijkt dat de standaard GNU-tools prima werken met lange paden, omdat ze de boom recursief maken in plaats van te proberen systeemaanroepen te maken met gigantische lange paden. Zelfs mkdir is prima als je het een 38k pad geeft op de opdrachtregel! - Peter Cordes


Ik kwam hetzelfde probleem tegen met een 5000+ map-deep map-fout die een bepaalde Java-applicatie deed en ik heb een programma geschreven dat je zal helpen deze map te verwijderen. De hele broncode staat in deze link:

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

Het heeft het hele ding na een tijdje verwijderd, maar het is gelukt om het werk te doen, ik hoop dat het mensen helpt die (als ik) dezelfde frustrerende kwestie tegenkomen


0
2017-08-08 18:35



Plaats geen antwoorden met alleen een link. Je moet de belangrijkste informatie van de link in de post zelf zetten en de link ter referentie aanbieden. - Frederik Nielsen
Oh sorry, het is een programma en ik wilde echt niet ALLE broncode hier plaatsen ... ik denk van wel vrij duidelijk dat ik een programma heb geschreven en dat ik het host door deze link te volgen, en de motivatie en alles is in het antwoord, dus het lijkt me vrij duidelijk dat het geen antwoord is, maar ik zal (duidelijker) specificeren dat het een software is die bedoeld is om te worden gebruikt om dit probleem op te lossen - Imanol Barba Sabariego


Ik had dit ook op een zelfstandig Windows 10-systeem. C: \ User \ Name \ Repeat \ Repeat \ Repeat \ Repeat \ Repeat \ Repeat \ Herhaal schijnbaar oneindig.

Ik zou kunnen navigeren met Windows of Command Prompt naar ongeveer de 50ste en niet verder. Ik kon het niet verwijderen, of erop klikken, enz.

C is mijn taal dus uiteindelijk schreef ik een programma met een lus van systeemoproepen, die herhaald worden tot ze falen. Je zou dit in elke taal kunnen doen, zelfs in DOS-batch. Ik heb een map gemaakt met de naam tmp en heb Repeat \ Repeat hierin verplaatst, de nu lege map Repeat gewist en tmp \ Repeat naar de huidige map verplaatst. Opnieuw en opnieuw!

 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 draait gewoon een system () aanroep en controleert de geretourneerde waarde, stopt als het niet lukt.

Belangrijk is dat het een aantal keren mislukt is. Ik dacht dat mijn programma misschien niet werkte, of dat het uiteindelijk toch oneindig lang was. Ik heb dit echter al eerder gehad met systeemaanroepen, waarbij de dingen niet synchroon liepen, dus ik heb het programma opnieuw uitgevoerd en het ging door van waar het was gebleven, dus denk niet meteen dat je programma niet werkt. Dus in totaal, na het ongeveer 20 keer te hebben gebruikt, heeft het ze allemaal gewist. In totaal waren het oorspronkelijk ongeveer 1280 mappen diep. Geen idee wat de oorzaak was. Gek.


0
2018-03-31 16:24