Files
LIAM/Sonstiges/LIAM_NTFS_DFS_Pfadklassifikation_Konzept.md
2026-03-11 17:09:46 +01:00

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

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:

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.