diff options
author | Nathan Scott <nathans@sgi.com> | 2002-02-25 22:26:13 +0000 |
---|---|---|
committer | Nathan Scott <nathans@sgi.com> | 2002-02-25 22:26:13 +0000 |
commit | cb47a0b5bfc507698c67c8474610f451b0a54e3b (patch) | |
tree | 0db70dbd2c003390a11b05eb36776f63cf0b6e3e /getfattr/getfattr.c | |
parent | c82edc1013cf28a096cb8f5ba21c28d3e9312227 (diff) | |
download | attr-cb47a0b5bfc507698c67c8474610f451b0a54e3b.tar.gz |
Merge of xfs-cmds-2.4.18:slinx:111335a by nathans.
Vastly reduce the amount of memory allocations we do by using a high-water
mark allocator. Fixes a bunch of memory leaks in the process.
Diffstat (limited to 'getfattr/getfattr.c')
-rw-r--r-- | getfattr/getfattr.c | 83 |
1 files changed, 48 insertions, 35 deletions
diff --git a/getfattr/getfattr.c b/getfattr/getfattr.c index bd642cf..2f08392 100644 --- a/getfattr/getfattr.c +++ b/getfattr/getfattr.c @@ -181,6 +181,28 @@ int do_listxattr(const char *path, char *list, size_t size) return listxattr(path, list, size); } +int high_water_alloc(void **buf, int *bufsize, int newsize) +{ + /* + * Goal here is to avoid unnecessary memory allocations by + * using static buffers which only grow when necessary. + * Size is increased in fixed size chunks (CHUNK_SIZE). + */ +#define CHUNK_SIZE 256 + if (bufsize < newsize) { + newsize = (newsize + CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); + *buf = realloc(newsize); + if (!*buf) { + perror(progname); + had_errors++; + *bufsize = 0; + return 1; + } + *bufsize = newsize; + } + return 0; +} + int pstrcmp(const char **a, const char **b) { return strcmp(*a, *b); @@ -188,30 +210,27 @@ int pstrcmp(const char **a, const char **b) int do_get_all(const char *path, struct stat *stat, void *dummy) { - /* nathans TODO - use a high-water-mark allocation here! */ + static char *list; + static ssize_t bufsize; + static char **names; + static int ncount; + char *v; - char *list; /* ie. make list & lbufsize "static" & realloc */ - int n = 0, count = 0; - ssize_t listsize, lbufsize; - const char **names = NULL; + ssize_t listsize; + int n, count = 0; - lbufsize = do_listxattr(path, NULL, 0); - if (lbufsize < 0) { + listsize = do_listxattr(path, NULL, 0); + if (listsize < 0) { if (errno != ENOATTR && errno != ENOTSUP) { perror(path); had_errors++; return 1; } - } else { - /* nathans TODO - use a high-water-mark allocation here! */ - list = malloc(++lbufsize); - if (!list) { - perror(progname); - had_errors++; + } else if (listsize > 0) { + if (high_water_alloc(&list, &bufsize, listsize)) return 1; - } - memset(list, 0, lbufsize); - listsize = do_listxattr(path, list, lbufsize - 1); + + listsize = do_listxattr(path, list, bufsize); if (listsize < 0) { perror(path); had_errors++; @@ -222,12 +241,10 @@ int do_get_all(const char *path, struct stat *stat, void *dummy) if (regexec(&re, v, (size_t) 0, NULL, 0) == 0) count++; if (count) { - names = (const char **)malloc(count * sizeof(char *)); - if (!names) { - perror(progname); - had_errors++; + n = count * sizeof(char *); + if (high_water_alloc(&names, &ncount, n)) return 1; - } + n = 0; for (v = list; v - list <= listsize; v += strlen(v)+1) if (regexec(&re, v, (size_t) 0, NULL, 0) == 0) names[n++] = v; @@ -258,9 +275,10 @@ int do_get_one(const char *path, struct stat *stat, void *name) int get_one(const char *path, const char *name) { - char *value = NULL; - size_t size = 0; - int error; + static char *value; + static size_t vsize; + + int error, lsize = 0; if (opt_dump || opt_value_only) { error = do_getxattr(path, name, NULL, 0); @@ -276,18 +294,13 @@ syscall_failed: fprintf(stderr, "%s: %s: %s\n", path, name, strerr); return 1; } - /* nathans TODO - high-water-mark allocate here too? */ - size = error; - value = (char *)malloc(size+1); - if (!value) { - perror(progname); + if (high_water_alloc(&value, &vsize, error + 1)) return 1; - } - error = do_getxattr(path, name, value, size); + error = do_getxattr(path, name, value, vsize); if (error < 0) goto syscall_failed; - value[size] = '\0'; - size = error; + lsize = error; + value[lsize] = '\0'; } if (opt_strip_leading_slash) { @@ -313,8 +326,8 @@ syscall_failed: } if (opt_value_only) puts(value); - else if (size) { - const char *e = encode(value, &size); + else if (lsize) { + const char *e = encode(value, &lsize); if (e) printf("%s=%s\n", name, e); |