Skip to content

Commit

Permalink
Feature: pasting hardlinked trees
Browse files Browse the repository at this point in the history
This feature is useful when there is a need to create a directory tree,
which is similar to an existing one while keeping all the files in this
new tree hardlinked to those existing ones. Such functionality might be
useful when rearranging a huge directory tree (or a set of directory
trees) into some new layout.

This operation is done synchronously (i.e. it doesn't use CommandLoader
to put the ongoing operation into the task queue).

Target end of the operation is handled the following way:

1. If target directory with the same name exists - it gets used.

2. If target folder does not exist - it is created with the same mode
   bits as corresponding source one.

3. If target file with the same name exists and is a hardlink of the
   source file already - it is getting left as it is. If it's not a
   hardlink of the source file - a new hardlink is created in a form of
   <original>_, <original>_1, ..., etc.

4. If target file does not exist - a hardlink is created.
  • Loading branch information
ototo authored and hut committed Feb 14, 2012
1 parent 824104a commit ec18cfa
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
26 changes: 24 additions & 2 deletions ranger/core/actions.py
Expand Up @@ -19,8 +19,8 @@
import shutil
import string
import tempfile
from os.path import join, isdir, realpath
from os import link, symlink, getcwd
from os.path import join, isdir, realpath, exists
from os import link, symlink, getcwd, listdir, stat
from inspect import cleandoc

import ranger
Expand Down Expand Up @@ -1003,6 +1003,28 @@ def paste_hardlink(self):
except Exception as x:
self.notify(x)

def paste_hardlinked_subtree(self):
for f in self.env.copy:
try:
target_path = join(getcwd(), f.basename)
self._recurse_hardlinked_tree(f.path, target_path)
except Exception as x:
self.notify(x)

def _recurse_hardlinked_tree(self, source_path, target_path):
if isdir(source_path):
if not exists(target_path):
os.mkdir(target_path, stat(source_path).st_mode)
for item in listdir(source_path):
self._recurse_hardlinked_tree(
join(source_path, item),
join(target_path, item))
else:
if not exists(target_path) \
or stat(source_path).st_ino != stat(target_path).st_ino:
link(source_path,
next_available_filename(target_path))

def paste(self, overwrite=False):
"""Paste the selected items into the current directory"""
copied_files = tuple(self.env.copy)
Expand Down
1 change: 1 addition & 0 deletions ranger/defaults/rc.conf
Expand Up @@ -147,6 +147,7 @@ map po paste overwrite=True
map pl paste_symlink relative=False
map pL paste_symlink relative=True
map phl paste_hardlink
map pht paste_hardlinked_subtree

map dd cut
map ud uncut
Expand Down

0 comments on commit ec18cfa

Please sign in to comment.