blob: f11c2afb2e786dff6d926e54d55583c3756307c3
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Utility routines. |
4 | * |
5 | * Copyright (C) many different people. |
6 | * If you wrote this, please acknowledge your work. |
7 | * |
8 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
9 | */ |
10 | |
11 | #include "libbb.h" |
12 | |
13 | typedef struct ino_dev_hash_bucket_struct { |
14 | ino_t ino; |
15 | dev_t dev; |
16 | /* |
17 | * Above fields can be 64-bit, while pointer may be 32-bit. |
18 | * Putting "next" field here may reduce size of this struct: |
19 | */ |
20 | struct ino_dev_hash_bucket_struct *next; |
21 | /* |
22 | * Reportedly, on cramfs a file and a dir can have same ino. |
23 | * Need to also remember "file/dir" bit: |
24 | */ |
25 | char isdir; /* bool */ |
26 | char name[1]; |
27 | } ino_dev_hashtable_bucket_t; |
28 | |
29 | #define HASH_SIZE 311u /* Should be prime */ |
30 | #define hash_inode(i) ((unsigned)(i) % HASH_SIZE) |
31 | |
32 | /* array of [HASH_SIZE] elements */ |
33 | static ino_dev_hashtable_bucket_t **ino_dev_hashtable; |
34 | |
35 | /* |
36 | * Return name if statbuf->st_ino && statbuf->st_dev are recorded in |
37 | * ino_dev_hashtable, else return NULL |
38 | */ |
39 | char* FAST_FUNC is_in_ino_dev_hashtable(const struct stat *statbuf) |
40 | { |
41 | ino_dev_hashtable_bucket_t *bucket; |
42 | |
43 | if (!ino_dev_hashtable) |
44 | return NULL; |
45 | |
46 | bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; |
47 | while (bucket != NULL) { |
48 | if ((bucket->ino == statbuf->st_ino) |
49 | && (bucket->dev == statbuf->st_dev) |
50 | && (bucket->isdir == !!S_ISDIR(statbuf->st_mode)) |
51 | ) { |
52 | return bucket->name; |
53 | } |
54 | bucket = bucket->next; |
55 | } |
56 | return NULL; |
57 | } |
58 | |
59 | /* Add statbuf to statbuf hash table */ |
60 | void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) |
61 | { |
62 | int i; |
63 | ino_dev_hashtable_bucket_t *bucket; |
64 | |
65 | if (!name) |
66 | name = ""; |
67 | bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name)); |
68 | bucket->ino = statbuf->st_ino; |
69 | bucket->dev = statbuf->st_dev; |
70 | bucket->isdir = !!S_ISDIR(statbuf->st_mode); |
71 | strcpy(bucket->name, name); |
72 | |
73 | if (!ino_dev_hashtable) |
74 | ino_dev_hashtable = xzalloc(HASH_SIZE * sizeof(*ino_dev_hashtable)); |
75 | |
76 | i = hash_inode(statbuf->st_ino); |
77 | bucket->next = ino_dev_hashtable[i]; |
78 | ino_dev_hashtable[i] = bucket; |
79 | } |
80 | |
81 | #if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP |
82 | /* Clear statbuf hash table */ |
83 | void FAST_FUNC reset_ino_dev_hashtable(void) |
84 | { |
85 | int i; |
86 | ino_dev_hashtable_bucket_t *bucket, *next; |
87 | |
88 | if (!ino_dev_hashtable) |
89 | return; |
90 | |
91 | for (i = 0; i < HASH_SIZE; i++) { |
92 | bucket = ino_dev_hashtable[i]; |
93 | |
94 | while (bucket != NULL) { |
95 | next = bucket->next; |
96 | free(bucket); |
97 | bucket = next; |
98 | } |
99 | } |
100 | free(ino_dev_hashtable); |
101 | ino_dev_hashtable = NULL; |
102 | } |
103 | #endif |
104 |