14 KiB
LIAM NTFS / DFS Pfadklassifikation - Zielkonzept
Ziel
Dieses Dokument beschreibt ein belastbares Zielkonzept fuer die Klassifikation von UNC-Pfaden im LIAM-NTFS-Provider.
Der aktuelle Code behandelt die Unterscheidung zwischen Share und Folder im Wesentlichen ueber die Pfadtiefe. Das ist fuer einfache klassische UNC-Freigaben teilweise ausreichend, aber fachlich nicht robust genug.
Insbesondere folgende Faelle sollen perspektivisch sauber unterstuetzt werden:
\\server\\server\share\\server\share\folder\\server\namespace\\server\namespace\link\\server\namespace\link\folder
Das Konzept ist bewusst noch keine Implementierung. Es beschreibt, welche semantischen Informationen benoetigt werden und wie die Entscheidung logisch aufgebaut sein sollte.
Problem des aktuellen Ansatzes
Der bestehende NTFS-Provider leitet den Objekttyp im Kern aus der Anzahl der UNC-Segmente ab.
Beispiel:
\\server\share-> wird als Share behandelt\\server\share\folder-> wird als Folder behandelt
Das hat mehrere fachliche Schwaechen:
- Ein DFS-Link wie
\\server\namespace\linkist semantisch oft ein Share-aehnlicher Einstiegspunkt, hat aber drei Segmente. - Ein Root wie
\\serverist mit der bisherigen Logik ueberhaupt nicht sinnvoll modellierbar. LoadDataArea()undgetDataAreasAsync()arbeiten nicht zwingend mit derselben Semantik.- Die Klassifikation basiert auf Syntax statt auf den tatsaechlichen Freigabe- und Namespace-Metadaten.
Die Folge ist, dass bei DFS und bei kuenftigem Server-Root-Support keine verlaessliche Typbestimmung moeglich ist.
Grundprinzip der richtigen Loesung
Die Klassifikation darf nicht von der Pfadtiefe abhaengen, sondern muss aus der tatsaechlichen Bedeutung des Pfads ermittelt werden.
Das bedeutet:
- Ein klassischer Windows-Share wird ueber Share-Metadaten erkannt.
- Ein DFS-Namespace oder DFS-Link wird ueber DFS-Metadaten erkannt.
- Ein Folder ist ein Pfad, der unterhalb eines Share- oder Link-Grenzpunkts liegt.
Die zentrale Regel lautet daher:
Nicht fragen "Wie tief liegt der Pfad?", sondern "Welches Namensobjekt repraesentiert dieser Pfad fachlich?".
Fachliche Objektarten
Fuer eine robuste interne Modellierung sollten mehr Typen unterschieden werden als nur Share und Folder.
Empfohlenes internes Zielmodell:
ServerRootClassicShareDfsNamespaceRootDfsLinkFolderUnknown
Nach aussen kann das bei Bedarf weiter auf bestehende LIAM-Typen gemappt werden:
ClassicShare->NtfsShareDfsNamespaceRoot-> je nach fachlicher EntscheidungNtfsShareoder Container-TypDfsLink->NtfsShareFolder->NtfsFolder
Der entscheidende Punkt ist, dass intern sauber unterschieden wird, auch wenn die externe API zunaechst kompatibel bleiben soll.
Semantische Datenquellen
1. Klassische Windows-Freigaben
Fuer klassische Shares ist die sichere Quelle die Share-Konfiguration des Zielservers.
Fachlich wird geprueft:
- Welche Shares existieren auf dem Server?
- Welcher UNC-Pfad repraesentiert exakt einen Share?
- Auf welchen lokalen Zielpfad zeigt der Share?
Aus dieser Sicht gilt:
\\server\shareist ein Share, wenn auf dem Server genau dieser Share publiziert ist.- Jeder Pfad unterhalb davon ist ein Folder.
2. DFS
Fuer DFS reicht die Share-Liste nicht aus.
Hier muss zusaetzlich geprueft werden:
- Ist
\\server\namespaceein DFS-Namespace-Root? - Ist
\\server\namespace\linkein DFS-Link? - Welche Link-Ziele sind hinterlegt?
Aus dieser Sicht gilt:
\\server\namespaceist ein Namespace-Objekt, nicht einfach nur ein Folder.\\server\namespace\linkist fachlich ein Share-aehnlicher Einstiegspunkt.- Jeder Pfad unterhalb eines DFS-Links ist ein Folder.
Zielbild fuer Roots
Fall 1: Root ist \\server
Wenn \\server als Root erlaubt sein soll, muss die erste Ebene alle publizierten Einstiegspunkte des Servers liefern.
Das bedeutet:
- klassische Shares des Servers
- DFS-Namespaces, die ueber diesen Server angesprochen werden koennen
- administrative Shares wie
C$,ADMIN$,IPC$sollten in der Regel herausgefiltert werden
Unter \\server duerfen also nicht einfach Dateisystemordner enumeriert werden. Stattdessen werden Namensobjekte auf Server-Ebene enumeriert.
Beispiele:
\\server\shareA->ClassicShare\\server\dfs->DfsNamespaceRoot\\server\shareA\team1->Folder\\server\dfs\link1->DfsLink
Fall 2: Root ist \\server\share
Bei einem klassischen Share als Root ist die Bedeutung eindeutig:
- Root selbst ist
ClassicShare - alle darunter liegenden Eintraege sind
Folder
Hier ist die fachliche Share-Grenze der Root-Pfad selbst.
Fall 3: Root ist \\server\namespace
Bei einem DFS-Namespace als Root muss die erste Ebene nicht als Folderliste, sondern als Namespace-Inhaltsliste verstanden werden.
Typischerweise bedeutet das:
- Root selbst ist
DfsNamespaceRoot - direkte Kinder koennen
DfsLink-Objekte sein - alles unterhalb eines
DfsLinkistFolder
Ob der Namespace-Root selbst nach aussen als NtfsShare oder als eigener Container-Typ behandelt wird, ist eine fachliche API-Entscheidung.
Fall 4: Root ist \\server\namespace\link
Wenn der Root-Pfad bereits ein DFS-Link ist, dann gilt:
- Root selbst ist
DfsLink - alles darunter ist
Folder
Fuer die bestehende LIAM-Semantik waere das nach aussen typischerweise ein NtfsShare.
Empfohlene zentrale Klassifikationslogik
Die Klassifikation sollte in einer einzigen zentralen Komponente gebuendelt werden.
Wichtig ist:
getDataAreasAsync()muss dieselbe Logik verwenden wieLoadDataArea()- die UI, Workflow-Aktivitaeten und Web-API duerfen nicht jeweils eigene Heuristiken haben
Empfohlenes konzeptionelles Interface:
ClassifyPath(path) -> PathClassification
EnumerateChildren(path) -> List<PathClassification>
Eine PathClassification sollte mindestens enthalten:
NormalizedPathKindDisplayNameBoundaryPathParentBoundaryPathBackingTypewieSMBoderDFS- optionale Diagnoseinformationen zur Herleitung
Empfohlene Entscheidungsreihenfolge
Die Aufloesung eines Pfads sollte in einer festen Reihenfolge passieren.
Schritt 1: Pfad normalisieren
Vor jeder Klassifikation:
- UNC-Pfad vereinheitlichen
- doppelte Separatoren bereinigen
- optional Gross-/Kleinschreibung fuer Vergleiche normalisieren
- Trailing Backslash konsistent behandeln
Beispiele:
\\server\share\\\SERVER\share\\server\\share
sollten intern auf einen stabilen Vergleichswert normalisiert werden.
Schritt 2: Root-Typ erkennen
Zuerst wird geprueft, ob der Pfad einer dieser Grundtypen ist:
- Server-Root
- klassischer Share
- DFS-Namespace-Root
- DFS-Link
- Folder unterhalb eines bekannten Grenzpunkts
Schritt 3: DFS zuerst pruefen
Fuer UNC-Pfade mit mehreren Segmenten sollte zuerst geprueft werden, ob ein Pfad oder ein Pfadpraefix ein DFS-Namespace oder DFS-Link ist.
Der Grund:
- DFS kann Pfade erzeugen, die syntaktisch wie normale Ordner wirken
- semantisch sind sie aber eigenstaendige Einstiegspunkte
Wenn ein Praefix als DFS-Link identifiziert wird, ist dieses Praefix die fachliche Share-Grenze.
Beispiel:
- Pfad:
\\server\namespace\link\teamA\finance - erkannter DFS-Link:
\\server\namespace\link - Klassifikation des Gesamtpfads:
Folder - fachlicher Parent-Share:
\\server\namespace\link
Schritt 4: Klassische Shares pruefen
Wenn kein DFS-Fall vorliegt, wird geprueft, ob der Pfad oder ein Praefix einem klassischen Share entspricht.
Beispiel:
- Pfad:
\\server\share\dept\project - erkannter Share:
\\server\share - Klassifikation des Gesamtpfads:
Folder - fachlicher Parent-Share:
\\server\share
Schritt 5: Fallback nur kontrolliert verwenden
Wenn weder DFS noch klassischer Share sicher ermittelt werden kann:
- nicht blind ueber Segmentzahl entscheiden
- stattdessen
Unknownliefern oder einen explizit konfigurierten Fallback nutzen
Das ist wichtig, damit Unsicherheit nicht als scheinbar sichere Fachlogik maskiert wird.
Share-Grenze als zentrales Konzept
Ein hilfreiches Kernmodell ist die sogenannte Share-Grenze.
Die Share-Grenze ist der fachliche Einstiegspunkt, unterhalb dessen normale Folder-Hierarchie beginnt.
Beispiele:
\\server\share-> Share-Grenze bei klassischem SMB-Share\\server\namespace\link-> Share-Grenze bei DFS-Link
Ein Pfad wird damit nicht nur als Share oder Folder klassifiziert, sondern auch relativ zu seiner Share-Grenze verstanden.
Das ist fuer mehrere Dinge wichtig:
- korrektes Setzen von
ParentUID - konsistente Anzeige des Root-Objekts
- korrektes Nachladen von Kindern
- spaetere Berechtigungs- oder Traverselogik
Zielverhalten fuer typische Beispiele
Beispiel A: Klassische Freigabe
\\filesrv\finance->ClassicShare\\filesrv\finance\2026->Folder\\filesrv\finance\2026\plan.xlsx-> fuer LIAM ggf. ausserhalb des Scope, falls nur Ordner modelliert werden
Beispiel B: DFS-Namespace
\\dfs01\file_shares->DfsNamespaceRoot\\dfs01\file_shares\shareA->DfsLink\\dfs01\file_shares\shareA\team1->Folder
Beispiel C: Server-Root
\\dfs01->ServerRoot- Kind
\\dfs01\file_shares->DfsNamespaceRoot - Kind
\\dfs01\public->ClassicShare
Beispiel D: Gemischte Landschaft
Ein Server kann gleichzeitig hosten:
- klassische Shares
- DFS-Namespaces
- administrative Shares
Die Enumeration unter \\server muss daher bewusst entscheiden, welche publizierten Namensobjekte sichtbar gemacht werden und welche nicht.
Konsequenzen fuer die LIAM-Architektur
1. Eine gemeinsame Path-Classification-Schicht
Die Logik darf nicht in mehreren Stellen verteilt bleiben.
Stattdessen sollte es eine zentrale Schicht geben, die:
- Pfade klassifiziert
- Kindobjekte enumeriert
- die Share-Grenze mitliefert
- Diagnoseinformationen fuer Logging bereitstellt
2. LoadDataArea() und getDataAreasAsync() muessen dieselbe Semantik teilen
Beide Methoden muessen dieselbe Klassifikation verwenden.
Sonst entsteht wieder ein Fehlerbild wie heute:
- Listenansicht liefert einen Typ
- Einzelaufladung liefert einen anderen Typ
Das ist fachlich unzulaessig.
3. Die Konstruktion von LIAM-Datenobjekten muss auf Klassifikation folgen
Nicht:
- Pfadtiefe bestimmen
- direkt
cLiamNtfsShareodercLiamNtfsFoldererzeugen
Sondern:
- Pfad klassifizieren
- daraus internes
Kindbestimmen - danach passendes LIAM-Objekt erzeugen
4. Nach aussen kann die API zunaechst kompatibel bleiben
Wenn eine API-Aenderung vermieden werden soll, koennen intern mehrere Arten von Share-artigen Objekten existieren, die nach aussen zunaechst auf NtfsShare gemappt werden.
Beispiel:
ClassicShare->NtfsShareDfsLink->NtfsShareDfsNamespaceRoot-> je nach Entscheidung ebenfallsNtfsShareoder eigener Typ spaeter
So laesst sich die Semantik verbessern, ohne sofort alle Konsumenten anpassen zu muessen.
Technische Grenzen und Realitaet
Die sichere Ermittlung ist programmatisch grundsaetzlich moeglich, aber an Infrastrukturbedingungen gebunden.
Moegliche Einschraenkungen:
- fehlende Rechte fuer Share- oder DFS-Abfragen
- Firewall- oder RPC-Beschraenkungen
- temporaer nicht verfuegbare Server
- unterschiedliche Betriebsweisen in der Kundenumgebung
Deshalb ist ein kontrollierter Unsicherheitszustand wichtig.
Empfohlene Regel:
- wenn die Semantik sicher ermittelt werden kann, klaren Typ liefern
- wenn die Semantik nicht sicher ermittelt werden kann,
Unknownoder einen expliziten diagnostischen Fehler liefern - nicht stillschweigend auf reine Pfadtiefe zurueckfallen, wenn dadurch fachlich falsche Typen entstehen
Empfohlene Implementierungsstrategie in Etappen
Etappe 1: Fachmodell einziehen
Intern neue Klassifikationsarten definieren:
ServerRootClassicShareDfsNamespaceRootDfsLinkFolderUnknown
Etappe 2: Zentrale Klassifikationskomponente bauen
Eine zentrale Komponente einfuehren, die:
- Pfade normalisiert
- Typen klassifiziert
- Share-Grenzen bestimmt
- Kinder kontextabhaengig enumeriert
Etappe 3: LoadDataArea() umstellen
LoadDataArea() sollte zuerst die neue Klassifikation verwenden, weil dort der heutige Fehlpfad am deutlichsten sichtbar ist.
Etappe 4: getDataAreasAsync() umstellen
Danach den Listenpfad auf dieselbe Klassifikation bringen.
Etappe 5: API-Mapping pruefen
Danach bewerten:
- reicht extern weiter
NtfsShare/NtfsFolder - oder wird spaeter ein eigener Typ fuer Namespace-Container benoetigt
Entscheidungspunkte, die fachlich geklaert werden muessen
Vor einer spaeteren Implementierung sollten einige Punkte explizit entschieden werden:
- Soll
\\serverals sichtbares DataArea-Objekt existieren oder nur als Enumerationsroot? - Soll ein DFS-Namespace-Root nach aussen als
NtfsSharegelten oder als eigener Container? - Sollen nur DFS-Links als Share-aehnliche Objekte gelten?
- Sollen administrative Shares immer ausgeblendet werden?
- Wie soll sich das System bei fehlenden Rechten fuer DFS-/Share-Abfragen verhalten?
Ohne diese Entscheidungen wird die technische Umsetzung sonst schnell inkonsistent.
Fazit
Die bisherige Heuristik "Pfadtiefe bestimmt Share oder Folder" ist fuer eine Umgebung mit klassischen Shares, DFS und kuenftigem \\server-Root nicht ausreichend.
Das richtige Zielbild ist:
- zentrale semantische Pfadklassifikation
- Unterscheidung von Server, klassischem Share, DFS-Namespace, DFS-Link und Folder
- gemeinsame Logik fuer Listen- und Einzel-Ladepfad
- externe Rueckgabe weiterhin kompatibel, intern aber fachlich korrekt modelliert
Nur mit diesem Ansatz koennen spaeter sowohl klassische Freigaben als auch DFS-Strukturen sauber und nachvollziehbar behandelt werden.