1#include "removefile.h"
2#include "removefile_priv.h"
3
4#include <TargetConditionals.h>
5
6removefile_state_t
7removefile_state_alloc() {
8	removefile_state_t state = (removefile_state_t)calloc(1, sizeof(struct _removefile_state));
9	if (state != NULL)
10		state->urand_file = -1;
11	return state;
12}
13
14int
15removefile_state_free(removefile_state_t state) {
16	if (state != NULL) {
17		if (state->urand_file != -1) {
18			close(state->urand_file);
19			state->urand_file = -1;
20		}
21		if (state->buffer != NULL) {
22			free(state->buffer);
23			state->buffer = NULL;
24		}
25		free(state);
26	}
27	return 0;
28}
29
30int
31removefile_state_get(removefile_state_t state, uint32_t key, void* dst) {
32	switch(key) {
33		case REMOVEFILE_STATE_CONFIRM_CALLBACK:
34			*(removefile_callback_t*)dst = state->confirm_callback;
35			break;
36		case REMOVEFILE_STATE_CONFIRM_CONTEXT:
37			*(void**)dst = state->confirm_context;
38			break;
39		case REMOVEFILE_STATE_ERROR_CALLBACK:
40			*(removefile_callback_t*)dst = state->error_callback;
41			break;
42		case REMOVEFILE_STATE_ERROR_CONTEXT:
43			*(void**)dst = state->error_context;
44			break;
45		case REMOVEFILE_STATE_ERRNO:
46			*(int*)dst = state->error_num;
47			break;
48		case REMOVEFILE_STATE_STATUS_CALLBACK:
49			*(removefile_callback_t*)dst = state->status_callback;
50			break;
51		case REMOVEFILE_STATE_STATUS_CONTEXT:
52			*(void**)dst = state->status_context;
53			break;
54		default:
55			errno = EINVAL;
56			return -1;
57	}
58	return 0;
59}
60
61int
62removefile_state_set(removefile_state_t state, uint32_t key, const void* value) {
63	switch(key) {
64		case REMOVEFILE_STATE_CONFIRM_CALLBACK:
65			state->confirm_callback = value;
66			break;
67		case REMOVEFILE_STATE_CONFIRM_CONTEXT:
68			state->confirm_context = (void *) value;
69			break;
70		case REMOVEFILE_STATE_ERROR_CALLBACK:
71			state->error_callback = value;
72			break;
73		case REMOVEFILE_STATE_ERROR_CONTEXT:
74			state->error_context = (void *) value;
75			break;
76		case REMOVEFILE_STATE_ERRNO:
77			state->error_num = *(int*)value;
78			break;
79		case REMOVEFILE_STATE_STATUS_CALLBACK:
80			state->status_callback = value;
81			break;
82		case REMOVEFILE_STATE_STATUS_CONTEXT:
83			state->status_context = (void *) value;
84			break;
85		default:
86			errno = EINVAL;
87			return -1;
88   }
89   return 0;
90}
91
92int
93removefile(const char* path, removefile_state_t state_param, removefile_flags_t flags) {
94	int res = 0;
95	char* paths[] = { NULL, NULL };
96	removefile_state_t state = state_param;
97
98	// allocate the state if it was not passed in
99	if (state_param == NULL) {
100		state = removefile_state_alloc();
101		if (state == NULL) {
102			errno = ENOMEM;
103			return -1;
104		}
105	}
106	state->cancelled = 0;
107	state->unlink_flags = flags;
108
109	if (flags & (REMOVEFILE_SECURE_7_PASS | REMOVEFILE_SECURE_35_PASS | REMOVEFILE_SECURE_1_PASS | REMOVEFILE_SECURE_3_PASS)) {
110		__removefile_init_random(getpid(), state);
111	}
112
113	paths[0] = strdup(path);
114	if (paths[0]) {
115		res = __removefile_tree_walker(paths, state);
116		free(paths[0]);
117	} else {
118		errno = ENOMEM;
119		res = -1;
120	}
121
122	// deallocate if allocated locally
123	if (state_param == NULL) {
124		removefile_state_free(state);
125	}
126
127	return res;
128}
129
130int
131removefile_cancel(removefile_state_t state) {
132	if (state == NULL) {
133		errno = EINVAL;
134		return -1;
135	} else {
136		state->cancelled = 1;
137		return 0;
138	}
139}
140