rust-lang / rust-lang/rust

`File::create` may not be able to truncate on macOS SMB share

Open
#159,054 13 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-filesystem C-bug needs-triage O-macos O-windows S-has-mcve T-libs
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Reproduction:

use std::path::PathBuf;

fn main() {
    let path = std::env::args().nth(1).expect("Expect a path on SMB share");

    let long_data = vec![b'A'; 1000];
    let short_data = vec![b'B'; 10];

    // Step 1: write 1000 bytes
    println!("[1] Writing {} bytes of 'A' ...", long_data.len());
    if let Err(e) = std::fs::write(&path, &long_data) {
        eprintln!("    FAILED to write: {e}");
        std::process::exit(1);
    }

    // Step 1b: verify
    match std::fs::read(&path) {
        Ok(buf) => println!("    Read back: {} bytes", buf.len()),
        Err(e) => {
            eprintln!("    FAILED to read back: {e}");
            std::process::exit(1);
        }
    }

    // Step 2: overwrite with 10 bytes
    println!("[2] Overwriting with {} bytes of 'B' ...", short_data.len());
    if let Err(e) = std::fs::write(&path, &short_data) {
        eprintln!("    FAILED to write: {e}");
        std::process::exit(1);
    }

    // Step 3: read back and check
    println!("[3] Reading back ...");
    match std::fs::read(&path) {
        Ok(buf) => {
            println!("    File size: {} bytes", buf.len());
            if buf.len() == short_data.len() {
                println!("    PASS: file was correctly truncated.");
            } else {
                println!("    FAIL: expected {} bytes, got {} bytes.", short_data.len(), buf.len());
                println!("    The file was NOT truncated -- stale tail data remains.");
                println!();
                println!("    First 10 bytes: {:?}", &buf[..10.min(buf.len())]);
                if buf.len() > 10 {
                    println!("    Stale tail:     {:?} ...", &buf[10..20.min(buf.len())]);
                }
            }
        }
        Err(e) => {
            eprintln!("    FAILED to read back: {e}");
            std::process::exit(1);
        }
    }

    // Cleanup
    let _ = std::fs::remove_file(&path);
}

This prints the following when a path on a normal filesystem is given:

[1] Writing 1000 bytes of 'A' ...
    Read back: 1000 bytes
[2] Overwriting with 10 bytes of 'B' ...
[3] Reading back ...
    File size: 10 bytes
    PASS: file was correctly truncated.

However for the unclear reason, a path on macOS SMB share will fail:

[1] Writing 1000 bytes of 'A' ...
    Read back: 1000 bytes
[2] Overwriting with 10 bytes of 'B' ...
[3] Reading back ...
    File size: 1000 bytes
    FAIL: expected 10 bytes, got 1000 bytes.
    The file was NOT truncated -- stale tail data remains.

    First 10 bytes: [66, 66, 66, 66, 66, 66, 66, 66, 66, 66]
    Stale tail:     [65, 65, 65, 65, 65, 65, 65, 65, 65, 65] ...

Ultimately this was traced back to #115745 where CREATE_ALWAYS is replaced with OPEN_ALWAYS, which macOS smbd doesn't seem to like (Notepad++ was also hit by the same bug: notepad-plus-plus/notepad-plus-plus#14300).

Meta
rustc 1.95.0 (59807616e 2026-04-14)
binary: rustc
commit-hash: 59807616e1fa2540724bfbac14d7976d7e4a3860
commit-date: 2026-04-14
host: x86_64-pc-windows-msvc
release: 1.95.0
LLVM version: 22.1.2

Since the relevant lines are still in the main branch, the precise version shouldn't matter much here though.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in library/std/src/sys/fs/windows.rs and review the change described in #115745 from CREATE_ALWAYS to OPEN_ALWAYS. Run the provided Rust reproduction against a macOS SMB share and compare it with a normal filesystem. Done means File::create or std::fs::write truncates an existing SMB file correctly without regressing other Windows filesystem behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.