Skip to content

Add 9P and remove SMB file sharing for Windows - #4879

Merged
anjannath merged 7 commits into
mainfrom
remove_smb
Dec 17, 2025
Merged

Add 9P and remove SMB file sharing for Windows#4879
anjannath merged 7 commits into
mainfrom
remove_smb

Conversation

@redbeam

@redbeam redbeam commented Aug 14, 2025

Copy link
Copy Markdown
Contributor

Note

Together with this PR, we also need to merge
crc-org/snc#1193 to add the 9pfs client to the bundle.


This adds 9P file sharing support as discussed in #4858.

We are also removing SMB file sharing support for Windows in favor of 9P. Some of the work has already been done by @anjannath, and it is included here (#4620).

Fixes #4768

Summary by CodeRabbit

  • New Features

    • Replaced SMB file sharing with 9P filesystem sharing on Windows.
    • Home directory now mounts automatically into the VM at startup.
    • Added redundant transport mechanism for improved reliability and compatibility.
  • Chores

    • Updated dependencies to support 9P filesystem protocol.

✏️ Tip: You can customize this high-level summary in your review settings.

@redbeam redbeam self-assigned this Aug 14, 2025
@redbeam redbeam added the kind/task Workable task label Aug 14, 2025
@openshift-ci
openshift-ci Bot requested review from anjannath and evidolob August 14, 2025 15:05
@coderabbitai

coderabbitai Bot commented Aug 14, 2025

Copy link
Copy Markdown

Walkthrough

Migrates CRC's shared directory mechanism from Windows SMB to cross-platform 9P protocol. Introduces a Go-based 9P server with hvsock listener support for Windows and TCP fallback. Replaces SMB share creation, configuration management, and mount logic throughout the codebase with 9P equivalents. Adds p9 library dependency.

Changes

Cohort / File(s) Change Summary
9P Server Implementation
pkg/fileserver/fs9p/server.go, pkg/fileserver/fs9p/server_windows.go, pkg/fileserver/fs9p/server_fallback.go
New 9P server type exposing a directory, supporting hvsock (Windows) and TCP listeners; includes Start(), Stop(), and WaitForError() lifecycle management.
Daemon 9P Setup
cmd/crc/cmd/daemon.go
Initializes 9P servers (hvsock and TCP fallback) for home directory sharing on Windows; wires listeners and error handlers.
Configuration & Constants
pkg/crc/config/settings.go, pkg/crc/constants/constants.go
Removes SMB-specific validation and unified EnableSharedDirs setting; adds Plan9 constants (Msize, TcpPort, HvsockGUID, HvsockPort).
Machine Driver Cleanup
pkg/crc/machine/driver.go, pkg/crc/machine/driver_darwin.go, pkg/crc/machine/driver_linux.go, pkg/crc/machine/driver_windows.go
Removes setSharedDirPassword and updateDriverStruct functions; eliminates OS-specific driver persistence logic.
Windows Shared Dir Mounting
pkg/crc/machine/libhvee/driver_windows.go, pkg/crc/machine/libhvee/driver.go
Changes shared directory type from CIFS to 9P; implements tag indexing and adds ConvertToUnixPath utility for path conversion.
VM Mount Configuration
pkg/crc/machine/start.go
Replaces CIFS/SMB mount flow with 9P-based mount logic; adds hvsock and TCP fallback handling; retains MicroShift guard.
SMB Code Removal
pkg/drivers/libhvee/libhvee_windows.go, pkg/drivers/libhvee/powershell_windows.go, cmd/crc/cmd/start.go
Removes SMB share existence checks, SMB helper functions (cmd, smbShareExists), and Windows username/password population.
Windows MSI Configuration
packaging/windows/product.wxs.template
Removes SMB share actions (CreateSMBShare, EnableFileAndPrinterSharing, RemoveSMBShare) and properties; adds Hvsock9pRegistryEntry component for 9P service registration.
9P Protocol Library (Vendor)
vendor/github.com/DeedleFake/p9/..., vendor/modules.txt
Adds complete p9 library (v0.7.1): protocol layer, client/server implementations, filesystem abstractions, stat model, encoding/decoding, address parsing, platform-specific QID generation.
Test Coverage
test/e2e/features/9pfs.feature, test/e2e/testsuite/testsuite.go
Adds Windows-specific 9pfs mount verification feature and helper functions for checking mount existence, filesystem access, file/directory operations.
Dependency Management
go.mod
Adds direct dependency on github.com/DeedleFake/p9 v0.7.1; github.com/linuxkit/virtsock becomes direct dependency.

Sequence Diagram

sequenceDiagram
    participant Daemon as CRC Daemon
    participant Server as 9P Server
    participant Hvsock as Hvsock Listener
    participant TCP as TCP Listener
    participant VM as Hyper-V VM
    participant Client as Client

    Daemon->>Server: New9pServer(hvsockListener, homeDir)
    Daemon->>Hvsock: Create hvsock listener via GetHvsockListener()
    Daemon->>Server: Start()
    Server->>Hvsock: proto.Serve(listener, fsConnHandler)
    activate Server
    Server->>Server: WaitForError() goroutine
    deactivate Server

    Daemon->>TCP: Create TCP listener (GatewayIP:564)
    Daemon->>Server: New9pServer(tcpListener, homeDir)
    Daemon->>Server: Start()
    Server->>TCP: proto.Serve(listener, fsConnHandler)
    activate Server
    Server->>Server: WaitForError() goroutine
    deactivate Server

    VM->>Hvsock: Attach via 9P
    activate Hvsock
    Hvsock-->>VM: Mounted (success path)
    deactivate Hvsock

    alt Hvsock unavailable
        VM->>TCP: Fallback to 9P over TCP
        activate TCP
        TCP-->>VM: Mounted (fallback path)
        deactivate TCP
    end

    Client->>VM: Access mounted directory
    VM->>Server: 9P protocol requests (stat, read, etc.)
    Server->>Server: Resolve path & filesystem ops
    Server-->>VM: 9P responses
    VM-->>Client: File operations complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Logic density: Multiple interdependent changes across daemon initialization, machine driver, VM mounting, and MSI configuration.
  • File diversity: Changes span configuration, daemon, drivers, fileserver, packaging, and tests with varying levels of complexity.
  • New public APIs: Added Plan9 constants, ConvertToUnixPath, New9pServer, and fsHandler interfaces.
  • Vendor audit: Large p9 library addition with protocol layer, client/server stacks, and platform-specific implementations.
  • Architecture shift: Complete replacement of SMB/CIFS logic with 9P protocol requires understanding both old and new patterns.

Areas requiring extra attention:

  • 9P server lifecycle management in daemon.go and error handling pathways
  • Windows hvsock listener implementation and GUID handling in server_windows.go
  • Mount fallback logic (hvsock → TCP) in machine/start.go
  • Shared directory tag indexing change from static "crc-dir0" to dynamic "dir%d"
  • ConvertToUnixPath correctness for Windows path normalization
  • Vendor dependency compatibility and protocol buffer encoding correctness
  • MSI registry entry for fs9p-hvsock service GUID alignment with code constants

Possibly related PRs

Suggested labels

dependencies

Suggested reviewers

  • cfergeau

Poem

🐰 From SMB's shadow to nine-protocol light,
Hvsock whispers where Windows shines bright,
TCP stands ready when channels grow tall,
Home directories mount through 9P's call,
Cross-platform magic, no share left behind!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add 9P and remove SMB file sharing for Windows' clearly summarizes the main objective: introducing 9P file sharing and removing SMB file sharing support for Windows.
Description check ✅ Passed The PR description provides context about the change (9P adoption, SMB removal), references linked issues and prior work, and notes external dependency on snc#1193. However, it lacks detail on testing performed and does not systematically address the template sections.
Linked Issues check ✅ Passed The PR addresses the primary objective of issue #4768 (remove SMB file sharing code) by removing SMB-related code paths, MSI setup logic, and shared directory password handling, while introducing 9P as the replacement file-sharing mechanism.
Out of Scope Changes check ✅ Passed Changes are tightly scoped to Windows file sharing migration: removal of SMB code, introduction of 9P infrastructure, and updates to related configuration and driver code. No unrelated changes detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch remove_smb

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 23

🧹 Nitpick comments (25)
vendor/github.com/DeedleFake/p9/addr_other.go (2)

11-16: Doc comment misleading for non-Unix build tag

This file is compiled on non-Linux/non-Darwin platforms, yet the comment explains Unix-like behavior. Clarify the comment to avoid confusion.

Apply this diff:

-// current namespace. On Unix-like systems, this is
-// /tmp/ns.$USER.$DISPLAY.
+// current namespace. On Unix-like systems, the path is typically
+// /tmp/ns.$USER.$DISPLAY, but for non-Unix platforms this implementation
+// uses os.TempDir() as the base.

1-1: Add modern build constraint for forward-compatibility

Consider adding the //go:build form alongside the legacy // +build for clarity and future-proofing. This mirrors Go's recommended syntax since 1.17.

Apply this diff:

+//go:build !linux && !darwin
 // +build !linux,!darwin
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (2)

1-1: Add //go:build for consistency

Add the modern //go:build constraint alongside the legacy form.

Apply this diff:

+//go:build p9debug
 // +build p9debug

10-12: Optional: append newline to logs

Current logging will not append a newline, which can jumble outputs in stderr across multiple calls. If callers don't consistently include "\n", consider appending one here.

Apply this diff:

-func Log(str string, args ...interface{}) {
-	fmt.Fprintf(os.Stderr, str, args...)
-}
+func Log(str string, args ...interface{}) {
+	if len(args) == 0 && len(str) > 0 && str[len(str)-1] == '\n' {
+		fmt.Fprint(os.Stderr, str)
+		return
+	}
+	fmt.Fprintf(os.Stderr, str+"\n", args...)
+}
vendor/github.com/DeedleFake/p9/README.md (1)

1-52: Vendor docs violate markdownlint rules; exclude vendor from linting

markdownlint is flagging heading styles and hard tabs in vendored README. Vendor content should generally be excluded from linters to avoid false positives and churn.

Consider updating your markdownlint configuration to ignore vendor/:

Example .markdownlint-cli2.yaml at repo root:

  • ignores:
    • "vendor/**"

If you prefer to keep linting vendor content, we can convert headings to setext style and replace tabs with spaces in this file.

vendor/github.com/DeedleFake/p9/addr_unix.go (1)

1-1: Add //go:build for clarity

Add the modern build constraint along with the legacy tag.

Apply this diff:

+//go:build linux || darwin
 // +build linux darwin
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)

82-84: Avoid encoding uintptr in a wire protocol

Including reflect.Uintptr introduces arch-dependent sizes. It's safer to reject uintptr or normalize it to a fixed width.

Apply this diff to drop uintptr support:

-	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uintptr:
+	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:

171-171: Prefer safe []byte->string conversion over unsafe.Pointer

The unsafe conversion ties the string lifetime to a transient []byte backing array and relies on runtime internals. For robustness, use string(buf). If performance is a concern, justify with benchmarks and limit to hot paths.

Apply this diff:

-		v.SetString(*(*string)(unsafe.Pointer(&buf)))
+		v.SetString(string(buf))
pkg/crc/constants/constants.go (1)

60-60: Validate msize across client implementations

Confirm that 1MiB msize works with the kernel 9p client(s) you target (Linux/macOS guests) and matches mount-time options. If necessary, consider making it configurable to ease tuning for performance/path MTU constraints.

vendor/github.com/DeedleFake/p9/dir_other.go (1)

1-1: Add go:build constraint for Go 1.17+ compatibility

The legacy // +build form is still supported, but pairing it with //go:build improves tooling compatibility.

Apply this diff:

+//go:build !linux && !darwin && !plan9 && !windows
 // +build !linux,!darwin,!plan9,!windows
vendor/github.com/DeedleFake/p9/encoding.go (1)

16-30: Graceful EOF handling is good; consider treating ErrUnexpectedEOF as end-of-stream too.

proto.Read may return io.ErrUnexpectedEOF on truncated directory streams. If your intent is “read until the stream ends,” it’s reasonable to treat both EOF and ErrUnexpectedEOF as a normal termination and return the accumulated entries.

Apply within this range:

-		err := proto.Read(r, &stat)
-		if err != nil {
-			if err == io.EOF {
-				err = nil
-			}
-			return entries, err
-		}
+		err := proto.Read(r, &stat)
+		if err != nil {
+			if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
+				return entries, nil
+			}
+			return entries, err
+		}

Additionally, add the import:

// add to imports
"errors"
vendor/github.com/DeedleFake/p9/internal/util/util.go (3)

8-13: Fix misleading comment about size semantics of N.

io.LimitedReader already uses int64, which is larger than uint32 on all architectures. The current comment suggests uint32 “allows larger sizes,” which is inaccurate. Recommend clarifying the rationale and the cap.

-// LimitedReader is a reimplementation of io.LimitedReader with two
-// main differences:
-//
-// * N is a uint32, allowing for larger sizes on 32-bit systems.
-// * A custom error can be returned if N becomes zero.
+// LimitedReader is similar to io.LimitedReader with two differences:
+//
+// * N is a uint32 (io.LimitedReader uses int64). This keeps the type small and
+//   consistent across architectures but caps the readable size at 4 GiB.
+// * A custom error can be returned when the limit is exhausted.

27-31: Use equality check for unsigned counter.

N is uint32; use N == 0 instead of N <= 0 for clarity.

-	if lr.N <= 0 {
+	if lr.N == 0 {
 		return 0, lr.err()
 	}

41-44: Align doc with implementation for Errorf.

The comment mentions “nil or io.EOF,” but the code only returns io.EOF directly. Either expand the implementation or narrow the comment. Suggest tightening the comment.

-// Errorf is a variant of fmt.Errorf that returns an error being
-// wrapped directly if it is one of a number of specific values, such
-// as nil or io.EOF.
+// Errorf is a variant of fmt.Errorf that returns io.EOF directly if it
+// appears among the arguments; otherwise it formats the error.
vendor/github.com/DeedleFake/p9/dir_plan9.go (2)

10-31: Populate QID fields in DirEntry when available.

When syscall.Dir is present, you can also fill DirEntry.Path and DirEntry.Version from sys.Qid to avoid an extra stat/QID lookup elsewhere.

 	return DirEntry{
 		FileMode:  ModeFromOS(fi.Mode()),
 		ATime:     time.Unix(int64(sys.Atime), 0),
 		MTime:     fi.ModTime(),
 		Length:    uint64(fi.Size()),
 		EntryName: fi.Name(),
 		UID:       sys.Uid,
 		GID:       sys.Gid,
 		MUID:      sys.Muid,
+		Path:      sys.Qid.Path,
+		Version:   sys.Qid.Vers,
 	}

39-42: Clarify error message to include the concrete type.

Improve diagnosability by naming the expected concrete type.

-		return QID{}, errors.New("failed to get QID: FileInfo was not Dir")
+		return QID{}, errors.New("failed to get QID: FileInfo.Sys() was not *syscall.Dir")
vendor/github.com/DeedleFake/p9/dir_linux.go (2)

52-55: Clarify error message to include the concrete type.

Improves diagnosability.

-	if sys == nil {
-		return QID{}, errors.New("failed to get QID: FileInfo was not Stat_t")
-	}
+	if sys == nil {
+		return QID{}, errors.New("failed to get QID: FileInfo.Sys() was not *syscall.Stat_t")
+	}

23-33: Optional: Fallback to numeric UID/GID when lookups fail.

LookupId/LookupGroupId can fail or be slow; consider falling back to numeric strings to retain information.

 	var uname string
 	uid, err := user.LookupId(strconv.FormatUint(uint64(sys.Uid), 10))
 	if err == nil {
 		uname = uid.Username
+	} else {
+		uname = strconv.FormatUint(uint64(sys.Uid), 10)
 	}
 
 	var gname string
 	gid, err := user.LookupGroupId(strconv.FormatUint(uint64(sys.Gid), 10))
 	if err == nil {
 		gname = gid.Name
+	} else {
+		gname = strconv.FormatUint(uint64(sys.Gid), 10)
 	}
vendor/github.com/DeedleFake/p9/proto/server.go (1)

80-93: Msizer handling: prevent double size negotiation warning spam

The setter.Do already guards the once-only behavior, but the outer check logs a warning even when the race resolves to first set wins. Consider moving the “already set” warning inside the Do block and only emit if setter wasn’t executed. Optional improvement.

vendor/github.com/DeedleFake/p9/proto/proto.go (1)

101-108: Dead branch on invalid type check.

Inside if t == nil { ... } the nested if err != nil { return ... } can never trigger; err wasn’t modified after the previous successful read. This is dead code and reduces clarity.

-	t := p.TypeFromID(msgType)
-	if t == nil {
-		if err != nil {
-			return nil, NoTag, err
-		}
-
-		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
-	}
+	t := p.TypeFromID(msgType)
+	if t == nil {
+		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
+	}
vendor/github.com/DeedleFake/p9/remote.go (2)

127-135: Variable shadowing obscures receiver; rename local for clarity.

file, err := file.walk(p) shadows the method receiver, reducing readability. Use a different name and avoid confusion.

-		file, err := file.walk(p)
+		next, err := file.walk(p)
 		if err != nil {
 			return err
 		}
 		// Close is not necessary. Remove is also a clunk.
 
-		return file.Remove("")
+		return next.Remove("")

323-331: Same shadowing issue in Stat(); rename local.

Avoid shadowing the receiver to keep code unambiguous.

-		file, err := file.walk(p)
+		next, err := file.walk(p)
 		if err != nil {
 			return DirEntry{}, err
 		}
-		defer file.Close()
+		defer next.Close()
 
-		return file.Stat("")
+		return next.Stat("")
vendor/github.com/DeedleFake/p9/fs.go (2)

179-186: Avoid unsafe string-to-byte conversion when hashing QID path.

Using unsafe to convert string to []byte is brittle and can break across Go versions. The allocation saved here is negligible compared to a SHA-256. Prefer a safe conversion.

-	sum := sha256.Sum256(*(*[]byte)(unsafe.Pointer(&p)))
+	sum := sha256.Sum256([]byte(p))
 	path := binary.LittleEndian.Uint64(sum[:])

Additionally remove the now-unused unsafe import from this file’s imports.
To support import cleanup, apply this change to the import block:

// Remove the "unsafe" import from the import list in this file.

446-527: Directory read handling is intentionally spec-relaxed; document client expectations.

The offset handling for directory reads is relaxed (offsets other than 0 are ignored). This is acceptable since the implementation returns the full entry list, but client-side code must not rely on precise offset semantics. Consider adding a short doc comment to the public-facing server wiring to set expectations.

vendor/github.com/DeedleFake/p9/stat.go (1)

135-153: Minor: unsafe-to-string conversion in String() is a trade-off.

Using unsafe to avoid allocation is fine in vendored perf-sensitive code, but note it ties to Go’s internal string representation. If we ever fork this lib, consider a safe string(buf) for maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3950d2d and 25ef0c7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (43)
  • cmd/crc/cmd/daemon.go (4 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (1 hunks)
  • packaging/windows/product.wxs.template (0 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/shares.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (8)
  • pkg/crc/machine/driver_darwin.go
  • pkg/crc/machine/driver_windows.go
  • cmd/crc/cmd/start.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver_linux.go
  • pkg/crc/machine/driver.go
  • packaging/windows/product.wxs.template
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • vendor/github.com/DeedleFake/p9/README.md
  • cmd/crc/cmd/daemon.go
  • pkg/fileserver/fs9p/server.go
  • vendor/github.com/DeedleFake/p9/fs.go
  • pkg/fileserver/fs9p/shares.go
🧬 Code Graph Analysis (28)
vendor/github.com/DeedleFake/p9/dir_other.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/encoding.go (2)
vendor/github.com/DeedleFake/p9/stat.go (2)
  • DirEntry (255-267)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Read (34-38)
  • Write (25-31)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/dir_plan9.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/dir_darwin.go (3)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/dir_windows.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/addr.go (2)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/client.go (5)
vendor/github.com/DeedleFake/p9/proto/client.go (3)
  • Client (18-31)
  • NewClient (35-56)
  • Dial (60-67)
vendor/github.com/DeedleFake/p9/msg.go (8)
  • Proto (75-77)
  • Tversion (79-82)
  • Tversion (84-84)
  • Rversion (86-89)
  • Tauth (95-99)
  • Rauth (101-103)
  • Tattach (105-110)
  • Rattach (112-114)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • Version (10-10)
  • NoFID (18-18)
  • QID (42-46)
vendor/github.com/DeedleFake/p9/remote.go (1)
  • Remote (19-27)
pkg/crc/machine/libhvee/driver_windows.go (1)
vendor/github.com/crc-org/machine/libmachine/drivers/base.go (1)
  • SharedDir (27-35)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/dir_linux.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
cmd/crc/cmd/daemon.go (2)
pkg/crc/constants/constants.go (2)
  • Plan9Port (59-59)
  • GetHomeDir (164-170)
pkg/fileserver/fs9p/shares.go (2)
  • StartShares (25-56)
  • Mount9p (12-15)
vendor/github.com/DeedleFake/p9/remote.go (6)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • Client (18-31)
vendor/github.com/DeedleFake/p9/p9.go (4)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • IOHeaderSize (70-70)
vendor/github.com/DeedleFake/p9/msg.go (14)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tremove (192-194)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
pkg/crc/config/settings.go (2)
pkg/crc/config/validations.go (1)
  • ValidateBool (19-25)
pkg/crc/config/callbacks.go (1)
  • SuccessfullyApplied (36-38)
pkg/crc/machine/start.go (1)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/fileserver/fs9p/server.go (3)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (60-60)
vendor/github.com/DeedleFake/p9/p9.go (1)
vendor/github.com/DeedleFake/p9/stat.go (1)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/fs.go (8)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • QID (42-46)
  • QIDType (49-49)
  • IOHeaderSize (70-70)
  • Version (10-10)
  • QTAuth (58-58)
  • NoFID (18-18)
  • QTDir (54-54)
vendor/github.com/DeedleFake/p9/proto/server.go (3)
  • MessageHandler (135-139)
  • ConnHandler (112-114)
  • ConnHandlerFunc (125-125)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/msg.go (2)
  • Tversion (79-82)
  • Tversion (84-84)
vendor/github.com/DeedleFake/p9/client.go (1)
  • ErrUnsupportedVersion (14-14)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • WriteDir (33-42)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Read (34-38)
  • Write (25-31)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/internal/util/util.go (2)
  • Errorf (44-52)
  • LimitedReader (13-17)
pkg/fileserver/fs9p/shares.go (1)
pkg/fileserver/fs9p/server.go (2)
  • Server (15-22)
  • New9pServer (26-62)
vendor/github.com/DeedleFake/p9/dir.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/fs.go (4)
  • File (100-119)
  • Attachment (44-74)
  • FileSystem (21-34)
  • QIDFS (89-91)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • OWRITE (27-27)
  • ORDWR (28-28)
  • OEXEC (29-29)
  • OTRUNC (31-31)
  • OCEXEC (32-32)
  • ORCLOSE (33-33)
  • OREAD (26-26)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/proto/client.go (6)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
  • Proto (38-41)
  • NoTag (27-27)
  • ErrClientClosed (22-22)
vendor/github.com/DeedleFake/p9/client.go (3)
  • NewClient (30-32)
  • Client (22-26)
  • Dial (36-43)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/msg.go (6)
vendor/github.com/DeedleFake/p9/proto/proto.go (2)
  • NewProto (44-60)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • Version (10-10)
  • QID (42-46)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • P9NoTag (221-223)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • ErrLargeStat (18-18)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Write (25-31)
  • Read (34-38)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
🪛 markdownlint-cli2 (0.17.2)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
  • GitHub Check: build (macOS-14, 1.23)
  • GitHub Check: Run OKD bundle with crc (1.23)
  • GitHub Check: build (ubuntu-latest, 1.23)
  • GitHub Check: build (windows-2022, 1.23)
  • GitHub Check: build (macOS-13, 1.23)
🔇 Additional comments (26)
vendor/github.com/DeedleFake/p9/LICENSE (1)

1-21: MIT license file correctly included for vendored dependency.

License content and attribution look correct for github.com/DeedleFake/p9.

vendor/modules.txt (1)

13-18: Vendoring metadata for p9 v0.6.12 looks consistent.

Entries for root and subpackages are present and marked explicit.

vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-5: No-op debug build variant is fine.

Build tag and signature match the debug counterpart; safe to vendor as-is.

pkg/crc/machine/libhvee/driver_windows.go (2)

4-4: fmt import is justified by dynamic 9P tag generation.

No issues.


39-45: No change needed — Windows uses TCP 9p, vsock support is disabled and 9p server does not rely on "dir%d" tags

Short summary: I verified that drivers set Tag = fmt.Sprintf("dir%d", i) client-side, but the fs9p server exposes a directory per net.Listener (no tag mapping) and vsock shares are disabled. Windows path already uses TCP/9p, so the original tag/vsock concern is not applicable.

Files to note:

  • pkg/crc/machine/libhvee/driver_windows.go — sets Tag: fmt.Sprintf("dir%d", i) and Type: "9p"
  • pkg/fileserver/fs9p/shares.go — StartVsockShares returns nil (vsock support removed); StartShares uses New9pServer(listener, path)
  • pkg/fileserver/fs9p/server.go — New9pServer serves exposeDir on the provided net.Listener (no tag mapping)
  • cmd/crc/cmd/daemon.go — creates a TCP listener and calls fs9p.StartShares(...)
  • pkg/crc/machine/start.go — configureSharedDirs mounts "9p" via "9pfs 192.168.127.1" (TCP), not vsock

Conclusion: the original review suggestion to align 9p share tags and avoid vsock assumptions is incorrect for this codebase — Windows is already using the TCP/GVProxy 9p path and the server is listener-bound rather than tag-mapped.

Likely an incorrect or invalid review comment.

pkg/crc/machine/start.go (1)

209-211: LGTM: explanatory comment is accurate

The note about rpc.ServerError wrapping and the limitation of errors.Is() is correct and useful context here.

pkg/crc/config/settings.go (1)

87-88: Clarify EnableSharedDirs help text; do NOT enforce HostNetworkAccess

Short summary: I verified the implementation — the 9P server is started on the CRC virtual-network gateway and the guest mounts that gateway address, so the shared-dir feature is served via the CRC virtual network (not by mounting host /). Therefore the proposed validator that forces HostNetworkAccess=true for user networking is incorrect: HostNetworkAccess controls NAT to the host loopback and is not required for the 9P server the daemon creates.

Files to note:

  • pkg/crc/config/settings.go — AddSetting for EnableSharedDirs (update help text here)
  • cmd/crc/cmd/daemon.go — vn.Listen on configuration.GatewayIP and fs9p.StartShares (9P server is bound to the virtual-network gateway)
  • pkg/crc/machine/start.go — configureSharedDirs uses "9pfs 192.168.127.1" (guest mounts the gateway, mountpoint is not '/')
  • pkg/fileserver/fs9p/server.go & shares.go — New9pServer / StartShares bind to the provided listener
  • pkg/crc/constants/constants.go — Plan9Port = 564 (9P port)

Proposed help-text change (apply to pkg/crc/config/settings.go where EnableSharedDirs is registered):

-	cfg.AddSetting(EnableSharedDirs, true, ValidateBool, SuccessfullyApplied,
-		"Mounts host's home directory at '/' in the CRC VM (true/false, default: true)")
+	cfg.AddSetting(EnableSharedDirs, true, ValidateBool, SuccessfullyApplied,
+		"Expose the host's home directory to the CRC VM via 9P (true/false, default: true). The share is served via the CRC virtual-network gateway (e.g. 192.168.127.1) and mounted inside the VM via 9P (not mounted at '/')")

Validator guidance:

  • Do not add a validator that requires HostNetworkAccess=true for NetworkMode=user. Verified evidence: daemon binds the 9P server to the CRC virtual network gateway (cmd/crc/cmd/daemon.go -> vn.Listen on configuration.GatewayIP) and the VM mounts that gateway address (pkg/crc/machine/start.go uses "9pfs 192.168.127.1"). HostNetworkAccess is a separate toggle that maps a virtual host IP to the host loopback and is not necessary for the 9P share.

Likely an incorrect or invalid review comment.

vendor/github.com/DeedleFake/p9/doc.go (1)

1-63: LGTM: Clear, useful package-level docs

The overview and examples set the right expectations for both client and server APIs. No code changes; nothing else to flag.

vendor/github.com/DeedleFake/p9/proto/encoding.go (1)

147-159: No change required — reads are already capped with LimitedReader

proto.Receive reads the message size, enforces msize, then wraps the connection with util.LimitedReader (N = size, E = ErrLargeMessage) and uses that reader for subsequent decoding, so decoder.decode runs against a length-limited reader.

  • vendor/github.com/DeedleFake/p9/proto/proto.go: Receive(...) — reads size, checks msize, constructs lr := &util.LimitedReader{R: r, N: size, E: ErrLargeMessage} and calls Read(lr, ...)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go: LimitedReader implementation that returns the configured error when the limit is reached
  • vendor/github.com/DeedleFake/p9/proto/encoding.go: decoder.decode handles slice lengths/allocations — safe when invoked via Receive
vendor/github.com/DeedleFake/p9/addr.go (1)

10-66: LGTM: ParseAddr covers common 9P forms and pseudo-port mapping

Solid handling of “$namespace”, Unix sockets, host:port (including 9p/9fs), and proto!addr[!port] forms. No functional issues spotted.

vendor/github.com/DeedleFake/p9/p9.go (2)

21-39: LGTM: Open mode/flag constants consistent with 9P semantics

The bit layout and the iota math are correct; no concerns.


41-66: LGTM: QID/QIDType and FileMode conversion look correct

QIDType->FileMode shift aligns with 9P’s mode top bits. No issues.

pkg/crc/constants/constants.go (1)

59-60: Plan 9 constants addition looks good

Using the standard 9P port (564) and a generous 1MiB msize is sensible for the initial integration.

cmd/crc/cmd/daemon.go (3)

27-27: Importing fs9p for 9P shares is appropriate

The new import aligns with the 9P home directory sharing introduced below.


181-185: Good: use net.JoinHostPort for listener address

This is safer (IPv6-aware) and avoids string formatting pitfalls.


197-211: Good: consistent JoinHostPort usage for network listener

Same benefits here; consistent and correct.

vendor/github.com/DeedleFake/p9/dir_other.go (1)

7-14: LGTM: sane fallback entry mapping

For non-listed OSes, mapping mode/mtime/size/name is correct and minimal.

vendor/github.com/DeedleFake/p9/dir_windows.go (1)

9-27: Windows DirEntry mapping looks correct

  • Safe type assertion on fi.Sys() and proper fallback when sys is nil.
  • Using Filetime.Nanoseconds() with time.Unix(0, ...) is the idiomatic conversion.
vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

46-62: Darwin QID generation approach is sound

Using inode for Path and deriving QID type from mode mirrors Linux behavior and is appropriate. Error on missing Stat_t keeps semantics clear.

vendor/github.com/DeedleFake/p9/encoding.go (1)

33-42: LGTM: WriteDir is straightforward and correct.

Looped encode via proto.Write is clear and returns on first error as expected.

vendor/github.com/DeedleFake/p9/proto/client.go (2)

69-75: LGTM: clean shutdown path

Close() cancels the coordination goroutines and closes the underlying connection. This aligns with the reader/coord loop design.


176-208: Solid tagged/untagged messaging coordination

The Send/reader/coord interplay correctly handles both tagged messages and the special untagged case (P9NoTag), with backpressure and cancellation paths.

vendor/github.com/DeedleFake/p9/dir.go (1)

18-21: Consider hardening against traversal in path resolution

Dir.path simply joins the base with the provided p. If upstream always supplies normalized, component-wise paths (as expected by the 9P Walk semantics), this is fine. If not guaranteed, normalize and reject any attempt to escape the base (e.g., by resolving and verifying that the result has the base as a prefix).

Would you like me to add a safe-join helper that rejects absolute paths and any result escaping the base?

vendor/github.com/DeedleFake/p9/stat.go (1)

191-216: Stat encoding/decoding looks correct and spec-compliant.

The size-prefix and LimitedReader enforcement align with 9P stat encoding, and error propagation is sound.

vendor/github.com/DeedleFake/p9/msg.go (2)

207-233: Rstat length-prefixing matches Stat.P9Encode; decode bounds are correct.

The extra +2 accounts for Stat’s internal size field, and the LimitedReader bounds prevent overreads. This aligns with the 9P2000 spec.


44-72: Protocol registry is comprehensive and type-safe mapping looks good.

The reflect-based registry setup matches the declared message types and provides a solid base for dispatch.

Comment thread cmd/crc/cmd/daemon.go
Comment thread go.mod Outdated
Comment thread pkg/crc/machine/libhvee/driver_windows.go
Comment thread pkg/crc/machine/start.go
Comment thread pkg/fileserver/fs9p/server.go Outdated
Comment thread vendor/github.com/DeedleFake/p9/proto/encoding.go
Comment thread vendor/github.com/DeedleFake/p9/proto/proto.go
Comment thread vendor/github.com/DeedleFake/p9/proto/server.go
Comment thread vendor/github.com/DeedleFake/p9/remote.go
Comment thread vendor/github.com/DeedleFake/p9/remote.go

@cfergeau cfergeau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only took a quick look, but it’s unexpected to see the 9p code being added in the first commits before being disabled, and then to have the smb code removal.
Regarding the 9p code, some of the comments of coderabbit.ai (including in the vendor’ed code) deserve a closer look.

@redbeam

redbeam commented Sep 9, 2025

Copy link
Copy Markdown
Contributor Author

@cfergeau

Only took a quick look, but it’s unexpected to see the 9p code being added in the first commits before being disabled, and then to have the smb code removal.

I based this branch on the 9p branch to avoid conflicts. This PR is expected to be merged as soon as 9p support is merged, so the 9p code will already be there.

Regarding the 9p code, some of the comments of coderabbit.ai (including in the vendor’ed code) deserve a closer look.

I'll look at comments on my parts of the code, but what can be done about the vendored code?

@cfergeau

Copy link
Copy Markdown
Contributor

I'll look at comments on my parts of the code, but what can be done about the vendored code?

If they are actual issues, in particular issues with security impacts, if it’s not too hard to fix them, I’d file PRs upstream, this way we’ll get the fixes in our codebase when they are merged.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packaging/windows/product.wxs.template (1)

95-103: Remove stray '~' in MSI condition strings

packaging/windows/product.wxs.template — occurrences of REMOVE~="ALL" at lines 96, 97, 98, 99, 100, 102. WiX conditions must be REMOVE="ALL" (no ''); replace all REMOVE="ALL" with REMOVE="ALL".

♻️ Duplicate comments (11)
vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

35-43: Fix Darwin build: Timespec.Unix() does not exist; use Sec/Nsec fields

This won’t compile on darwin; syscall.Timespec has Sec/Nsec, not Unix().

Please also send this fix upstream to DeedleFake/p9 so we don’t carry a long‑term vendor delta.

 return DirEntry{
   FileMode:  ModeFromOS(fi.Mode()),
-  ATime:     time.Unix(sys.Atimespec.Unix()),
+  ATime:     time.Unix(int64(sys.Atimespec.Sec), int64(sys.Atimespec.Nsec)),
   MTime:     fi.ModTime(),
   Length:    uint64(fi.Size()),
   EntryName: fi.Name(),
   UID:       uname,
   GID:       gname,
 }
#!/bin/bash
# Confirm there are no other invalid Timespec.Unix() calls.
rg -nP 'Atimespec\.Unix\(' -S
pkg/crc/machine/libhvee/driver_windows.go (1)

39-45: Deterministic 9P tag mapping; keep in sync with server (duplicate)

Sort the list before assigning tags to keep tag->share stable across runs and avoid drift with the 9P server’s aname. Also consider centralizing the tag format constant so both sides stay aligned.

@@
-import (
-	"fmt"
-	"path/filepath"
-	"strings"
-)
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+	"sort"
+)
@@
-	for i, dir := range machineConfig.SharedDirs {
+	dirs := append([]string(nil), machineConfig.SharedDirs...)
+	sort.Strings(dirs)
+	for i, dir := range dirs {
 		sharedDir := drivers.SharedDir{
 			Source: dir,
 			Target: convertToUnixPath(dir),
 			Tag:    fmt.Sprintf("dir%d", i),
 			Type:   "9p",
 		}
cmd/crc/cmd/daemon.go (1)

253-266: Don’t drop 9P server handles; defer Stop() for clean shutdown (duplicate)

Keep the returned servers and stop them to avoid goroutine/listener leaks.

 	// 9p home directory sharing
 	if runtime.GOOS == "windows" {
-		if _, err := fs9p.StartHvsockShares([]fs9p.HvsockMount9p{{Path: constants.GetHomeDir(), HvsockGUID: constants.Plan9HvsockGUID}}); err != nil {
+		if servers, err := fs9p.StartHvsockShares([]fs9p.HvsockMount9p{{Path: constants.GetHomeDir(), HvsockGUID: constants.Plan9HvsockGUID}}); err != nil {
 			logging.Warnf("Failed to start 9p file server on hvsock: %v", err)
 			logging.Warnf("Falling back to 9p over TCP")
 			listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9TcpPort)))
 			if err != nil {
 				return err
 			}
-			if _, err := fs9p.StartShares([]fs9p.Mount9p{{Listener: listener9p, Path: constants.GetHomeDir()}}); err != nil {
+			if serversTCP, err := fs9p.StartShares([]fs9p.Mount9p{{Listener: listener9p, Path: constants.GetHomeDir()}}); err != nil {
 				return err
+			} else {
+				defer func() {
+					for _, s := range serversTCP {
+						if stopErr := s.Stop(); stopErr != nil {
+							logging.Errorf("Error stopping 9p server: %v", stopErr)
+						}
+					}
+				}()
 			}
+		} else {
+			defer func() {
+				for _, s := range servers {
+					if stopErr := s.Stop(); stopErr != nil {
+						logging.Errorf("Error stopping 9p server: %v", stopErr)
+					}
+				}
+			}()
 		}
 	}
pkg/crc/machine/start.go (1)

244-256: 9P mount should be privileged, idempotent, and explicit; avoid brittle helper

Mounting requires root; using sshRunner.Run will likely fail. Also, add mountpoint check and use explicit 9P mount with options and tag for TCP fallback. Keep the hvsock attempt if needed, but run it privileged.

 		case "9p":
-			// change owner to core user to allow mounting to it as a non-root user
-			if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
-				return err
-			}
-			if _, _, err := sshRunner.Run("9pfs -V -p", fmt.Sprintf("%d", constants.Plan9HvsockPort), mount.Target); err != nil {
-				logging.Warnf("Failed to connect to 9p server over hvsock: %v", err)
-				logging.Warnf("Falling back to 9p over TCP")
-				if _, _, err := sshRunner.Run("9pfs 192.168.127.1", mount.Target); err != nil {
-					return err
-				}
-			}
+			// idempotency
+			if _, _, err := sshRunner.RunPrivileged("Check if already mounted", "mountpoint", "-q", mount.Target); err == nil {
+				logging.Debugf("Already mounted, skipping: %s", mount.Target)
+				continue
+			}
+			// change owner to core user to allow non-root access after mounting
+			if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown", "core:core", mount.Target); err != nil {
+				return err
+			}
+			// Try hvsock via helper (if present) with elevated privileges
+			if _, _, err := sshRunner.RunPrivileged("Mounting 9p over hvsock", "9pfs", "-V", "-p", fmt.Sprintf("%d", constants.Plan9HvsockPort), mount.Target); err != nil {
+				logging.Warnf("Failed to connect to 9p server over hvsock: %v", err)
+				logging.Warnf("Falling back to 9p over TCP")
+				opts := fmt.Sprintf("trans=tcp,port=%d,msize=%d,cache=loose,version=9p2000.L,aname=%s", constants.Plan9TcpPort, constants.Plan9Msize, mount.Tag)
+				if _, _, err := sshRunner.RunPrivileged(
+					fmt.Sprintf("Mounting %s (9p tag %s) over TCP", mount.Target, mount.Tag),
+					"mount", "-t", "9p", "-o", opts, "192.168.127.1", mount.Target,
+				); err != nil {
+					return err
+				}
+			}

Follow-ups:

  • Consider gating the hvsock attempt behind a feature flag until client support stabilizes.
pkg/fileserver/fs9p/shares.go (1)

24-61: Fix loop-variable capture; close listener on per-mount failures; preallocate slice

Avoid capturing loop vars in defer/goroutine, and ensure the current mount’s listener is closed on errors before the defer is installed. Also preallocate the servers slice.

-func StartShares(mounts []Mount9p) (servers []*Server, defErr error) {
-	servers9p := []*Server{}
+func StartShares(mounts []Mount9p) (servers []*Server, defErr error) {
+	servers = make([]*Server, 0, len(mounts))
 	for _, m := range mounts {
 		server, err := New9pServer(m.Listener, m.Path)
 		if err != nil {
-			return nil, fmt.Errorf("serving directory %s on %s: %w", m.Path, m.Listener.Addr().String(), err)
+			_ = m.Listener.Close() // avoid leaking a listener on constructor failure
+			return nil, fmt.Errorf("serving directory %s on %s: %w", m.Path, m.Listener.Addr().String(), err)
 		}
 
-		err = server.Start()
+		if err := server.Start(); err != nil {
+			_ = server.Stop() // close listener if start fails before defer is in place
 			if err != nil {
-			return nil, fmt.Errorf("starting 9p server for directory %s: %w", m.Path, err)
+				return nil, fmt.Errorf("starting 9p server for directory %s: %w", m.Path, err)
 			}
-		}
-
-		servers9p = append(servers9p, server)
+		}
+		servers = append(servers, server)
 
-		defer func() {
+		s := server
+		defer func(s *Server) {
 			if defErr != nil {
-				if err := server.Stop(); err != nil {
+				if err := s.Stop(); err != nil {
 					logrus.Errorf("Error stopping 9p server: %v", err)
 				}
 			}
-		}()
+		}(s)
 
-		serverDir := m.Path
+		serverDir := m.Path
+		addr := m.Listener.Addr().String()
 
-		go func() {
-			if err := server.WaitForError(); err != nil {
-				logrus.Errorf("Error from 9p server on %s for %s: %v", m.Listener.Addr().String(), serverDir, err)
+		go func(s *Server, address, dir string) {
+			if err := s.WaitForError(); err != nil {
+				logrus.Errorf("Error from 9p server on %s for %s: %v", address, dir, err)
 			} else {
 				// We do not expect server exits - this should run until the program exits.
-				logrus.Warnf("9p server on %s for %s exited without error", m.Listener.Addr().String(), serverDir)
+				logrus.Warnf("9p server on %s for %s exited without error", address, dir)
 			}
-		}()
+		}(s, addr, serverDir)
 	}
 
-	return servers9p, nil
+	return servers, nil
 }
pkg/fileserver/fs9p/server.go (1)

42-51: Buffer ErrChan and treat net.ErrClosed as clean shutdown to avoid leaks/noise

Unbuffered ErrChan can block the server goroutine if nobody reads; also treat listener closure as non-error in WaitForError.

-import (
+import (
+	"errors"
 	"fmt"
 	"net"
 	"os"
 	"path/filepath"
@@
-	errChan := make(chan error)
+	errChan := make(chan error, 1)
@@
-func (s *Server) WaitForError() error {
-	err := <-s.ErrChan
-	return err
-}
+func (s *Server) WaitForError() error {
+	if err, ok := <-s.ErrChan; ok {
+		if errors.Is(err, net.ErrClosed) {
+			return nil
+		}
+		return err
+	}
+	return nil
+}

Also applies to: 83-87

vendor/github.com/DeedleFake/p9/proto/proto.go (1)

85-93: Off‑by‑4 framing: bound LimitedReader to size‑4 and guard undersized frames.

9P size includes the size field; using N=size leaks 4 bytes into the next frame on boundaries.

Apply this diff:

 	if (msize > 0) && (size > msize) {
 		return nil, NoTag, util.Errorf("receive: %w", ErrLargeMessage)
 	}
 
-	lr := &util.LimitedReader{
-		R: r,
-		N: size,
-		E: ErrLargeMessage,
-	}
+	if size < 4 {
+		return nil, NoTag, util.Errorf("receive: invalid frame size: %d", size)
+	}
+	rem := size - 4
+	if rem < 3 { // need at least 1 byte type + 2 bytes tag
+		return nil, NoTag, util.Errorf("receive: frame too small for header: %d", size)
+	}
+	lr := &util.LimitedReader{
+		R: r,
+		N: rem,
+		E: ErrLargeMessage,
+	}
vendor/github.com/DeedleFake/p9/remote.go (4)

37-43: Build Twalk Wname correctly for absolute paths (no empty elements).

Leading “/” currently yields an empty first element or “/” entry, which is invalid for Twalk.

-	w := []string{path.Clean(p)}
-	if w[0] != "/" {
-		w = strings.Split(w[0], "/")
-	}
-	if (len(w) == 1) && (w[0] == ".") {
-		w = nil
-	}
+	p = path.Clean(p)
+	var w []string
+	switch {
+	case p == "" || p == ".":
+		w = nil
+	default:
+		if strings.HasPrefix(p, "/") {
+			p = strings.TrimPrefix(p, "/")
+		}
+		if p != "" {
+			w = strings.Split(p, "/")
+		} else {
+			w = nil
+		}
+	}

184-185: Don’t panic on invalid whence; return error.

-	panic(util.Errorf("Invalid whence: %v", whence))
+	return int64(file.pos), util.Errorf("invalid whence: %v", whence)

198-201: Guard maxBufSize underflow; avoid infinite loops on small msize.

int(msize-IOHeaderSize) can underflow or be 0, causing ReadAt/WriteAt to loop forever.

-func (file *Remote) maxBufSize() int {
-	return int(file.client.Msize() - IOHeaderSize)
-}
+func (file *Remote) maxBufSize() int {
+	m := file.client.Msize()
+	if m <= uint32(IOHeaderSize) {
+		// Minimum 1 to ensure forward progress; handshake should reject too-small msize.
+		return 1
+	}
+	return int(m - uint32(IOHeaderSize))
+}

Additionally, validate negotiated msize during handshake (in vendor/github.com/DeedleFake/p9/client.go) and fail if msize <= IOHeaderSize. Want a patch?


230-239: Prevent zero/negative chunk size in ReadAt.

If maxBufSize ≤ 0, the loop never advances.

-	size := len(buf)
-	if size > file.maxBufSize() {
-		size = file.maxBufSize()
-	}
+	size := len(buf)
+	max := file.maxBufSize()
+	if max <= 0 {
+		return 0, util.Errorf("msize too small: %d", file.client.Msize())
+	}
+	if size > max {
+		size = max
+	}
🧹 Nitpick comments (10)
vendor/github.com/DeedleFake/p9/dir_darwin.go (2)

23-33: Preserve identity when name lookup fails by falling back to numeric UID/GID

Avoid empty UID/GID fields; default to the numeric IDs and override on successful lookup.

-var uname string
-uid, err := user.LookupId(strconv.FormatUint(uint64(sys.Uid), 10))
-if err == nil {
-	uname = uid.Username
-}
+uname := strconv.FormatUint(uint64(sys.Uid), 10)
+if u, err := user.LookupId(uname); err == nil && u != nil && u.Username != "" {
+	uname = u.Username
+}
 
-var gname string
-gid, err := user.LookupGroupId(strconv.FormatUint(uint64(sys.Gid), 10))
-if err == nil {
-	gname = gid.Name
-}
+gname := strconv.FormatUint(uint64(sys.Gid), 10)
+if g, err := user.LookupGroupId(gname); err == nil && g != nil && g.Name != "" {
+	gname = g.Name
+}

52-55: Improve diagnostics when FileInfo.Sys() isn’t Stat_t

Including the path and actual type eases debugging. Optional, but helpful.

-import (
-	"errors"
+import (
+	"fmt"
 	"os"
 	"os/user"
 	"strconv"
 	"syscall"
 	"time"
 )
@@
-	sys, _ := fi.Sys().(*syscall.Stat_t)
-	if sys == nil {
-		return QID{}, errors.New("failed to get QID: FileInfo was not Stat_t")
-	}
+	sys, _ := fi.Sys().(*syscall.Stat_t)
+	if sys == nil {
+		return QID{}, fmt.Errorf("failed to get QID for %q: FileInfo.Sys()=%T; want *syscall.Stat_t", d.path(p), fi.Sys())
+	}
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)

1-1: Add go:build tag and newline in debug output

Include the modern build tag for Go 1.17+ and add a newline to avoid run‑on log lines.

-// +build p9debug
+//go:build p9debug
+// +build p9debug
@@
 func Log(str string, args ...interface{}) {
-	fmt.Fprintf(os.Stderr, str, args...)
+	_, _ = fmt.Fprintf(os.Stderr, str+"\n", args...)
 }

Also applies to: 10-12

vendor/github.com/DeedleFake/p9/README.md (1)

1-52: Markdown lint noise from vendored docs: exclude vendor/

Static analysis flags heading style/tabs here. Prefer excluding vendor/** from markdownlint rather than editing upstream docs.

pkg/crc/config/settings.go (1)

87-88: Help text: don’t claim mountpoint ‘/’ across OSes

The mount location differs by platform. Make the message neutral.

- cfg.AddSetting(EnableSharedDirs, true, ValidateBool, SuccessfullyApplied,
- 	"Mounts host's home directory at '/' in the CRC VM (true/false, default: true)")
+ cfg.AddSetting(EnableSharedDirs, true, ValidateBool, SuccessfullyApplied,
+ 	"Enable sharing of the host home directory into the CRC VM (true/false, default: true)")
pkg/fileserver/fs9p/shares_fallback.go (1)

5-13: Return a sentinel error instead of a formatted string

Makes detection easier for callers without string matching.

-import (
-	"fmt"
-	"runtime"
-)
+import (
+	"errors"
+	"runtime"
+)
+
+var ErrHvsockUnsupported = errors.New("fs9p: StartHvsockShares is only supported on windows")
@@
 func StartHvsockShares(mounts []HvsockMount9p) ([]*Server, error) {
-	return nil, fmt.Errorf("StartHvsockShares() not implemented on %s", runtime.GOOS)
+	_ = runtime.GOOS // keep message parity with windows-only implementation if needed elsewhere
+	return nil, ErrHvsockUnsupported
 }
pkg/crc/machine/start.go (2)

237-243: SELinux context: virtiofs uses container_file_t; 9P may need labeling or doc

9P often doesn’t support SELinux contexts like virtiofs. If containers need access, ensure appropriate labeling/workaround is applied or document the limitation.


320-323: Leftover SMB creds in machine config?

SharedDirPassword/Username are still passed into MachineConfig though SMB is removed. If unused, drop them to avoid confusion.

pkg/fileserver/fs9p/server.go (1)

61-69: Avoid flagging immediate net.ErrClosed as startup error

If the listener gets closed quickly, Start() will surface net.ErrClosed as a startup error. Consider ignoring net.ErrClosed here as well to reduce false alarms.

vendor/github.com/DeedleFake/p9/proto/proto.go (1)

101-108: Remove dead check and return a clear error for unknown msg type.

-	t := p.TypeFromID(msgType)
-	if t == nil {
-		if err != nil {
-			return nil, NoTag, err
-		}
-
-		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
-	}
+	t := p.TypeFromID(msgType)
+	if t == nil {
+		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
+	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25ef0c7 and f330f89.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (44)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (2 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/shares.go (1 hunks)
  • pkg/fileserver/fs9p/shares_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/shares_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
💤 Files with no reviewable changes (7)
  • pkg/crc/machine/driver_linux.go
  • pkg/crc/machine/driver_darwin.go
  • pkg/crc/machine/driver_windows.go
  • cmd/crc/cmd/start.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver.go
✅ Files skipped from review due to trivial changes (1)
  • vendor/github.com/DeedleFake/p9/doc.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • vendor/github.com/DeedleFake/p9/LICENSE
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go
  • vendor/github.com/DeedleFake/p9/addr_unix.go
  • vendor/github.com/DeedleFake/p9/proto/encoding.go
  • vendor/github.com/DeedleFake/p9/addr.go
  • vendor/github.com/DeedleFake/p9/proto/server.go
  • vendor/github.com/DeedleFake/p9/dir_other.go
  • vendor/github.com/DeedleFake/p9/encoding.go
  • vendor/github.com/DeedleFake/p9/fs.go
  • vendor/github.com/DeedleFake/p9/stat.go
  • vendor/github.com/DeedleFake/p9/dir_plan9.go
  • vendor/github.com/DeedleFake/p9/dir_windows.go
  • vendor/github.com/DeedleFake/p9/addr_other.go
  • vendor/github.com/DeedleFake/p9/dir.go
  • go.mod
  • vendor/github.com/DeedleFake/p9/dir_linux.go
  • vendor/github.com/DeedleFake/p9/internal/util/util.go
  • vendor/github.com/DeedleFake/p9/msg.go
  • vendor/github.com/DeedleFake/p9/client.go
  • vendor/github.com/DeedleFake/p9/p9.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • pkg/fileserver/fs9p/shares_fallback.go
  • pkg/fileserver/fs9p/shares_windows.go
  • cmd/crc/cmd/daemon.go
  • pkg/fileserver/fs9p/shares.go
  • pkg/fileserver/fs9p/server.go
  • vendor/github.com/DeedleFake/p9/README.md
🧬 Code graph analysis (13)
pkg/fileserver/fs9p/shares_fallback.go (3)
pkg/fileserver/fs9p/shares_windows.go (1)
  • StartHvsockShares (12-33)
pkg/fileserver/fs9p/shares.go (1)
  • HvsockMount9p (19-22)
pkg/fileserver/fs9p/server.go (1)
  • Server (15-24)
pkg/fileserver/fs9p/shares_windows.go (3)
pkg/fileserver/fs9p/shares_fallback.go (1)
  • StartHvsockShares (11-13)
pkg/fileserver/fs9p/shares.go (3)
  • HvsockMount9p (19-22)
  • Mount9p (12-15)
  • StartShares (25-61)
pkg/fileserver/fs9p/server.go (1)
  • Server (15-24)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/dir_darwin.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
pkg/crc/machine/libhvee/driver_windows.go (1)
vendor/github.com/crc-org/machine/libmachine/drivers/base.go (1)
  • SharedDir (27-35)
vendor/github.com/DeedleFake/p9/proto/proto.go (4)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Read (34-38)
  • Write (25-31)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/internal/util/util.go (2)
  • Errorf (44-52)
  • LimitedReader (13-17)
cmd/crc/cmd/daemon.go (5)
pkg/fileserver/fs9p/shares_fallback.go (1)
  • StartHvsockShares (11-13)
pkg/fileserver/fs9p/shares_windows.go (1)
  • StartHvsockShares (12-33)
pkg/fileserver/fs9p/shares.go (3)
  • HvsockMount9p (19-22)
  • StartShares (25-61)
  • Mount9p (12-15)
pkg/crc/constants/constants.go (3)
  • GetHomeDir (166-172)
  • Plan9HvsockGUID (61-61)
  • Plan9TcpPort (60-60)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
pkg/crc/config/settings.go (2)
pkg/crc/config/validations.go (1)
  • ValidateBool (19-25)
pkg/crc/config/callbacks.go (1)
  • SuccessfullyApplied (36-38)
vendor/github.com/DeedleFake/p9/remote.go (7)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • Client (18-31)
vendor/github.com/DeedleFake/p9/p9.go (4)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • IOHeaderSize (70-70)
vendor/github.com/DeedleFake/p9/msg.go (13)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • ReadDir (16-30)
pkg/crc/machine/start.go (3)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/crc/constants/constants.go (1)
  • Plan9HvsockPort (62-62)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
pkg/fileserver/fs9p/shares.go (1)
pkg/fileserver/fs9p/server.go (2)
  • Server (15-24)
  • New9pServer (29-52)
vendor/github.com/DeedleFake/p9/proto/client.go (5)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
  • Proto (38-41)
  • NoTag (27-27)
  • ErrClientClosed (22-22)
vendor/github.com/DeedleFake/p9/client.go (3)
  • NewClient (30-32)
  • Client (22-26)
  • Dial (36-43)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
pkg/fileserver/fs9p/server.go (3)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
🪛 markdownlint-cli2 (0.17.2)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: build (macOS-14, 1.24)
  • GitHub Check: build (ubuntu-22.04, 1.24)
  • GitHub Check: build (macOS-14, 1.24)
  • GitHub Check: build-qe (linux, arm64)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: build-qe (windows, amd64)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (macOS-13, 1.24)
  • GitHub Check: build-qe (darwin, amd64)
  • GitHub Check: build-qe (linux, amd64)
  • GitHub Check: build-qe (darwin, arm64)
  • GitHub Check: build-installer (windows-2022, 1.24)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: Run OKD bundle with crc (1.24)
  • GitHub Check: verify-devcontainer
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (7)
pkg/crc/machine/libhvee/driver_windows.go (1)

41-45: LGTM: switch to 9P and drop SMB creds

Using Type="9p" with no Username/Password on Windows is correct for the new path.

pkg/crc/constants/constants.go (1)

59-62: LGTM: 9P constants added

Values look sane for 9P defaults and hvsock integration.

cmd/crc/cmd/daemon.go (1)

182-186: LGTM: net.JoinHostPort

Safer IPv6‑aware address construction.

Also applies to: 198-202

pkg/crc/config/settings.go (1)

33-35: Do not remove SharedDirPassword — it's referenced in the code.
SharedDirPassword is referenced in pkg/crc/machine/start.go:321, pkg/crc/machine/types/types.go:37, and pkg/crc/machine/config/config.go:24; remove only after updating/removing those usages.

Likely an incorrect or invalid review comment.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

115-146: Skip NoTag (0xFFFF) when allocating tags to prevent protocol collision

When nextTag wraps it can equal NoTag; advance past NoTag before returning the next tag.

-	var nextTag uint16
+	var nextTag uint16
 	tags := make(map[uint16]chan interface{})
@@
-		case c.nextTag <- nextTag:
-			for {
-				nextTag++
-				if _, ok := tags[nextTag]; !ok {
-					break
-				}
-			}
+		case c.nextTag <- nextTag:
+			for {
+				nextTag++
+				if nextTag == NoTag {
+					nextTag++
+				}
+				if _, ok := tags[nextTag]; !ok {
+					break
+				}
+			}

Given this is vendored, send the fix upstream so it persists across updates.

packaging/windows/product.wxs.template (2)

111-112: LGTM: Feature references include the new HVSOCK 9P component.


69-73: Resolved — GUIDs are aligned

pkg/crc/constants/constants.go defines Plan9HvsockGUID = "00009000-FACB-11E6-BD58-64006A7986D3"; the same value is present in packaging/windows/product.wxs.template and used via constants.Plan9HvsockGUID in cmd/crc/cmd/daemon.go. No action required.

Comment thread packaging/windows/product.wxs.template
Comment thread pkg/fileserver/fs9p/shares_windows.go Outdated
Comment thread vendor/github.com/DeedleFake/p9/remote.go Outdated
@redbeam
redbeam force-pushed the remove_smb branch 2 times, most recently from 5959d98 to f06fba0 Compare October 1, 2025 17:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

♻️ Duplicate comments (17)
pkg/crc/machine/libhvee/driver_windows.go (1)

39-45: Past review concerns remain unaddressed: tag determinism and centralization.

The previous review's concerns about tag/name symmetry, deterministic ordering, and centralizing the tag format are still applicable. The tag generation using fmt.Sprintf("dir%d", i) remains:

  1. Non-deterministic: Tag assignment depends on iteration order; reordering SharedDirs will change tags and break existing mounts.
  2. Not centralized: The "dir%d" format is hardcoded here and must match the 9P server's share naming. If they diverge, mounts will fail.

The removal of the Username field is correct for 9p (which doesn't require Windows credentials), and the Type: "9p" change aligns with the PR's migration from SMB to 9p.

To verify tag format consistency with the 9P server, run:

#!/bin/bash
# Description: Find where 9P share names/tags are defined on the server side.
# Expected: Server should use matching "dir%d" format or derive from same source.

# Search for 9P share/tag/aname definitions in fileserver code
rg -n -C3 --type=go 'Share.*Tag|aname|dir%d|Plan9.*Tag' pkg/fileserver/

# Search for any tag format constants or helpers
rg -n -C3 --type=go 'ShareTag|Plan9Tag|dir%d' pkg/crc/constants/ pkg/fileserver/
vendor/github.com/DeedleFake/p9/addr_other.go (1)

23-28: Critical Windows path issue requires upstream fix.

As flagged in the previous review, using DISPLAY values containing ":" (like the default ":0") creates invalid Windows paths, causing runtime failures. This is a critical correctness issue for Windows deployments.

Per the PR discussion, this vendored code issue should be fixed upstream. Please file a PR to the DeedleFake/p9 repository with the sanitization fix suggested in the previous comment (adding runtime.GOOS check and replacing ":" with "_" on Windows).

Based on PR discussion guidance.

cmd/crc/cmd/daemon.go (1)

253-280: Missing graceful shutdown for 9P servers.

Both server9pHvsock (line 260-264) and server9pTCP (line 273-277) are started but their handles are not retained for cleanup. When the daemon shuts down, these servers will leak goroutines and listeners.

Capture the server instances and defer their cleanup to ensure graceful shutdown.

For example:

 // 9p home directory sharing
 if runtime.GOOS == "windows" {
   // 9p over hvsock
   listener9pHvsock, err := fs9p.GetHvsockListener(constants.Plan9HvsockGUID)
   if err != nil {
     return err
   }
   server9pHvsock, err := fs9p.New9pServer(listener9pHvsock, constants.GetHomeDir())
   if err != nil {
     return err
   }
   if err := server9pHvsock.Start(); err != nil {
     return err
   }
+  defer func() {
+    if err := server9pHvsock.Stop(); err != nil {
+      logging.Errorf("Error stopping hvsock 9p server: %v", err)
+    }
+  }()

   // 9p over TCP (as a backup)
   listener9pTCP, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9TcpPort)))
   if err != nil {
     return err
   }
   server9pTCP, err := fs9p.New9pServer(listener9pTCP, constants.GetHomeDir())
   if err != nil {
     return err
   }
   if err := server9pTCP.Start(); err != nil {
     return err
   }
+  defer func() {
+    if err := server9pTCP.Stop(); err != nil {
+      logging.Errorf("Error stopping TCP 9p server: %v", err)
+    }
+  }()
 }

Note: This issue was previously flagged in an earlier review.

pkg/crc/machine/start.go (1)

244-256: Make 9P mount idempotent and clarify privilege/options (FUSE vs kernel 9p)

  • Add a pre-check to skip if already mounted.
  • If this uses a kernel 9p mount, run it privileged and pass aname, msize, version, cache. If it’s a FUSE client, keep unprivileged but ensure tag/export is specified and consider msize.

Example (kernel mount path):

         case "9p":
+            // Skip if already mounted
+            if _, _, err := sshRunner.RunPrivileged("Check mountpoint", "mountpoint", "-q", mount.Target); err == nil {
+                logging.Debugf("Already mounted: %s", mount.Target)
+                continue
+            }
             // change owner to core user to allow mounting to it as a non-root user
             if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown", "core:core", mount.Target); err != nil {
                 return err
             }
-            if _, _, err := sshRunner.Run("9pfs", "-V", "-p", fmt.Sprintf("%d", constants.Plan9HvsockPort), mount.Target); err != nil {
+            // Prefer explicit 9p kernel mount with options; if you intend to use FUSE 9pfs, please confirm and keep it.
+            opts := fmt.Sprintf("trans=tcp,port=%d,msize=%d,cache=loose,version=9p2000.L,aname=%s", constants.Plan9TcpPort, constants.Plan9Msize, mount.Tag)
+            if _, _, err := sshRunner.RunPrivileged(
+                fmt.Sprintf("Mounting %s (9p tag %s)", mount.Target, mount.Tag),
+                "mount", "-t", "9p", "-o", opts, constants.VSockGateway, mount.Target,
+            ); err != nil {
                 logging.Warnf("Failed to connect to 9p server over hvsock: %v", err)
                 logging.Warnf("Falling back to 9p over TCP")
-                if _, _, err := sshRunner.Run("9pfs", "192.168.127.1", mount.Target); err != nil {
+                if _, _, err := sshRunner.RunPrivileged("Mount 9p over TCP", "mount", "-t", "9p", "-o", opts, constants.VSockGateway, mount.Target); err != nil {
                     return err
                 }
             }

If you intend to use a FUSE-based 9pfs client, please confirm its CLI for specifying the export/tag and msize, and we’ll adjust accordingly instead of using mount -t 9p.

Run to find other combined-token calls:

#!/bin/bash
rg -nP -C2 'Run(?:Privileged)?\([^,]+,\s*"[^",\s]+ [^"]+"' --type go
vendor/github.com/DeedleFake/p9/dir_linux.go (1)

35-43: Fix ATime construction: syscall.Timespec lacks Unix() (compile error)

Use Sec/Nsec fields of Stat_t.Atim.

-        ATime:     time.Unix(sys.Atim.Unix()),
+        ATime:     time.Unix(int64(sys.Atim.Sec), int64(sys.Atim.Nsec)),
pkg/fileserver/fs9p/server.go (2)

71-80: Stop() is a hard close; consider graceful shutdown or document clearly

Either track connections and drain with a timeout, or document at call sites that Stop forcibly interrupts active I/O and callers should ignore net.ErrClosed from WaitForError.


3-13: Avoid goroutine leak; treat net.ErrClosed as clean shutdown

Make ErrChan buffered and ignore net.ErrClosed in WaitForError. Adds errors import.

@@
-import (
+import (
+	"errors"
 	"fmt"
 	"net"
 	"os"
 	"path/filepath"
@@
-	errChan := make(chan error)
+	errChan := make(chan error, 1)
@@
-func (s *Server) WaitForError() error {
-	err := <-s.ErrChan
-	return err
-}
+func (s *Server) WaitForError() error {
+	if err, ok := <-s.ErrChan; ok {
+		if errors.Is(err, net.ErrClosed) {
+			return nil
+		}
+		return err
+	}
+	return nil
+}

Also applies to: 43-51, 83-87

vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

35-43: Fix Darwin build: ATime construction uses non-existent Timespec.Unix()

Use time.Unix(sec, nsec) with Timespec fields. Current code won’t compile on darwin.

 return DirEntry{
   FileMode:  ModeFromOS(fi.Mode()),
-  ATime:     time.Unix(sys.Atimespec.Unix()),
+  ATime:     time.Unix(int64(sys.Atimespec.Sec), int64(sys.Atimespec.Nsec)),
   MTime:     fi.ModTime(),
   Length:    uint64(fi.Size()),
   EntryName: fi.Name(),
   UID:       uname,
   GID:       gname,
 }
vendor/github.com/DeedleFake/p9/client.go (1)

3-9: Guard response type assertions to avoid panics (Handshake/Auth/Attach)

Unchecked rsp.(*Type) will panic on protocol errors. Guard and return errors; add fmt import.

@@
-import (
+import (
 	"errors"
+	"fmt"
 	"net"
 	"sync/atomic"
@@
-	version := rsp.(*Rversion)
+	version, ok := rsp.(*Rversion)
+	if !ok {
+		return 0, fmt.Errorf("handshake: expected Rversion, got %T", rsp)
+	}
@@
-	rauth := rsp.(*Rauth)
+	rauth, ok := rsp.(*Rauth)
+	if !ok {
+		return nil, fmt.Errorf("auth: expected Rauth, got %T", rsp)
+	}
@@
-	attach := rsp.(*Rattach)
+	attach, ok := rsp.(*Rattach)
+	if !ok {
+		return nil, fmt.Errorf("attach: expected Rattach, got %T", rsp)
+	}

Also applies to: 61-69, 84-91, 113-120

vendor/github.com/DeedleFake/p9/dir.go (2)

52-60: Avoid clobbering timestamps on partial ATime/MTime updates

Calling Chtimes with only one set overwrites the other with zero. Reject partial updates.

-	atime, ok1 := changes.ATime()
-	mtime, ok2 := changes.MTime()
-	if ok1 || ok2 {
-		err := os.Chtimes(p, atime, mtime)
+	atime, ok1 := changes.ATime()
+	mtime, ok2 := changes.MTime()
+	if ok1 != ok2 {
+		return errors.New("setting only one of ATime or MTime is not supported")
+	}
+	if ok1 && ok2 {
+		err := os.Chtimes(p, atime, mtime)
 		if err != nil {
 			return err
 		}
 	}

69-75: Prevent path traversal on rename (validate name is a base name)

New name must not contain separators or traversal; keep rename within directory.

@@
-import (
+import (
 	"errors"
 	"os"
 	"path/filepath"
+	"strings"
 )
@@
-	name, ok := changes.Name()
+	name, ok := changes.Name()
 	if ok {
-		err := os.Rename(p, filepath.Join(base, filepath.FromSlash(name)))
+		// disallow separators/traversal; only a base name is allowed
+		if name != filepath.Base(name) || strings.ContainsRune(name, os.PathSeparator) {
+			return errors.New("invalid name: must be a base name without path separators")
+		}
+		err := os.Rename(p, filepath.Join(base, name))
 		if err != nil {
 			return err
 		}
 	}

Also applies to: 3-7

vendor/github.com/DeedleFake/p9/proto/server.go (1)

3-9: Don’t dispatch after Receive errors; exit on closed connections

Break/continue appropriately; avoid using stale msg/tag and busy-looping on closed sockets. Add errors import.

@@
-import (
+import (
+	"errors"
 	"io"
 	"log"
 	"net"
 	"sync"
 )
@@
-		tmsg, tag, err := p.Receive(c, msize)
+		tmsg, tag, err := p.Receive(c, msize)
 		if err != nil {
-			if err == io.EOF {
-				return
-			}
-
-			log.Printf("Error reading message: %v", err)
+			// Terminate on EOF or closed connection; otherwise log and continue.
+			if err == io.EOF || errors.Is(err, net.ErrClosed) {
+				return
+			}
+			log.Printf("Error reading message: %v", err)
+			continue
 		}

Also applies to: 69-78

packaging/windows/product.wxs.template (2)

64-68: Do the same for gvisor‑tap‑vsock for consistency.

Prevent potential redirection for the existing vsock key as well.

-                    <Component Id="VsockRegistryEntry" Guid="*">
+                    <Component Id="VsockRegistryEntry" Guid="*" Win64="yes">

69-73: Write 9P HVSOCK registry to 64‑bit hive (avoid Wow6432 redirection).

Mark component as 64‑bit so the key lands under the native HKLM hive.

-                    <Component Id="Hvsock9pRegistryEntry" Guid="*">
+                    <Component Id="Hvsock9pRegistryEntry" Guid="*" Win64="yes">
vendor/github.com/DeedleFake/p9/remote.go (3)

37-43: Fix Wname building for absolute paths.

Leading “/” yields empty element; “/” yields invalid path. Clean, trim leading slash, split, drop empties.

-	w := []string{path.Clean(p)}
-	if w[0] != "/" {
-		w = strings.Split(w[0], "/")
-	}
-	if (len(w) == 1) && (w[0] == ".") {
-		w = nil
-	}
+	p = path.Clean(p)
+	var w []string
+	switch {
+	case p == "" || p == "." || p == "/":
+		w = nil
+	default:
+		w = strings.Split(strings.TrimPrefix(p, "/"), "/")
+	}

184-185: Don’t panic on invalid whence; return error.

Library code should not abort the process.

-	panic(util.Errorf("Invalid whence: %v", whence))
+	return int64(file.pos), util.Errorf("invalid whence: %v", whence)

198-201: Avoid underflow/zero in maxBufSize; guard for tiny msize.

If Msize() <= IOHeaderSize, the subtraction underflows or returns 0; callers then loop forever.

-func (file *Remote) maxBufSize() int {
-	return int(file.client.Msize() - IOHeaderSize)
-}
+func (file *Remote) maxBufSize() int {
+	m := file.client.Msize()
+	if m <= uint32(IOHeaderSize) {
+		return -1
+	}
+	return int(m - uint32(IOHeaderSize))
+}
🧹 Nitpick comments (7)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-1: Consider updating to modern build tag format (upstream).

The old-style // +build !p9debug constraint is deprecated in favor of the //go:build !p9debug format introduced in Go 1.17. Since this is vendored code, if you consider this worth addressing, you could file an upstream PR to modernize the build tags.

Based on learnings (cfergeau's guidance on vendored code).

vendor/github.com/DeedleFake/p9/README.md (3)

4-5: Use HTTPS and pkg.go.dev for the docs badge/link (upstream change).

Prefer pkg.go.dev over the legacy GoDoc URL and enforce HTTPS to avoid mixed-content/link-rot.

If we keep vendor pristine, consider an upstream PR. Locally, ensure link checkers ignore vendor paths.


15-19: Hard tabs inside fenced code blocks trigger MD010; decide policy.

Either keep tabs (common in Go) and ignore vendor/** in markdownlint, or replace with spaces upstream. Avoid local edits to vendored files.

Also applies to: 24-51


12-12: Consistent heading style or vendor exclusion
The vendored README mixes ATX (### Server) with setext headings, triggering markdownlint’s style rules. Either update the upstream file to unify heading styles or add vendor/** to your .markdownlintignore (or CI exclude patterns) so vendored docs are skipped.

pkg/crc/constants/constants.go (1)

59-62: Constants look good; consider documenting expected units and consumers

Add short comments for Plan9Msize (bytes), Plan9TcpPort, Plan9HvsockGUID/Port, and ensure both client and server use the same msize.

vendor/github.com/DeedleFake/p9/stat.go (1)

187-193: Guard stat size overflow.

size() sums into uint16; very long names/IDs overflow silently. Validate before encode.

 func (s Stat) size() uint16 {
-	return uint16(47 + len(s.Name) + len(s.UID) + len(s.GID) + len(s.MUID))
+	return uint16(47 + len(s.Name) + len(s.UID) + len(s.GID) + len(s.MUID))
 }
 
 func (s Stat) P9Encode() (r []byte, err error) {
+	if int(47+len(s.Name)+len(s.UID)+len(s.GID)+len(s.MUID)) > 0xFFFF {
+		return nil, ErrLargeStat
+	}
vendor/github.com/DeedleFake/p9/remote.go (1)

124-141: Minor: avoid shadowing the receiver in Remove().

Using file, err := file.walk(p) shadows file (receiver), hurting readability.

-		file, err := file.walk(p)
+		target, err := file.walk(p)
 		if err != nil {
 			return err
 		}
 		// Close is not necessary. Remove is also a clunk.
-		return file.Remove("")
+		return target.Remove("")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f330f89 and f06fba0.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (44)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (1 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/server_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/server_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (7)
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/crc/machine/driver_darwin.go
  • pkg/crc/machine/driver.go
  • pkg/crc/machine/driver_windows.go
  • cmd/crc/cmd/start.go
  • pkg/crc/machine/driver_linux.go
✅ Files skipped from review due to trivial changes (1)
  • vendor/github.com/DeedleFake/p9/doc.go
🚧 Files skipped from review as they are similar to previous changes (12)
  • vendor/github.com/DeedleFake/p9/addr_unix.go
  • vendor/github.com/DeedleFake/p9/LICENSE
  • vendor/github.com/DeedleFake/p9/proto/proto.go
  • vendor/github.com/DeedleFake/p9/proto/encoding.go
  • go.mod
  • vendor/github.com/DeedleFake/p9/dir_plan9.go
  • pkg/crc/config/settings.go
  • vendor/github.com/DeedleFake/p9/p9.go
  • vendor/modules.txt
  • vendor/github.com/DeedleFake/p9/msg.go
  • vendor/github.com/DeedleFake/p9/internal/util/util.go
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • pkg/fileserver/fs9p/server_windows.go
  • pkg/fileserver/fs9p/server_fallback.go
🧬 Code graph analysis (21)
pkg/fileserver/fs9p/server_windows.go (1)
pkg/fileserver/fs9p/server_fallback.go (1)
  • GetHvsockListener (13-15)
vendor/github.com/DeedleFake/p9/encoding.go (2)
vendor/github.com/DeedleFake/p9/stat.go (2)
  • DirEntry (255-267)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Read (34-38)
  • Write (25-31)
vendor/github.com/DeedleFake/p9/dir_windows.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
pkg/crc/machine/start.go (3)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/crc/constants/constants.go (1)
  • Plan9HvsockPort (62-62)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
pkg/fileserver/fs9p/server.go (3)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/client.go (4)
vendor/github.com/DeedleFake/p9/proto/client.go (3)
  • Client (18-31)
  • NewClient (35-56)
  • Dial (60-67)
vendor/github.com/DeedleFake/p9/msg.go (8)
  • Proto (75-77)
  • Tversion (79-82)
  • Tversion (84-84)
  • Rversion (86-89)
  • Tauth (95-99)
  • Rauth (101-103)
  • Tattach (105-110)
  • Rattach (112-114)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • Version (10-10)
  • NoFID (18-18)
  • QID (42-46)
vendor/github.com/DeedleFake/p9/remote.go (1)
  • Remote (19-27)
vendor/github.com/DeedleFake/p9/dir_linux.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
cmd/crc/cmd/daemon.go (4)
pkg/fileserver/fs9p/server_fallback.go (1)
  • GetHvsockListener (13-15)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
pkg/crc/constants/constants.go (3)
  • Plan9HvsockGUID (61-61)
  • GetHomeDir (166-172)
  • Plan9TcpPort (60-60)
pkg/fileserver/fs9p/server.go (1)
  • New9pServer (29-52)
vendor/github.com/DeedleFake/p9/remote.go (7)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • Client (18-31)
vendor/github.com/DeedleFake/p9/p9.go (4)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • IOHeaderSize (70-70)
vendor/github.com/DeedleFake/p9/msg.go (14)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tremove (192-194)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • ReadDir (16-30)
vendor/github.com/DeedleFake/p9/dir.go (3)
vendor/github.com/DeedleFake/p9/stat.go (5)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
  • ModeDir (27-27)
vendor/github.com/DeedleFake/p9/fs.go (4)
  • File (100-119)
  • Attachment (44-74)
  • FileSystem (21-34)
  • QIDFS (89-91)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • OWRITE (27-27)
  • ORDWR (28-28)
  • OEXEC (29-29)
  • OTRUNC (31-31)
  • OCEXEC (32-32)
  • ORCLOSE (33-33)
  • OREAD (26-26)
vendor/github.com/DeedleFake/p9/fs.go (7)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • QID (42-46)
  • QIDType (49-49)
  • IOHeaderSize (70-70)
  • Version (10-10)
  • QTAuth (58-58)
  • NoFID (18-18)
  • QTDir (54-54)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • MessageHandler (135-139)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/msg.go (27)
  • Tversion (79-82)
  • Tversion (84-84)
  • Rerror (118-120)
  • Rversion (86-89)
  • Tauth (95-99)
  • Rauth (101-103)
  • Tflush (126-128)
  • Tattach (105-110)
  • Rattach (112-114)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Rclunk (189-190)
  • Tremove (192-194)
  • Rremove (196-197)
  • Tstat (199-201)
  • Rstat (203-205)
  • Twstat (235-238)
  • Rwstat (278-279)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • WriteDir (33-42)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/proto/client.go (5)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
  • Proto (38-41)
  • NoTag (27-27)
  • ErrClientClosed (22-22)
vendor/github.com/DeedleFake/p9/client.go (3)
  • NewClient (30-32)
  • Client (22-26)
  • Dial (36-43)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
pkg/crc/machine/libhvee/driver_windows.go (1)
vendor/github.com/crc-org/machine/libmachine/drivers/base.go (1)
  • SharedDir (27-35)
vendor/github.com/DeedleFake/p9/addr.go (2)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/dir_darwin.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/dir_other.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
pkg/fileserver/fs9p/server_fallback.go (1)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
🪛 markdownlint-cli2 (0.18.1)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: build (macOS-14, 1.24)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (14)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

3-5: LGTM! Clean no-op debug stub.

The implementation correctly provides a no-op debug interface for non-debug builds. The function signature matches the active debug implementation, and the build constraint ensures proper conditional compilation.

pkg/crc/machine/libhvee/driver_windows.go (1)

4-4: LGTM: Import needed for dynamic tag generation.

The fmt import is correctly added to support the fmt.Sprintf call on line 43.

vendor/github.com/DeedleFake/p9/addr.go (3)

32-66: LGTM - ParseAddr logic is sound.

The multi-path parsing logic correctly handles namespace addresses, Unix sockets, TCP with ports, and the network!address[!port] format. The pseudo-port mapping for "9p" and "9fs" to standard port 564 is appropriate.


70-72: GetNamespace inherits Windows path issue from NamespaceDir().

This function correctly constructs Unix socket paths for namespaces, but it will inherit the Windows path safety issue from NamespaceDir() in addr_other.go (where DISPLAY with ":" creates invalid Windows paths). Once that upstream issue is fixed, this function will work correctly on Windows.


76-78: LGTM - IsNamespaceAddr is correct.

Simple and correct implementation for detecting namespace addresses by checking for the "$" prefix.

vendor/github.com/DeedleFake/p9/README.md (1)

1-51: Vendored p9 includes its LICENSE (v0.6.12); no changes required. Continue filing any fixes upstream and update the vendor commit rather than modifying vendored sources.

pkg/fileserver/fs9p/server_windows.go (1)

12-29: LGTM! Clean HVSOCK listener implementation.

The function correctly parses the HVSOCK GUID, creates a listener with a wildcard VMID to accept connections from any VM, and provides clear error messages with proper context wrapping.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

1-224: Vendored 9P client looks reasonable.

This is vendored code from github.com/DeedleFake/p9. The implementation includes proper goroutine coordination, error handling, and resource cleanup. No obvious critical issues that would require immediate upstream reporting.

Per the PR discussion, if issues are discovered later (particularly security-related), they should be reported upstream for proper propagation.

vendor/github.com/DeedleFake/p9/dir_other.go (1)

1-15: Vendored fallback implementation for non-major platforms.

This is vendored code providing a minimal os.FileInfoDirEntry conversion for platforms other than Linux, Darwin, Plan9, and Windows. The implementation omits UID/GID/MUID/Path/Version fields (zero values). Since this PR targets Windows (which has its own platform-specific implementation), this fallback is unlikely to be exercised in crc.

If issues arise with missing fields on edge-case platforms, they should be reported upstream.

pkg/fileserver/fs9p/server_fallback.go (1)

11-15: LGTM! Appropriate non-Windows stub.

The fallback implementation correctly returns a not-implemented error for non-Windows platforms, allowing the codebase to compile across platforms while providing clear feedback if the function is mistakenly called.

vendor/github.com/DeedleFake/p9/dir_windows.go (1)

9-27: LGTM: safe type assertion and sane defaults

Graceful fallback when Sys() lacks Win32 data; ATime filled when available; Mode/Length/Name always set.

vendor/github.com/DeedleFake/p9/encoding.go (2)

16-30: LGTM: ReadDir handles EOF correctly and preserves partial results

EOF normalization and accumulation are appropriate for directory streams.


33-41: LGTM: WriteDir writes sequentially and fails fast

Early return on first error is fine for callers.

vendor/github.com/DeedleFake/p9/dir_linux.go (1)

46-62: QID derivation looks correct

Using inode for Path and Mode-derived QID type is reasonable on Linux.

Comment thread pkg/crc/machine/start.go Outdated
Comment thread vendor/github.com/DeedleFake/p9/addr_other.go
Comment thread vendor/github.com/DeedleFake/p9/dir.go
Comment thread vendor/github.com/DeedleFake/p9/fs.go Outdated
Comment thread vendor/github.com/DeedleFake/p9/fs.go Outdated
Comment thread vendor/github.com/DeedleFake/p9/fs.go
Comment thread vendor/github.com/DeedleFake/p9/remote.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (20)
packaging/windows/product.wxs.template (1)

69-73: Mark Hvsock component as 64-bit to avoid registry redirection.

Without Win64="yes" the installer writes the GuestCommunicationServices key under Wow6432Node, so the 9P HVSOCK endpoint never registers. Please add the attribute (same fix previously suggested).

-                    <Component Id="Hvsock9pRegistryEntry" Guid="*">
+                    <Component Id="Hvsock9pRegistryEntry" Guid="*" Win64="yes">
vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

35-43: Fix ATime construction to use Timespec fields

sys.Atimespec has no Unix() method on Darwin, so this code does not compile. Build ATime with the Sec/Nsec fields (cast to int64) instead.

-	ATime:     time.Unix(sys.Atimespec.Unix()),
+	ATime:     time.Unix(int64(sys.Atimespec.Sec), int64(sys.Atimespec.Nsec)),
vendor/github.com/DeedleFake/p9/dir.go (1)

18-127: Critical security issues from previous review remain unaddressed.

This vendored file still contains the following critical vulnerabilities identified in prior reviews:

  1. Path traversal vulnerability (lines 18-20 and throughout): filepath.Join alone does not prevent ".." from escaping the served root directory, allowing clients to access arbitrary filesystem paths.

  2. Timestamp corruption (lines 52-60): Partial ATime/MTime updates can clobber timestamps when only one is provided.

  3. Name change path traversal (lines 69-75): The rename operation allows path separators in names, enabling directory traversal.

Per the PR discussion and learnings, these issues should be addressed upstream in the DeedleFake/p9 repository. Consider filing PRs with the fixes suggested in the previous review comments, then updating the vendor when merged.

Based on learnings.

vendor/github.com/DeedleFake/p9/proto/proto.go (1)

85-94: Critical framing bug from previous review remains unaddressed.

The LimitedReader bound is still set to N: size instead of N: size - 4. The 9P size field includes its own 4 bytes, so the remaining frame length after reading the size is size - 4. This off-by-4 error allows reads to leak 4 bytes into the next frame, breaking message boundaries and causing hard-to-debug protocol errors.

As with other issues in this vendored code, consider filing an upstream PR with the fix suggested in the previous review comment.

Based on learnings.

vendor/github.com/DeedleFake/p9/fs.go (3)

179-185: Unsafe string→[]byte cast causes undefined behavior.

Line 179 uses *(*[]byte)(unsafe.Pointer(&p)) to convert a string to []byte for hashing. This is invalid because string and slice headers have different layouts, resulting in undefined behavior that can corrupt memory or crash under GC/stack movement.

The safe fix is simple: sum := sha256.Sum256([]byte(p)).

Based on learnings.


244-249: Tflush handler violates 9P spec by returning Rerror.

The 9P specification requires that Tflush requests be acknowledged with Rflush, not Rerror. Even if the implementation cannot cancel in-flight operations, it should return &Rflush{} as a best-effort acknowledgment.

Based on learnings.


593-599: Type assertion bug prevents clunk error propagation.

Line 596 checks rsp.(error), but h.clunk() returns *Rerror, not error. This assertion never succeeds, so clunk errors are silently ignored instead of being propagated to the client.

The correct check is if er, ok := rsp.(*Rerror); ok { return er }.

Based on learnings.

vendor/github.com/DeedleFake/p9/proto/server.go (1)

70-99: Error handling bug allows handler invocation with invalid data.

After a Receive error at line 70, the code logs the error but continues to line 79, calling the handler with potentially garbage tmsg and tag values. This can cause panics or invalid protocol responses.

The correct behavior is:

  • On io.EOF or net.ErrClosed: return/break to terminate the connection cleanly
  • On other errors: log and continue to skip handler invocation and retry receiving

The previous review comment provides the complete fix.

Based on learnings.

vendor/github.com/DeedleFake/p9/remote.go (5)

34-71: Absolute path handling remains broken (duplicate).

This issue was flagged in previous reviews: walk() incorrectly splits absolute paths, producing empty elements or invalid "/" in Wname, violating the 9P protocol. Based on coding guidelines, file an upstream PR so the fix propagates when the vendor dependency is updated.


147-185: panic on invalid whence remains (duplicate).

Previous review flagged that library code should not panic for invalid input. Return an error instead. File an upstream PR per project guidance.


198-200: maxBufSize() underflow guard missing (duplicate).

Previous reviews identified that when Msize() <= IOHeaderSize, the subtraction wraps/underflows, and returning 0 causes infinite loops in ReadAt/WriteAt. The extended comment in past reviews recommends validating negotiated msize at handshake (client.go) and clamping to a safe positive value here. File an upstream PR.


229-248: ReadAt loop guard missing (duplicate).

Previous review flagged that if maxBufSize() <= 0, the loop increments by zero or negative size, causing an infinite loop. Guard against non-positive chunk size before entering the loop. File an upstream PR.


288-308: WriteAt loop guard missing (duplicate).

Previous review flagged the same infinite-loop risk as ReadAt. Guard against non-positive chunk size. File an upstream PR.

vendor/github.com/DeedleFake/p9/stat.go (1)

135-153: Unsafe string conversion creates dangling pointer (duplicate).

Previous review correctly identified that *(*string)(unsafe.Pointer(&buf)) at line 152 creates a string header pointing to stack memory in buf, which is freed when the function returns. This is a use-after-free bug. Use return string(buf) for safe conversion. File an upstream PR per project guidance.

pkg/fileserver/fs9p/server.go (4)

3-13: Add missing import for errors.

 import (
+	"errors"
 	"fmt"
 	"net"
 	"os"
 	"path/filepath"

71-81: Stop() is a hard close; consider graceful shutdown or tighten contract.

If graceful isn’t feasible now, document at call sites and ensure callers either drain/ignore WaitForError (net.ErrClosed ignored per earlier change) and don’t leave clients stuck. Add a TODO with rationale and link to tracking issue.


42-50: Buffer ErrChan to avoid goroutine leak if nobody is receiving.

Unbuffered channel can block the Serve goroutine on shutdown. Use capacity 1.

-	fs := p9.FileSystem(p9.Dir(exposeDir))
-	errChan := make(chan error)
+	fs := p9.FileSystem(p9.Dir(exposeDir))
+	errChan := make(chan error, 1)

83-87: Treat net.ErrClosed as clean shutdown and handle closed channel.

WaitForError should not surface net.ErrClosed when Stop() closes the listener; also handle closed channel.

-func (s *Server) WaitForError() error {
-	err := <-s.ErrChan
-	return err
-}
+func (s *Server) WaitForError() error {
+	if err, ok := <-s.ErrChan; ok {
+		if errors.Is(err, net.ErrClosed) {
+			return nil
+		}
+		return err
+	}
+	return nil
+}
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)

33-38: Fail fast if Read target isn’t a non-nil pointer (prevents panic).

Avoid panic when callers pass non-pointers or nil.

 func Read(r io.Reader, v interface{}) error {
-	d := &decoder{r: r}
-	d.decode(reflect.ValueOf(v))
+	d := &decoder{r: r}
+	rv := reflect.ValueOf(v)
+	if rv.Kind() != reflect.Ptr || rv.IsNil() {
+		return util.Errorf("proto.Read expects a non-nil pointer, got %T", v)
+	}
+	d.decode(rv)
 	return d.err
 }

97-100: Guard against strings > 65535 bytes to avoid uint16 wrap/truncation.

 case reflect.String:
-	e.mode(uint16(v.Len()))
-	e.mode([]byte(v.String()))
+	if v.Len() > 0xFFFF {
+		e.err = util.Errorf("string too long: %d bytes", v.Len())
+		return
+	}
+	e.mode(uint16(v.Len()))
+	e.mode([]byte(v.String()))
🧹 Nitpick comments (2)
pkg/fileserver/fs9p/server.go (2)

29-41: Guard against nil listener in New9pServer.

Fail fast if a nil listener is passed.

 func New9pServer(listener net.Listener, exposeDir string) (*Server, error) {
+	if listener == nil {
+		return nil, fmt.Errorf("listener must not be nil")
+	}
 	// Verify that exposeDir makes sense.

55-69: Add an idempotency guard to Server.Start. Although existing callers only invoke Start once per instance (e.g. server9pHvsock and server9pTCP in cmd/crc/cmd/daemon.go), a repeated call would panic from closing ErrChan twice. Introduce a started uint32 flag and wrap Start with atomic.CompareAndSwapUint32(&s.started, 0, 1) to return an error on duplicate starts.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f06fba0 and 19db067.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (44)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (2 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/server_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/server_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (7)
  • pkg/crc/machine/driver_darwin.go
  • pkg/crc/machine/driver_windows.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/crc/machine/driver.go
  • cmd/crc/cmd/start.go
  • pkg/crc/machine/driver_linux.go
✅ Files skipped from review due to trivial changes (1)
  • vendor/github.com/DeedleFake/p9/doc.go
🚧 Files skipped from review as they are similar to previous changes (16)
  • pkg/crc/constants/constants.go
  • vendor/github.com/DeedleFake/p9/dir_other.go
  • vendor/github.com/DeedleFake/p9/addr_unix.go
  • pkg/crc/machine/start.go
  • pkg/fileserver/fs9p/server_windows.go
  • vendor/github.com/DeedleFake/p9/client.go
  • go.mod
  • vendor/github.com/DeedleFake/p9/proto/client.go
  • vendor/modules.txt
  • vendor/github.com/DeedleFake/p9/dir_linux.go
  • pkg/crc/machine/libhvee/driver_windows.go
  • vendor/github.com/DeedleFake/p9/LICENSE
  • cmd/crc/cmd/daemon.go
  • vendor/github.com/DeedleFake/p9/addr_other.go
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go
  • vendor/github.com/DeedleFake/p9/encoding.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • pkg/fileserver/fs9p/server_fallback.go
🧬 Code graph analysis (18)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
pkg/crc/config/settings.go (2)
pkg/crc/config/validations.go (1)
  • ValidateBool (19-25)
pkg/crc/config/callbacks.go (1)
  • SuccessfullyApplied (36-38)
vendor/github.com/DeedleFake/p9/dir_darwin.go (3)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/dir_windows.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
pkg/fileserver/fs9p/server_fallback.go (1)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
vendor/github.com/DeedleFake/p9/dir_plan9.go (3)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/proto.go (2)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Read (34-38)
  • Write (25-31)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (2)
  • Errorf (44-52)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/addr.go (2)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/fs.go (8)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (5)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • QTAuth (58-58)
  • QTDir (54-54)
vendor/github.com/DeedleFake/p9/proto/server.go (3)
  • MessageHandler (135-139)
  • ConnHandler (112-114)
  • ConnHandlerFunc (125-125)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
vendor/github.com/DeedleFake/p9/msg.go (25)
  • Tversion (79-82)
  • Tversion (84-84)
  • Rversion (86-89)
  • Tauth (95-99)
  • Rauth (101-103)
  • Tattach (105-110)
  • Rattach (112-114)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Rclunk (189-190)
  • Tremove (192-194)
  • Rremove (196-197)
  • Tstat (199-201)
  • Rstat (203-205)
  • Twstat (235-238)
  • Rwstat (278-279)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • WriteDir (33-42)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
  • Read (34-38)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
pkg/fileserver/fs9p/server.go (3)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
vendor/github.com/DeedleFake/p9/dir.go (3)
vendor/github.com/DeedleFake/p9/stat.go (5)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
  • ModeDir (27-27)
vendor/github.com/DeedleFake/p9/fs.go (4)
  • File (100-119)
  • Attachment (44-74)
  • FileSystem (21-34)
  • QIDFS (89-91)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • OWRITE (27-27)
  • ORDWR (28-28)
  • OEXEC (29-29)
  • OTRUNC (31-31)
  • OCEXEC (32-32)
  • ORCLOSE (33-33)
  • OREAD (26-26)
vendor/github.com/DeedleFake/p9/remote.go (6)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/p9.go (4)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • IOHeaderSize (70-70)
vendor/github.com/DeedleFake/p9/msg.go (13)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • ReadDir (16-30)
vendor/github.com/DeedleFake/p9/msg.go (5)
vendor/github.com/DeedleFake/p9/proto/proto.go (2)
  • NewProto (44-60)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • P9NoTag (221-223)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • ErrLargeStat (18-18)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Write (25-31)
  • Read (34-38)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/p9.go (1)
vendor/github.com/DeedleFake/p9/stat.go (1)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
  • Read (34-38)
🪛 markdownlint-cli2 (0.18.1)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (11)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-5: LGTM! Vendored no-op debug implementation is correct.

This vendored file correctly implements a no-op debug logger that's compiled when the p9debug build tag is not set, complementing the active implementation in debug.go. The build constraint and function signature are appropriate for conditional compilation of debug logging.

pkg/crc/config/settings.go (2)

87-88: LGTM! Clean cross-platform shared directory configuration.

The unconditional EnableSharedDirs setting correctly replaces the OS-specific SMB configuration with a universal approach that works with 9p. The default value of true maintains backward compatibility, and the implementation properly uses standard validation and callback functions.


34-34: Keep SharedDirPassword constant as it’s still in use
SharedDirPassword is referenced in pkg/crc/machine/config/config.go, pkg/crc/machine/types/types.go, and pkg/crc/machine/start.go and must not be removed.

Likely an incorrect or invalid review comment.

pkg/fileserver/fs9p/server_fallback.go (1)

1-15: LGTM!

The build tag separation and error message are appropriate. The stub correctly signals that HVSOCK is Windows-only.

vendor/github.com/DeedleFake/p9/addr.go (1)

32-66: LGTM!

The address parsing logic correctly handles multiple address formats (namespace, Unix socket, TCP, and bang notation). The implementation is sound for a vendored 9P library.

vendor/github.com/DeedleFake/p9/dir_windows.go (1)

9-27: LGTM!

The Windows-specific FileInfo-to-DirEntry conversion correctly handles both cases (with and without syscall data) and properly extracts ATime from Windows file attributes.

vendor/github.com/DeedleFake/p9/dir_plan9.go (2)

10-31: LGTM!

The Plan9-specific FileInfo-to-DirEntry conversion correctly handles syscall.Dir metadata extraction, including proper time conversion for Plan9's uint32 Atime field.


33-49: LGTM!

The QID extraction correctly stats the file, validates the syscall.Dir type, and constructs the QID from the native Plan9 Qid fields.

vendor/github.com/DeedleFake/p9/p9.go (1)

1-72: LGTM – Vendored 9P constants and types.

The constants and types defined here are standard 9P protocol scaffolding. No issues identified.

vendor/github.com/DeedleFake/p9/stat.go (1)

1-351: Rest of stat.go looks reasonable.

FileMode conversions, Stat/DirEntry types, and P9Encode/P9Decode implementations follow safe patterns and match the 9P protocol specification.

vendor/github.com/DeedleFake/p9/msg.go (1)

1-280: LGTM – 9P message types and protocol registry.

Message type constants, structs, and encoding/decoding implementations follow the 9P2000 specification and use safe patterns. No issues identified.

Comment thread vendor/github.com/DeedleFake/p9/proto/encoding.go
@redbeam

redbeam commented Oct 4, 2025

Copy link
Copy Markdown
Contributor Author

/hold

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (15)
pkg/crc/machine/start.go (2)

246-246: Fix argv tokenization: chown core:core will fail binary lookup

The RunPrivileged method expects the binary and each argument as separate tokens. Passing "chown core:core" as a single string will attempt to execute a binary named "chown core:core" and fail.

Apply this diff to split the command into separate arguments:

-			if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
+			if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown", "core:core", mount.Target); err != nil {

249-251: Fix multiple critical issues with 9P mounting

This implementation has several critical issues:

  1. Argv tokenization: "9pfs 192.168.127.1" will fail binary lookup (should be "9pfs", "192.168.127.1")
  2. Missing privileges: Mounting requires root; using Run instead of RunPrivileged will likely fail
  3. Missing mount options: No trans, port, version, msize, cache specified
  4. Missing tag/aname: The 9P server can't resolve which export to mount without the tag
  5. Non-standard helper: Using 9pfs is brittle; prefer explicit mount -t 9p

Apply this diff to use explicit 9P mount with all required options:

-			if _, _, err := sshRunner.Run("9pfs 192.168.127.1", mount.Target); err != nil {
-				return err
+			opts := fmt.Sprintf("trans=tcp,port=%d,msize=%d,cache=loose,version=9p2000.L,aname=%s", constants.Plan9Port, constants.Plan9Msize, mount.Tag)
+			if _, _, err := sshRunner.RunPrivileged(
+				fmt.Sprintf("Mounting %s (9p tag %s)", mount.Target, mount.Tag),
+				"mount", "-t", "9p", "-o", opts, "192.168.127.1", mount.Target,
+			); err != nil {
+				return err
 			}

Note: This assumes constants.Plan9Port and constants.Plan9Msize are defined. If not, use standard values (e.g., port 564, msize 65536).

cmd/crc/cmd/daemon.go (1)

253-266: Stop and monitor the Windows 9p server

We still start the 9p server but never tear it down or surface its failures; this leaks the listener/goroutine after run returns (tests or retries in the same process will fail with “address already in use”) and hides runtime faults. Please defer a Stop() and forward ErrChan into errCh so the daemon can shut down cleanly and react to 9p errors.

 	if runtime.GOOS == "windows" {
 		listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9TcpPort)))
 		if err != nil {
 			return err
 		}
 		server9p, err := fs9p.New9pServer(listener9p, constants.GetHomeDir())
 		if err != nil {
 			return err
 		}
+		defer func() {
+			if err := server9p.Stop(); err != nil {
+				logging.Errorf("error stopping 9p server: %v", err)
+			}
+		}()
+		go func() {
+			for err := range server9p.ErrChan {
+				errCh <- errors.Wrap(err, "9p server failed")
+			}
+		}()
 		if err := server9p.Start(); err != nil {
 			return err
 		}
 	}
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)

33-38: Guard against nil or non-pointer inputs in Read

Read still calls reflect.Indirect on whatever comes in, so a nil interface or non-pointer will panic. Please fail fast before decoding.

Apply this diff to harden the decoder:

 func Read(r io.Reader, v interface{}) error {
-	d := &decoder{r: r}
-	d.decode(reflect.ValueOf(v))
+	rv := reflect.ValueOf(v)
+	if rv.Kind() != reflect.Ptr || rv.IsNil() {
+		return util.Errorf("proto.Read expects a non-nil pointer, got %T", v)
+	}
+
+	d := &decoder{r: r}
+	d.decode(rv)
 	return d.err
 }

97-100: Enforce the 64 KiB string limit instead of truncating

Casting len to uint16 silently wraps for payloads >65 535 bytes, so the wire length prefix no longer matches the bytes we emit—subsequent fields decode incorrectly. Please detect oversize strings and return a descriptive error.

Apply this diff to enforce the boundary:

 case reflect.String:
-	e.mode(uint16(v.Len()))
-	e.mode([]byte(v.String()))
+	if v.Len() > 0xFFFF {
+		e.err = util.Errorf("string too long: %d bytes", v.Len())
+		return
+	}
+	e.mode(uint16(v.Len()))
+	e.mode([]byte(v.String()))
vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

35-41: Restore darwin build: use Sec/Nsec when building ATime

sys.Atimespec.Unix() does not exist on Darwin, so this file will not compile. Please construct the timestamp with the Sec/Nsec fields explicitly.

Apply this diff to fix the build:

 return DirEntry{
 	FileMode:  ModeFromOS(fi.Mode()),
-	ATime:     time.Unix(sys.Atimespec.Unix()),
+	ATime:     time.Unix(int64(sys.Atimespec.Sec), int64(sys.Atimespec.Nsec)),
 	MTime:     fi.ModTime(),
 	Length:    uint64(fi.Size()),
 	EntryName: fi.Name(),
 	UID:       uname,
 	GID:       gname,
vendor/github.com/DeedleFake/p9/dir.go (3)

3-35: Keep requests inside the served root

Dir.path just does filepath.Join, so inputs like ../../Windows/System32 break out of the share. Every method here relies on it, so this is a full sandbox bypass.

dir := p9.Dir("C:\\crc")
_, _ = dir.Open("../../Windows/System32", p9.OREAD) // escapes root

Please harden path() to validate the resolved path stays under the base and thread that error through all call sites (Stat, WriteStat, Open, Create, Remove, etc.).

@@
-import (
-	"errors"
-	"os"
-	"path/filepath"
-)
+import (
+	"errors"
+	"os"
+	"path/filepath"
+	"strings"
+)
@@
-func (d Dir) path(p string) string {
-	return filepath.Join(string(d), filepath.FromSlash(p))
+func (d Dir) path(p string) (string, error) {
+	base := string(d)
+	joined := filepath.Join(base, filepath.FromSlash(p))
+	rel, err := filepath.Rel(base, joined)
+	if err != nil {
+		return "", err
+	}
+	if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
+		return "", errors.New("path escapes base")
+	}
+	return joined, nil
 }
@@
-	fi, err := os.Stat(d.path(p))
+	tpath, err := d.path(p)
+	if err != nil {
+		return DirEntry{}, err
+	}
+	fi, err := os.Stat(tpath)

Apply the same pattern anywhere d.path is used.

Also applies to: 41-126


39-68: Reject partial ATime/MTime updates

Passing only one of ATime/MTime drops the other to the zero time via os.Chtimes, silently corrupting metadata.

-	atime, ok1 := changes.ATime()
-	mtime, ok2 := changes.MTime()
-	if ok1 || ok2 {
-		err := os.Chtimes(p, atime, mtime)
+	atime, ok1 := changes.ATime()
+	mtime, ok2 := changes.MTime()
+	if ok1 != ok2 {
+		return errors.New("setting only one of ATime or MTime is not supported")
+	}
+	if ok1 && ok2 {
+		err := os.Chtimes(tpath, atime, mtime)

69-75: Validate rename targets stay in the same directory

filepath.Join(base, filepath.FromSlash(name)) accepts inputs with separators and .., letting clients move files outside base.

-	name, ok := changes.Name()
-	if ok {
-		err := os.Rename(p, filepath.Join(base, filepath.FromSlash(name)))
+	name, ok := changes.Name()
+	if ok {
+		if name != filepath.Base(name) || strings.ContainsRune(name, os.PathSeparator) {
+			return errors.New("invalid name: must be a base name without path separators")
+		}
+		err := os.Rename(tpath, filepath.Join(base, name))
vendor/github.com/DeedleFake/p9/proto/server.go (1)

3-8: Don’t dispatch after a failed Receive

After p.Receive fails you still call the handler with zeroed tmsg/tag, which can panic or send garbage, and you loop forever on net.ErrClosed.

-import (
+import (
+	"errors"
 	"io"
 	"log"
 	"net"
 	"sync"
 )
@@
-		if err != nil {
-			if err == io.EOF {
-				return
-			}
-
-			log.Printf("Error reading message: %v", err)
-		}
+		if err != nil {
+			if err == io.EOF || errors.Is(err, net.ErrClosed) {
+				return
+			}
+			log.Printf("Error reading message: %v", err)
+			continue
+		}

Also applies to: 69-99

vendor/github.com/DeedleFake/p9/proto/proto.go (1)

85-114: Fix 9P framing off-by-4

size already includes the 4-byte length field, so bounding the reader with N: size lets reads spill into the next frame. Frames under 4 bytes should be rejected.

-	if (msize > 0) && (size > msize) {
+	if (msize > 0) && (size > msize) {
 		return nil, NoTag, util.Errorf("receive: %w", ErrLargeMessage)
 	}
-
-	lr := &util.LimitedReader{
-		R: r,
-		N: size,
-		E: ErrLargeMessage,
-	}
+	if size < 4 {
+		return nil, NoTag, util.Errorf("receive: invalid frame size: %d", size)
+	}
+	lr := &util.LimitedReader{
+		R: r,
+		N: size - 4,
+		E: ErrLargeMessage,
+	}
vendor/github.com/DeedleFake/p9/remote.go (3)

34-67: Produce valid Twalk components

Leading slashes turn into empty Wname entries (["", "foo"]) and / becomes ["/"], both invalid. Absolute roots should walk zero components; everything else must split into non-empty names.

-	w := []string{path.Clean(p)}
-	if w[0] != "/" {
-		w = strings.Split(w[0], "/")
-	}
-	if (len(w) == 1) && (w[0] == ".") {
-		w = nil
-	}
+	p = path.Clean(p)
+	var w []string
+	switch {
+	case p == "", p == ".":
+		// stay on current fid
+	case strings.HasPrefix(p, "/"):
+		p = strings.TrimPrefix(p, "/")
+		if p != "" {
+			w = strings.FieldsFunc(p, func(r rune) bool { return r == '/' })
+		}
+	default:
+		w = strings.FieldsFunc(p, func(r rune) bool { return r == '/' })
+	}

151-185: Return an error for invalid whence

Library code shouldn’t panic on bad input; return the current position and an error instead.

 	default:
-		panic(util.Errorf("Invalid whence: %v", whence))
+		return int64(file.pos), util.Errorf("invalid whence: %v", whence)
 	}

198-308: Guard negotiated msize before chunking

int(client.Msize() - IOHeaderSize) underflows when msize ≤ header, and ReadAt/WriteAt then loop with size≤0. Fail fast with a clear error.

 func (file *Remote) maxBufSize() int {
-	return int(file.client.Msize() - IOHeaderSize)
+	msize := file.client.Msize()
+	if msize <= uint32(IOHeaderSize) {
+		return 0
+	}
+	return int(msize - uint32(IOHeaderSize))
 }
@@
 func (file *Remote) ReadAt(buf []byte, off int64) (int, error) {
-	size := len(buf)
-	if size > file.maxBufSize() {
-		size = file.maxBufSize()
-	}
+	max := file.maxBufSize()
+	if max <= 0 {
+		return 0, util.Errorf("msize too small: %d", file.client.Msize())
+	}
+	size := len(buf)
+	if size > max {
+		size = max
+	}
@@
 func (file *Remote) WriteAt(data []byte, off int64) (int, error) {
-	size := len(data)
-	if size > file.maxBufSize() {
-		size = file.maxBufSize()
-	}
+	max := file.maxBufSize()
+	if max <= 0 {
+		return 0, util.Errorf("msize too small: %d", file.client.Msize())
+	}
+	size := len(data)
+	if size > max {
+		size = max
+	}
vendor/github.com/DeedleFake/p9/stat.go (1)

3-12: Remove unsafe string conversion

return *(*string)(unsafe.Pointer(&buf)) hands back a string referencing stack memory. Use the standard conversion and drop the unsafe import.

-import (
-	"bytes"
-	"errors"
-	"io"
-	"os"
-	"time"
-	"unsafe"
+import (
+	"bytes"
+	"errors"
+	"io"
+	"os"
+	"time"
@@
-	return *(*string)(unsafe.Pointer(&buf))
+	return string(buf)

Also applies to: 135-153

🧹 Nitpick comments (1)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-5: LGTM! Vendored no-op debug implementation is correct.

The no-op Log function correctly provides zero-overhead debug logging when the p9debug build tag is not set. The implementation matches the expected pattern for conditional compilation of debug helpers.

Note: The build constraint uses the older // +build syntax rather than the newer //go:build directive introduced in Go 1.17. While both syntaxes remain valid, the newer directive is preferred. However, since this is vendored code, any such improvements should be contributed upstream per the guidance from cfergeau.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19db067 and a8f9db0.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (42)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (1 hunks)
  • packaging/windows/product.wxs.template (0 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (8)
  • pkg/crc/machine/driver_darwin.go
  • pkg/drivers/libhvee/powershell_windows.go
  • cmd/crc/cmd/start.go
  • pkg/crc/machine/driver.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • packaging/windows/product.wxs.template
  • pkg/crc/machine/driver_linux.go
  • pkg/crc/machine/driver_windows.go
✅ Files skipped from review due to trivial changes (2)
  • vendor/github.com/DeedleFake/p9/LICENSE
  • vendor/github.com/DeedleFake/p9/doc.go
🚧 Files skipped from review as they are similar to previous changes (16)
  • go.mod
  • pkg/crc/config/settings.go
  • vendor/github.com/DeedleFake/p9/dir_linux.go
  • vendor/github.com/DeedleFake/p9/dir_windows.go
  • vendor/github.com/DeedleFake/p9/encoding.go
  • pkg/fileserver/fs9p/server.go
  • vendor/github.com/DeedleFake/p9/internal/util/util.go
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go
  • vendor/github.com/DeedleFake/p9/addr_other.go
  • vendor/github.com/DeedleFake/p9/fs.go
  • pkg/crc/machine/libhvee/driver_windows.go
  • pkg/crc/constants/constants.go
  • vendor/github.com/DeedleFake/p9/addr_unix.go
  • vendor/github.com/DeedleFake/p9/msg.go
  • vendor/github.com/DeedleFake/p9/client.go
  • vendor/github.com/DeedleFake/p9/p9.go
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
🧬 Code graph analysis (14)
pkg/crc/machine/start.go (1)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
vendor/github.com/DeedleFake/p9/dir_darwin.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/proto/client.go (4)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
  • Proto (38-41)
  • NoTag (27-27)
  • ErrClientClosed (22-22)
vendor/github.com/DeedleFake/p9/client.go (3)
  • NewClient (30-32)
  • Client (22-26)
  • Dial (36-43)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (10-12)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (5-5)
cmd/crc/cmd/daemon.go (2)
pkg/crc/constants/constants.go (2)
  • Plan9TcpPort (60-60)
  • GetHomeDir (164-170)
pkg/fileserver/fs9p/server.go (1)
  • New9pServer (29-53)
vendor/github.com/DeedleFake/p9/dir_plan9.go (3)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/addr.go (2)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (17-29)
vendor/github.com/DeedleFake/p9/remote.go (7)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • Client (18-31)
vendor/github.com/DeedleFake/p9/p9.go (4)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • IOHeaderSize (70-70)
vendor/github.com/DeedleFake/p9/msg.go (14)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tremove (192-194)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • ReadDir (16-30)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Read (34-38)
  • Write (25-31)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (2)
  • Errorf (44-52)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/dir.go (3)
vendor/github.com/DeedleFake/p9/stat.go (5)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
  • ModeDir (27-27)
vendor/github.com/DeedleFake/p9/fs.go (4)
  • File (100-119)
  • Attachment (44-74)
  • FileSystem (21-34)
  • QIDFS (89-91)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • OWRITE (27-27)
  • ORDWR (28-28)
  • OEXEC (29-29)
  • OTRUNC (31-31)
  • OCEXEC (32-32)
  • ORCLOSE (33-33)
  • OREAD (26-26)
vendor/github.com/DeedleFake/p9/dir_other.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
🪛 markdownlint-cli2 (0.18.1)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build (macOS-14, 1.24)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request

Comment thread vendor/github.com/DeedleFake/p9/addr.go
Comment thread vendor/github.com/DeedleFake/p9/proto/client.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
pkg/crc/machine/start.go (1)

244-251: 9P mount: still non‑privileged, wrong argv, missing options/aname (tag)

Mount needs root and proper 9P opts. Also split argv; passing "chown core:core" and "9pfs 192.168.127.1" as single tokens will fail lookup. Use explicit mount with aname=mount.Tag and constants.

Apply:

 case "9p":
-  // change owner to core user to allow mounting to it as a non-root user
-  if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
-    return err
-  }
-  if _, _, err := sshRunner.Run("9pfs 192.168.127.1", mount.Target); err != nil {
-    return err
-  }
+  // change owner to core user to allow non-root access after mounting
+  if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown", "core:core", mount.Target); err != nil {
+    return err
+  }
+  opts := fmt.Sprintf("trans=tcp,port=%d,msize=%d,cache=loose,version=9p2000.L,aname=%s",
+    constants.Plan9TcpPort, constants.Plan9Msize, mount.Tag)
+  if _, _, err := sshRunner.RunPrivileged(
+    fmt.Sprintf("Mounting %s (9p tag %s)", mount.Target, mount.Tag),
+    "mount", "-t", "9p", "-o", opts, "192.168.127.1", mount.Target,
+  ); err != nil {
+    return err
+  }

Optional follow-ups:

  • Idempotency: skip if already mounted (e.g., mountpoint -q), or unmount/retry. I can propose a patch.
🧹 Nitpick comments (1)
pkg/fileserver/fs9p/server.go (1)

3-13: Ignore net.ErrClosed on shutdown in WaitForError

Closing the listener causes proto.Serve to return net.ErrClosed; that shouldn’t surface as an error after Stop(). Handle it explicitly.

@@
-import (
+import (
+	"errors"
 	"fmt"
 	"net"
 	"os"
 	"path/filepath"
@@
-func (s *Server) WaitForError() error {
-	err := <-s.ErrChan
-	return err
-}
+func (s *Server) WaitForError() error {
+	if err, ok := <-s.ErrChan; ok {
+		if errors.Is(err, net.ErrClosed) {
+			return nil
+		}
+		return err
+	}
+	return nil
+}

Also applies to: 84-88

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8f9db0 and b4aad5f.

📒 Files selected for processing (14)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • packaging/windows/product.wxs.template (0 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
💤 Files with no reviewable changes (8)
  • pkg/crc/machine/driver_windows.go
  • cmd/crc/cmd/start.go
  • packaging/windows/product.wxs.template
  • pkg/crc/machine/driver.go
  • pkg/crc/machine/driver_darwin.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver_linux.go
  • pkg/drivers/libhvee/libhvee_windows.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/crc/constants/constants.go
  • pkg/crc/machine/libhvee/driver_windows.go
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: redbeam
PR: crc-org/crc#4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
🧬 Code graph analysis (4)
pkg/crc/machine/start.go (1)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
cmd/crc/cmd/daemon.go (3)
pkg/crc/constants/constants.go (2)
  • Plan9TcpPort (60-60)
  • GetHomeDir (164-170)
pkg/fileserver/fs9p/server.go (1)
  • New9pServer (29-53)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
pkg/crc/config/settings.go (2)
pkg/crc/config/validations.go (1)
  • ValidateBool (19-25)
pkg/crc/config/callbacks.go (1)
  • SuccessfullyApplied (36-38)
pkg/fileserver/fs9p/server.go (3)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (macOS-14, 1.24)
  • GitHub Check: build-qe (darwin, arm64)
  • GitHub Check: build-qe (linux, amd64)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (ubuntu-22.04, 1.24)
  • GitHub Check: build (macOS-13, 1.24)
  • GitHub Check: Run OKD bundle with crc (1.24)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (2)
cmd/crc/cmd/daemon.go (2)

182-196: LGTM: use net.JoinHostPort

Safer and clearer than manual fmt for host:port.


198-212: LGTM: host virtual IP listener uses net.JoinHostPort

Consistent, correct.

Comment thread cmd/crc/cmd/daemon.go
Comment thread pkg/crc/config/settings.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
packaging/windows/product.wxs.template (1)

69-73: Add Win64="yes" to prevent registry redirection on 64-bit Windows.

This component registers a HVSOCK registry key for Guest Communication Services. Without the Win64="yes" attribute, the registry entry may be redirected to Wow6432Node on 64-bit Windows, preventing the 64-bit Guest Communication Services from discovering and using the 9P endpoint.

-                    <Component Id="Hvsock9pRegistryEntry" Guid="*">
+                    <Component Id="Hvsock9pRegistryEntry" Guid="*" Win64="yes">
                         <RegistryKey Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices\00009000-FACB-11E6-BD58-64006A7986D3">
                             <RegistryValue Type="string" Name="ElementName" Value="fs9p-hvsock" KeyPath="yes"/>
                         </RegistryKey>
                     </Component>
pkg/crc/machine/start.go (1)

249-249: Fix argv tokenization and clarify the "2" argument.

The first argument "9pfs -V -p" is passed as a single string, which will cause binary lookup to fail since Run() expects separate argv tokens. Additionally, the "2" argument between the port and mount target is unclear.

Apply this diff to fix the argv tokenization:

-			if _, _, err := sshRunner.Run("9pfs -V -p", fmt.Sprintf("%d", constants.Plan9HvsockPort), "2", mount.Target); err != nil {
+			if _, _, err := sshRunner.Run("9pfs", "-V", "-p", fmt.Sprintf("%d", constants.Plan9HvsockPort), mount.Target); err != nil {

If the "2" represents a tag/share index or other parameter, please document its purpose or verify it's needed.

🧹 Nitpick comments (1)
pkg/fileserver/fs9p/server.go (1)

90-98: Consider checking for net.ErrClosed directly instead of string matching.

The current implementation uses string matching on net.OpError to detect shutdown errors. This is fragile compared to checking errors.Is(err, net.ErrClosed). If the Windows-specific error differs from net.ErrClosed, document why string matching is necessary.

Consider this more robust approach:

 func (s *Server) WaitForError() error {
 	err := <-s.ErrChan
-	// captures "accept tcp: endpoint is in invalid state" errors on exit
+	// Treat listener closed errors as normal shutdown
+	if errors.Is(err, net.ErrClosed) {
+		return nil
+	}
+	// Windows-specific: captures "accept tcp: endpoint is in invalid state" errors
 	var opErr *net.OpError
 	if errors.As(err, &opErr) && strings.Contains(opErr.Error(), "endpoint is in invalid state") {
 		return nil
 	}
 	return err
 }

If the string matching is required for Windows-specific errors, add a comment explaining why.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e1f697 and 79b3483.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (17)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (2 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/server_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/server_windows.go (1 hunks)
💤 Files with no reviewable changes (7)
  • pkg/crc/machine/driver.go
  • pkg/crc/machine/driver_darwin.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver_windows.go
  • pkg/crc/machine/driver_linux.go
  • cmd/crc/cmd/start.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/crc/config/settings.go
  • pkg/crc/constants/constants.go
  • pkg/crc/machine/libhvee/driver_windows.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • pkg/fileserver/fs9p/server_windows.go
  • pkg/crc/machine/start.go
  • pkg/fileserver/fs9p/server_fallback.go
  • cmd/crc/cmd/daemon.go
  • pkg/fileserver/fs9p/server.go
  • go.mod
🧬 Code graph analysis (5)
pkg/fileserver/fs9p/server_windows.go (1)
pkg/fileserver/fs9p/server_fallback.go (1)
  • GetHvsockListener (13-15)
pkg/crc/machine/start.go (3)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/crc/constants/constants.go (2)
  • Plan9HvsockPort (62-62)
  • VSockGateway (42-42)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
pkg/fileserver/fs9p/server_fallback.go (1)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
cmd/crc/cmd/daemon.go (6)
pkg/crc/config/settings.go (1)
  • EnableSharedDirs (33-33)
pkg/fileserver/fs9p/server_fallback.go (1)
  • GetHvsockListener (13-15)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
pkg/crc/constants/constants.go (3)
  • Plan9HvsockGUID (61-61)
  • GetHomeDir (166-172)
  • Plan9TcpPort (60-60)
pkg/fileserver/fs9p/server.go (1)
  • New9pServer (34-58)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
pkg/fileserver/fs9p/server.go (3)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (macOS-13, 1.24)
  • GitHub Check: build (macOS-14, 1.24)
  • GitHub Check: build (macOS-13, 1.24)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: verify-devcontainer
  • GitHub Check: Run OKD bundle with crc (1.24)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (8)
packaging/windows/product.wxs.template (1)

111-111: Component reference correctly added to feature.

The Hvsock9pRegistryEntry reference is properly included in DefaultFeature, ensuring the 9P registry entry is installed as part of the core installation. Once the Win64 attribute issue above is resolved, this change is good to go.

go.mod (1)

7-7: LGTM! 9P dependencies properly added.

The addition of github.com/DeedleFake/p9 and promotion of github.com/linuxkit/virtsock to direct dependencies correctly support the 9P-based file sharing implementation that replaces SMB on Windows.

Also applies to: 31-31

pkg/fileserver/fs9p/server_fallback.go (1)

1-15: LGTM! Standard cross-platform fallback.

The non-Windows stub implementation correctly returns a clear not-implemented error and follows standard Go cross-platform patterns.

pkg/fileserver/fs9p/server_windows.go (1)

14-29: LGTM! Windows hvsock listener properly implemented.

The Windows-specific implementation correctly parses the hvsock GUID, creates a listener with GUIDWildcard VMID (accepting connections from any VM), and provides proper error wrapping.

cmd/crc/cmd/daemon.go (2)

182-182: LGTM! Cleaner address construction.

Using net.JoinHostPort is more idiomatic and explicit than fmt.Sprintf for constructing network addresses.

Also applies to: 198-198


253-300: LGTM! Windows 9P server setup properly implemented.

The Windows-specific 9P server setup correctly:

  • Gates on EnableSharedDirs config and Windows OS
  • Provides both hvsock (primary) and TCP (backup) transport options
  • Manages server lifecycle with proper Start(), defer Stop(), and error monitoring goroutines
  • Logs errors appropriately

All concerns from previous reviews have been addressed.

pkg/fileserver/fs9p/server.go (2)

34-58: LGTM! Server initialization properly validates inputs.

The constructor correctly validates that exposeDir is absolute and exists as a directory, creates a buffered error channel to prevent goroutine blocking, and initializes the 9P filesystem wrapper.


61-75: LGTM! Server startup with immediate error check.

The Start() method launches the server asynchronously and performs an immediate error check via select with default. While this creates a narrow race window where errors occurring after the check won't be returned here, the pattern is acceptable since callers use WaitForError() in a background goroutine to catch runtime errors.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (20)
pkg/fileserver/fs9p/server.go (1)

89-98: Consider also treating net.ErrClosed as a clean shutdown in WaitForError

Right now WaitForError special-cases only *net.OpError whose string contains “endpoint is in invalid state”. For normal listeners closed via Stop, Accept may return net.ErrClosed, which you probably also want to treat as a non-error.

You can do this cheaply by adding an errors.Is(err, net.ErrClosed) check before the string match:

 func (s *Server) WaitForError() error {
-	err := <-s.ErrChan
-	// captures "accept tcp: endpoint is in invalid state" errors on exit
-	var opErr *net.OpError
-	if errors.As(err, &opErr) && strings.Contains(opErr.Error(), "endpoint is in invalid state") {
-		return nil
-	}
-	return err
+	err := <-s.ErrChan
+	if errors.Is(err, net.ErrClosed) {
+		return nil
+	}
+	// captures "accept tcp: endpoint is in invalid state" errors on exit
+	var opErr *net.OpError
+	if errors.As(err, &opErr) && strings.Contains(opErr.Error(), "endpoint is in invalid state") {
+		return nil
+	}
+	return err
 }

This keeps the hvsock-specific workaround while also handling the standard closed-listener case more cleanly.

pkg/crc/machine/libhvee/driver_windows.go (1)

21-33: 9P tag generation: keep it deterministic and in sync with server share names

Using fmt.Sprintf("dir%d", i) is fine as long as the 9P server uses the same tag naming scheme and the order of machineConfig.SharedDirs is stable. To reduce coupling and surprises:

  • Derive the tag format from a shared constant/helper used by both the client and the 9P server.
  • Optionally sort a copy of machineConfig.SharedDirs before tagging to make tag assignment deterministic across runs.

Not a blocker, but worth aligning to avoid subtle mount issues if ordering changes.

vendor/github.com/DeedleFake/p9/proto/encoding.go (1)

33-38: Harden proto (de)serialization: guard Read, bound-check lengths, and fix Size for strings

There are a few correctness issues here that are worth addressing:

  1. Read can panic on non-pointer or nil v
    decode unconditionally takes v.Addr() after reflect.Indirect, which panics if v is not a non-nil pointer. Add a fast guard:

    func Read(r io.Reader, v any) error {
  • d := &decoder{r: r}
  • d.decode(reflect.ValueOf(v))
  • return d.err
  • rv := reflect.ValueOf(v)
  • if rv.Kind() != reflect.Ptr || rv.IsNil() {
  •    return util.Errorf("proto.Read expects a non-nil pointer, got %T", v)
    
  • }
  • d := &decoder{r: r}
  • d.decode(rv)
  • return d.err
    }

2. **Slice and string lengths silently wrap at 64 KiB**  
Non-`[]byte` slices and strings are length-prefixed with `uint16`, but there’s no bounds checking:

```go
case reflect.Array, reflect.Slice:
    switch v.Type().Elem().Kind() {
    case reflect.Uint8:
        e.mode(uint32(v.Len()))
    default:
        e.mode(uint16(v.Len()))
    }
...
case reflect.String:
    e.mode(uint16(v.Len()))
    e.mode([]byte(v.String()))

For lengths > 65535 this will wrap and produce invalid on-wire data. You can fail fast instead:

case reflect.Array, reflect.Slice:
    switch v.Type().Elem().Kind() {
    case reflect.Uint8:
        e.mode(uint32(v.Len()))
    default:
-          e.mode(uint16(v.Len()))
+          if v.Len() > 0xFFFF {
+              e.err = util.Errorf("slice too long: %d elements", v.Len())
+              return
+          }
+          e.mode(uint16(v.Len()))
    }
...
case reflect.String:
-      e.mode(uint16(v.Len()))
-      e.mode([]byte(v.String()))
+      if v.Len() > 0xFFFF {
+          e.err = util.Errorf("string too long: %d bytes", v.Len())
+          return
+      }
+      e.mode(uint16(v.Len()))
+      s := v.String()
+      if e.w == nil {
+          // Size mode: account for string bytes without using binary.Size on []byte.
+          e.n += uint32(len(s))
+      } else {
+          e.mode([]byte(s))
+      }
  1. Size is incorrect for values containing strings
    As written, Size() uses binary.Size under the hood. For strings, the branch e.mode([]byte(v.String())) causes binary.Size to see a slice and return -1, so Size ends up accumulating ^uint32(0) instead of the actual string length. The adjusted string branch above fixes this by counting bytes directly in “size mode” (e.w == nil) rather than routing through binary.Size on a slice.

These changes keep the API the same while preventing panics and subtle on-wire corruption for large payloads.

Also applies to: 81-109, 124-183

vendor/github.com/DeedleFake/p9/client.go (3)

61-69: Unchecked type assertion can panic on protocol errors.

The direct type assertion rsp.(*Rversion) will panic if the server returns an unexpected response type (e.g., *Rerror). A guarded assertion would be safer.

This issue was previously flagged. Since this is vendored code, consider filing an upstream PR if fixes are feasible, as recommended by cfergeau in the PR comments.


84-91: Unchecked type assertion in Auth can panic.

Same issue as Handshake: rsp.(*Rauth) should use a guarded assertion to handle protocol errors gracefully.


113-120: Unchecked type assertion in Attach can panic.

rsp.(*Rattach) should use a guarded assertion to prevent panics on unexpected response types.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

138-145: Tag allocation can emit reserved NoTag and spin indefinitely.

The loop at lines 139-144 doesn't skip NoTag (0xFFFF) and will spin forever when all tags are in use. Per the 9P protocol, NoTag is reserved and must never be used for tagged messages.

This issue was previously flagged. The suggested fix was to skip NoTag explicitly and bail out or wait when the full tag space is exhausted.

vendor/github.com/DeedleFake/p9/proto/server.go (1)

69-99: Handler called with invalid message after Receive error.

After a non-EOF Receive error at line 71, the code logs the error at line 76 but then falls through to line 79, calling the handler with a potentially garbage tmsg and tag. This can cause panics or send invalid responses. A continue statement is needed after logging.

This issue was previously flagged. The fix should add continue after line 76 to avoid dispatching invalid messages.

 		if err != nil {
 			if err == io.EOF {
 				return
 			}
 
 			log.Printf("Error reading message: %v", err)
+			continue
 		}
vendor/github.com/DeedleFake/p9/fs.go (2)

244-249: Tflush should respond with Rflush per 9P spec.

The 9P protocol specification requires that Tflush always receives an Rflush response, even if the flush cannot actually cancel in-flight operations. Returning Rerror violates the protocol and may cause client misbehavior.

This was previously flagged and marked as addressed, but the code still returns &Rerror. The fix should return &Rflush{} with a comment noting best-effort semantics.

 func (h *fsHandler) flush(msg *Tflush) any {
-	// TODO: Implement this.
-	return &Rerror{
-		Ename: "flush is not supported",
-	}
+	// TODO: Track and cancel in-flight ops by tag.
+	// Best-effort: we acknowledge the flush but don't actually cancel operations.
+	return &Rflush{}
 }

593-599: Type assertion rsp.(error) never matches; clunk errors are silently ignored.

*Rerror does not implement the error interface, so the check at line 596 always fails. This means clunk errors from h.clunk() are never propagated, and remove() proceeds even when clunk fails.

 	rsp := h.clunk(&Tclunk{
 		FID: msg.FID,
 	})
-	if _, ok := rsp.(error); ok {
+	if _, ok := rsp.(*Rerror); ok {
 		return rsp
 	}
vendor/github.com/DeedleFake/p9/remote.go (5)

34-71: walk() sends invalid Wname for root path "/".

When p is "/" or an absolute path, path.Clean(p) returns "/", and since w[0] == "/", the code skips the split and sends Wname = ["/"]. The 9P Twalk message requires Wname elements to be valid path components (no slashes, no empty strings). Sending "/" as a name element violates the protocol.

This was previously flagged and marked as addressed, but the logic appears unchanged. The fix should handle root path and absolute paths correctly:

-	w := []string{path.Clean(p)}
-	if w[0] != "/" {
-		w = strings.Split(w[0], "/")
-	}
-	if (len(w) == 1) && (w[0] == ".") {
-		w = nil
-	}
+	p = path.Clean(p)
+	var w []string
+	switch {
+	case p == "" || p == "." || p == "/":
+		w = nil
+	default:
+		p = strings.TrimPrefix(p, "/")
+		w = strings.Split(p, "/")
+	}

183-185: Panic on invalid whence; return error instead.

Library code should not panic for invalid input. Returning an error allows callers to handle the situation gracefully.

-	panic(util.Errorf("Invalid whence: %v", whence))
+	return int64(file.pos), util.Errorf("invalid whence: %v", whence)

198-200: maxBufSize() can underflow or return non-positive value.

If Msize() is less than or equal to IOHeaderSize (24), the subtraction underflows (uint32 wrap) or returns 0/negative after int conversion. This causes ReadAt/WriteAt loops to hang or behave incorrectly.

This was previously flagged. The fix should guard against non-positive results:

 func (file *Remote) maxBufSize() int {
-	return int(file.client.Msize() - IOHeaderSize)
+	m := file.client.Msize()
+	if m <= uint32(IOHeaderSize) {
+		return 1 // Avoid infinite loop; callers should validate msize at handshake
+	}
+	return int(m - uint32(IOHeaderSize))
 }

229-243: ReadAt loop can hang if maxBufSize() returns 0.

When min(len(buf), file.maxBufSize()) returns 0, the loop makes no progress (start += 0), causing an infinite loop. Add a guard to bail early.

 func (file *Remote) ReadAt(buf []byte, off int64) (int, error) {
 	size := min(len(buf), file.maxBufSize())
+	if size <= 0 {
+		return 0, util.Errorf("msize too small: %d", file.client.Msize())
+	}
 
 	var total int

282-296: WriteAt loop has same infinite-loop risk as ReadAt.

Same issue: if maxBufSize() returns 0, the loop hangs. Apply the same guard.

 func (file *Remote) WriteAt(data []byte, off int64) (int, error) {
 	size := min(len(data), file.maxBufSize())
+	if size <= 0 {
+		return 0, util.Errorf("msize too small: %d", file.client.Msize())
+	}
 
 	var total int
vendor/github.com/DeedleFake/p9/proto/proto.go (1)

85-94: Off-by-4 framing bug remains unresolved in vendored library.

The LimitedReader is still bounded to size instead of size-4. Since the 9P size field includes its own 4 bytes, the current code allows reads to leak 4 bytes into the next frame, breaking message framing.

As noted in the PR discussion, vendored code issues should be fixed upstream. Please file a PR with the DeedleFake/p9 project to bound reads correctly: N: size - 4 with a guard for size < 4.

vendor/github.com/DeedleFake/p9/dir.go (3)

18-20: Critical path traversal vulnerability remains in vendored Dir implementation.

The path() helper still uses filepath.Join without validation, allowing ".." to escape the served root directory. Every filesystem operation (Stat, WriteStat, Open, Create, Remove) is affected and can access files outside the intended share.

For example: accessing /share/../../etc/passwd would resolve to /etc/passwd, bypassing the share boundary.

Given this is vendored code, please file an upstream PR with DeedleFake/p9 to add path validation (e.g., using filepath.Rel to detect ".." escape attempts and rejecting them).

Also applies to: 22-35, 41-51, 61-68, 69-75, 95-103, 105-122, 124-127


52-60: Partial timestamp updates can corrupt file times.

When only one of ATime or MTime is provided, os.Chtimes is called with a zero-value for the other timestamp, which can clobber the unset field instead of preserving it.

Consider filing an upstream PR to reject partial updates (return error when ok1 != ok2) or fetch current values for missing timestamps.


69-75: Name change allows path traversal via directory separators.

Using filepath.FromSlash(name) without validation allows slashes or ".." in the new name to move files outside the current directory. 9P wstat name changes should only rename within the same directory.

Please file an upstream PR to validate that name contains no path separators and equals filepath.Base(name).

vendor/github.com/DeedleFake/p9/stat.go (1)

135-153: Unsafe string conversion from stack slice should use safe copy.

Line 152 uses unsafe.String(unsafe.SliceData(buf), len(buf)) which creates a string header pointing to the stack-allocated slice. If the returned string escapes and the stack frame is reused, this can cause memory corruption or read invalid data.

Please file an upstream PR to change line 152 to return string(buf) for a safe heap copy.

🧹 Nitpick comments (3)
vendor/github.com/DeedleFake/p9/README.md (1)

1-51: Vendored README markdown issues are better handled via tooling config

markdownlint’s heading-style and hard-tab warnings are against upstream vendored content; I’d avoid editing this README just for style and instead configure your markdown tooling to ignore vendor/** if these warnings are noisy.

pkg/crc/constants/constants.go (1)

59-62: Plan9 constants look fine; consider documenting msize usage

Values are sensible for 9P (1 MiB msize, port 564, fixed GUID/port). It may help future readers to add a short comment that Plan9Msize is the negotiated 9P message size and should match both server and guest configuration.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

90-97: Read errors (except EOF) are silently swallowed, continuing the loop.

When Receive fails with a non-EOF error (e.g., timeout from the 10-second deadline at line 80), the error is ignored and the loop continues at line 96. While timeouts are expected, other transient errors may hide real problems. Consider logging non-timeout errors or distinguishing error types.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b4f78b and 514277a.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (48)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (2 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_test.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/server_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/server_windows.go (1 hunks)
  • test/e2e/features/9pfs.feature (1 hunks)
  • test/e2e/testsuite/testsuite.go (3 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (7)
  • cmd/crc/cmd/start.go
  • pkg/crc/machine/driver.go
  • pkg/crc/machine/driver_linux.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver_darwin.go
  • pkg/crc/machine/driver_windows.go
✅ Files skipped from review due to trivial changes (2)
  • vendor/github.com/DeedleFake/p9/LICENSE
  • vendor/github.com/DeedleFake/p9/addr_unix.go
🚧 Files skipped from review as they are similar to previous changes (12)
  • vendor/github.com/DeedleFake/p9/dir_other.go
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go
  • pkg/crc/machine/start.go
  • vendor/github.com/DeedleFake/p9/addr.go
  • vendor/github.com/DeedleFake/p9/dir_linux.go
  • test/e2e/testsuite/testsuite.go
  • vendor/github.com/DeedleFake/p9/doc.go
  • test/e2e/features/9pfs.feature
  • vendor/github.com/DeedleFake/p9/dir_windows.go
  • pkg/fileserver/fs9p/server_windows.go
  • vendor/modules.txt
  • vendor/github.com/DeedleFake/p9/addr_other.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • pkg/fileserver/fs9p/server_fallback.go
  • cmd/crc/cmd/daemon.go
  • vendor/github.com/DeedleFake/p9/README.md
  • pkg/fileserver/fs9p/server.go
  • vendor/github.com/DeedleFake/p9/p9.go
  • vendor/github.com/DeedleFake/p9/msg.go
  • vendor/github.com/DeedleFake/p9/fs.go
  • vendor/github.com/DeedleFake/p9/remote.go
  • go.mod
🧬 Code graph analysis (14)
pkg/fileserver/fs9p/server_fallback.go (1)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
vendor/github.com/DeedleFake/p9/dir_darwin.go (2)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
pkg/crc/machine/libhvee/driver_test.go (1)
pkg/crc/machine/libhvee/driver.go (1)
  • ConvertToUnixPath (9-20)
pkg/crc/config/settings.go (2)
pkg/crc/config/validations.go (1)
  • ValidateBool (19-25)
pkg/crc/config/callbacks.go (1)
  • SuccessfullyApplied (36-38)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
pkg/fileserver/fs9p/server.go (4)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
vendor/github.com/DeedleFake/p9/encoding.go (2)
vendor/github.com/DeedleFake/p9/stat.go (2)
  • DirEntry (255-267)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Read (34-38)
  • Write (25-31)
vendor/github.com/DeedleFake/p9/proto/proto.go (4)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Read (34-38)
  • Write (25-31)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/internal/util/util.go (2)
  • Errorf (44-52)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (11-13)
vendor/github.com/DeedleFake/p9/p9.go (1)
vendor/github.com/DeedleFake/p9/stat.go (1)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/fs.go (4)
vendor/github.com/DeedleFake/p9/stat.go (2)
  • DirEntry (255-267)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • QID (42-46)
  • QIDType (49-49)
  • IOHeaderSize (70-70)
  • Version (10-10)
  • QTAuth (58-58)
  • NoFID (18-18)
  • QTDir (54-54)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (11-13)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (6-6)
pkg/crc/machine/libhvee/driver_windows.go (2)
vendor/github.com/crc-org/machine/libmachine/drivers/base.go (1)
  • SharedDir (27-35)
pkg/crc/machine/libhvee/driver.go (1)
  • ConvertToUnixPath (9-20)
vendor/github.com/DeedleFake/p9/proto/client.go (6)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
  • Proto (38-41)
  • NoTag (27-27)
  • ErrClientClosed (22-22)
vendor/github.com/DeedleFake/p9/client.go (2)
  • NewClient (30-32)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (11-13)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (6-6)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
🪛 markdownlint-cli2 (0.18.1)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (ubuntu-22.04, 1.24)
  • GitHub Check: build (macOS-26, 1.24)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: verify-devcontainer
  • GitHub Check: build-qe (linux, amd64)
  • GitHub Check: build (macOS-15-intel, 1.24)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: Run OKD bundle with crc (1.24)
  • GitHub Check: build-qe (windows, amd64)
  • GitHub Check: build-qe (darwin, arm64)
  • GitHub Check: build-qe (darwin, amd64)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: build-qe (linux, arm64)
  • GitHub Check: build-installer (windows-2022, 1.24)
🔇 Additional comments (18)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-6: Build tags and no-op debug logger look correct

The !p9debug build constraints and the no-op Log implementation cleanly mirror the real logger in debug.go and should work as intended to strip debug output in normal builds. No issues found.

go.mod (1)

5-31: 9P and virtsock dependency wiring looks consistent

Adding github.com/DeedleFake/p9 and making github.com/linuxkit/virtsock a direct requirement matches the new 9P/hvsock server usage; nothing else needed here.

pkg/crc/config/settings.go (1)

87-88: EnableSharedDirs config text and default align with 9P behavior

The unified EnableSharedDirs setting and updated description (“into the CRC VM”) match the new 9P-based sharing semantics; this looks good.

vendor/github.com/DeedleFake/p9/encoding.go (1)

1-42: ReadDir/WriteDir implementations are straightforward and correct

EOF handling, error propagation, and StatDirEntry conversions look sane for these helpers; fine to keep as-is in the vendored library.

pkg/fileserver/fs9p/server.go (1)

31-75: 9P server construction and startup flow look solid

Validating an absolute, existing directory, wrapping it as p9.Dir, and using a buffered ErrChan to carry the proto.Serve result is a good pattern; startup behavior and logging look reasonable.

packaging/windows/product.wxs.template (1)

69-73: 9P hvsock GCS registry entry and feature wiring look correct

The Hvsock9pRegistryEntry component and its DefaultFeature reference cleanly register the fs9p-hvsock GuestCommunicationService under the expected GUID, matching the new Windows 9P/hvsock flow.

Also applies to: 111-111

pkg/crc/machine/libhvee/driver.go (1)

8-19: ConvertToUnixPath correctly mirrors Podman’s /mnt/<drive>/... mapping

The normalization logic (ToSlash + drive-letter detection + /mnt/<lowercase> prefix) matches Podman’s expectations for Windows paths; this is a good shared helper for 9P-based mounts.

pkg/fileserver/fs9p/server_fallback.go (1)

11-15: Non-Windows GetHvsockListener stub is appropriate

The !windows build-tagged stub makes the API available but clearly reports that hvsock isn’t implemented off-Windows, which is the right trade-off here.

pkg/crc/machine/libhvee/driver_test.go (1)

9-11: Tests correctly cover Windows path conversion cases

Both upper- and lower-case drive letters are validated against ConvertToUnixPath, matching the helper’s behavior. Looks good.

cmd/crc/cmd/daemon.go (1)

182-201: 9P daemon wiring and listeners look correct

Switching to net.JoinHostPort for the vn listeners is cleaner and avoids manual string formatting. The Windows-only 9P setup is properly gated on EnableSharedDirs, starts both hvsock and TCP servers against the home directory, and ensures cleanup via Stop() plus background WaitForError() logging. No issues from a lifecycle or gating standpoint.

Also applies to: 253-300

vendor/github.com/DeedleFake/p9/dir_plan9.go (1)

1-49: Plan9 DirEntry/QID helpers are straightforward and safe

The Plan9-specific infoToEntry and GetQID implementations safely handle the presence/absence of *syscall.Dir and map QID fields directly from the kernel struct. This looks correct and idiomatic for the platform.

vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

12-62: Darwin DirEntry/QID implementation looks consistent and robust

The Darwin-specific mapping correctly enriches DirEntry with ATime/UID/GID when *syscall.Stat_t is available and falls back gracefully otherwise. GetQID’s use of ModeFromOS(fi.Mode()).QIDType() and sys.Ino is consistent with the other platform backends.

vendor/github.com/DeedleFake/p9/client.go (1)

45-47: LGTM: Atomic FID generation.

The nextFID implementation correctly uses atomic operations for thread-safe FID allocation.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

35-56: LGTM: Client initialization and lifecycle.

The client properly initializes channels, spawns reader/coord goroutines, and uses context cancellation for cleanup.

vendor/github.com/DeedleFake/p9/proto/server.go (1)

17-42: LGTM: Server connection handling.

The Serve function properly handles connection lifecycle with deferred close, optional connect/disconnect hooks, and per-connection message handlers.

vendor/github.com/DeedleFake/p9/fs.go (2)

179-186: Safe string-to-byte conversion using Go 1.20+ idiom.

The code uses unsafe.Slice(unsafe.StringData(p), len(p)) which is the idiomatic Go 1.20+ way to convert a string to []byte without copying. This is safe and avoids the undefined behavior of the older *(*[]byte)(unsafe.Pointer(&p)) pattern that was previously flagged.


665-717: LGTM: Message dispatch and handler routing.

The HandleMessage function properly routes all 9P message types to their handlers with appropriate error handling for unknown types.

vendor/github.com/DeedleFake/p9/remote.go (1)

339-341: LGTM: Readdir implementation.

The Readdir function correctly uses a buffered reader sized to maxBufSize() for efficient directory reading.

Comment thread vendor/github.com/DeedleFake/p9/internal/util/util.go
Comment thread vendor/github.com/DeedleFake/p9/remote.go
Comment thread vendor/github.com/DeedleFake/p9/remote.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (18)
vendor/github.com/DeedleFake/p9/addr.go (1)

41-48: IPv6 host:port parsing is broken.

strings.SplitN(addr, ":", 2) incorrectly parses IPv6 addresses like [fe80::1]:564, splitting at the first colon and mangling the address. This prevents IPv6 9P connections from working.

This issue was flagged in a previous review. Consider filing an upstream PR to use net.SplitHostPort for correct parsing:

+import "net"
...
-	parts := strings.SplitN(addr, ":", 2)
-	if len(parts) == 2 {
-		if (parts[1] == "9p") || (parts[1] == "9fs") {
-			parts[1] = standardPort
-		}
-		return "tcp", strings.Join(parts, ":")
-	}
+	if strings.Contains(addr, ":") {
+		if host, port, err := net.SplitHostPort(addr); err == nil {
+			switch port {
+			case "9p", "9fs":
+				port = standardPort
+			}
+			return "tcp", net.JoinHostPort(host, port)
+		}
+	}
vendor/github.com/DeedleFake/p9/proto/proto.go (1)

85-94: Off-by-4 framing bug: LimitedReader bound should be size-4.

The 9P protocol's size field includes its own 4 bytes. After reading size, the remaining frame is size-4 bytes. Using N: size allows reads to leak 4 bytes into the next frame, causing message framing errors.

This was flagged in a previous review. Apply this fix upstream or locally:

+	if size < 4 {
+		return nil, NoTag, util.Errorf("receive: invalid frame size: %d", size)
+	}
 	lr := &util.LimitedReader{
 		R: r,
-		N: size,
+		N: size - 4,
 		E: ErrLargeMessage,
 	}
pkg/crc/machine/start.go (1)

249-255: Fix argv tokenization: "9pfs -V -p" passed as single token will fail.

The sshRunner.Run function expects the binary and arguments as separate parameters. Passing "9pfs -V -p" as a single string will cause the shell to look for a binary literally named "9pfs -V -p", which will fail.

Apply this diff to fix the argument parsing:

-			if _, _, err := sshRunner.Run("9pfs -V -p", fmt.Sprintf("%d", constants.Plan9HvsockPort), "2", mount.Target); err != nil {
+			if _, _, err := sshRunner.Run("9pfs", "-V", "-p", fmt.Sprintf("%d", constants.Plan9HvsockPort), "2", mount.Target); err != nil {
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)

85-100: Silent integer overflow for large slices/strings—data corruption risk.

Non-byte slices and strings encode their length as uint16, but there's no bounds check. Values exceeding 65535 elements/bytes will silently wrap, producing corrupted wire data.

This is vendored code, but the issue is significant. Consider filing an upstream PR or adding local bounds checks:

 case reflect.String:
+	if v.Len() > 0xFFFF {
+		e.err = util.Errorf("string too long: %d bytes", v.Len())
+		return
+	}
 	e.mode(uint16(v.Len()))
 	e.mode([]byte(v.String()))
cmd/crc/cmd/daemon.go (1)

253-300: Windows 9P home-dir sharing is correctly gated and cleaned up; error propagation could be enhanced

The 9P servers are:

  • Only started on Windows when EnableSharedDirs is true.
  • Started over both hvsock and TCP with separate listeners.
  • Stopped via defers and monitored via WaitForError with appropriate logging.

This addresses earlier concerns about unconditional exposure and lack of cleanup. If you ever want 9P failures to be fatal for the daemon rather than just logged, you could route WaitForError results into errCh instead of (or in addition to) logging, but that’s an optional behavior change.

pkg/crc/machine/libhvee/driver_windows.go (1)

4-29: 9P share configuration is correct; consider stabilizing tag naming/order

Using ConvertToUnixPath and Type "9p" aligns this driver with the new 9P backend. However, tags based on the loop index (dir%d) depend on the order of machineConfig.SharedDirs; if that slice comes from an unordered source or is reordered, tag→path mapping can change and potentially diverge from the server’s expected aname list.

Consider:

  • Building a sorted copy of machineConfig.SharedDirs before tagging, and/or
  • Centralizing the tag format in a shared helper/constant used by both the 9P server and this client-side configuration.

That would make tag naming deterministic and keep client/server naming in sync.

vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

35-43: Duplicate: ATime construction may have compilation issue

This was already flagged in a previous review. The call time.Unix(sys.Atimespec.Unix()) relies on syscall.Timespec.Unix() returning (sec, nsec) which is then passed directly to time.Unix(sec, nsec). This syntax is valid in Go when the return values match the function parameters exactly.

However, since this is vendored code, any fixes should be submitted upstream as noted in the PR comments.

test/e2e/testsuite/testsuite.go (1)

589-600: Gate 9P test step registration to Windows platform.

The 9P file sharing test steps call libhvee.ConvertToUnixPath() unconditionally during step definition registration. While the feature file may be tagged @windows, step definitions are registered at initialization time regardless of platform tags. This is consistent with the pattern used elsewhere in this file (lines 972, 1036, 1043, 1084).

Apply this diff:

 	// 9P file sharing checks
+	if runtime.GOOS == "windows" {
 	mountedHomeDir := libhvee.ConvertToUnixPath(constants.GetHomeDir())
 	s.Step(`^home directory mount exists in VM$`,
 		func() error { return directoryExistInVM(mountedHomeDir) })
 	s.Step(`^filesystem is mounted$`,
 		filesystemIsMounted)
 	s.Step(`^listing files in mounted home directory should succeed$`,
 		func() error { return listingFilesInDirectoryShouldSucceed(mountedHomeDir) })
 	s.Step(`^basic file operations in mounted home directory should succeed$`,
 		func() error { return basicFileOperationsInDirectoryShouldSucceed(mountedHomeDir) })
 	s.Step(`^basic directory operations in mounted home directory should succeed$`,
 		func() error { return basicDirectoryOperationsInDirectoryShouldSucceed(mountedHomeDir) })
+	}
vendor/github.com/DeedleFake/p9/client.go (3)

61-69: Duplicate: Unguarded type assertion in Handshake can panic

This was already flagged in a previous review. The direct type assertion rsp.(*Rversion) can panic if the server returns an unexpected response type. Since this is vendored code, any fix should be submitted upstream per the PR discussion.


84-91: Duplicate: Unguarded type assertion in Auth can panic

This was already flagged in a previous review. The direct type assertion rsp.(*Rauth) can panic on unexpected response types.


113-120: Duplicate: Unguarded type assertion in Attach can panic

This was already flagged in a previous review. The direct type assertion rsp.(*Rattach) can panic on protocol mismatches.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

138-145: Duplicate: Tag allocation can emit reserved NoTag and spin indefinitely

This was already flagged in a previous review. The tag allocation loop doesn't skip the reserved NoTag value (0xFFFF) and will spin forever if all tags are exhausted. Since this is vendored code, the fix should be submitted upstream.

vendor/github.com/DeedleFake/p9/fs.go (2)

244-249: Vendored code: flush must respond with Rflush per 9P spec.

The implementation returns Rerror but the 9P specification requires responding with Rflush. This was flagged in past reviews as addressed, but the code still shows Rerror.

If this is intended for upstream, the 9P spec requires acknowledging flush requests with Rflush, even if cancellation is not supported.

Based on learnings, file PRs upstream so fixes can propagate into vendored copies.


583-608: Vendored code: wrong type assertion misses clunk errors.

Line 596 uses rsp.(error) which will never match because clunk() returns *Rerror for errors, not error. This means clunk failures during remove are silently ignored.

Apply this fix:

-	if _, ok := rsp.(error); ok {
-		return rsp
-	}
+	if er, ok := rsp.(*Rerror); ok {
+		return er
+	}

Based on learnings, if this is a real issue (security-related or functional), file a PR upstream so fixes can propagate into vendored copies.

vendor/github.com/DeedleFake/p9/proto/server.go (1)

61-100: Vendored code: handler called with invalid data after receive errors.

After a Receive error (lines 71-77), the code logs but continues to line 79, invoking the handler with invalid tmsg and tag. This can cause panics or send invalid responses.

Apply this fix:

 	for {
 		tmsg, tag, err := p.Receive(c, msize)
 		if err != nil {
 			if err == io.EOF {
 				return
 			}
 
 			log.Printf("Error reading message: %v", err)
+			continue
 		}

Also consider handling net.ErrClosed like EOF for clean shutdowns. Add "errors" to imports and check errors.Is(err, net.ErrClosed).

Based on learnings, file a PR upstream for this critical fix.

vendor/github.com/DeedleFake/p9/dir.go (3)

18-20: Vendored code: critical path traversal vulnerability.

The path() method allows ".." to escape the served root (e.g., /share/../../etc/passwd). This affects all filesystem operations (Stat, Open, Create, Remove, etc.) that use this method.

This must be fixed by validating that resolved paths remain within the base directory:

-func (d Dir) path(p string) string {
-	return filepath.Join(string(d), filepath.FromSlash(p))
-}
+func (d Dir) path(p string) (string, error) {
+	base := string(d)
+	joined := filepath.Join(base, filepath.FromSlash(p))
+	rel, err := filepath.Rel(base, joined)
+	if err != nil {
+		return "", err
+	}
+	if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) {
+		return "", errors.New("path escapes base")
+	}
+	return joined, nil
+}

All callers must be updated to handle the error return. Based on learnings, file an urgent upstream PR for this security vulnerability.


52-60: Vendored code: partial time updates can corrupt timestamps.

Lines 54-59 call os.Chtimes when only one of ATime/MTime is set, passing a zero-value for the other. This can set invalid timestamps or unexpectedly overwrite the unmodified time.

Reject partial updates:

 	atime, ok1 := changes.ATime()
 	mtime, ok2 := changes.MTime()
-	if ok1 || ok2 {
+	if ok1 != ok2 {
+		return errors.New("setting only one of ATime or MTime is not supported")
+	}
+	if ok1 && ok2 {
 		err := os.Chtimes(p, atime, mtime)
 		if err != nil {
 			return err
 		}
 	}

Based on learnings, file an upstream PR for this fix.


69-75: Vendored code: name change allows path traversal.

Line 71 uses filepath.Join(base, filepath.FromSlash(name)) without validating that name is a simple basename. This allows slashes or ".." to move files outside the intended directory.

Validate the name:

 	name, ok := changes.Name()
 	if ok {
+		if name != filepath.Base(name) || strings.ContainsRune(name, os.PathSeparator) {
+			return errors.New("invalid name: must be a base name without path separators")
+		}
 		err := os.Rename(p, filepath.Join(base, name))
 		if err != nil {
 			return err
 		}
 	}

Add "strings" to imports. Based on learnings, file an upstream PR for this security issue.

🧹 Nitpick comments (6)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)

101-108: Dead code: unreachable if err != nil check.

Line 103 checks if err != nil but err was already checked and returned on line 98. This condition is unreachable. While minor, it suggests incomplete error handling logic.

 	t := p.TypeFromID(msgType)
 	if t == nil {
-		if err != nil {
-			return nil, NoTag, err
-		}
-
 		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
 	}
vendor/github.com/DeedleFake/p9/README.md (1)

1-51: Vendor README: prefer tweaking markdownlint config over editing vendored text

This README mirrors the upstream p9 project; the MD003/MD010 markdownlint warnings are purely stylistic. To avoid divergence from upstream, it’s better to exclude vendor paths from markdownlint (or relax those rules there) rather than reformatting this file.

pkg/crc/constants/constants.go (1)

59-62: Plan9 constants look reasonable; optional doc comments*

The new Plan9Msize/Plan9TcpPort/Plan9HvsockGUID/Plan9HvsockPort constants are well-grouped with other networking-related constants. For future maintainers, consider brief comments (e.g., “default 9P msize in bytes”, “default 9P TCP port”) to document where these values come from and how they’re used.

vendor/github.com/DeedleFake/p9/client.go (1)

45-47: Consider FID overflow behavior.

The nextFID() function uses atomic increment but doesn't handle the case when the uint32 counter wraps around to 0, potentially reusing FIDs that are still in use. For long-running connections with many file operations, this could cause conflicts.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

78-109: Reader silently continues on non-EOF I/O errors.

When c.p.Receive fails with an error that is neither a context cancellation nor EOF (line 92-96), the reader silently continues to the next iteration. This swallows potentially important errors (e.g., malformed messages, connection issues) without logging, making debugging difficult.

Consider logging non-EOF errors before continuing:

 		if err != nil {
 			if (ctx.Err() != nil) || (err == io.EOF) {
 				return
 			}
 
+			log.Printf("Receive error (continuing): %v", err)
 			continue
 		}
vendor/github.com/DeedleFake/p9/fs.go (1)

169-186: Vendored code: unsafe conversion is valid but could be simplified.

Line 179 uses unsafe.Slice(unsafe.StringData(p), len(p)) which is valid Go 1.20+ code. However, a simpler []byte(p) would be more idiomatic and avoid unsafe. If this is a real performance concern and feasible to fix, consider filing an upstream PR.

Based on learnings, this is vendored code and should be fixed upstream if needed.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 514277a and 7572298.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (48)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (2 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_test.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/server_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/server_windows.go (1 hunks)
  • test/e2e/features/9pfs.feature (1 hunks)
  • test/e2e/testsuite/testsuite.go (3 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (7)
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver.go
  • cmd/crc/cmd/start.go
  • pkg/crc/machine/driver_windows.go
  • pkg/crc/machine/driver_linux.go
  • pkg/crc/machine/driver_darwin.go
  • pkg/drivers/libhvee/libhvee_windows.go
✅ Files skipped from review due to trivial changes (1)
  • vendor/github.com/DeedleFake/p9/LICENSE
🚧 Files skipped from review as they are similar to previous changes (13)
  • vendor/github.com/DeedleFake/p9/addr_unix.go
  • vendor/github.com/DeedleFake/p9/dir_windows.go
  • vendor/github.com/DeedleFake/p9/addr_other.go
  • pkg/fileserver/fs9p/server_windows.go
  • vendor/github.com/DeedleFake/p9/doc.go
  • vendor/github.com/DeedleFake/p9/dir_linux.go
  • vendor/modules.txt
  • vendor/github.com/DeedleFake/p9/encoding.go
  • test/e2e/features/9pfs.feature
  • pkg/crc/config/settings.go
  • vendor/github.com/DeedleFake/p9/remote.go
  • vendor/github.com/DeedleFake/p9/dir_other.go
  • vendor/github.com/DeedleFake/p9/internal/util/util.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • pkg/crc/machine/start.go
  • pkg/fileserver/fs9p/server_fallback.go
  • cmd/crc/cmd/daemon.go
  • test/e2e/testsuite/testsuite.go
  • pkg/fileserver/fs9p/server.go
  • vendor/github.com/DeedleFake/p9/proto/server.go
  • go.mod
  • vendor/github.com/DeedleFake/p9/fs.go
  • vendor/github.com/DeedleFake/p9/msg.go
  • vendor/github.com/DeedleFake/p9/p9.go
  • vendor/github.com/DeedleFake/p9/README.md
🧬 Code graph analysis (17)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (11-13)
pkg/crc/machine/start.go (3)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/crc/constants/constants.go (2)
  • Plan9HvsockPort (62-62)
  • VSockGateway (42-42)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
pkg/fileserver/fs9p/server_fallback.go (1)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
cmd/crc/cmd/daemon.go (5)
pkg/crc/config/settings.go (1)
  • EnableSharedDirs (33-33)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
pkg/crc/constants/constants.go (2)
  • Plan9HvsockGUID (61-61)
  • Plan9TcpPort (60-60)
pkg/fileserver/fs9p/server.go (1)
  • New9pServer (34-58)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
vendor/github.com/DeedleFake/p9/dir_plan9.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (6-6)
pkg/crc/machine/libhvee/driver_test.go (1)
pkg/crc/machine/libhvee/driver.go (1)
  • ConvertToUnixPath (10-25)
test/e2e/testsuite/testsuite.go (3)
pkg/crc/machine/libhvee/driver.go (1)
  • ConvertToUnixPath (10-25)
pkg/crc/constants/constants.go (1)
  • GetHomeDir (166-172)
test/extended/util/util.go (1)
  • SendCommandToVM (237-254)
pkg/fileserver/fs9p/server.go (5)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
vendor/github.com/DeedleFake/p9/addr.go (2)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (18-30)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (18-30)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/proto/proto.go (3)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Read (34-38)
  • Write (25-31)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/p9.go (1)
  • NoTag (15-15)
vendor/github.com/DeedleFake/p9/internal/util/util.go (2)
  • Errorf (44-52)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/fs.go (5)
vendor/github.com/DeedleFake/p9/stat.go (2)
  • DirEntry (255-267)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (11-13)
vendor/github.com/DeedleFake/p9/msg.go (2)
  • Tversion (79-82)
  • Tversion (84-84)
vendor/github.com/DeedleFake/p9/client.go (1)
  • ErrUnsupportedVersion (14-14)
vendor/github.com/DeedleFake/p9/msg.go (6)
vendor/github.com/DeedleFake/p9/proto/proto.go (2)
  • NewProto (44-60)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • Version (10-10)
  • QID (42-46)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • P9NoTag (221-223)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • ErrLargeStat (18-18)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Write (25-31)
  • Read (34-38)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/p9.go (1)
vendor/github.com/DeedleFake/p9/stat.go (1)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
🪛 markdownlint-cli2 (0.18.1)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: verify-devcontainer
  • GitHub Check: build (ubuntu-22.04, 1.24)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: build-qe (linux, amd64)
  • GitHub Check: build-qe (windows, amd64)
  • GitHub Check: build-qe (darwin, amd64)
  • GitHub Check: build (macOS-26, 1.24)
  • GitHub Check: build-installer (windows-2022, 1.24)
  • GitHub Check: build-qe (linux, arm64)
  • GitHub Check: build-qe (darwin, arm64)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: Run OKD bundle with crc (1.24)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (20)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)

1-13: LGTM — Standard conditional debug logging pattern.

This vendored file correctly implements build-tag-conditional debug logging. The dual build tag format (Go 1.17+ and legacy) ensures compatibility across Go versions, and the function signature matches the no-op variant in nodebug.go.

vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-6: LGTM — Correct no-op implementation for non-debug builds.

The build tags correctly invert the p9debug condition, and the empty function body ensures zero runtime overhead. The function signature matches the debug variant, maintaining API consistency.

go.mod (1)

7-7: Dependency addition aligns with PR objectives.

The github.com/DeedleFake/p9 v0.7.1 dependency is appropriate for the 9P file sharing implementation. Note that a previous review flagged the library as "experimental" per its README—ensure adequate integration testing is performed before production deployment.

vendor/github.com/DeedleFake/p9/msg.go (1)

44-77: Protocol registry and message types look correct.

The message type definitions follow the 9P2000 protocol specification. The registry correctly maps type IDs to Go structs, and the custom P9Encode/P9Decode implementations for Rstat and Twstat properly handle the nested size prefix required by the protocol.

vendor/github.com/DeedleFake/p9/stat.go (1)

155-251: Stat serialization implementation looks correct.

The Stat struct and its P9Encode/P9Decode methods correctly implement the 9P stat format with proper size prefix handling and field ordering per the protocol specification.

pkg/crc/machine/start.go (1)

321-322: These fields are user-configurable settings and should be retained for backward compatibility.

SharedDirPassword and SharedDirUsername are defined in the settings configuration (pkg/crc/config/settings.go) and can be set by users in config files. While these SMB-related credentials are not currently used by the 9P implementation, removing them would break configuration parsing for existing deployments. The fields should remain as-is during the ongoing migration from SMB to 9P file sharing.

Likely an incorrect or invalid review comment.

pkg/crc/machine/libhvee/driver_test.go (1)

10-11: Tests correctly exercise the exported ConvertToUnixPath helper

Switching the test to use ConvertToUnixPath keeps it aligned with the public API while preserving the expected semantics across platforms.

pkg/fileserver/fs9p/server_fallback.go (1)

1-15: Non-Windows GetHvsockListener stub is appropriate

Providing a stub that always errors on non-Windows keeps the API available for all builds while making any accidental non-Windows use fail fast with a clear, GOOS-specific error message.

cmd/crc/cmd/daemon.go (1)

182-212: Use of net.JoinHostPort for HTTP listeners is a solid portability improvement

Replacing manual string formatting with net.JoinHostPort for the gateway and host virtual IP listeners avoids subtle issues with IPv6/port formatting and improves clarity.

pkg/crc/machine/libhvee/driver.go (1)

1-25: ConvertToUnixPath helper cleanly encapsulates Windows path normalization

The function correctly:

  • Normalizes separators (filepath.ToSlash on Windows, backslash replacement elsewhere).
  • Detects drive-letter paths and maps them to /mnt/<lowercase-drive>... as Podman expects.
  • Leaves non–drive-letter paths untouched.

Centralizing this logic as an exported helper reduces duplication and keeps driver-specific code simpler.

vendor/github.com/DeedleFake/p9/dir_plan9.go (1)

1-49: Plan9 DirEntry/QID helpers handle syscall.Dir safely

infoToEntry cleanly handles both *syscall.Dir-backed and generic os.FileInfo values without panicking, and Dir.GetQID validates that the underlying Sys() value is a *syscall.Dir before constructing the QID. This looks correct for Plan9 stat integration and provides a graceful error when the expected metadata is missing.

vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

46-62: LGTM!

The GetQID function correctly handles the case where FileInfo.Sys() doesn't return a *syscall.Stat_t, and properly extracts the inode for the QID path.

test/e2e/testsuite/testsuite.go (1)

1370-1480: LGTM! Well-structured 9P file sharing test helpers.

The helper functions provide comprehensive coverage for validating 9P mount functionality:

  • directoryExistInVM validates mount point existence
  • filesystemIsMounted confirms 9P filesystem is mounted
  • File operations cover the full CRUD cycle plus permissions and rename
  • Directory operations cover creation, listing, and deletion

The use of path.Join is appropriate since these commands execute inside the VM.

packaging/windows/product.wxs.template (2)

69-73: LGTM! Registry entry for 9P over hvsock.

The new Hvsock9pRegistryEntry component follows the same pattern as the existing VsockRegistryEntry and correctly registers the fs9p-hvsock service under the Hyper-V Guest Communication Services registry path.


111-111: LGTM!

The ComponentRef is correctly added to the DefaultFeature to ensure the 9P hvsock registry entry is installed.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

165-208: LGTM! Send method has proper cancellation handling.

The Send method correctly handles client closure at multiple points:

  • Before acquiring a tag
  • Before registering the message
  • After receiving the response

The cancellation path properly cleans up the allocated tag via cancelMsg.

pkg/fileserver/fs9p/server.go (3)

34-58: LGTM: Constructor properly validates inputs and addresses goroutine leak concern.

The buffered channel (line 49) correctly prevents goroutine leaks when WaitForError is not called, addressing the concern from past reviews.


60-75: LGTM: Start method uses appropriate pattern for error detection.

The select with default (lines 68-74) provides a best-effort check for immediate startup failures. While there's a theoretical race window, this pattern is reasonable for detecting synchronous errors during server initialization.


77-87: Documentation addresses known limitation.

The warning comment (lines 78-80) clearly documents the forceful shutdown behavior. This addresses the graceful shutdown concern from past reviews by explicitly documenting the contract.

vendor/github.com/DeedleFake/p9/p9.go (1)

1-71: LGTM: Clean constant and type definitions.

The foundational 9P types and constants are well-defined with appropriate documentation. No issues found.

Comment thread pkg/fileserver/fs9p/server.go
Comment thread vendor/github.com/DeedleFake/p9/proto/encoding.go
Comment thread vendor/github.com/DeedleFake/p9/stat.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (18)
pkg/crc/machine/libhvee/driver_windows.go (1)

21-32: LGTM! SMB to 9P migration looks correct.

The transition from CIFS/SMB to 9P is properly implemented:

  • Type correctly changed to "9p"
  • Username field appropriately removed (not needed for 9P)
  • Path conversion delegated to the shared ConvertToUnixPath helper

The concern about tag determinism (sorting SharedDirs before assigning indexed tags) was already raised in a previous review.

pkg/crc/machine/start.go (1)

244-255: Fix argv tokenization on line 249: combined command string will fail.

The first sshRunner.Run call on line 249 passes "9pfs -V -p" as a single token, which will fail binary lookup since Run expects separate argv elements. The subsequent arguments suggest the intent to split, but the command portion is still combined.

Apply this diff to split the command properly:

-			if _, _, err := sshRunner.Run("9pfs -V -p", fmt.Sprintf("%d", constants.Plan9HvsockPort), "2", mount.Target); err != nil {
+			if _, _, err := sshRunner.Run("9pfs", "-V", "-p", fmt.Sprintf("%d", constants.Plan9HvsockPort), "2", mount.Target); err != nil {

Note: A past review comment indicated this was addressed in commits 2d84a72 to 19db067, but the issue persists in the current code.

vendor/github.com/DeedleFake/p9/dir.go (1)

1-260: Vendored code with known security issues reported upstream.

This vendored file contains critical path traversal vulnerabilities that were flagged in previous reviews and reported upstream as DeedleFake/p9 issue #82. The key issues are:

  1. Lines 18-20: Dir.path() allows .. to escape the served root
  2. Lines 52-60: Partial ATime/MTime updates can corrupt timestamps
  3. Lines 69-75: Name change allows path traversal

Until upstream merges a fix, consider applying local patches to the vendored copy to mitigate these security risks, especially if the 9P server will be exposed to untrusted clients.

vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

35-43: Compile-time error: time.Unix signature mismatch.

time.Unix(sys.Atimespec.Unix()) is invalid—Atimespec.Unix() returns two values (sec int64, nsec int64), but you're passing only one argument to time.Unix.

Apply this diff:

 return DirEntry{
   FileMode:  ModeFromOS(fi.Mode()),
-  ATime:     time.Unix(sys.Atimespec.Unix()),
+  ATime:     time.Unix(sys.Atimespec.Sec, sys.Atimespec.Nsec),
   MTime:     fi.ModTime(),
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)

34-38: Panic risk on non-pointer input—consider upstream fix.

Read() will panic if passed a non-pointer or nil value because decode() calls v.Addr() on the indirect value. This is vendored code, so per project guidelines, consider filing a PR upstream.


85-100: Length overflow risks for slices and strings already flagged.

Non-byte slices and strings with lengths exceeding 65535 will silently truncate when cast to uint16. These concerns were raised in prior reviews.

vendor/github.com/DeedleFake/p9/client.go (3)

61-69: Unguarded type assertion can panic on protocol errors.

If the server returns an unexpected response type, rsp.(*Rversion) will panic. This was flagged in prior reviews—consider a guarded assertion.


84-91: Unguarded type assertion for Auth response.

Same concern as Handshake: rsp.(*Rauth) can panic if the response type is unexpected.


113-120: Unguarded type assertion for Attach response.

Same concern: rsp.(*Rattach) can panic on protocol mismatches.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

138-145: Tag exhaustion and NoTag handling issue already flagged.

The coordinator can spin forever if all tags are in use, and can return NoTag (0xFFFF) which is reserved. This was identified in prior reviews.

vendor/github.com/DeedleFake/p9/proto/server.go (1)

3-8: Avoid dispatching on failed Receive and terminate cleanly on closed connections

handleMessages currently logs non-EOF errors from p.Receive but still calls handler.HandleMessage(tmsg) with whatever was left in tmsg/tag, and it doesn’t terminate on net.ErrClosed. This can panic or send bogus responses, and it may busy‑loop on a closed connection.

Consider:

-import (
-	"io"
-	"log"
-	"net"
-	"sync"
-)
+import (
+	"errors"
+	"io"
+	"log"
+	"net"
+	"sync"
+)
@@
 func handleMessages(c net.Conn, p Proto, handler MessageHandler) {
@@
-	for {
-		tmsg, tag, err := p.Receive(c, msize)
-		if err != nil {
-			if err == io.EOF {
-				return
-			}
-
-			log.Printf("Error reading message: %v", err)
-		}
-
-		mode(func() {
+	for {
+		tmsg, tag, err := p.Receive(c, msize)
+		if err != nil {
+			// EOF or closed connection: stop serving this client.
+			if errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) {
+				return
+			}
+			// Other errors: log and stop; do not dispatch a handler
+			// with a failed/partial message.
+			log.Printf("Error reading message: %v", err)
+			return
+		}
+
+		mode(func() {
 			rmsg := handler.HandleMessage(tmsg)

This ensures the handler is only called for successfully decoded messages and that closed connections don’t spin the loop.

Also applies to: 61-99

vendor/github.com/DeedleFake/p9/fs.go (1)

147-150: Tflush should reply with Rflush, not Rerror

flush currently returns an Rerror (“flush is not supported”), and the comment above FSHandler still says Tflush is “not handled”. Per 9P, flush requests must be acknowledged with Rflush; even if you can’t cancel in‑flight I/O, you should still respond success‑fully as best effort.

Suggested change:

-// BUG: Tflush requests are not currently handled at all by this
-// implementation due to no clear method of stopping a pending call to
-// ReadAt or WriteAt.
+// BUG: Tflush requests are only acknowledged; in-flight ReadAt/WriteAt
+// operations are not actually cancelled.

 func (h *fsHandler) flush(msg *Tflush) any {
-	// TODO: Implement this.
-	return &Rerror{
-		Ename: "flush is not supported",
-	}
+	// Best-effort: acknowledge the flush without attempting to cancel
+	// already in-flight operations.
+	return &Rflush{}
 }

This keeps behavior compatible with the spec while documenting that cancellation is not implemented.

Also applies to: 244-249

vendor/github.com/DeedleFake/p9/remote.go (5)

34-71: Fix walk path handling and guard response type assertion

For absolute paths, walk can send invalid Wname (empty elements or "/") and it blindly asserts rsp.(*Rwalk), which will panic if the server replies with *Rerror or anything unexpected.

Recommend:

 func (file *Remote) walk(p string) (*Remote, error) {
 	fid := file.client.nextFID()
 
-	w := []string{path.Clean(p)}
-	if w[0] != "/" {
-		w = strings.Split(w[0], "/")
-	}
-	if (len(w) == 1) && (w[0] == ".") {
-		w = nil
-	}
+	p = path.Clean(p)
+	var w []string
+	switch {
+	case p == "", p == ".", p == "/":
+		// Root/no-op walk uses empty Wname.
+		w = nil
+	default:
+		if strings.HasPrefix(p, "/") {
+			p = strings.TrimPrefix(p, "/")
+		}
+		if p != "" && p != "." {
+			w = strings.Split(p, "/")
+		}
+	}
 	rsp, err := file.client.Send(&Twalk{
 		FID:    file.fid,
 		NewFID: fid,
 		Wname:  w,
 	})
 	if err != nil {
 		return nil, err
 	}
-	walk := rsp.(*Rwalk)
+	if er, ok := rsp.(*Rerror); ok {
+		return nil, er
+	}
+	walk, ok := rsp.(*Rwalk)
+	if !ok {
+		return nil, util.Errorf("walk: expected *Rwalk, got %T", rsp)
+	}

This avoids invalid Wname components and safely handles protocol errors instead of panicking.


79-97: Guard all response type assertions and surface Rerror instead of panicking

Similar to walk, several methods assume a successful typed response and will panic if the server sends *Rerror or any other message type:

  • Line 92: open := rsp.(*Ropen)
  • Line 117: create := rsp.(*Rcreate)
  • Line 211: read := rsp.(*Rread)
  • Line 265: write := rsp.(*Rwrite)
  • Line 327: stat := rsp.(*Rstat)

They also silently ignore server-side Rerror.

Pattern to apply (example for Open):

 	rsp, err := file.client.Send(&Topen{
 		FID:  next.fid,
 		Mode: mode,
 	})
 	if err != nil {
 		return nil, err
 	}
-	open := rsp.(*Ropen)
+	if er, ok := rsp.(*Rerror); ok {
+		return nil, er
+	}
+	open, ok := rsp.(*Ropen)
+	if !ok {
+		return nil, util.Errorf("open: expected *Ropen, got %T", rsp)
+	}

Do the same *Rerror check and guarded assertion for Create, readPart, writePart, and Stat. This turns server-provided errors into Go errors instead of crashes.

Also applies to: 101-122, 202-218, 256-271, 311-330


126-141: Propagate server-side errors from Remove and Close

Both Remove (when p == "") and Close ignore the response body, so an Rerror from the server is silently dropped; callers only see transport errors.

Suggested adjustments:

 func (file *Remote) Remove(p string) error {
@@
-	_, err := file.client.Send(&Tremove{
-		FID: file.fid,
-	})
-	return err
+	rsp, err := file.client.Send(&Tremove{
+		FID: file.fid,
+	})
+	if err != nil {
+		return err
+	}
+	if er, ok := rsp.(*Rerror); ok {
+		return er
+	}
+	return nil
 }
@@
 func (file *Remote) Close() error {
-	_, err := file.client.Send(&Tclunk{
-		FID: file.fid,
-	})
-	return err
+	rsp, err := file.client.Send(&Tclunk{
+		FID: file.fid,
+	})
+	if err != nil {
+		return err
+	}
+	if er, ok := rsp.(*Rerror); ok {
+		return er
+	}
+	return nil
 }

This keeps the API honest about server failures (permission denied, busy, etc.).

Also applies to: 298-305


147-185: Seek should return an error instead of panicking on invalid whence

On an unsupported whence, Seek panics:

panic(util.Errorf("Invalid whence: %v", whence))

Library code should not panic on invalid input; return an error and leave pos unchanged:

 	case io.SeekEnd:
@@
 		file.pos = uint64(npos)
 		return npos, nil
 	}
 
-	panic(util.Errorf("Invalid whence: %v", whence))
+	return int64(file.pos), util.Errorf("invalid whence: %v", whence)

This matches idiomatic io.Seeker behavior and avoids crashing callers.


198-243: Guard maxBufSize and chunk sizes to avoid underflow and infinite loops

maxBufSize currently does:

return int(file.client.Msize() - IOHeaderSize)

If Msize() <= IOHeaderSize, this underflows (uint32) or returns 0, and:

  • ReadAt/WriteAt compute size := min(len(...), file.maxBufSize()) which can be 0, so the for start += size loop never progresses (infinite loop).
  • Readdir passes a raw maxBufSize() (possibly 0 or huge) to bufio.NewReaderSize, risking nonsensical buffer sizes.

Recommended:

 func (file *Remote) maxBufSize() int {
-	return int(file.client.Msize() - IOHeaderSize)
+	m := file.client.Msize()
+	if m <= uint32(IOHeaderSize) {
+		return 0
+	}
+	return int(m - uint32(IOHeaderSize))
 }
@@
 func (file *Remote) ReadAt(buf []byte, off int64) (int, error) {
-	size := min(len(buf), file.maxBufSize())
+	max := file.maxBufSize()
+	if max <= 0 {
+		return 0, util.Errorf("msize too small: %d", file.client.Msize())
+	}
+	size := len(buf)
+	if size > max {
+		size = max
+	}
@@
 func (file *Remote) WriteAt(data []byte, off int64) (int, error) {
-	size := min(len(data), file.maxBufSize())
+	max := file.maxBufSize()
+	if max <= 0 {
+		return 0, util.Errorf("msize too small: %d", file.client.Msize())
+	}
+	size := len(data)
+	if size > max {
+		size = max
+	}
@@
 func (file *Remote) Readdir() ([]DirEntry, error) {
-	return ReadDir(bufio.NewReaderSize(file, file.maxBufSize()))
+	max := file.maxBufSize()
+	if max <= 0 {
+		return nil, util.Errorf("msize too small: %d", file.client.Msize())
+	}
+	return ReadDir(bufio.NewReaderSize(file, max))
 }

You may also want to validate negotiated Msize during the client handshake so Msize <= IOHeaderSize fails fast.

Also applies to: 283-296, 339-341

vendor/github.com/DeedleFake/p9/stat.go (1)

3-13: FileMode.String returns a string backed by stack memory (unsafe use‑after‑return)

String() builds a local slice and then uses unsafe.String(unsafe.SliceData(buf), len(buf)). That string points at stack-allocated memory and can become invalid once the function returns, leading to undefined behavior.

You can avoid this and drop unsafe entirely:

-import (
-	"bytes"
-	"errors"
-	"io"
-	"os"
-	"time"
-	"unsafe"
-
-	"github.com/DeedleFake/p9/internal/util"
-	"github.com/DeedleFake/p9/proto"
-)
+import (
+	"bytes"
+	"errors"
+	"io"
+	"os"
+	"time"
+
+	"github.com/DeedleFake/p9/internal/util"
+	"github.com/DeedleFake/p9/proto"
+)
@@
 func (m FileMode) String() string {
 	buf := []byte("----------")
@@
-	return unsafe.String(unsafe.SliceData(buf), len(buf))
+	return string(buf)
 }

This adds a tiny allocation for a 10-byte buffer but restores memory safety and removes the need for unsafe.

Also applies to: 135-153

🧹 Nitpick comments (2)
cmd/crc/cmd/daemon.go (1)

253-300: 9P server setup looks correct; consider propagating errors to errCh.

The implementation properly:

  • Gates on EnableSharedDirs config (addressing the past review comment)
  • Captures server handles and defers Stop() for graceful shutdown
  • Sets up both hvsock and TCP fallback

One optional improvement: the WaitForError() goroutines only log errors. For consistency with other components (lines 178, 194, 210, 249), consider sending 9P server errors to errCh so the daemon exits on fatal 9P failures:

 go func() {
     if err := server9pHvsock.WaitForError(); err != nil {
-        logging.Errorf("9p server (hvsock) error: %v", err)
+        errCh <- errors.Wrap(err, "9p server (hvsock) failed")
     }
 }()
vendor/github.com/DeedleFake/p9/proto/client.go (1)

90-97: Read errors are silently swallowed.

When c.p.Receive returns an error that isn't EOF and context isn't cancelled, the loop continues without logging or propagating the error. This could mask protocol or connection issues.

Consider logging transient errors or implementing a retry limit to avoid infinite silent retries on persistent failures. Since this is vendored code, file upstream if desired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7572298 and afdee8a.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (49)
  • Makefile (1 hunks)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (2 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_test.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/server_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/server_windows.go (1 hunks)
  • test/e2e/features/9pfs.feature (1 hunks)
  • test/e2e/testsuite/testsuite.go (3 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (7)
  • cmd/crc/cmd/start.go
  • pkg/crc/machine/driver_windows.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/crc/machine/driver_linux.go
  • pkg/drivers/libhvee/powershell_windows.go
  • pkg/crc/machine/driver_darwin.go
  • pkg/crc/machine/driver.go
✅ Files skipped from review due to trivial changes (2)
  • Makefile
  • vendor/github.com/DeedleFake/p9/LICENSE
🚧 Files skipped from review as they are similar to previous changes (14)
  • pkg/fileserver/fs9p/server_fallback.go
  • vendor/github.com/DeedleFake/p9/addr_other.go
  • pkg/crc/constants/constants.go
  • vendor/github.com/DeedleFake/p9/internal/util/util.go
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go
  • test/e2e/features/9pfs.feature
  • pkg/crc/config/settings.go
  • vendor/github.com/DeedleFake/p9/dir_linux.go
  • vendor/github.com/DeedleFake/p9/encoding.go
  • vendor/github.com/DeedleFake/p9/doc.go
  • vendor/github.com/DeedleFake/p9/dir_windows.go
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go
  • vendor/github.com/DeedleFake/p9/p9.go
  • go.mod
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • pkg/fileserver/fs9p/server_windows.go
  • cmd/crc/cmd/daemon.go
  • test/e2e/testsuite/testsuite.go
  • pkg/fileserver/fs9p/server.go
  • vendor/github.com/DeedleFake/p9/fs.go
  • pkg/crc/machine/start.go
  • vendor/github.com/DeedleFake/p9/msg.go
  • vendor/github.com/DeedleFake/p9/README.md
🧬 Code graph analysis (15)
vendor/github.com/DeedleFake/p9/dir_other.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
pkg/fileserver/fs9p/server_windows.go (1)
pkg/fileserver/fs9p/server_fallback.go (1)
  • GetHvsockListener (13-15)
pkg/crc/machine/libhvee/driver_test.go (1)
pkg/crc/machine/libhvee/driver.go (1)
  • ConvertToUnixPath (10-25)
vendor/github.com/DeedleFake/p9/addr.go (2)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (18-30)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
  • NamespaceDir (18-30)
vendor/github.com/DeedleFake/p9/addr_unix.go (1)
vendor/github.com/DeedleFake/p9/addr_other.go (1)
  • NamespaceDir (18-30)
pkg/fileserver/fs9p/server.go (5)
vendor/github.com/DeedleFake/p9/fs.go (2)
  • FileSystem (21-34)
  • FSConnHandler (162-167)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/proto/server.go (1)
  • Serve (17-42)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
pkg/crc/constants/constants.go (1)
  • Plan9Msize (59-59)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
vendor/github.com/DeedleFake/p9/msg.go (1)
  • Proto (75-77)
vendor/github.com/DeedleFake/p9/proto/proto.go (1)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/dir_plan9.go (4)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/miekg/dns/types.go (2)
  • UID (1448-1451)
  • GID (1456-1459)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
vendor/github.com/DeedleFake/p9/fs.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • QID (42-46)
  • QIDType (49-49)
  • IOHeaderSize (70-70)
  • Version (10-10)
  • QTAuth (58-58)
  • NoFID (18-18)
  • QTDir (54-54)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • WriteDir (33-42)
vendor/github.com/DeedleFake/p9/dir_darwin.go (2)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/remote.go (4)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • Client (18-31)
vendor/github.com/DeedleFake/p9/msg.go (7)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
pkg/crc/machine/start.go (3)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/crc/constants/constants.go (2)
  • Plan9HvsockPort (62-62)
  • VSockGateway (42-42)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
vendor/github.com/DeedleFake/p9/stat.go (3)
vendor/github.com/DeedleFake/p9/p9.go (3)
  • QIDType (49-49)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/proto/encoding.go (3)
  • Write (25-31)
  • Read (34-38)
  • Size (14-20)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
vendor/github.com/DeedleFake/p9/dir.go (3)
vendor/github.com/DeedleFake/p9/stat.go (5)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
  • ModeDir (27-27)
vendor/github.com/DeedleFake/p9/fs.go (4)
  • File (100-119)
  • Attachment (44-74)
  • FileSystem (21-34)
  • QIDFS (89-91)
vendor/github.com/DeedleFake/p9/p9.go (6)
  • OWRITE (27-27)
  • ORDWR (28-28)
  • OEXEC (29-29)
  • OTRUNC (31-31)
  • OCEXEC (32-32)
  • ORCLOSE (33-33)
🪛 markdownlint-cli2 (0.18.1)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: build-qe (darwin, arm64)
  • GitHub Check: build-qe (linux, amd64)
  • GitHub Check: build-qe (linux, arm64)
  • GitHub Check: build-qe (windows, amd64)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: build-qe (darwin, amd64)
  • GitHub Check: build-installer (windows-2022, 1.24)
  • GitHub Check: Run OKD bundle with crc (1.24)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: verify-devcontainer
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (19)
pkg/crc/machine/libhvee/driver_test.go (1)

9-12: LGTM! Consider expanding test coverage.

The test correctly exercises the exported ConvertToUnixPath function. The two test cases cover the primary use case (Windows drive-letter paths). You might consider adding edge cases (empty string, paths without drive letters, already-slash paths) in a follow-up.

pkg/crc/machine/libhvee/driver.go (1)

9-25: Well-documented path conversion helper.

The implementation correctly handles Windows-style paths with drive letters, converting them to the /mnt/<drive>/... format expected by Podman. The reference to the Podman source is helpful for maintainability.

Minor observation: The runtime.GOOS branch (lines 16-20) ensures tests can run on non-Windows platforms with backslash-containing test strings, since filepath.ToSlash on non-Windows would not convert backslashes. Good defensive coding.

vendor/modules.txt (1)

13-18: LGTM! Vendor dependency addition is correct.

The DeedleFake/p9 v0.7.1 package and its subpackages are properly declared with the explicit tag and Go version 1.24.0. This aligns with the PR's objective to add 9P file sharing support.

test/e2e/testsuite/testsuite.go (2)

604-615: LGTM! 9P test step registration is well-structured.

The test steps properly validate 9P file sharing functionality by checking mount existence, filesystem type, and basic file/directory operations. The libhvee.ConvertToUnixPath usage is appropriate per the earlier clarification that this function is now cross-platform.


1382-1492: LGTM! 9P test helpers provide comprehensive coverage.

The helper functions systematically verify:

  • Directory existence in VM (directoryExistInVM)
  • Filesystem mount type verification (filesystemIsMounted)
  • Directory listing (listingFilesInDirectoryShouldSucceed)
  • CRUD operations on files (basicFileOperationsInDirectoryShouldSucceed)
  • Directory operations (basicDirectoryOperationsInDirectoryShouldSucceed)

The implementations correctly use util.SendCommandToVM and validate outputs appropriately.

packaging/windows/product.wxs.template (1)

69-73: LGTM! Hvsock 9P registry entry is correctly configured.

The new component registers the fs9p-hvsock service under Windows Virtualization Guest Communication Services with GUID 00009000-FACB-11E6-BD58-64006A7986D3. The structure follows the existing pattern for VsockRegistryEntry, and per the earlier discussion, the Win64 attribute is not required for this single-arch installer.

vendor/github.com/DeedleFake/p9/dir_other.go (1)

1-15: LGTM!

This fallback implementation for non-listed platforms correctly populates the available fields from os.FileInfo while leaving platform-specific fields (ATime, UID, GID, MUID) as zero values, which is consistent with the approach in other OS-specific variants.

pkg/fileserver/fs9p/server_windows.go (1)

12-29: LGTM!

Clean implementation with proper error wrapping. The use of hvsock.GUIDWildcard for VMID allows any VM to connect to this listener, which is appropriate for the CRC VM use case.

cmd/crc/cmd/daemon.go (1)

182-182: LGTM!

Good use of net.JoinHostPort instead of string formatting—this properly handles IPv6 addresses.

vendor/github.com/DeedleFake/p9/dir_plan9.go (2)

10-31: LGTM!

The infoToEntry function correctly handles both cases: when syscall.Dir is available (populating ATime, UID, GID, MUID) and falling back to basic fields otherwise.


33-49: GetQID inherits the path traversal vulnerability from d.path().

This method uses d.path(p) which has the same path traversal issue flagged in dir.go. The vulnerability will be resolved when the upstream fix for issue #82 is merged.

Minor nit: The error message on line 41 could be clearer—"FileInfo was not Dir" may be confused with the directory type check. Consider: "FileInfo.Sys() was not *syscall.Dir".

vendor/github.com/DeedleFake/p9/dir_darwin.go (1)

46-62: LGTM!

The GetQID implementation correctly handles the Darwin-specific Stat_t type assertion and constructs a valid QID from the inode number.

vendor/github.com/DeedleFake/p9/proto/encoding.go (1)

166-173: LGTM for string decoding.

The unsafe.String + unsafe.SliceData pattern is idiomatic Go 1.20+ for zero-copy string creation from a byte slice.

vendor/github.com/DeedleFake/p9/client.go (1)

45-47: LGTM!

The nextFID implementation correctly uses atomic operations to generate sequential FIDs in a thread-safe manner.

vendor/github.com/DeedleFake/p9/proto/client.go (1)

165-208: LGTM!

The Send method correctly handles tag acquisition, message dispatch, and response routing with proper cleanup on errors.

pkg/fileserver/fs9p/server.go (3)

89-98: LGTM for Windows-specific error filtering.

The filtering of "endpoint is in invalid state" errors is appropriate since 9P is Windows-only in this codebase, as clarified in prior review discussions.


77-87: LGTM with useful warning documented.

The comment about client zombification on abrupt shutdown is helpful. The behavior is clearly documented.


34-58: LGTM!

Path validation is thorough—checking for absolute path, existence, and directory type before constructing the server.

vendor/github.com/DeedleFake/p9/msg.go (1)

12-277: 9P message definitions and protocol registry look consistent

The message type constants, protocol type map, and the T*/R* structs (including Rerror, Rstat, Twstat) are internally consistent and match the expected 9P message set. The custom encode/decode paths for Rstat and Twstat correctly pair with Stat.size() and the LimitedReader bounds.

No changes needed here.

Comment thread test/e2e/testsuite/testsuite.go
@anjannath

Copy link
Copy Markdown
Member

@redbeam microshift doesn't have a new release yet, and we need a new bundle of it with the 9pfs client installed, otherwise crc start fails with the microshift preset

INFO Configuring shared directories
WARN Failed to connect to 9p server over hvsock: ssh command error:
command : 9pfs -V -p 36864 2 /mnt/c/Users/rhqp
err     : Process exited with status 127
WARN Falling back to 9p over TCP
ERRO ssh command error:
command : 9pfs 192.168.127.1 /mnt/c/Users/rhqp
err     : Process exited with status 127

we need to add a check to skip mounting shared directories when preset is microshift and the os is windows, wdyt?

@anjannath

Copy link
Copy Markdown
Member

@redbeam could you please also rebase it on main again

cfergeau and others added 7 commits December 17, 2025 10:56
This commit adds 9P file sharing support to replace the existing
SMB file sharing solution (#3205, #3220, #4858).
This enables communication through hvsocks instead
of TCP sockets for 9P file sharing. TCP is still
utilized, as a backup option.
After the addition of 9p file sharing for Windows, we are removing
SMB file sharing support (#4768).

Part of this effort is to remove at least some of the warnings
reported by virustotal for the MSI:
https://www.virustotal.com/gui/file/31b402dcc1da24265074a21a26018d6cde8eef0b63c77a18f89eb079b6556790
@redbeam

redbeam commented Dec 17, 2025

Copy link
Copy Markdown
Contributor Author

@anjannath I've addressed the microshift issue and rebased on the latest main.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (12)
pkg/crc/machine/libhvee/driver_windows.go (1)

23-29: Past review comment still applies: tag generation determinism.

The concern about non-deterministic tag assignment based on iteration order has already been flagged in a previous review. If machineConfig.SharedDirs order changes, tag names will change, potentially causing mount failures. The suggestion to sort the directories before assigning tags remains valid.

vendor/github.com/DeedleFake/p9/proto/encoding.go (2)

34-38: Read() can panic on non-pointer input.

This issue was flagged in previous reviews. Per PR comments, consider filing an upstream PR to add a guard that validates v is a non-nil pointer before calling decode().


85-100: Missing bounds checks for slice and string lengths encoded as uint16.

Non-byte slices and strings use uint16 length prefixes, which will silently wrap for lengths exceeding 65535. This was flagged in previous reviews.

vendor/github.com/DeedleFake/p9/remote.go (3)

183-185: Library code should not panic for invalid whence.

As flagged in previous reviews, panic(util.Errorf(...)) should be replaced with returning an error. This prevents crashes from invalid input.


52-52: Unchecked type assertion can panic on protocol errors.

rsp.(*Rwalk) at line 52 will panic if the server returns an unexpected response type. This applies to similar assertions at lines 92, 117, 211, 265, and 327.


229-243: ReadAt loop may hang if maxBufSize() returns zero or negative.

If Msize() <= IOHeaderSize, maxBufSize() returns zero or negative, causing min(len(buf), 0) to yield 0. The loop for start := 0; start < len(buf); start += size never advances when size == 0, resulting in an infinite loop.

vendor/github.com/DeedleFake/p9/fs.go (1)

593-598: Type assertion rsp.(error) never matches; use *Rerror.

clunk() returns *Rerror for errors, not the error interface. The check at line 596 will never be true, so clunk errors are silently ignored before the remove proceeds.

Apply this fix:

-	if _, ok := rsp.(error); ok {
+	if _, ok := rsp.(*Rerror); ok {
 		return rsp
 	}
vendor/github.com/DeedleFake/p9/proto/proto.go (1)

89-93: Off-by-4 framing: LimitedReader should bound to size-4.

The 9P size field includes its own 4 bytes. After reading size, the remaining frame is size-4 bytes. Using N: size allows reads to consume 4 bytes from the next frame on boundary-aligned payloads.

+	if size < 4 {
+		return nil, NoTag, util.Errorf("receive: invalid frame size: %d", size)
+	}
 	lr := &util.LimitedReader{
 		R: r,
-		N: size,
+		N: size - 4,
 		E: ErrLargeMessage,
 	}
vendor/github.com/DeedleFake/p9/dir.go (3)

18-20: Critical: Path traversal via ".." allows filesystem escape.

filepath.Join alone doesn't prevent .. from escaping the root directory. For example, /share/../../etc/passwd resolves to /etc/passwd. This was reported upstream as issue #82.

Consider applying a local patch until upstream fixes this, as this is a critical security vulnerability.


52-59: Partial ATime/MTime updates can corrupt timestamps.

When only one of ATime or MTime is provided, os.Chtimes is called with a zero-value for the other, potentially clobbering it. Either fetch the current value for the missing timestamp or reject partial updates.


69-75: Name change allows path traversal outside parent directory.

filepath.FromSlash(name) doesn't validate that name is a simple filename. A name like ../../../etc/passwd would move the file outside the intended directory.

vendor/github.com/DeedleFake/p9/stat.go (1)

135-153: Memory safety issue with unsafe.String already flagged—ensure upstream fix.

This is a duplicate of a previous review comment. The unsafe.String usage on line 152 creates a memory safety risk by returning a string that points to a stack-allocated slice buffer.

As per PR comments, real issues in vendored code should be filed upstream so fixes propagate when merged. Please verify if an upstream issue or PR has been created for this fix.

🧹 Nitpick comments (3)
test/e2e/testsuite/testsuite.go (1)

1409-1468: Consider cleanup on partial failure in file operations test.

If a step fails after file creation (e.g., write succeeds but read fails), the test file story_9pfs_test_file or story_9pfs_test_file_renamed may remain on the host. For test isolation, consider adding cleanup logic or documenting that test artifacts may persist on failure.

 func basicFileOperationsInDirectoryShouldSucceed(dirName string) error {
 	filename := path.Join(dirName, "story_9pfs_test_file")
+	newFilename := path.Join(dirName, "story_9pfs_test_file_renamed")
 	content := "test content"
+
+	// Cleanup helper for partial failures
+	cleanup := func() {
+		_, _ = util.SendCommandToVM(fmt.Sprintf("rm -f %s %s", filename, newFilename))
+	}
+	defer cleanup()

 	// Create
 	_, err := util.SendCommandToVM(fmt.Sprintf("> %s", filename))
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)

106-108: Error message logs reflect.Value type instead of the actual type.

At line 107, util.Errorf("invalid type: %T", v) will print reflect.Value rather than the underlying type since v is a reflect.Value. Use v.Interface() or v.Type() to get a meaningful type name.

The same issue exists at line 181.

-	default:
-		e.err = util.Errorf("invalid type: %T", v)
+	default:
+		e.err = util.Errorf("invalid type: %v", v.Type())

Also applies to line 181:

-	default:
-		d.err = util.Errorf("invalid type: %T", v)
+	default:
+		d.err = util.Errorf("invalid type: %v", v.Type())
vendor/github.com/DeedleFake/p9/proto/proto.go (1)

101-108: Dead code: err check at line 103 is unreachable.

At line 103, if err != nil checks an error that would have caused an early return at line 98. When execution reaches line 102, err is always nil, making lines 103-105 dead code.

 	t := p.TypeFromID(msgType)
 	if t == nil {
-		if err != nil {
-			return nil, NoTag, err
-		}
-
 		return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType)
 	}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 122ea1a and dafbfb7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (48)
  • cmd/crc/cmd/daemon.go (5 hunks)
  • cmd/crc/cmd/start.go (0 hunks)
  • go.mod (2 hunks)
  • packaging/windows/product.wxs.template (2 hunks)
  • pkg/crc/config/settings.go (1 hunks)
  • pkg/crc/constants/constants.go (1 hunks)
  • pkg/crc/machine/driver.go (0 hunks)
  • pkg/crc/machine/driver_darwin.go (0 hunks)
  • pkg/crc/machine/driver_linux.go (0 hunks)
  • pkg/crc/machine/driver_windows.go (0 hunks)
  • pkg/crc/machine/libhvee/driver.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_test.go (1 hunks)
  • pkg/crc/machine/libhvee/driver_windows.go (2 hunks)
  • pkg/crc/machine/start.go (2 hunks)
  • pkg/drivers/libhvee/libhvee_windows.go (0 hunks)
  • pkg/drivers/libhvee/powershell_windows.go (0 hunks)
  • pkg/fileserver/fs9p/server.go (1 hunks)
  • pkg/fileserver/fs9p/server_fallback.go (1 hunks)
  • pkg/fileserver/fs9p/server_windows.go (1 hunks)
  • test/e2e/features/9pfs.feature (1 hunks)
  • test/e2e/testsuite/testsuite.go (3 hunks)
  • vendor/github.com/DeedleFake/p9/LICENSE (1 hunks)
  • vendor/github.com/DeedleFake/p9/README.md (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/addr_unix.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_darwin.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_linux.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_other.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_plan9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/dir_windows.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/doc.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/fs.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/internal/util/util.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/msg.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/p9.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/client.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/encoding.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/proto.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/proto/server.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/remote.go (1 hunks)
  • vendor/github.com/DeedleFake/p9/stat.go (1 hunks)
  • vendor/modules.txt (1 hunks)
💤 Files with no reviewable changes (7)
  • pkg/crc/machine/driver_windows.go
  • pkg/drivers/libhvee/powershell_windows.go
  • cmd/crc/cmd/start.go
  • pkg/drivers/libhvee/libhvee_windows.go
  • pkg/crc/machine/driver_linux.go
  • pkg/crc/machine/driver.go
  • pkg/crc/machine/driver_darwin.go
✅ Files skipped from review due to trivial changes (1)
  • pkg/fileserver/fs9p/server_fallback.go
🚧 Files skipped from review as they are similar to previous changes (21)
  • vendor/github.com/DeedleFake/p9/dir_other.go
  • vendor/github.com/DeedleFake/p9/addr_unix.go
  • test/e2e/features/9pfs.feature
  • pkg/fileserver/fs9p/server_windows.go
  • pkg/crc/machine/libhvee/driver_test.go
  • vendor/github.com/DeedleFake/p9/internal/debug/debug.go
  • vendor/github.com/DeedleFake/p9/addr_other.go
  • vendor/modules.txt
  • vendor/github.com/DeedleFake/p9/proto/server.go
  • vendor/github.com/DeedleFake/p9/encoding.go
  • pkg/crc/config/settings.go
  • vendor/github.com/DeedleFake/p9/proto/client.go
  • vendor/github.com/DeedleFake/p9/dir_linux.go
  • vendor/github.com/DeedleFake/p9/dir_darwin.go
  • vendor/github.com/DeedleFake/p9/client.go
  • pkg/crc/constants/constants.go
  • vendor/github.com/DeedleFake/p9/LICENSE
  • vendor/github.com/DeedleFake/p9/doc.go
  • vendor/github.com/DeedleFake/p9/internal/util/util.go
  • vendor/github.com/DeedleFake/p9/addr.go
  • vendor/github.com/DeedleFake/p9/p9.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.
📚 Learning: 2025-08-06T09:48:10.441Z
Learnt from: redbeam
Repo: crc-org/crc PR: 4866
File: pkg/fileserver/fs9p/shares.go:0-0
Timestamp: 2025-08-06T09:48:10.441Z
Learning: The vsock implementation in pkg/fileserver/fs9p/shares.go was temporarily removed because 9pfs doesn't fully support it yet. It will be added back when 9pfs provides proper vsock support.

Applied to files:

  • go.mod
  • pkg/crc/machine/start.go
  • test/e2e/testsuite/testsuite.go
  • vendor/github.com/DeedleFake/p9/fs.go
  • pkg/fileserver/fs9p/server.go
  • cmd/crc/cmd/daemon.go
  • vendor/github.com/DeedleFake/p9/msg.go
  • vendor/github.com/DeedleFake/p9/README.md
🧬 Code graph analysis (11)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
vendor/github.com/DeedleFake/p9/internal/debug/debug.go (1)
  • Log (11-13)
vendor/github.com/DeedleFake/p9/proto/encoding.go (1)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
pkg/crc/machine/start.go (3)
pkg/os/exec.go (1)
  • RunPrivileged (48-59)
pkg/crc/constants/constants.go (2)
  • Plan9HvsockPort (62-62)
  • VSockGateway (42-42)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
vendor/github.com/DeedleFake/p9/dir_plan9.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/dir.go (1)
  • Dir (16-16)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • QID (42-46)
  • Version (10-10)
vendor/github.com/DeedleFake/p9/dir_windows.go (1)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • DirEntry (255-267)
  • FileMode (23-23)
  • ModeFromOS (43-78)
vendor/github.com/DeedleFake/p9/fs.go (6)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/p9.go (7)
  • QID (42-46)
  • QIDType (49-49)
  • IOHeaderSize (70-70)
  • Version (10-10)
  • QTAuth (58-58)
  • NoFID (18-18)
  • QTDir (54-54)
vendor/github.com/DeedleFake/p9/proto/server.go (2)
  • MessageHandler (135-139)
  • ConnHandler (112-114)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)
  • Log (6-6)
vendor/github.com/DeedleFake/p9/msg.go (2)
  • Tversion (79-82)
  • Tversion (84-84)
vendor/github.com/DeedleFake/p9/encoding.go (1)
  • WriteDir (33-42)
vendor/github.com/DeedleFake/p9/dir.go (3)
vendor/github.com/DeedleFake/p9/stat.go (4)
  • Stat (156-168)
  • DirEntry (255-267)
  • StatChanges (316-318)
  • FileMode (23-23)
vendor/github.com/DeedleFake/p9/fs.go (3)
  • File (100-119)
  • Attachment (44-74)
  • FileSystem (21-34)
vendor/github.com/DeedleFake/p9/p9.go (6)
  • OWRITE (27-27)
  • ORDWR (28-28)
  • OEXEC (29-29)
  • OTRUNC (31-31)
  • OCEXEC (32-32)
  • ORCLOSE (33-33)
vendor/github.com/DeedleFake/p9/remote.go (5)
vendor/github.com/DeedleFake/p9/client.go (1)
  • Client (22-26)
vendor/github.com/DeedleFake/p9/p9.go (4)
  • QID (42-46)
  • QIDType (49-49)
  • Version (10-10)
  • IOHeaderSize (70-70)
vendor/github.com/DeedleFake/p9/msg.go (14)
  • Twalk (133-137)
  • Rwalk (139-141)
  • Topen (143-146)
  • Ropen (148-151)
  • Tcreate (153-158)
  • Rcreate (160-163)
  • Tremove (192-194)
  • Tread (165-169)
  • Rread (171-173)
  • Twrite (175-179)
  • Rwrite (181-183)
  • Tclunk (185-187)
  • Tstat (199-201)
  • Rstat (203-205)
vendor/github.com/DeedleFake/p9/stat.go (3)
  • FileMode (23-23)
  • Stat (156-168)
  • DirEntry (255-267)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • Errorf (44-52)
pkg/crc/machine/libhvee/driver_windows.go (2)
vendor/github.com/crc-org/machine/libmachine/drivers/base.go (1)
  • SharedDir (27-35)
pkg/crc/machine/libhvee/driver.go (1)
  • ConvertToUnixPath (10-25)
cmd/crc/cmd/daemon.go (5)
pkg/crc/config/settings.go (1)
  • EnableSharedDirs (33-33)
pkg/fileserver/fs9p/server_windows.go (1)
  • GetHvsockListener (14-29)
pkg/crc/constants/constants.go (2)
  • Plan9HvsockGUID (61-61)
  • Plan9TcpPort (60-60)
pkg/fileserver/fs9p/server.go (1)
  • New9pServer (34-58)
pkg/crc/logging/logging.go (1)
  • Warnf (100-102)
vendor/github.com/DeedleFake/p9/msg.go (6)
vendor/github.com/DeedleFake/p9/proto/proto.go (2)
  • NewProto (44-60)
  • Proto (38-41)
vendor/github.com/DeedleFake/p9/p9.go (2)
  • Version (10-10)
  • QID (42-46)
vendor/github.com/DeedleFake/p9/proto/client.go (1)
  • P9NoTag (221-223)
vendor/github.com/DeedleFake/p9/stat.go (2)
  • FileMode (23-23)
  • Stat (156-168)
vendor/github.com/DeedleFake/p9/proto/encoding.go (2)
  • Write (25-31)
  • Read (34-38)
vendor/github.com/DeedleFake/p9/internal/util/util.go (1)
  • LimitedReader (13-17)
🪛 markdownlint-cli2 (0.18.1)
vendor/github.com/DeedleFake/p9/README.md

12-12: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


26-26: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: verify-devcontainer
  • GitHub Check: Run OKD bundle with crc (1.24)
  • GitHub Check: build-qe (linux, amd64)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build (macOS-15-intel, 1.24)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: build-qe (linux, arm64)
  • GitHub Check: build (windows-2022, 1.24)
  • GitHub Check: build (macOS-15, 1.24)
  • GitHub Check: build (ubuntu-22.04, 1.24)
  • GitHub Check: build-qe (darwin, arm64)
  • GitHub Check: build (macOS-26, 1.24)
  • GitHub Check: build-qe (darwin, amd64)
  • GitHub Check: build (ubuntu-latest, 1.24)
  • GitHub Check: build-installer (windows-2022, 1.24)
  • GitHub Check: build-qe (windows, amd64)
  • GitHub Check: Konflux kflux-prd-rh02 / crc-binary-on-pull-request
🔇 Additional comments (19)
vendor/github.com/DeedleFake/p9/internal/debug/nodebug.go (1)

1-6: LGTM! Standard conditional compilation pattern.

This vendored file correctly implements a no-op debug stub using Go's build constraint system. The implementation follows best practices: both new and legacy build tag syntax for backward compatibility, matching function signature with the real implementation in debug.go, and appropriate no-op behavior when debugging is disabled.

pkg/crc/machine/libhvee/driver.go (1)

10-25: LGTM! Path conversion logic is sound.

The function correctly handles Windows-style path conversion to Unix format for podman compatibility. The OS-specific branching (filepath.ToSlash for Windows vs strings.ReplaceAll for non-Windows) is intentional and correct—the function may run on non-Windows platforms while still needing to convert Windows-style paths. The drive letter detection safely checks length before indexing and appropriately converts to the /mnt/<drive>/ format.

pkg/crc/machine/libhvee/driver_windows.go (1)

25-28: LGTM! Migration to 9P correctly implemented.

The configuration correctly transitions from SMB/CIFS to 9P:

  • Type changed to "9p" (Line 28)
  • Public ConvertToUnixPath used for target path conversion (Line 26)
  • Username field removed (appropriate for 9P)

The changes align with the PR objective of migrating Windows file sharing from SMB to 9P.

pkg/crc/machine/start.go (2)

245-249: MicroShift guard is appropriate

The guard to skip 9P mounting for MicroShift bundles aligns with the PR objectives, which note that the microshift preset requires the 9pfs client in the bundle and will fail without it.


244-260: mount.Tag is not passed to 9pfs commands; verify if it should be passed as aname

The 9P protocol requires aname to specify the file tree to access when the server offers multiple exported file systems. The code at line 237 logs mount.Tag, and at line 240, mount.Tag is correctly passed to the virtiofs mount command. However, the 9pfs commands at lines 254 and 257 do not include mount.Tag.

Line 254 calls: 9pfs -V -p <port> 2 <mount.Target>
Line 257 calls: 9pfs <VSockGateway> <mount.Target>

Neither passes mount.Tag. The 9pfuse helper accepts -a aname to specify the mount aname. If mount.Tag represents the aname or export identifier on the 9P server, it should be passed to the 9pfs command to identify which export to mount.

go.mod (1)

7-7: Dependencies align with 9P implementation.

The addition of github.com/DeedleFake/p9 and promotion of github.com/linuxkit/virtsock to a direct dependency are appropriate for the 9P over hvsock implementation on Windows.

Also applies to: 31-31

test/e2e/testsuite/testsuite.go (2)

604-616: 9P file sharing test steps properly integrated.

The test step registrations cleanly integrate 9P file sharing verification into the scenario context, using libhvee.ConvertToUnixPath for cross-platform path conversion. The closure pattern for passing mountedHomeDir to step functions is appropriate.


1382-1398: VM helper functions are well-implemented.

The directoryExistInVM, filesystemIsMounted, and listingFilesInDirectoryShouldSucceed functions provide clear error messages and appropriate checks for 9P mount verification.

packaging/windows/product.wxs.template (1)

69-73: 9P hvsock registry entry correctly configured.

The Hvsock9pRegistryEntry component properly registers the 9P hvsock service GUID (00009000-FACB-11E6-BD58-64006A7986D3) matching constants.Plan9HvsockGUID, and is correctly referenced in DefaultFeature. This follows the same pattern as the existing VsockRegistryEntry.

Also applies to: 111-111

pkg/fileserver/fs9p/server.go (2)

61-75: Startup error check may race with server goroutine.

The non-blocking select at lines 68-74 checks for an error immediately after spawning the goroutine, but proto.Serve may not have had a chance to fail yet. This means legitimate startup errors (e.g., bind failures) could be missed, with errors only surfacing later via WaitForError().

If proto.Serve fails quickly (e.g., listener already closed), the caller sees success from Start() but an error later in WaitForError(). This might be acceptable for this use case, but consider documenting this behavior or adding a brief startup delay/handshake if synchronous error detection is important.


31-58: Server constructor with proper validation.

New9pServer correctly validates that the exposed directory is an absolute path, exists, and is a directory. The buffered error channel (size 1) prevents goroutine leaks when no one reads from ErrChan.

cmd/crc/cmd/daemon.go (1)

253-300: 9P server integration is well-structured.

The implementation correctly:

  • Gates on Windows platform and EnableSharedDirs configuration
  • Sets up both hvsock (primary) and TCP (backup) 9P servers
  • Uses proper error handling with immediate return on setup failures
  • Defers Stop() calls for graceful cleanup
  • Spawns goroutines for async error monitoring via WaitForError()

The dual-transport approach (hvsock + TCP fallback) provides good resilience for different VM connectivity scenarios.

vendor/github.com/DeedleFake/p9/README.md (1)

1-51: Vendored README provides context for the p9 library.

This is standard vendored documentation from the upstream github.com/DeedleFake/p9 library. The static analysis warnings about markdown style are expected in third-party vendored content and should not be modified.

vendor/github.com/DeedleFake/p9/dir_windows.go (1)

1-27: Vendored Windows-specific DirEntry conversion.

This is vendored code from the upstream p9 library providing Windows-specific os.FileInfo to DirEntry conversion with graceful fallback when Win32FileAttributeData is unavailable.

vendor/github.com/DeedleFake/p9/dir_plan9.go (1)

1-49: Vendored Plan9-specific directory handling.

This is vendored code from the upstream p9 library providing Plan9-native infoToEntry and GetQID implementations. No modifications should be made to vendored code.

vendor/github.com/DeedleFake/p9/fs.go (1)

169-186: LGTM: Safe string-to-bytes conversion using Go 1.20+ idiom.

The unsafe.Slice(unsafe.StringData(p), len(p)) pattern at line 179 is the correct and safe way to get a byte slice view of a string in Go 1.20+. This avoids the allocation of []byte(p) while being well-defined behavior, unlike the previously flagged *(*[]byte)(unsafe.Pointer(&p)) pattern.

vendor/github.com/DeedleFake/p9/dir.go (2)

239-260: LGTM: Flag mapping logic is straightforward.

The toOSFlags function correctly maps 9P open modes to OS-level flags. The commented-out sections for OEXCL and OAPPEND suggest these may be added later.


146-180: LGTM: ReadOnlyFS wrapper correctly delegates while enforcing read-only semantics.

The ReadOnlyFS wrapper properly blocks write operations (WriteStat, Create, Remove) and restricts Open modes. The passQIDFS helper correctly preserves QIDFS capabilities when wrapping attachments.

vendor/github.com/DeedleFake/p9/msg.go (1)

1-279: Vendored 9P protocol implementation looks correct.

This vendored file implements the 9P2000 protocol message types and registry. The implementation correctly defines all standard message types, includes proper encoding/decoding with size bounds checking for Rstat/Twstat (lines 207-233, 240-276), and follows the 9P specification (including the intentional Terror slot skip on line 20).

Comment thread pkg/crc/machine/start.go
Comment thread pkg/crc/machine/start.go
Comment thread vendor/github.com/DeedleFake/p9/fs.go
Comment thread vendor/github.com/DeedleFake/p9/remote.go
@redbeam

redbeam commented Dec 17, 2025

Copy link
Copy Markdown
Contributor Author

/unhold

@openshift-ci

openshift-ci Bot commented Dec 17, 2025

Copy link
Copy Markdown

@redbeam: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security dafbfb7 link false /test security
ci/prow/integration-crc dafbfb7 link true /test integration-crc
ci/prow/e2e-crc dafbfb7 link true /test e2e-crc

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@anjannath

Copy link
Copy Markdown
Member

/lgtm
/approve

@openshift-ci

openshift-ci Bot commented Dec 17, 2025

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: anjannath

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@anjannath
anjannath merged commit 54c1407 into main Dec 17, 2025
30 of 38 checks passed
@github-project-automation github-project-automation Bot moved this from Ready for review to Done in Project planning: crc Dec 17, 2025
@anjannath
anjannath deleted the remove_smb branch December 17, 2025 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Remove SMB file sharing code completely from Windows

4 participants