Commit 537a20c1135 for nodejs

commit 537a20c113528da44323edf78deb83cc93c3a30a
Author: Hamza Kargin <hamzakargin@outlook.com>
Date:   Sun Nov 15 13:43:51 2026 +0400

    fs: respect setDefaultHighWaterMark in ReadStream

    ReadStream ignored stream.setDefaultHighWaterMark() and always used
    64 KiB. Use the user-set value when there is one, and keep 64 KiB
    otherwise so Windows does not drop to the 16 KiB stream default.

    Fixes: https://github.com/nodejs/node/issues/66937
    Signed-off-by: Hamza Kargın <hamzakargin@outlook.com>
    PR-URL: https://github.com/nodejs/node/pull/66956
    Reviewed-By: Robert Nagy <ronagy@icloud.com>
    Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>

diff --git a/doc/api/fs.md b/doc/api/fs.md
index 93e6e7c68a1..929ea302957 100644
--- a/doc/api/fs.md
+++ b/doc/api/fs.md
@@ -265,7 +265,8 @@ added: v16.11.0
   * `emitClose` {boolean} **Default:** `true`
   * `start` {integer}
   * `end` {integer} **Default:** `Infinity`
-  * `highWaterMark` {integer} **Default:** `64 * 1024`
+  * `highWaterMark` {integer} **Default:** `64 * 1024`, or the value set with
+    [`stream.setDefaultHighWaterMark()`][]
   * `signal` {AbortSignal|undefined} **Default:** `undefined`
 * Returns: {fs.ReadStream}

@@ -781,7 +782,8 @@ added: v18.11.0
   * `emitClose` {boolean} **Default:** `true`
   * `start` {integer}
   * `end` {integer} **Default:** `Infinity`
-  * `highWaterMark` {integer} **Default:** `64 * 1024`
+  * `highWaterMark` {integer} **Default:** `64 * 1024`, or the value set with
+    [`stream.setDefaultHighWaterMark()`][]
 * Returns: {readline.InterfaceConstructor}

 Convenience method to create a `readline` interface and stream over the file.
@@ -3104,7 +3106,8 @@ changes:
   * `emitClose` {boolean} **Default:** `true`
   * `start` {integer}
   * `end` {integer} **Default:** `Infinity`
-  * `highWaterMark` {integer} **Default:** `64 * 1024`
+  * `highWaterMark` {integer} **Default:** `64 * 1024`, or the value set with
+    [`stream.setDefaultHighWaterMark()`][]
   * `fs` {Object|null} **Default:** `null`
   * `signal` {AbortSignal|null} **Default:** `null`
   * `windowsHandle` {bigint} A raw Win32 `HANDLE` value to read from, in place
@@ -9787,6 +9790,7 @@ the file contents.
 [`path.matchesGlob()`]: path.md#pathmatchesglobpath-pattern
 [`statfs.bsize`]: #statfsbsize
 [`stream.getDefaultHighWaterMark()`]: stream.md#streamgetdefaulthighwatermarkobjectmode
+[`stream.setDefaultHighWaterMark()`]: stream.md#streamsetdefaulthighwatermarkobjectmode-value
 [`stream/iter pipeTo()`]: stream_iter.md#pipetosource-transforms-writer-options
 [`stream/iter pull()`]: stream_iter.md#pullsource-transforms-options
 [`stream/iter pullSync()`]: stream_iter.md#pullsyncsource-transforms
diff --git a/lib/internal/fs/streams.js b/lib/internal/fs/streams.js
index 5fd47bb5e49..9bfbaa01125 100644
--- a/lib/internal/fs/streams.js
+++ b/lib/internal/fs/streams.js
@@ -33,6 +33,7 @@ const {
   validateThisInternalField,
 } = require('internal/validators');
 const { errorOrDestroy } = require('internal/streams/destroy');
+const { getUserDefaultHighWaterMark } = require('internal/streams/state');
 const fs = require('fs');
 const { kRef, kUnref, FileHandle } = require('internal/fs/promises');
 const { Buffer } = require('buffer');
@@ -193,7 +194,7 @@ function ReadStream(path, options) {
   // A little bit bigger buffer and water marks by default
   options = copyObject(getOptions(options, kEmptyObject));
   if (options.highWaterMark === undefined)
-    options.highWaterMark = 64 * 1024;
+    options.highWaterMark = getUserDefaultHighWaterMark() ?? 64 * 1024;

   if (options.autoDestroy === undefined) {
     options.autoDestroy = false;
diff --git a/lib/internal/streams/state.js b/lib/internal/streams/state.js
index 46e0ff9c955..c68dba2a4d8 100644
--- a/lib/internal/streams/state.js
+++ b/lib/internal/streams/state.js
@@ -11,6 +11,7 @@ const { ERR_INVALID_ARG_VALUE } = require('internal/errors').codes;
 // TODO (fix): For some reason Windows CI fails with bigger hwm.
 let defaultHighWaterMarkBytes = process.platform === 'win32' ? 16 * 1024 : 64 * 1024;
 let defaultHighWaterMarkObjectMode = 16;
+let defaultHighWaterMarkBytesSet = false;

 function highWaterMarkFrom(options, isDuplex, duplexKey) {
   return options.highWaterMark != null ? options.highWaterMark :
@@ -27,9 +28,14 @@ function setDefaultHighWaterMark(objectMode, value) {
     defaultHighWaterMarkObjectMode = value;
   } else {
     defaultHighWaterMarkBytes = value;
+    defaultHighWaterMarkBytesSet = true;
   }
 }

+function getUserDefaultHighWaterMark() {
+  return defaultHighWaterMarkBytesSet ? defaultHighWaterMarkBytes : undefined;
+}
+
 function getHighWaterMark(state, options, duplexKey, isDuplex) {
   const hwm = highWaterMarkFrom(options, isDuplex, duplexKey);
   if (hwm != null) {
@@ -47,5 +53,6 @@ function getHighWaterMark(state, options, duplexKey, isDuplex) {
 module.exports = {
   getHighWaterMark,
   getDefaultHighWaterMark,
+  getUserDefaultHighWaterMark,
   setDefaultHighWaterMark,
 };
diff --git a/test/parallel/test-fs-read-stream-set-default-hwm.js b/test/parallel/test-fs-read-stream-set-default-hwm.js
new file mode 100644
index 00000000000..3ec78dacc43
--- /dev/null
+++ b/test/parallel/test-fs-read-stream-set-default-hwm.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const common = require('../common');
+
+const assert = require('node:assert');
+const fs = require('node:fs');
+const { setDefaultHighWaterMark } = require('node:stream');
+
+{
+  const stream = fs.createReadStream(__filename);
+  assert.strictEqual(stream.readableHighWaterMark, 64 * 1024);
+  stream.destroy();
+}
+
+setDefaultHighWaterMark(false, 1024 * 1024);
+
+{
+  const stream = fs.createReadStream(__filename);
+  assert.strictEqual(stream.readableHighWaterMark, 1024 * 1024);
+  stream.destroy();
+}
+
+{
+  const stream = fs.createReadStream(__filename, { highWaterMark: 1024 });
+  assert.strictEqual(stream.readableHighWaterMark, 1024);
+  stream.destroy();
+}
+
+fs.promises.open(__filename).then(async (fh) => {
+  const stream = fh.createReadStream({ autoClose: false });
+  assert.strictEqual(stream.readableHighWaterMark, 1024 * 1024);
+  stream.destroy();
+  await fh.close();
+}).then(common.mustCall());