Skip to content

fix: Directories created via panel are owned by root:root#183

Open
QuintenQVD0 wants to merge 2 commits into
pelican-dev:mainfrom
QuintenQVD0:dir-root
Open

fix: Directories created via panel are owned by root:root#183
QuintenQVD0 wants to merge 2 commits into
pelican-dev:mainfrom
QuintenQVD0:dir-root

Conversation

@QuintenQVD0

@QuintenQVD0 QuintenQVD0 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Changes:

see : pterodactyl/wings#328

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability of directory creation operations with enhanced tracking of newly created directories.
    • Ensured proper ownership assignment for all directories created during filesystem operations.
    • Enhanced handling of directory entries during archive extraction to prevent permission issues.
  • Tests

    • Expanded test coverage for directory creation scenarios, including edge cases with existing paths.

@QuintenQVD0 QuintenQVD0 requested a review from a team as a code owner June 15, 2026 11:48
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

MkdirAll is changed across the ufs layer to return ([]string, error) where the slice contains newly created directory paths ordered shallowest to deepest. A new internal mkdirAll helper on server/filesystem.Filesystem wraps this call and chowns each returned path, then replaces direct unixFS.MkdirAll calls in Write, CreateDirectory, and extractStream.

Changes

MkdirAll chown integration

Layer / File(s) Summary
mkdirAll contract and recursive implementation
internal/ufs/filesystem.go, internal/ufs/mkdir_unix.go, internal/ufs/fs_unix.go
Filesystem interface MkdirAll signature updated to ([]string, error). The recursive mkdirAll helper tracks and propagates a created []string slice through fast-path and slow-path returns, appending each newly created path on success. UnixFS.MkdirAll updated to match.
Existing call sites and tests
internal/ufs/fs_unix.go, internal/ufs/fs_unix_test.go
Rename and TouchPath discard the returned slice with _, err :=. TestUnixFS_MkdirAll is expanded into three subtests covering full creation, partial creation, and idempotent no-op scenarios, each with os.Lstat sanity checks.
Server filesystem chown wrapper and consumers
server/filesystem/filesystem.go, server/filesystem/compress.go
New internal Filesystem.mkdirAll calls unixFS.MkdirAll, then chowns every directory in the returned slice via chownFile. Write calls it to pre-create and chown parent directories. CreateDirectory routes through it. extractStream now creates archive directory entries explicitly instead of skipping them.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • pelican-dev/wings#174: Both PRs address ownership of newly created directories — that PR chowns directories in the router handler, while this PR introduces chowning directly in the mkdirAll helper based on the newly returned created-paths list.

Suggested reviewers

  • parkervcp

Poem

🐇 Hop hop, I dig my burrow anew,
Each tunnel I carve, I remember it too!
The shallow ones first, then deeper we go,
And chown every chamber before I say "whoa."
No orphan directory left in the cold —
This rabbit's bookkeeping is sharp as gold! 🏠

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'fix: Directories created via panel are owned by root:root' directly and clearly describes the main issue being addressed in the changeset - ensuring directories created via the panel have proper ownership instead of being owned by root:root.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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: 1

Caution

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

⚠️ Outside diff range comments (1)
server/filesystem/filesystem.go (1)

120-123: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Route the remaining parent-creating server paths through the chowning helper.

Writefile still lets unixFS.Touch create missing parents, and Rename delegates to unixFS.Rename, whose UFS implementation creates missing destination parents with MkdirAll. Both paths bypass Filesystem.mkdirAll, so nested paths created through these APIs can still leave directories owned by the Wings/root process user. Preserve Rename’s existing validation/no-op behavior, but make the server layer chown any missing parents before or after the UFS rename path.

Also applies to: 207-209

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/filesystem/filesystem.go` around lines 120 - 123, The Writefile
function (around line 120-123) and the Rename function (around line 207-209)
both create missing parent directories but bypass the Filesystem.mkdirAll
chowning helper, leaving directories owned by the root/Wings process user. For
Writefile, remove the parent-directory creation from unixFS.Touch by using a
flag that prevents auto-creation, then ensure missing parents are created
through Filesystem.mkdirAll before calling Touch. For Rename, preserve the
existing validation and no-op behavior, but add a server-layer chowning step
that calls Filesystem.mkdirAll on any missing destination parents before or
after delegating to unixFS.Rename. This ensures all parent directories created
through these APIs are properly chowned to the intended user.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/filesystem/filesystem.go`:
- Around line 229-232: The MkdirAll function returns a partial list of created
directories when an error occurs, but the current code returns immediately on
error before chowning those partially created paths. To fix this, capture the
created directories list from the unixFS.MkdirAll call, and ensure all
directories in that created list are chowned before returning any error. This
way, even if MkdirAll fails partway through, the directories it did create will
have the correct ownership, preventing ownership-related failures on retries.

---

Outside diff comments:
In `@server/filesystem/filesystem.go`:
- Around line 120-123: The Writefile function (around line 120-123) and the
Rename function (around line 207-209) both create missing parent directories but
bypass the Filesystem.mkdirAll chowning helper, leaving directories owned by the
root/Wings process user. For Writefile, remove the parent-directory creation
from unixFS.Touch by using a flag that prevents auto-creation, then ensure
missing parents are created through Filesystem.mkdirAll before calling Touch.
For Rename, preserve the existing validation and no-op behavior, but add a
server-layer chowning step that calls Filesystem.mkdirAll on any missing
destination parents before or after delegating to unixFS.Rename. This ensures
all parent directories created through these APIs are properly chowned to the
intended user.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e426b59b-9437-482f-9060-01414450a0da

📥 Commits

Reviewing files that changed from the base of the PR and between a0306eb and 1c7fbdd.

📒 Files selected for processing (6)
  • internal/ufs/filesystem.go
  • internal/ufs/fs_unix.go
  • internal/ufs/fs_unix_test.go
  • internal/ufs/mkdir_unix.go
  • server/filesystem/compress.go
  • server/filesystem/filesystem.go
📜 Review details
⏰ 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). (5)
  • GitHub Check: Analyze (go)
  • GitHub Check: Build and Test (ubuntu-22.04, 1.25.7, linux, arm64)
  • GitHub Check: Build and Test (ubuntu-22.04, 1.26.0, linux, arm64)
  • GitHub Check: Build and Test (ubuntu-22.04, 1.26.0, linux, amd64)
  • GitHub Check: Build and Test (ubuntu-22.04, 1.25.7, linux, amd64)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-02T13:53:08.995Z
Learnt from: parkervcp
Repo: pelican-dev/wings PR: 171
File: server/power.go:190-203
Timestamp: 2026-03-02T13:53:08.995Z
Learning: In the server package, when quotas are enabled via config.Get().System.Quotas.Enabled, the disk space check using used >= s.DiskSpace() does not require a special guard for unlimited-disk scenarios (DiskSpace() <= 0). The filesystem handles such cases, so the existing check is sufficient. Apply this pattern to similar quota-related disk checks in the server package and ensure tests/docs reflect that unlimited-disk behavior is governed by the filesystem, not by an extra guard in code.

Applied to files:

  • server/filesystem/filesystem.go
  • server/filesystem/compress.go
🔇 Additional comments (6)
internal/ufs/filesystem.go (1)

76-84: LGTM!

internal/ufs/mkdir_unix.go (1)

13-18: LGTM!

Also applies to: 27-33, 47-67

internal/ufs/fs_unix.go (1)

209-222: LGTM!

Also applies to: 474-475, 626-627

internal/ufs/fs_unix_test.go (1)

167-168: LGTM!

Also applies to: 177-178, 327-378

server/filesystem/filesystem.go (1)

163-168: LGTM!

Also applies to: 203-204

server/filesystem/compress.go (1)

372-384: LGTM!

Comment on lines +229 to +232
created, err := fs.unixFS.MkdirAll(p, mode)
if err != nil {
return err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Chown partially created directories before returning MkdirAll errors.

UnixFS.MkdirAll returns the partial created list when a later mkdir fails, but this wrapper returns on err before chowning those paths. A failed or raced nested create can therefore leave newly created parents owned by the process user, making retries hit the same ownership problem.

Proposed fix
 func (fs *Filesystem) mkdirAll(p string, mode ufs.FileMode) error {
-	created, err := fs.unixFS.MkdirAll(p, mode)
-	if err != nil {
-		return err
-	}
+	created, mkdirErr := fs.unixFS.MkdirAll(p, mode)
 	for _, dir := range created {
 		if err := fs.chownFile(dir); err != nil {
+			if mkdirErr != nil {
+				return fmt.Errorf("error creating directories: %w; additionally failed to chown %q: %v", mkdirErr, dir, err)
+			}
 			return err
 		}
 	}
-	return nil
+	return mkdirErr
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
created, err := fs.unixFS.MkdirAll(p, mode)
if err != nil {
return err
}
func (fs *Filesystem) mkdirAll(p string, mode ufs.FileMode) error {
created, mkdirErr := fs.unixFS.MkdirAll(p, mode)
for _, dir := range created {
if err := fs.chownFile(dir); err != nil {
if mkdirErr != nil {
return fmt.Errorf("error creating directories: %w; additionally failed to chown %q: %v", mkdirErr, dir, err)
}
return err
}
}
return mkdirErr
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/filesystem/filesystem.go` around lines 229 - 232, The MkdirAll
function returns a partial list of created directories when an error occurs, but
the current code returns immediately on error before chowning those partially
created paths. To fix this, capture the created directories list from the
unixFS.MkdirAll call, and ensure all directories in that created list are
chowned before returning any error. This way, even if MkdirAll fails partway
through, the directories it did create will have the correct ownership,
preventing ownership-related failures on retries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant