# 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.
