summaryrefslogtreecommitdiffhomepage
path: root/libbb
diff options
context:
space:
mode:
authorMatt Kraai <kraai@debian.org>2001-12-17 15:26:36 +0000
committerMatt Kraai <kraai@debian.org>2001-12-17 15:26:36 +0000
commitace02dc9cd3ca0c95db5b5ebe87b9d6cd6ca1733 (patch)
tree1dec04901febc0fd63ac5b92bc2cca4333689477 /libbb
parent46ea0e4696456061ad7ce799658f737c24f781a6 (diff)
Make cp and mv optionally preserve hard links.
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Makefile2
-rw-r--r--libbb/copy_file.c24
-rw-r--r--libbb/inode_hash.c7
3 files changed, 31 insertions, 2 deletions
diff --git a/libbb/Makefile b/libbb/Makefile
index ef8fef4b7..879be2452 100644
--- a/libbb/Makefile
+++ b/libbb/Makefile
@@ -45,7 +45,7 @@ obj-y += ask_confirmation.o chomp.o concat_path_file.o copy_file.o \
xgetcwd.o xreadlink.o xregcomp.o interface.o remove_file.o last_char_is.o \
copyfd.o vherror_msg.o herror_msg.o herror_msg_and_die.o xgethostbyname.o \
dirname.o make_directory.o create_icmp_socket.o u_signal_names.o arith.o \
- simplify_path.o inet_common.o $(LIBBB_MOBJS) $(LIBBB_AROBJS)
+ simplify_path.o inet_common.o inode_hash.o $(LIBBB_MOBJS) $(LIBBB_AROBJS)
# Hand off to toplevel Rules.mak
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 29778f2a4..ea05c9b8e 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -30,7 +30,7 @@
#include <stdlib.h>
#include <string.h>
-#include "libbb.h"
+#include "busybox.h"
int copy_file(const char *source, const char *dest, int flags)
{
@@ -131,6 +131,19 @@ int copy_file(const char *source, const char *dest, int flags)
}
} else if (S_ISREG(source_stat.st_mode)) {
FILE *sfp, *dfp=NULL;
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+ char *link_name;
+
+ if (!(flags & FILEUTILS_DEREFERENCE) &&
+ is_in_ino_dev_hashtable(&source_stat, &link_name)) {
+ if (link(link_name, dest) < 0) {
+ perror_msg("unable to link `%s'", dest);
+ return -1;
+ }
+
+ return 0;
+ }
+#endif
if ((sfp = fopen(source, "r")) == NULL) {
perror_msg("unable to open `%s'", source);
@@ -212,12 +225,21 @@ int copy_file(const char *source, const char *dest, int flags)
if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
perror_msg("unable to preserve ownership of `%s'", dest);
#endif
+
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+ add_to_ino_dev_hashtable(&source_stat, dest);
+#endif
+
return 0;
} else {
error_msg("internal error: unrecognized file type");
return -1;
}
+#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
+ add_to_ino_dev_hashtable(&source_stat, dest);
+#endif
+
end:
if (flags & FILEUTILS_PRESERVE_STATUS) {
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index 52c54cdc1..36484e6ae 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -29,6 +29,13 @@
#define HASH_SIZE 311 /* Should be prime */
#define hash_inode(i) ((i) % HASH_SIZE)
+typedef struct ino_dev_hash_bucket_struct {
+ struct ino_dev_hash_bucket_struct *next;
+ ino_t ino;
+ dev_t dev;
+ char name[1];
+} ino_dev_hashtable_bucket_t;
+
static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
/*