diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2015-01-03 20:47:47 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-01-03 20:47:47 +0100 |
commit | 134c53098bdcbf7a0c34b60b97c46280d86eb48f (patch) | |
tree | 7c149d5eeb92085183e928908d8a648142fc4bb1 /libpwdgrp | |
parent | 20c0a16334e96493077eaaad6f4c5690af0aa6e8 (diff) | |
download | busybox-w32-134c53098bdcbf7a0c34b60b97c46280d86eb48f.tar.gz busybox-w32-134c53098bdcbf7a0c34b60b97c46280d86eb48f.tar.bz2 busybox-w32-134c53098bdcbf7a0c34b60b97c46280d86eb48f.zip |
libpwdgrp: store getXXnam result in a single malloc block
This saves a bit of memory but more importantly, allows to create
xmalloc_getpwnam() API where result can be deleted simply using free().
function old new delta
getXXnam 134 173 +39
parse_common 188 212 +24
convert_to_struct 277 290 +13
get_S 90 88 -2
tokenize 129 126 -3
bb_internal_getpwent_r 175 172 -3
getXXnam_r 208 198 -10
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/4 up/down: 76/-18) Total: 58 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libpwdgrp')
-rw-r--r-- | libpwdgrp/pwd_grp.c | 58 |
1 files changed, 32 insertions, 26 deletions
diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c index 1b2418a8d..4b61b61d2 100644 --- a/libpwdgrp/pwd_grp.c +++ b/libpwdgrp/pwd_grp.c | |||
@@ -34,24 +34,21 @@ | |||
34 | 34 | ||
35 | struct const_passdb { | 35 | struct const_passdb { |
36 | const char *filename; | 36 | const char *filename; |
37 | const char def[9]; | 37 | const char def[7 + 2*ENABLE_USE_BB_SHADOW]; |
38 | const uint8_t off[9]; | 38 | const uint8_t off[7 + 2*ENABLE_USE_BB_SHADOW]; |
39 | uint8_t numfields; | 39 | uint8_t numfields; |
40 | uint8_t size_of; | ||
40 | }; | 41 | }; |
41 | struct passdb { | 42 | struct passdb { |
42 | const char *filename; | 43 | const char *filename; |
43 | const char def[9]; | 44 | const char def[7 + 2*ENABLE_USE_BB_SHADOW]; |
44 | const uint8_t off[9]; | 45 | const uint8_t off[7 + 2*ENABLE_USE_BB_SHADOW]; |
45 | uint8_t numfields; | 46 | uint8_t numfields; |
47 | uint8_t size_of; | ||
46 | FILE *fp; | 48 | FILE *fp; |
47 | char *malloced; | 49 | char *malloced; |
48 | char struct_result[ | ||
49 | /* Should be max(sizeof passwd,group,spwd), but this will do: */ | ||
50 | IF_NOT_USE_BB_SHADOW(sizeof(struct passwd)) | ||
51 | IF_USE_BB_SHADOW(sizeof(struct spwd)) | ||
52 | ]; | ||
53 | }; | 50 | }; |
54 | /* Note: for shadow db, def[9] will not contain terminating NUL, | 51 | /* Note: for shadow db, def[] will not contain terminating NUL, |
55 | * but convert_to_struct() logic detects def[] end by "less than SP?", | 52 | * but convert_to_struct() logic detects def[] end by "less than SP?", |
56 | * not by "is it NUL?" condition; and off[0] happens to be zero | 53 | * not by "is it NUL?" condition; and off[0] happens to be zero |
57 | * for every db anyway, so there _is_ in fact a terminating NUL there. | 54 | * for every db anyway, so there _is_ in fact a terminating NUL there. |
@@ -76,7 +73,7 @@ static const struct const_passdb const_pw_db = { | |||
76 | offsetof(struct passwd, pw_dir), /* 5 S */ | 73 | offsetof(struct passwd, pw_dir), /* 5 S */ |
77 | offsetof(struct passwd, pw_shell) /* 6 S */ | 74 | offsetof(struct passwd, pw_shell) /* 6 S */ |
78 | }, | 75 | }, |
79 | sizeof(PW_DEF)-1 | 76 | sizeof(PW_DEF)-1, sizeof(struct passwd) |
80 | }; | 77 | }; |
81 | static const struct const_passdb const_gr_db = { | 78 | static const struct const_passdb const_gr_db = { |
82 | _PATH_GROUP, GR_DEF, | 79 | _PATH_GROUP, GR_DEF, |
@@ -86,7 +83,7 @@ static const struct const_passdb const_gr_db = { | |||
86 | offsetof(struct group, gr_gid), /* 2 I */ | 83 | offsetof(struct group, gr_gid), /* 2 I */ |
87 | offsetof(struct group, gr_mem) /* 3 m (char **) */ | 84 | offsetof(struct group, gr_mem) /* 3 m (char **) */ |
88 | }, | 85 | }, |
89 | sizeof(GR_DEF)-1 | 86 | sizeof(GR_DEF)-1, sizeof(struct group) |
90 | }; | 87 | }; |
91 | #if ENABLE_USE_BB_SHADOW | 88 | #if ENABLE_USE_BB_SHADOW |
92 | static const struct const_passdb const_sp_db = { | 89 | static const struct const_passdb const_sp_db = { |
@@ -102,19 +99,20 @@ static const struct const_passdb const_sp_db = { | |||
102 | offsetof(struct spwd, sp_expire), /* 7 l */ | 99 | offsetof(struct spwd, sp_expire), /* 7 l */ |
103 | offsetof(struct spwd, sp_flag) /* 8 r Reserved */ | 100 | offsetof(struct spwd, sp_flag) /* 8 r Reserved */ |
104 | }, | 101 | }, |
105 | sizeof(SP_DEF)-1 | 102 | sizeof(SP_DEF)-1, sizeof(struct spwd) |
106 | }; | 103 | }; |
107 | #endif | 104 | #endif |
108 | 105 | ||
109 | /* We avoid having big global data. */ | 106 | /* We avoid having big global data. */ |
110 | struct statics { | 107 | struct statics { |
111 | /* It's ok to use same buffer (db[0].struct_result) for getpwuid and getpwnam. | 108 | /* It's ok to use same buffer (db[0].malloced) for getpwuid and getpwnam. |
112 | * Manpage says: | 109 | * Manpage says: |
113 | * "The return value may point to a static area, and may be overwritten | 110 | * "The return value may point to a static area, and may be overwritten |
114 | * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." | 111 | * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." |
115 | */ | 112 | */ |
116 | struct passdb db[2 + ENABLE_USE_BB_SHADOW]; | 113 | struct passdb db[2 + ENABLE_USE_BB_SHADOW]; |
117 | char *tokenize_end; | 114 | char *tokenize_end; |
115 | unsigned string_size; | ||
118 | }; | 116 | }; |
119 | 117 | ||
120 | static struct statics *ptr_to_statics; | 118 | static struct statics *ptr_to_statics; |
@@ -205,21 +203,21 @@ static char *parse_common(FILE *fp, const char *filename, | |||
205 | bb_error_msg("bad record at %s:%u", filename, count); | 203 | bb_error_msg("bad record at %s:%u", filename, count); |
206 | goto free_and_next; | 204 | goto free_and_next; |
207 | } | 205 | } |
206 | S.string_size = S.tokenize_end - buf; | ||
208 | 207 | ||
209 | /* Ugly hack: group db requires aqdditional buffer space | 208 | /* Ugly hack: group db requires additional buffer space |
210 | * for members[] array. If there is only one group, we need space | 209 | * for members[] array. If there is only one group, we need space |
211 | * for 3 pointers: alignment padding, group name, NULL. | 210 | * for 3 pointers: alignment padding, group name, NULL. |
212 | * +1 for every additional group. | 211 | * +1 for every additional group. |
213 | */ | 212 | */ |
214 | if (n_fields == sizeof(GR_DEF)-1) { /* if we read group file */ | 213 | if (n_fields == sizeof(GR_DEF)-1) { /* if we read group file */ |
215 | int resize = 3; | 214 | int cnt = 3; |
216 | char *p = buf; | 215 | char *p = buf; |
217 | while (*p) | 216 | while (*p) |
218 | if (*p++ == ',') | 217 | if (*p++ == ',') |
219 | resize++; | 218 | cnt++; |
220 | resize *= sizeof(char**); | 219 | S.string_size += cnt * sizeof(char*); |
221 | resize += S.tokenize_end - buf; | 220 | buf = xrealloc(buf, S.string_size); |
222 | buf = xrealloc(buf, resize); | ||
223 | } | 221 | } |
224 | 222 | ||
225 | if (!key) { | 223 | if (!key) { |
@@ -258,8 +256,8 @@ static void *convert_to_struct(struct passdb *db, | |||
258 | const char *def = db->def; | 256 | const char *def = db->def; |
259 | const uint8_t *off = db->off; | 257 | const uint8_t *off = db->off; |
260 | 258 | ||
261 | /* TODO? for consistency, zero out all fields */ | 259 | /* For consistency, zero out all fields */ |
262 | /* memset(result, 0, size_of_result);*/ | 260 | memset(result, 0, db->size_of); |
263 | 261 | ||
264 | for (;;) { | 262 | for (;;) { |
265 | void *member = (char*)result + (*off++); | 263 | void *member = (char*)result + (*off++); |
@@ -305,7 +303,7 @@ static void *convert_to_struct(struct passdb *db, | |||
305 | /* def "r" does nothing */ | 303 | /* def "r" does nothing */ |
306 | 304 | ||
307 | def++; | 305 | def++; |
308 | if ((unsigned char)*def < (unsigned char)' ') | 306 | if ((unsigned char)*def <= (unsigned char)' ') |
309 | break; | 307 | break; |
310 | buffer += strlen(buffer) + 1; | 308 | buffer += strlen(buffer) + 1; |
311 | } | 309 | } |
@@ -328,7 +326,9 @@ static int FAST_FUNC getXXnam_r(const char *name, uintptr_t db_and_field_pos, | |||
328 | db = &S.db[db_and_field_pos >> 2]; | 326 | db = &S.db[db_and_field_pos >> 2]; |
329 | 327 | ||
330 | *(void**)result = NULL; | 328 | *(void**)result = NULL; |
331 | buf = parse_file(db->filename, db->numfields, name, db_and_field_pos & 3); | 329 | buf = parse_file(db->filename, db->numfields, name, 0 /*db_and_field_pos & 3*/); |
330 | /* "db_and_field_pos & 3" is commented out since so far we don't implement | ||
331 | * getXXXid_r() functions which would use that to pass 2 here */ | ||
332 | if (buf) { | 332 | if (buf) { |
333 | size_t size = S.tokenize_end - buf; | 333 | size_t size = S.tokenize_end - buf; |
334 | if (size > buflen) { | 334 | if (size > buflen) { |
@@ -433,8 +433,14 @@ static void* FAST_FUNC getXXnam(const char *name, unsigned db_and_field_pos) | |||
433 | buf = parse_common(db->fp, db->filename, db->numfields, name, db_and_field_pos & 3); | 433 | buf = parse_common(db->fp, db->filename, db->numfields, name, db_and_field_pos & 3); |
434 | if (buf) { | 434 | if (buf) { |
435 | free(db->malloced); | 435 | free(db->malloced); |
436 | db->malloced = buf; | 436 | /* We enlarge buf and move string data up, freeing space |
437 | result = convert_to_struct(db, buf, db->struct_result); | 437 | * for struct passwd/group/spwd at the beginning. This way, |
438 | * entire result of getXXnam is in a single malloced block. | ||
439 | * This enables easy creation of xmalloc_getpwnam() API. | ||
440 | */ | ||
441 | db->malloced = buf = xrealloc(buf, db->size_of + S.string_size); | ||
442 | memmove(buf + db->size_of, buf, S.string_size); | ||
443 | result = convert_to_struct(db, buf + db->size_of, buf); | ||
438 | } | 444 | } |
439 | return result; | 445 | return result; |
440 | } | 446 | } |