Add NTFS DFS path classification concept
This commit is contained in:
431
Sonstiges/LIAM_NTFS_DFS_Pfadklassifikation_Konzept.md
Normal file
431
Sonstiges/LIAM_NTFS_DFS_Pfadklassifikation_Konzept.md
Normal file
@@ -0,0 +1,431 @@
|
||||
# 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\link` ist semantisch oft ein Share-aehnlicher Einstiegspunkt, hat aber drei Segmente.
|
||||
- Ein Root wie `\\server` ist mit der bisherigen Logik ueberhaupt nicht sinnvoll modellierbar.
|
||||
- `LoadDataArea()` und `getDataAreasAsync()` 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:
|
||||
|
||||
- `ServerRoot`
|
||||
- `ClassicShare`
|
||||
- `DfsNamespaceRoot`
|
||||
- `DfsLink`
|
||||
- `Folder`
|
||||
- `Unknown`
|
||||
|
||||
Nach aussen kann das bei Bedarf weiter auf bestehende LIAM-Typen gemappt werden:
|
||||
|
||||
- `ClassicShare` -> `NtfsShare`
|
||||
- `DfsNamespaceRoot` -> je nach fachlicher Entscheidung `NtfsShare` oder Container-Typ
|
||||
- `DfsLink` -> `NtfsShare`
|
||||
- `Folder` -> `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\share` ist 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\namespace` ein DFS-Namespace-Root?
|
||||
- Ist `\\server\namespace\link` ein DFS-Link?
|
||||
- Welche Link-Ziele sind hinterlegt?
|
||||
|
||||
Aus dieser Sicht gilt:
|
||||
|
||||
- `\\server\namespace` ist ein Namespace-Objekt, nicht einfach nur ein Folder.
|
||||
- `\\server\namespace\link` ist 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 `DfsLink` ist `Folder`
|
||||
|
||||
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 wie `LoadDataArea()`
|
||||
- die UI, Workflow-Aktivitaeten und Web-API duerfen nicht jeweils eigene Heuristiken haben
|
||||
|
||||
Empfohlenes konzeptionelles Interface:
|
||||
|
||||
```text
|
||||
ClassifyPath(path) -> PathClassification
|
||||
EnumerateChildren(path) -> List<PathClassification>
|
||||
```
|
||||
|
||||
Eine `PathClassification` sollte mindestens enthalten:
|
||||
|
||||
- `NormalizedPath`
|
||||
- `Kind`
|
||||
- `DisplayName`
|
||||
- `BoundaryPath`
|
||||
- `ParentBoundaryPath`
|
||||
- `BackingType` wie `SMB` oder `DFS`
|
||||
- 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 `Unknown` liefern 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 `cLiamNtfsShare` oder `cLiamNtfsFolder` erzeugen
|
||||
|
||||
Sondern:
|
||||
|
||||
1. Pfad klassifizieren
|
||||
2. daraus internes `Kind` bestimmen
|
||||
3. 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` -> `NtfsShare`
|
||||
- `DfsLink` -> `NtfsShare`
|
||||
- `DfsNamespaceRoot` -> je nach Entscheidung ebenfalls `NtfsShare` oder 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, `Unknown` oder 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:
|
||||
|
||||
- `ServerRoot`
|
||||
- `ClassicShare`
|
||||
- `DfsNamespaceRoot`
|
||||
- `DfsLink`
|
||||
- `Folder`
|
||||
- `Unknown`
|
||||
|
||||
### 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 `\\server` als sichtbares DataArea-Objekt existieren oder nur als Enumerationsroot?
|
||||
- Soll ein DFS-Namespace-Root nach aussen als `NtfsShare` gelten 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.
|
||||
Reference in New Issue
Block a user