stop using big static buffer for inode hash
No binary (build failed)
—
(log yok)
| @@ -229,6 +229,7 @@ extern void trim(char *s); | |
| extern char *skip_whitespace(const char *); | |
| extern char *skip_non_whitespace(const char *); | |
| + | //TODO: supply a pointer to char[11] buffer (avoid statics)? |
| extern const char *bb_mode_string(mode_t mode); | |
| extern int is_directory(const char *name, int followLinks, struct stat *statBuf); | |
| extern int remove_file(const char *path, int flags); | |
| @@ -556,9 +557,11 @@ extern int del_loop(const char *device); | |
| extern int set_loop(char **device, const char *file, unsigned long long offset); | |
| + | //TODO: provide pointer to buf (avoid statics)? |
| const char *make_human_readable_str(unsigned long long size, | |
| unsigned long block_size, unsigned long display_unit); | |
| + | //TODO: pass buf pointer or return allocated buf (avoid statics)? |
| char *bb_askpass(int timeout, const char * prompt); | |
| int bb_ask_confirmation(void); | |
| int klogctl(int type, char * b, int len); | |
| @@ -624,7 +627,7 @@ extern void vfork_daemon_rexec(int nochdir, int noclose, | |
| #endif | |
| extern int get_terminal_width_height(const int fd, int *width, int *height); | |
| - | int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name); |
| + | char *is_in_ino_dev_hashtable(const struct stat *statbuf); |
| void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name); | |
| void reset_ino_dev_hashtable(void); | |
| #ifdef __GLIBC__ | |
| @@ -172,22 +172,21 @@ int copy_file(const char *source, const char *dest, int flags) | |
| if (ENABLE_FEATURE_PRESERVE_HARDLINKS) { | |
| char *link_name; | |
| - | if (!FLAGS_DEREF |
| - | && is_in_ino_dev_hashtable(&source_stat, &link_name) |
| - | ) { |
| - | if (link(link_name, dest) < 0) { |
| - | ovr = retry_overwrite(dest, flags); |
| - | if (ovr <= 0) |
| - | return ovr; |
| + | if (!FLAGS_DEREF) { |
| + | link_name = is_in_ino_dev_hashtable(&source_stat); |
| + | if (link_name) { |
| if (link(link_name, dest) < 0) { | |
| - | bb_perror_msg("cannot create link '%s'", dest); |
| - | return -1; |
| + | ovr = retry_overwrite(dest, flags); |
| + | if (ovr <= 0) |
| + | return ovr; |
| + | if (link(link_name, dest) < 0) { |
| + | bb_perror_msg("cannot create link '%s'", dest); |
| + | return -1; |
| + | } |
| } | |
| + | return 0; |
| } | |
| - | return 0; |
| } | |
| - | // TODO: probably is_in_.. and add_to_... |
| - | // can be combined: find_or_add_... |
| add_to_ino_dev_hashtable(&source_stat, dest); | |
| } | |
| @@ -13,41 +13,40 @@ | |
| #include <string.h> | |
| #include "libbb.h" | |
| - | #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]; |
| + | 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]; |
| + | #define HASH_SIZE 311 /* Should be prime */ |
| + | #define hash_inode(i) ((i) % HASH_SIZE) |
| + | |
| + | /* array of [HASH_SIZE] elements */ |
| + | static ino_dev_hashtable_bucket_t **ino_dev_hashtable; |
| /* | |
| - | * 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. |
| + | * Return name if statbuf->st_ino && statbuf->st_dev are recorded in |
| + | * ino_dev_hashtable, else return NULL |
| */ | |
| - | int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) |
| + | char *is_in_ino_dev_hashtable(const struct stat *statbuf) |
| { | |
| ino_dev_hashtable_bucket_t *bucket; | |
| + | if (!ino_dev_hashtable) |
| + | return NULL; |
| + | |
| 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; |
| + | if ((bucket->ino == statbuf->st_ino) |
| + | && (bucket->dev == statbuf->st_dev) |
| + | ) { |
| + | return bucket->name; |
| + | } |
| + | bucket = bucket->next; |
| } | |
| - | return 0; |
| + | return NULL; |
| } | |
| /* Add statbuf to statbuf hash table */ | |
| @@ -58,19 +57,21 @@ void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) | |
| 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); |
| + | if (!name) |
| + | name = ""; |
| + | bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name)); |
| bucket->ino = statbuf->st_ino; | |
| bucket->dev = statbuf->st_dev; | |
| - | if (name) |
| - | strcpy(bucket->name, name); |
| - | else |
| - | bucket->name[0] = '\0'; |
| + | strcpy(bucket->name, name); |
| + | |
| + | if (!ino_dev_hashtable) |
| + | ino_dev_hashtable = xzalloc(HASH_SIZE * sizeof(*ino_dev_hashtable)); |
| + | |
| bucket->next = ino_dev_hashtable[i]; | |
| ino_dev_hashtable[i] = bucket; | |
| } | |
| - | #ifdef CONFIG_FEATURE_CLEAN_UP |
| + | #if ENABLE_FEATURE_CLEAN_UP |
| /* Clear statbuf hash table */ | |
| void reset_ino_dev_hashtable(void) | |
| { | |
| @@ -84,5 +85,7 @@ void reset_ino_dev_hashtable(void) | |
| ino_dev_hashtable[i] = bucket; | |
| } | |
| } | |
| + | free(ino_dev_hashtable); |
| + | ino_dev_hashtable = NULL; |
| } | |
| #endif | |