summaryrefslogtreecommitdiff
path: root/src/remove.c
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2008-09-24 10:27:35 +0200
committerJim Meyering <meyering@redhat.com>2008-09-27 00:10:08 +0200
commita5111af33ea6a5d27c3f7ab67afdb2a5884c38b6 (patch)
tree1d24b81a2662dd08404c3776d570215516c7518c /src/remove.c
parent1e3ebd660add628cfc135825dc801026a0cba80d (diff)
downloadcoreutils-a5111af33ea6a5d27c3f7ab67afdb2a5884c38b6.tar.xz
remove.c: don't use xmalloc; don't let obstack call exit on failure
(obstack_chunk_alloc, obstack_chunk_free): Don't define. (top_dir): Param is no longer "const". Use malloc, not xmalloc, and call longjmp upon failed malloc. (obstack_init_minimal): New function. (ds_init): Don't use xmalloc. Instead, use caller-supplied buffer. Use obstack_specify_allocation_with_arg, not obstack_init, so that we control what happens upon allocation failure. Arrange for ds_free not to free uninitialized if/when any obstack_specify_allocation_with_arg allocation fails. (ds_free): Don't free DS, now that it's no longer malloc'd. (rm): Allocate DS on the stack. Arrange to handle ds_init allocation failure. step1
Diffstat (limited to 'src/remove.c')
-rw-r--r--src/remove.c58
1 files changed, 42 insertions, 16 deletions
diff --git a/src/remove.c b/src/remove.c
index 7c63dfe80..8143f5015 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -45,9 +45,6 @@
#define dir_name rm_dir_name
#define dir_len rm_dir_len
-#define obstack_chunk_alloc malloc
-#define obstack_chunk_free free
-
/* This is the maximum number of consecutive readdir/unlink calls that
can be made (with no intervening rewinddir or closedir/opendir) before
triggering a bug that makes readdir return NULL even though some
@@ -245,13 +242,15 @@ push_dir (Dirstack_state *ds, const char *dir_name)
/* Return the entry name of the directory on the top of the stack
in malloc'd storage. */
static inline char *
-top_dir (Dirstack_state const *ds)
+top_dir (Dirstack_state *ds)
{
size_t n_lengths = obstack_object_size (&ds->len_stack) / sizeof (size_t);
size_t *length = obstack_base (&ds->len_stack);
size_t top_len = length[n_lengths - 1];
char const *p = obstack_next_free (&ds->dir_stack) - top_len;
- char *q = xmalloc (top_len);
+ char *q = malloc (top_len);
+ if (q == NULL)
+ longjmp (ds->current_arg_jumpbuf, 1);
memcpy (q, p, top_len - 1);
q[top_len - 1] = 0;
return q;
@@ -440,14 +439,32 @@ AD_stack_clear (Dirstack_state *ds)
}
}
-static Dirstack_state *
-ds_init (void)
+/* Initialize obstack O just enough so that it may be freed
+ with obstack_free. */
+static void
+obstack_init_minimal (struct obstack *o)
+{
+ o->chunk = NULL;
+}
+
+static void
+ds_init (Dirstack_state *ds)
{
- Dirstack_state *ds = xmalloc (sizeof *ds);
- obstack_init (&ds->dir_stack);
- obstack_init (&ds->len_stack);
- obstack_init (&ds->Active_dir);
- return ds;
+ unsigned int i;
+ struct obstack *o[3];
+ o[0] = &ds->dir_stack;
+ o[1] = &ds->len_stack;
+ o[2] = &ds->Active_dir;
+
+ /* Ensure each of these is NULL, in case init/allocation
+ fails and we end up calling ds_free on all three while only
+ one or two has been initialized. */
+ for (i = 0; i < 3; i++)
+ obstack_init_minimal (o[i]);
+
+ for (i = 0; i < 3; i++)
+ obstack_specify_allocation_with_arg
+ (o[i], 0, 0, rm_malloc, rm_free, &ds->current_arg_jumpbuf);
}
static void
@@ -466,7 +483,6 @@ ds_free (Dirstack_state *ds)
obstack_free (&ds->dir_stack, NULL);
obstack_free (&ds->len_stack, NULL);
obstack_free (&ds->Active_dir, NULL);
- free (ds);
}
/* Pop the active directory (AD) stack and prepare to move `up' one level,
@@ -1594,10 +1610,19 @@ extern enum RM_status
rm (size_t n_files, char const *const *file, struct rm_options const *x)
{
enum RM_status status = RM_OK;
- Dirstack_state *ds = ds_init ();
+ Dirstack_state ds;
int cwd_errno = 0;
size_t i;
+ /* Arrange for obstack allocation failure to longjmp. */
+ if (setjmp (ds.current_arg_jumpbuf))
+ {
+ status = RM_ERROR;
+ goto cleanup;
+ }
+
+ ds_init (&ds);
+
for (i = 0; i < n_files; i++)
{
if (cwd_errno && IS_RELATIVE_FILE_NAME (file[i]))
@@ -1607,7 +1632,7 @@ rm (size_t n_files, char const *const *file, struct rm_options const *x)
}
else
{
- enum RM_status s = rm_1 (ds, file[i], x, &cwd_errno);
+ enum RM_status s = rm_1 (&ds, file[i], x, &cwd_errno);
assert (VALID_STATUS (s));
UPDATE_STATUS (status, s);
}
@@ -1620,7 +1645,8 @@ rm (size_t n_files, char const *const *file, struct rm_options const *x)
status = RM_ERROR;
}
- ds_free (ds);
+ cleanup:;
+ ds_free (&ds);
return status;
}