char e_name[1]; /* Name of the directory */
};
+struct state {
+ struct elt *sp; /* Stack pointer for list */
+ dstr path; /* Current path string */
+};
/*----- Static variables --------------------------------------------------*/
static const struct elt rootnode = { 0, 0, 0 }; /* Root of the list */
-static struct elt *sp; /* Stack pointer for list */
-static dstr d = DSTR_INIT; /* Current path string */
/*----- Main code ---------------------------------------------------------*/
/* --- @pop@ --- *
*
- * Arguments: ---
+ * Arguments: @struct state *state@ = working state
*
* Returns: ---
*
* Use: Removes the top item from the directory stack.
*/
-static void pop(void)
+static void pop(struct state *state)
{
+ struct elt *sp = state->sp, *e;
+
if (sp->e_link) {
- struct elt *e = sp->e_link;
- d.len = sp->e_offset;
- DPUTZ(&d);
- xfree(sp); sp = e;
+ e = sp->e_link;
+ state->path.len = sp->e_offset;
+ DPUTZ(&state->path);
+ xfree(state->sp); state->sp = e;
}
}
/* --- @popall@ --- *
*
- * Arguments: ---
+ * Arguments: @struct state *state@ = working state
*
* Returns: ---
*
* Use: Removes all the items from the directory stack.
*/
-static void popall(void)
- { while (sp->e_link) pop(); }
+static void popall(struct state *state)
+ { while (state->sp->e_link) pop(state); }
/* --- @push@ --- *
*
- * Arguments: @struct elt *e@ = pointer to directory element
+ * Arguments: @struct state *state@ = working state
+ * @struct elt *e@ = pointer to directory element
*
* Returns: ---
*
* Use: Pushes a new subdirectory onto the stack.
*/
-static void push(struct elt *e)
+static void push(struct state *state, struct elt *e)
{
- e->e_link = sp;
- e->e_offset = d.len;
- DPUTC(&d, '/');
- DPUTS(&d, e->e_name);
- sp = e;
+ e->e_link = state->sp;
+ e->e_offset = state->path.len;
+ DPUTC(&state->path, '/');
+ DPUTS(&state->path, e->e_name);
+ state->sp = e;
}
/* --- @report@ --- *
{
char cwd[PATH_MAX];
struct elt *e, *ee;
+ struct state state;
struct stat st;
unsigned bad = 0;
dstr buf = DSTR_INIT;
int i;
- /* --- Initialize stack pointer and path string --- */
+ /* --- Initialize the state --- */
- sp = (/*unconst*/ struct elt *)&rootnode;
- dstr_destroy(&d);
+ state.sp = (/*unconst*/ struct elt *)&rootnode;
+ dstr_create(&state.path);
/* --- Try to find the current directory --- */
/* --- Backtrack on `..' elements --- */
else if (strcmp(ee->e_name, "..") == 0) {
- pop();
+ pop(&state);
xfree(ee);
ee = e;
continue;
/* --- Everything else gets pushed on the end --- */
- push(ee);
+ push(&state, ee);
ee = e;
/* --- Find out what sort of a thing this is --- */
- if (lstat(d.buf, &st)) {
- report(cp, CP_ERROR, 0, d.buf, "can't stat: %e");
+ if (lstat(state.path.buf, &st)) {
+ report(cp, CP_ERROR, 0, state.path.buf, "can't stat: %e");
bad |= CP_ERROR;
break;
}
dstr_reset(&buf);
dstr_ensure(&buf, st.st_size + 1);
- if ((i = readlink(d.buf, buf.buf, buf.sz)) < 0) {
- report(cp, CP_ERROR, 0, d.buf, "can't readlink: %e");
+ if ((i = readlink(state.path.buf, buf.buf, buf.sz)) < 0) {
+ report(cp, CP_ERROR, 0, state.path.buf, "can't readlink: %e");
bad |= CP_ERROR;
break;
}
buf.buf[i] = 0;
- report(cp, CP_SYMLINK, 2, d.buf, "symlink -> `%s'", buf.buf);
+ report(cp, CP_SYMLINK, 2, state.path.buf, "symlink -> `%s'", buf.buf);
/* --- Handle sticky parents --- *
*
*/
if ((cp->cp_what & CP_WROTHUSR) &&
- (sp->e_link->e_flags & EF_STICKY) &&
+ (state.sp->e_link->e_flags & EF_STICKY) &&
st.st_uid != cp->cp_uid && st.st_uid != 0) {
bad |= CP_WROTHUSR;
- report(cp, CP_WROTHUSR, 1, d.buf,
+ report(cp, CP_WROTHUSR, 1, state.path.buf,
"symlink modifiable by user %u", st.st_uid);
}
/* --- Sort out what to do from here --- */
if (buf.buf[0] == '/')
- popall();
+ popall(&state);
else
- pop();
+ pop(&state);
ee = splitpath(buf.buf, ee);
continue;
}
/* --- Run the sanity check on this path element --- */
- bad |= sanity(d.buf, &st, cp, ee ? 0 : SF_LAST);
+ bad |= sanity(state.path.buf, &st, cp, ee ? 0 : SF_LAST);
if (S_ISDIR(st.st_mode)) {
if (st.st_mode & S_ISVTX)
- sp->e_flags |= EF_STICKY;
- report(cp, CP_REPORT, 4, d.buf, "directory");
+ state.sp->e_flags |= EF_STICKY;
+ report(cp, CP_REPORT, 4, state.path.buf, "directory");
continue;
}
}
}
- popall();
+ popall(&state);
+ dstr_destroy(&state.path);
dstr_destroy(&buf);
return (bad);
}