Add DFS metadata classification concept
This commit is contained in:
396
Sonstiges/LIAM_NTFS_DFS_Metadaten_Klassifikation_Konzept.md
Normal file
396
Sonstiges/LIAM_NTFS_DFS_Metadaten_Klassifikation_Konzept.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# LIAM NTFS / DFS Metadaten-Klassifikation - konkretes Umsetzungskonzept
|
||||
|
||||
## Ziel
|
||||
|
||||
Dieses Dokument beschreibt die konkrete Zielumsetzung fuer die robuste Klassifikation von UNC-Pfaden im LIAM-NTFS-Provider.
|
||||
|
||||
Rahmenbedingungen:
|
||||
|
||||
- keine Erweiterung der bestehenden Provider-Config
|
||||
- der Code darf nicht voraussetzen, auf dem DFS- oder SMB-Server selbst zu laufen
|
||||
- DFS-Strukturen koennen unterschiedlich aufgebaut sein
|
||||
- es muss sauber unterschieden werden zwischen:
|
||||
- klassischem SMB-Share
|
||||
- DFS-Namespace-Root
|
||||
- DFS-Link
|
||||
- echtem Folder
|
||||
|
||||
Die bestehende Config liefert dafuer nur den Einstiegspunkt und die Zugriffsrechte:
|
||||
|
||||
- `RootPath`
|
||||
- `Domain`
|
||||
- `Credential`
|
||||
|
||||
Die eigentliche Typbestimmung muss daher zur Laufzeit ueber Metadaten des adressierten UNC-Pfads erfolgen.
|
||||
|
||||
## Kurzfazit
|
||||
|
||||
Die robuste Loesung ist:
|
||||
|
||||
1. UNC-Pfad normalisieren
|
||||
2. DFS-Metadaten fuer den Pfad und relevante Praefixe abfragen
|
||||
3. wenn kein DFS-Treffer vorliegt, SMB-Share-Metadaten abfragen
|
||||
4. alles unterhalb einer erkannten fachlichen Grenze als Folder behandeln
|
||||
|
||||
Die aktuelle Segment-Heuristik wird damit ersetzt, nicht nur verbessert.
|
||||
|
||||
## Fachregeln
|
||||
|
||||
Es gelten folgende semantische Regeln:
|
||||
|
||||
- `\\server\\namespace` ist ein `DfsNamespaceRoot`, wenn der Pfad als DFS-Namespace-Root aufgeloest werden kann.
|
||||
- `\\server\\namespace\\link` ist ein `DfsLink`, wenn der Pfad als DFS-Link aufgeloest werden kann.
|
||||
- `\\server\\share` ist ein `ClassicShare`, wenn der Share auf dem Server publiziert ist und kein DFS-Treffer vorliegt.
|
||||
- jeder Pfad unterhalb eines `DfsLink` ist ein `Folder`
|
||||
- jeder Pfad unterhalb eines `ClassicShare` ist ein `Folder`
|
||||
- jeder Pfad unterhalb eines `DfsNamespaceRoot`, aber oberhalb eines `DfsLink`, ist nur dann `Folder`, wenn er kein DFS-Link ist und fachlich wirklich Dateisystemstruktur repraesentiert; fuer den Normalfall sind direkte Kinder eines Namespace-Roots als DFS-Links zu erwarten
|
||||
|
||||
## Verwendbare Laufzeit-Metadaten
|
||||
|
||||
### 1. DFS-Metadaten
|
||||
|
||||
Primaere Quelle fuer DFS:
|
||||
|
||||
- Win32 DFS API, bevorzugt `NetDfsGetInfo`
|
||||
|
||||
Damit kann fuer einen UNC-Pfad geprueft werden:
|
||||
|
||||
- ist der Pfad ein DFS-Objekt?
|
||||
- handelt es sich um Root oder Link?
|
||||
- welche Targets sind hinterlegt?
|
||||
|
||||
Wichtig:
|
||||
|
||||
- diese Abfrage funktioniert remote gegen den adressierten Namespace
|
||||
- sie benoetigt keine lokale Ausfuehrung auf dem DFS-Server
|
||||
- sie ist fachlich deutlich verlaesslicher als `Directory.Exists(...)`
|
||||
|
||||
### 2. SMB-Share-Metadaten
|
||||
|
||||
Primaere Quelle fuer klassische Shares:
|
||||
|
||||
- `NetShareEnum`
|
||||
- optional ergaenzend `NetShareGetInfo`
|
||||
|
||||
Das ist fuer LIAM bereits teilweise vorhanden:
|
||||
|
||||
- `cNetworkConnection.EnumNetShares(server)`
|
||||
|
||||
Damit kann geprueft werden:
|
||||
|
||||
- ob `\\server\\share` ein echter publizierter SMB-Share ist
|
||||
- welche sichtbaren Disk-Shares auf dem Host existieren
|
||||
|
||||
### 3. Dateisystem-Metadaten
|
||||
|
||||
Nur fuer Folder:
|
||||
|
||||
- `Directory.Exists`
|
||||
- `DirectoryInfo`
|
||||
|
||||
Diese Daten duerfen nicht fuer die Unterscheidung zwischen DFS und Share benutzt werden, sondern nur nachdem bereits eine fachliche Grenze erkannt wurde.
|
||||
|
||||
## Nicht ausreichende Datenquellen
|
||||
|
||||
Folgende Informationen reichen fuer die Typbestimmung nicht aus:
|
||||
|
||||
- Anzahl der UNC-Segmente
|
||||
- `RootPath` alleine
|
||||
- `Directory.Exists`
|
||||
- ACLs
|
||||
- Naming Conventions
|
||||
- Custom Tags
|
||||
- Group Strategy
|
||||
|
||||
Diese Daten koennen ergaenzend helfen, liefern aber keine robuste Aussage ueber DFS vs. SMB.
|
||||
|
||||
## Zielmodell
|
||||
|
||||
Internes Modell:
|
||||
|
||||
- `ServerRoot`
|
||||
- `ClassicShare`
|
||||
- `DfsNamespaceRoot`
|
||||
- `DfsLink`
|
||||
- `Folder`
|
||||
- `Unknown`
|
||||
|
||||
Externe LIAM-Abbildung:
|
||||
|
||||
- `ClassicShare` -> `NtfsShare`
|
||||
- `DfsNamespaceRoot` -> `DfsNamespaceRoot`
|
||||
- `DfsLink` -> `NtfsShare`
|
||||
- `Folder` -> `NtfsFolder`
|
||||
|
||||
Damit bleibt die fachliche Aussenwirkung stabil:
|
||||
|
||||
- DFS-Link bleibt nach aussen ein share-aehnliches Objekt
|
||||
- DFS-Namespace-Root bleibt eigenstaendig sichtbar
|
||||
|
||||
## Konkreter Klassifikationsalgorithmus
|
||||
|
||||
### Schritt 1: Normalisierung
|
||||
|
||||
Jeder Eingabepfad wird zuerst vereinheitlicht:
|
||||
|
||||
- Slash zu Backslash
|
||||
- doppelte Separatoren bereinigen
|
||||
- UNC-Praefix sicherstellen
|
||||
- Trailing Backslash entfernen
|
||||
|
||||
Beispiel:
|
||||
|
||||
- `\\SERVER\\share\\`
|
||||
- `//server/share`
|
||||
|
||||
werden intern zu:
|
||||
|
||||
- `\\server\\share`
|
||||
|
||||
fuer Vergleiche kann case-insensitive gearbeitet werden.
|
||||
|
||||
### Schritt 2: DFS zuerst pruefen
|
||||
|
||||
Fuer den gesamten Pfad und seine relevanten Praefixe werden DFS-Metadaten geprueft.
|
||||
|
||||
Beispiele:
|
||||
|
||||
- bei `\\server\\namespace\\link\\folder`
|
||||
- pruefe `\\server\\namespace`
|
||||
- pruefe `\\server\\namespace\\link`
|
||||
|
||||
Entscheidungsregel:
|
||||
|
||||
- wenn der volle Pfad ein DFS-Namespace-Root ist -> `DfsNamespaceRoot`
|
||||
- wenn der volle Pfad ein DFS-Link ist -> `DfsLink`
|
||||
- wenn ein Praefix ein DFS-Link ist und der Gesamtpfad darunter liegt -> `Folder`
|
||||
- wenn ein Praefix ein DFS-Namespace-Root ist, aber noch kein DFS-Link erkannt wurde, wird weiter geprueft
|
||||
|
||||
Wichtig:
|
||||
|
||||
- der tiefste erkannte DFS-Link gewinnt als fachliche Grenze
|
||||
- die Share-Grenze ist dann genau dieser Link-Pfad
|
||||
|
||||
### Schritt 3: SMB-Share pruefen
|
||||
|
||||
Nur wenn kein DFS-Ergebnis vorliegt:
|
||||
|
||||
- ermittle sichtbare Shares des Servers per `NetShareEnum`
|
||||
- pruefe, ob `\\server\\share` exakt ein publizierter Share ist
|
||||
|
||||
Entscheidungsregel:
|
||||
|
||||
- wenn der volle Pfad exakt einem Share entspricht -> `ClassicShare`
|
||||
- wenn ein Praefix exakt einem Share entspricht und der Gesamtpfad darunter liegt -> `Folder`
|
||||
|
||||
### Schritt 4: Folder nur relativ zu einer erkannten Grenze
|
||||
|
||||
Ein Pfad ist nur dann sicher `Folder`, wenn bereits eine fachliche Grenze erkannt wurde:
|
||||
|
||||
- klassischer Share
|
||||
- DFS-Link
|
||||
|
||||
Beispiele:
|
||||
|
||||
- `\\server\\share\\dept` -> `Folder`, wenn `\\server\\share` ein ClassicShare ist
|
||||
- `\\server\\namespace\\link\\dept` -> `Folder`, wenn `\\server\\namespace\\link` ein DfsLink ist
|
||||
|
||||
### Schritt 5: Unknown statt falscher Sicherheit
|
||||
|
||||
Wenn weder DFS noch SMB sicher bestimmt werden koennen:
|
||||
|
||||
- liefere intern `Unknown`
|
||||
- logge die Ursache
|
||||
- triff keine stille Segment-basierten Fallback-Entscheidung
|
||||
|
||||
## Erforderliche Runtime-Abfragen
|
||||
|
||||
### DFSResolver
|
||||
|
||||
Neue interne Hilfskomponente:
|
||||
|
||||
- `TryGetDfsMetadata(path, out metadata)`
|
||||
|
||||
Rueckgabedaten:
|
||||
|
||||
- `Exists`
|
||||
- `IsNamespaceRoot`
|
||||
- `IsLink`
|
||||
- `Path`
|
||||
- `EntryPath`
|
||||
- `Targets`
|
||||
|
||||
Empfohlene Implementierung:
|
||||
|
||||
- P/Invoke gegen `NetDfsGetInfo`
|
||||
|
||||
Sinnvolle Aufrufmuster:
|
||||
|
||||
- pruefe `\\server\\namespace`
|
||||
- pruefe `\\server\\namespace\\link`
|
||||
- cache Ergebnisse je Pfad
|
||||
|
||||
### ShareResolver
|
||||
|
||||
Bestehende Hilfskomponente weiterverwenden:
|
||||
|
||||
- `EnumNetShares(server)`
|
||||
|
||||
Ergaenzung:
|
||||
|
||||
- optional Hilfsmethode `IsPublishedShare(server, shareName)`
|
||||
- Cache je Server
|
||||
|
||||
## Neue zentrale Datenstruktur
|
||||
|
||||
Empfohlene interne Rueckgabe:
|
||||
|
||||
```text
|
||||
PathClassification
|
||||
- NormalizedPath
|
||||
- Kind
|
||||
- BoundaryPath
|
||||
- ParentBoundaryPath
|
||||
- BackingType
|
||||
- ResolvedFrom
|
||||
- Diagnostics
|
||||
```
|
||||
|
||||
Dabei bedeutet:
|
||||
|
||||
- `BoundaryPath`: fachliche Share-Grenze
|
||||
- `ParentBoundaryPath`: Parent-Objekt fuer LIAM-ParentUID
|
||||
- `BackingType`: `DFS` oder `SMB`
|
||||
- `ResolvedFrom`: z. B. `DfsLinkPrefix`, `SharePrefix`, `FullPathDfsRoot`
|
||||
|
||||
## Verhalten fuer typische Faelle
|
||||
|
||||
### Fall A
|
||||
|
||||
Pfad:
|
||||
|
||||
- `\\SRVWSM001.imagoverum.com\\file_shares`
|
||||
|
||||
Erwartung:
|
||||
|
||||
- wenn DFS-Metadaten Root bestaetigen -> `DfsNamespaceRoot`
|
||||
|
||||
### Fall B
|
||||
|
||||
Pfad:
|
||||
|
||||
- `\\SRVWSM001.imagoverum.com\\file_shares\\share2`
|
||||
|
||||
Erwartung:
|
||||
|
||||
- wenn DFS-Metadaten Link bestaetigen -> intern `DfsLink`, extern `NtfsShare`
|
||||
|
||||
### Fall C
|
||||
|
||||
Pfad:
|
||||
|
||||
- `\\SRVWSM001.imagoverum.com\\file_shares\\share2\\test33`
|
||||
|
||||
Erwartung:
|
||||
|
||||
- wenn `\\...\\file_shares\\share2` als DFS-Link erkannt wurde -> `Folder`
|
||||
|
||||
## Anpassung von `getDataAreasAsync()`
|
||||
|
||||
Die Enumeration darf nicht mehr nur mit `RequestFoldersListAsync(RootPath, depth)` arbeiten.
|
||||
|
||||
Stattdessen:
|
||||
|
||||
- Root zuerst klassifizieren
|
||||
- Kinder je nach Root-Typ enumerieren
|
||||
|
||||
Regeln:
|
||||
|
||||
- `ClassicShare`
|
||||
- Kinder per Dateisystem-Verzeichnisliste
|
||||
- `DfsNamespaceRoot`
|
||||
- direkte Kinder primaer ueber DFS-Namespace-Inhaltsmetadaten
|
||||
- nur diese direkten Kinder sind fachlich Share-aehnliche Eintraege
|
||||
- `DfsLink`
|
||||
- Kinder per Dateisystem-Verzeichnisliste unterhalb des Link-Ziels bzw. unter dem UNC-Linkpfad
|
||||
- `Folder`
|
||||
- Kinder per Dateisystem-Verzeichnisliste
|
||||
|
||||
Der aktuelle Fehler entsteht gerade dadurch, dass direkte Kinder eines DFS-Namespace-Roots wie normale Ordner enumeriert und spaeter wieder als Folder behandelt werden.
|
||||
|
||||
## Anpassung von `LoadDataArea()`
|
||||
|
||||
`LoadDataArea()` muss dieselbe zentrale Klassifikation benutzen wie `getDataAreasAsync()`.
|
||||
|
||||
Wichtig:
|
||||
|
||||
- keine eigene Kurzlogik
|
||||
- keine Typentscheidung ueber Segmentzahl
|
||||
- gleiche `PathClassification` fuer denselben Pfad wie im Listenpfad
|
||||
|
||||
## Logging
|
||||
|
||||
Fuer Diagnosefaelle sollten folgende Logeintraege vorhanden sein:
|
||||
|
||||
- welcher Pfad wird klassifiziert
|
||||
- welcher DFS-Check wurde ausgefuehrt
|
||||
- welcher Share-Check wurde ausgefuehrt
|
||||
- welcher Praefix als Boundary erkannt wurde
|
||||
- warum ein Pfad `Unknown` wurde
|
||||
|
||||
Beispiel:
|
||||
|
||||
- `Path '\\server\\namespace\\link\\team' classified as Folder via DFS link boundary '\\server\\namespace\\link'`
|
||||
|
||||
## Fehlerverhalten
|
||||
|
||||
Wenn DFS-Abfragen fehlschlagen:
|
||||
|
||||
- Fehler loggen
|
||||
- weiter mit SMB-Pruefung
|
||||
|
||||
Wenn SMB-Abfragen fehlschlagen:
|
||||
|
||||
- Fehler loggen
|
||||
- nicht automatisch Folder annehmen
|
||||
|
||||
Wenn beides fehlschlaegt:
|
||||
|
||||
- `Unknown`
|
||||
|
||||
Damit wird falsche Typvergabe vermieden.
|
||||
|
||||
## Performance
|
||||
|
||||
Noetige Caches:
|
||||
|
||||
- DFS-Metadaten-Cache pro Pfad
|
||||
- Share-Liste pro Server
|
||||
|
||||
Empfehlung:
|
||||
|
||||
- innerhalb eines Provider-Laufs cachen
|
||||
- keine globale Langzeitpersistenz
|
||||
|
||||
## Konkrete Implementierungsschritte
|
||||
|
||||
1. neue interne Resolver-Komponente fuer DFS-Metadaten einfuehren
|
||||
2. bestehende Share-Abfrage in dedizierte Share-Resolver-Methode kapseln
|
||||
3. `ClassifyPath()` auf Metadaten-basierte Entscheidung umbauen
|
||||
4. `getDataAreasAsync()` root-typabhaengig enumerieren
|
||||
5. `LoadDataArea()` auf dieselbe Klassifikation umstellen
|
||||
6. JSON-Rueckgabe unveraendert lassen:
|
||||
- `DfsNamespaceRoot` als eigener `DataAreaType`
|
||||
- `DfsLink` nach aussen als `NtfsShare`
|
||||
- `Folder` als `NtfsFolder`
|
||||
|
||||
## Entscheidung
|
||||
|
||||
Die empfohlene Umsetzung ohne Config-Erweiterung ist:
|
||||
|
||||
- `RootPath` aus der vorhandenen Config nur als Einstieg verwenden
|
||||
- DFS-Metadaten zur Laufzeit ueber API abfragen
|
||||
- SMB-Share-Metadaten zur Laufzeit ueber `NetShareEnum` abfragen
|
||||
- Folder ausschliesslich relativ zu einer erkannten fachlichen Grenze ableiten
|
||||
|
||||
Nur so koennen klassische Shares, DFS-Namespaces, DFS-Links und echte Folder belastbar unterschieden werden, auch wenn LIAM nicht auf dem Zielserver selbst laeuft.
|
||||
Reference in New Issue
Block a user