diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/copy_file.c | 23 | ||||
-rw-r--r-- | libbb/inode_hash.c | 63 |
2 files changed, 44 insertions, 42 deletions
diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 07564afd0..636fbdc1d 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c | |||
@@ -172,22 +172,21 @@ int copy_file(const char *source, const char *dest, int flags) | |||
172 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS) { | 172 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS) { |
173 | char *link_name; | 173 | char *link_name; |
174 | 174 | ||
175 | if (!FLAGS_DEREF | 175 | if (!FLAGS_DEREF) { |
176 | && is_in_ino_dev_hashtable(&source_stat, &link_name) | 176 | link_name = is_in_ino_dev_hashtable(&source_stat); |
177 | ) { | 177 | if (link_name) { |
178 | if (link(link_name, dest) < 0) { | ||
179 | ovr = retry_overwrite(dest, flags); | ||
180 | if (ovr <= 0) | ||
181 | return ovr; | ||
182 | if (link(link_name, dest) < 0) { | 178 | if (link(link_name, dest) < 0) { |
183 | bb_perror_msg("cannot create link '%s'", dest); | 179 | ovr = retry_overwrite(dest, flags); |
184 | return -1; | 180 | if (ovr <= 0) |
181 | return ovr; | ||
182 | if (link(link_name, dest) < 0) { | ||
183 | bb_perror_msg("cannot create link '%s'", dest); | ||
184 | return -1; | ||
185 | } | ||
185 | } | 186 | } |
187 | return 0; | ||
186 | } | 188 | } |
187 | return 0; | ||
188 | } | 189 | } |
189 | // TODO: probably is_in_.. and add_to_... | ||
190 | // can be combined: find_or_add_... | ||
191 | add_to_ino_dev_hashtable(&source_stat, dest); | 190 | add_to_ino_dev_hashtable(&source_stat, dest); |
192 | } | 191 | } |
193 | 192 | ||
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c index 2ac1623f4..55a7564ce 100644 --- a/libbb/inode_hash.c +++ b/libbb/inode_hash.c | |||
@@ -13,41 +13,40 @@ | |||
13 | #include <string.h> | 13 | #include <string.h> |
14 | #include "libbb.h" | 14 | #include "libbb.h" |
15 | 15 | ||
16 | #define HASH_SIZE 311 /* Should be prime */ | ||
17 | #define hash_inode(i) ((i) % HASH_SIZE) | ||
18 | |||
19 | typedef struct ino_dev_hash_bucket_struct { | 16 | typedef struct ino_dev_hash_bucket_struct { |
20 | struct ino_dev_hash_bucket_struct *next; | 17 | struct ino_dev_hash_bucket_struct *next; |
21 | ino_t ino; | 18 | ino_t ino; |
22 | dev_t dev; | 19 | dev_t dev; |
23 | char name[1]; | 20 | char name[1]; |
24 | } ino_dev_hashtable_bucket_t; | 21 | } ino_dev_hashtable_bucket_t; |
25 | 22 | ||
26 | static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE]; | 23 | #define HASH_SIZE 311 /* Should be prime */ |
24 | #define hash_inode(i) ((i) % HASH_SIZE) | ||
25 | |||
26 | /* array of [HASH_SIZE] elements */ | ||
27 | static ino_dev_hashtable_bucket_t **ino_dev_hashtable; | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in | 30 | * Return name if statbuf->st_ino && statbuf->st_dev are recorded in |
30 | * `ino_dev_hashtable', else return 0 | 31 | * ino_dev_hashtable, else return NULL |
31 | * | ||
32 | * If NAME is a non-NULL pointer to a character pointer, and there is | ||
33 | * a match, then set *NAME to the value of the name slot in that | ||
34 | * bucket. | ||
35 | */ | 32 | */ |
36 | int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) | 33 | char *is_in_ino_dev_hashtable(const struct stat *statbuf) |
37 | { | 34 | { |
38 | ino_dev_hashtable_bucket_t *bucket; | 35 | ino_dev_hashtable_bucket_t *bucket; |
39 | 36 | ||
37 | if (!ino_dev_hashtable) | ||
38 | return NULL; | ||
39 | |||
40 | bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; | 40 | bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; |
41 | while (bucket != NULL) { | 41 | while (bucket != NULL) { |
42 | if ((bucket->ino == statbuf->st_ino) && | 42 | if ((bucket->ino == statbuf->st_ino) |
43 | (bucket->dev == statbuf->st_dev)) | 43 | && (bucket->dev == statbuf->st_dev) |
44 | { | 44 | ) { |
45 | if (name) *name = bucket->name; | 45 | return bucket->name; |
46 | return 1; | 46 | } |
47 | } | 47 | bucket = bucket->next; |
48 | bucket = bucket->next; | ||
49 | } | 48 | } |
50 | return 0; | 49 | return NULL; |
51 | } | 50 | } |
52 | 51 | ||
53 | /* Add statbuf to statbuf hash table */ | 52 | /* Add statbuf to statbuf hash table */ |
@@ -58,19 +57,21 @@ void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) | |||
58 | ino_dev_hashtable_bucket_t *bucket; | 57 | ino_dev_hashtable_bucket_t *bucket; |
59 | 58 | ||
60 | i = hash_inode(statbuf->st_ino); | 59 | i = hash_inode(statbuf->st_ino); |
61 | s = name ? strlen(name) : 0; | 60 | if (!name) |
62 | bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s); | 61 | name = ""; |
62 | bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name)); | ||
63 | bucket->ino = statbuf->st_ino; | 63 | bucket->ino = statbuf->st_ino; |
64 | bucket->dev = statbuf->st_dev; | 64 | bucket->dev = statbuf->st_dev; |
65 | if (name) | 65 | strcpy(bucket->name, name); |
66 | strcpy(bucket->name, name); | 66 | |
67 | else | 67 | if (!ino_dev_hashtable) |
68 | bucket->name[0] = '\0'; | 68 | ino_dev_hashtable = xzalloc(HASH_SIZE * sizeof(*ino_dev_hashtable)); |
69 | |||
69 | bucket->next = ino_dev_hashtable[i]; | 70 | bucket->next = ino_dev_hashtable[i]; |
70 | ino_dev_hashtable[i] = bucket; | 71 | ino_dev_hashtable[i] = bucket; |
71 | } | 72 | } |
72 | 73 | ||
73 | #ifdef CONFIG_FEATURE_CLEAN_UP | 74 | #if ENABLE_FEATURE_CLEAN_UP |
74 | /* Clear statbuf hash table */ | 75 | /* Clear statbuf hash table */ |
75 | void reset_ino_dev_hashtable(void) | 76 | void reset_ino_dev_hashtable(void) |
76 | { | 77 | { |
@@ -84,5 +85,7 @@ void reset_ino_dev_hashtable(void) | |||
84 | ino_dev_hashtable[i] = bucket; | 85 | ino_dev_hashtable[i] = bucket; |
85 | } | 86 | } |
86 | } | 87 | } |
88 | free(ino_dev_hashtable); | ||
89 | ino_dev_hashtable = NULL; | ||
87 | } | 90 | } |
88 | #endif | 91 | #endif |