Skip to content

extract_item: do not delete an existing directory if possible#7866

Closed
intelfx wants to merge 1 commit intoborgbackup:masterfrom
intelfx:work/btrfs
Closed

extract_item: do not delete an existing directory if possible#7866
intelfx wants to merge 1 commit intoborgbackup:masterfrom
intelfx:work/btrfs

Conversation

@intelfx
Copy link
Contributor

@intelfx intelfx commented Oct 10, 2023

A pre-existing directory might be a Btrfs subvolume that was created by the user ahead of time when restoring several nested subvolumes from a single archive.


I'm also interested in this feature being backported to Borg 1.2. I have a patch that applies on top of 1.2-maint.

See: #4233

A pre-existing directory might be a Btrfs subvolume that was created by
the user ahead of time when restoring several nested subvolumes from a
single archive.
@codecov-commenter
Copy link

codecov-commenter commented Oct 10, 2023

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.65%. Comparing base (9108039) to head (aee25c3).
⚠️ Report is 1374 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7866      +/-   ##
==========================================
- Coverage   83.67%   83.65%   -0.02%     
==========================================
  Files          66       66              
  Lines       11853    11854       +1     
  Branches     2149     2150       +1     
==========================================
- Hits         9918     9917       -1     
- Misses       1361     1362       +1     
- Partials      574      575       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment on lines +866 to +867
elif not stat.S_ISDIR(item.mode):
os.rmdir(path)
Copy link
Member

@ThomasWaldmann ThomasWaldmann Oct 10, 2023

Choose a reason for hiding this comment

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

It's rather unclear still whether the resulting directory after extraction will be correct (== as in the archive) in all cases:

  • simple attrs
  • xattrs
  • acls
  • (bsd/fs)flags

The existing directory could have some metadata set already, but the resulting directory must be exactly what we have in the archived item, not a mix up of fs item and archived item.

Copy link
Member

Choose a reason for hiding this comment

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

The code that makes sure about this could be also useful later if we implement extracting into a non-empty directory (for more than the simplest cases, like the already implemented "continue an extraction").

Copy link
Member

Choose a reason for hiding this comment

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

hmm, thinking about it...

we currently more or less require extracting into an empty dir (exception: that "continue extraction" feature). we could also require that if there is any pre-existing directory inside the extraction directory, it must not have any special attrs set.

if not stat.S_ISDIR(st.st_mode):
os.unlink(path)
# only remove a directory if it is conflicting
# preserve existing directories because they might be subvolumes
Copy link
Member

Choose a reason for hiding this comment

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

is subvolumes a feature implemented by other fs than btrfs?

if not, maybe we better call it "btrfs subvolumes" here, so it is more clear.

@ThomasWaldmann
Copy link
Member

A small test with an existing fs dir and then extracting "over" that would be good.

@ThomasWaldmann
Copy link
Member

@intelfx can you add tests?

ThomasWaldmann added a commit to ThomasWaldmann/borg that referenced this pull request Feb 8, 2026
…up#4233

A pre-existing directory might be a btrfs subvolume that was created by
the user ahead of time when restoring several nested subvolumes from a
single archive.

If the archive item to be extracted is a directory and there is already
a directory at the destination path, do not remove (and recreate) it,
but just use it.

That way, btrfs subvolumes (which look like directories) are not deleted.

Fix originally contributed by @intelfx in borgbackup#7866, but needed more work,
so I thought more about the implications and added a test.

Note:

In the past, we first removed (empty) directories, then created a fresh
one, then called restore_attrs for that. That produced correct metadata,
but only for the case of an EMPTY exisiting directory. If the existing
directory was not empty, the simply os.rmdir we tried did not work
anyway and did not remove the existing directory.

Usually we extract to an empty base directory, thus encountering this
edge case is mostly limited to continuing a previous extraction.
In that case, calling restore_attrs again on a directory that already has
existing attrs should be harmless, because they are identical.
@ThomasWaldmann
Copy link
Member

superceded by #9288.

ThomasWaldmann added a commit to ThomasWaldmann/borg that referenced this pull request Feb 8, 2026
…up#4233

A pre-existing directory might be a btrfs subvolume that was created by
the user ahead of time when restoring several nested subvolumes from a
single archive.

If the archive item to be extracted is a directory and there is already
a directory at the destination path, do not remove (and recreate) it,
but just use it.

That way, btrfs subvolumes (which look like directories) are not deleted.

Fix originally contributed by @intelfx in borgbackup#7866, but needed more work,
so I thought more about the implications and added a test.

Note:

In the past, we first removed (empty) directories, then created a fresh
one, then called restore_attrs for that. That produced correct metadata,
but only for the case of an EMPTY exisiting directory. If the existing
directory was not empty, the simply os.rmdir we tried did not work
anyway and did not remove the existing directory.

Usually we extract to an empty base directory, thus encountering this
edge case is mostly limited to continuing a previous extraction.
In that case, calling restore_attrs again on a directory that already has
existing attrs should be harmless, because they are identical.
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.

3 participants