Make cp and mv optionally preserve hard links.
No binary (build failed)
—
(log yok)
| @@ -59,78 +59,6 @@ static void print_summary(long size, char *filename) | |
| } | |
| } | |
| - | #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]; |
| - | |
| - | /* |
| - | * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in |
| - | * `ino_dev_hashtable', else return 0 |
| - | * |
| - | * If NAME is a non-NULL pointer to a character pointer, and there is |
| - | * a match, then set *NAME to the value of the name slot in that |
| - | * bucket. |
| - | */ |
| - | static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) |
| - | { |
| - | ino_dev_hashtable_bucket_t *bucket; |
| - | |
| - | bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; |
| - | while (bucket != NULL) { |
| - | if ((bucket->ino == statbuf->st_ino) && |
| - | (bucket->dev == statbuf->st_dev)) |
| - | { |
| - | if (name) *name = bucket->name; |
| - | return 1; |
| - | } |
| - | bucket = bucket->next; |
| - | } |
| - | return 0; |
| - | } |
| - | |
| - | /* Add statbuf to statbuf hash table */ |
| - | static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) |
| - | { |
| - | int i; |
| - | size_t s; |
| - | ino_dev_hashtable_bucket_t *bucket; |
| - | |
| - | i = hash_inode(statbuf->st_ino); |
| - | s = name ? strlen(name) : 0; |
| - | bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s); |
| - | bucket->ino = statbuf->st_ino; |
| - | bucket->dev = statbuf->st_dev; |
| - | if (name) |
| - | strcpy(bucket->name, name); |
| - | else |
| - | bucket->name[0] = '\0'; |
| - | bucket->next = ino_dev_hashtable[i]; |
| - | ino_dev_hashtable[i] = bucket; |
| - | } |
| - | |
| - | /* Clear statbuf hash table */ |
| - | static void reset_ino_dev_hashtable(void) |
| - | { |
| - | int i; |
| - | ino_dev_hashtable_bucket_t *bucket; |
| - | |
| - | for (i = 0; i < HASH_SIZE; i++) { |
| - | while (ino_dev_hashtable[i] != NULL) { |
| - | bucket = ino_dev_hashtable[i]->next; |
| - | free(ino_dev_hashtable[i]); |
| - | ino_dev_hashtable[i] = bucket; |
| - | } |
| - | } |
| - | } |
| - | |
| /* tiny recursive du */ | |
| static long du(char *filename) | |
| { | |
| @@ -246,7 +174,7 @@ int du_main(int argc, char **argv) | |
| return status; | |
| } | |
| - | /* $Id: du.c,v 1.51 2001/10/24 04:59:27 andersen Exp $ */ |
| + | /* $Id: du.c,v 1.52 2001/12/17 15:26:25 kraai Exp $ */ |
| /* | |
| Local Variables: | |
| c-file-style: "linux" | |
| @@ -286,4 +286,8 @@ extern const char * const can_not_create_raw_socket; | |
| #define CURRENT_TTY "/dev/tty" | |
| #define CONSOLE_DEV "/dev/console" | |
| + | int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name); |
| + | void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name); |
| + | void reset_ino_dev_hashtable(void); |
| + | |
| #endif /* __LIBCONFIG_H__ */ | |
| @@ -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 | |
| @@ -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) { | |
| @@ -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]; | |
| /* | |
| @@ -0,0 +1,6 @@ | |
| + | # UNSUPPORTED: CONFIG_FEATURE_PRESERVE_HARDLINKS |
| + | touch foo |
| + | ln foo bar |
| + | mkdir baz |
| + | busybox cp -d foo bar baz |
| + | test baz/foo -ef baz/bar |