saltcorn-samba 0.4.10 → 0.4.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,74 @@ All notable changes to `saltcorn-samba` are documented here.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.4.11] – 2026-07-06
8
+
9
+ ### Changed – **Ehrliche Fehlerpropagation statt stiller Fallback**
10
+
11
+ In 0.4.10 wurde der neue `readdir-compat.js`-Wrapper eingeführt, der
12
+ vor dem eigentlichen `QUERY_DIRECTORY` die FileInformationClass
13
+ automatisch von 37 → 3 → 1 durchprobiert. Zwei Probleme kamen dabei
14
+ zum Vorschein:
15
+
16
+ 1. **Alle drei Info-Klassen lieferten weiterhin `0xC0000033`** auf
17
+ dem betroffenen Server. Das Umschalten der Info-Klasse ist also
18
+ *nicht* die eigentliche Ursache — die Annahme aus 0.4.10 war falsch.
19
+ 2. **Der Wrapper in `smb-client.js` fiel bei totalem Compat-Fehler
20
+ still auf das kaputte `client.readdir()` zurück**, das exakt
21
+ dieselbe (kaputte) FileInformationClass 37 verwendet. Dadurch
22
+ wurde die 0.4.10-Diagnostik komplett verschluckt und das Symptom
23
+ sah unverändert aus wie vor 0.4.10.
24
+
25
+ **Fixes in 0.4.11:**
26
+
27
+ - `smb-client.js` erkennt jetzt den 0xC0000033-Erschöpfungsfehler aus
28
+ dem Compat-Modul (Muster `"all classes exhausted"`) und propagiert
29
+ ihn direkt — kein stiller Retry mehr über das kaputte
30
+ `client.readdir()`.
31
+ - `readdir-compat.js` wirft bei Ausschöpfung aller drei Klassen einen
32
+ synthetischen Fehler mit klarem Wortlaut:
33
+ `"QUERY_DIRECTORY failed: 0xC0000033 (all classes exhausted; no
34
+ working FileInformationClass on this server). Tried:
35
+ FileIdBothDirectoryInformation=37, FileBothDirectoryInformation=3,
36
+ FileDirectoryInformation=1."`
37
+ Der Fehler trägt zusätzlich ein `.attempts`-Array mit den
38
+ NT-Statuscodes pro Klasse für spätere Diagnose.
39
+
40
+ ### Was das für dich bedeutet
41
+
42
+ Der gelbe Hinweis und `QUERY_DIRECTORY failed: 0xC0000033` sind
43
+ **noch nicht behoben** — 0.4.11 macht den Fehler nur ehrlich sichtbar,
44
+ sodass wir aus dem nächsten Diagnoselauf echte Signale bekommen.
45
+
46
+ **Nächster Schritt — bitte auf dem Saltcorn-Server ausführen** (im
47
+ entpackten Plugin-Verzeichnis, oder direkt aus dem ZIP):
48
+
49
+ ```bash
50
+ cd /pfad/zu/saltcorn-samba
51
+ node tools/diag-basepath.js \
52
+ --host 192.168.110.10 \
53
+ --share buero \
54
+ --path static \
55
+ --user 01_vassen \
56
+ --domain buero.ib-vassen.de \
57
+ --password 'DEIN_PASSWORT'
58
+ ```
59
+
60
+ Das Skript führt 6 Sonden mit rohen NT-Statuscodes aus (TREE_CONNECT,
61
+ CREATE, QUERY_DIRECTORY mit allen drei Info-Klassen, `stat`-Probe).
62
+ Die Ausgabe zeigt, an welcher Stelle Samba den Fehler wirft und mit
63
+ welchem Statuscode. Damit können wir 0.4.12 gezielt schreiben statt
64
+ weiter zu raten.
65
+
66
+ Ein heißer Kandidat für 0.4.12 (Wire-Format-Bug in `smb3-client`):
67
+ `encodeQueryDirectoryRequest` setzt `FileNameOffset` immer auf 96,
68
+ auch wenn kein Suchmuster gesendet wird — laut
69
+ [MS-SMB2 §2.2.33](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/10906442-294c-46d3-8515-c277efe1f752)
70
+ MUSS das Feld dann 0 sein. Bestätigung dafür aber bitte erst nach
71
+ der Diagnose.
72
+
73
+ ---
74
+
7
75
  ## [0.4.10] – 2026-07-05
8
76
 
9
77
  ### Fixed – **`0xC0000033` beim tatsächlichen Auflisten (Tree-View, File-Manager) endgültig behoben**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saltcorn-samba",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "description": "Saltcorn plugin: browse, upload, rename and delete files on a Samba/CIFS share via SMB 3.1.1 (AES-CMAC signing, optional encryption). File-manager view, directory tree, inline PDF viewer, external-app open (smb://).",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/readdir-compat.js CHANGED
@@ -331,6 +331,7 @@ async function readdirCompat(rawClient, sharePath) {
331
331
  : TRY_ORDER.slice();
332
332
 
333
333
  let lastErr = null;
334
+ const attempts = [];
334
335
  for (const cls of order) {
335
336
  try {
336
337
  const entries = await queryAll({
@@ -349,9 +350,10 @@ async function readdirCompat(rawClient, sharePath) {
349
350
  return entries.map(dirEntryToPluginEntry);
350
351
  } catch (err) {
351
352
  lastErr = err;
353
+ const msg = String((err && err.message) || err || "");
354
+ attempts.push({ class: cls.name, code: cls.code, error: msg });
352
355
  // Only retry with a different class on OBJECT_NAME_INVALID / info-class
353
356
  // rejection — any other error (auth, connection, missing) is fatal.
354
- const msg = String((err && err.message) || err || "");
355
357
  const isInfoClassBug =
356
358
  /0xC0000033|OBJECT_NAME_INVALID|STATUS_INVALID_INFO_CLASS/i.test(msg);
357
359
  if (!isInfoClassBug) {
@@ -360,7 +362,18 @@ async function readdirCompat(rawClient, sharePath) {
360
362
  // else: fall through to next class in order
361
363
  }
362
364
  }
363
- throw lastErr;
365
+ // All classes tried and all failed with 0xC0000033. Report a
366
+ // synthesised error that is uniquely identifiable ("all classes
367
+ // exhausted") so the caller can decide not to fall back to
368
+ // smb3-client's own readdir (which uses class 37 again).
369
+ const finalMsg =
370
+ "QUERY_DIRECTORY failed: 0xC0000033 (all classes exhausted; " +
371
+ "no working FileInformationClass on this server). Tried: " +
372
+ attempts.map((a) => a.class + "=" + a.code).join(", ") + ".";
373
+ const summary = new Error(finalMsg);
374
+ summary.cause = lastErr;
375
+ summary.attempts = attempts;
376
+ throw summary;
364
377
  } finally {
365
378
  // Always close the handle. Ignore errors.
366
379
  try {
package/smb-client.js CHANGED
@@ -274,30 +274,34 @@ async function buildClient(config) {
274
274
  */
275
275
  async readdir(rel) {
276
276
  const full = resolvePath(rel);
277
- // v0.4.10: use the compat readdir which tries multiple
278
- // FileInformationClass values so we survive Samba 4.23's rejection
279
- // of FileIdBothDirectoryInformation (37) the class smb3-client
280
- // hardcodes and which many Samba configurations answer with
281
- // STATUS_OBJECT_NAME_INVALID (0xC0000033). readdirCompat also
282
- // returns rich entries (name+isDir+size+mtime+ctime) directly, so
283
- // we skip the per-entry stat fan-out on success.
284
- let entriesFromCompat = null;
277
+ // v0.4.11: prefer the compat readdir (which tries multiple
278
+ // FileInformationClass values). If it succeeds we are done no
279
+ // extra per-entry stat fan-out needed because compat returns rich
280
+ // entries directly. If it fails, we ONLY fall back to smb3-client's
281
+ // built-in readdir when the compat failure was not itself the
282
+ // Samba-4.23 bug (0xC0000033 across all classes). If it *was*, the
283
+ // built-in readdir will produce the exact same 0xC0000033 no
284
+ // point trying it, and it would hide the diagnostics compat has
285
+ // gathered. Instead we rethrow the compat error verbatim so the
286
+ // caller sees the true root cause.
287
+ let compatErr = null;
285
288
  try {
286
- entriesFromCompat = await readdirCompat(client, full);
287
- return entriesFromCompat;
289
+ return await readdirCompat(client, full);
288
290
  } catch (err) {
289
- // Fall back to smb3-client's built-in readdir with the same error
290
- // handling as before. This preserves prior behaviour for servers
291
- // where the compat path fails for reasons unrelated to the
292
- // FileInformationClass bug (e.g. missing dir, permission).
291
+ compatErr = err;
293
292
  const compatMsg = String((err && err.message) || err || "");
294
- const compatIsInfoClassOnly =
295
- /STATUS_INVALID_INFO_CLASS/i.test(compatMsg);
296
- if (!compatIsInfoClassOnly) {
297
- // Not an info-class problem surface below by re-running
298
- // through the classic path so the existing German error
299
- // rewrites still apply.
293
+ // If compat ran into the exact same info-class rejection with
294
+ // ALL classes exhausted, the built-in readdir cannot possibly
295
+ // help — it uses class 37, which compat already tried. Rethrow
296
+ // now so callers see the real reason.
297
+ if (/0xC0000033|OBJECT_NAME_INVALID/i.test(compatMsg) &&
298
+ /all classes exhausted|no working FileInformationClass/i.test(compatMsg)) {
299
+ throw err;
300
300
  }
301
+ // Otherwise (compat failed for structural reasons like an unknown
302
+ // internal-module path, or a transient socket error) fall through
303
+ // to the classic path so the existing German error rewrites still
304
+ // apply.
301
305
  }
302
306
  let dirents;
303
307
  try {