#include <Python.h>
#include <ftw.h>

/* Global variable; it's ok cause usage of it will only be done with the
 * global interpreter lock held.
 */
static PyObject* callback = NULL;

static int
each_item(const char* filename, const struct stat* stat, int flags)
{
	PyObject* callback_return = \
		PyObject_CallFunction(callback, "ss#i",
							  filename,
							  (const char*)stat, sizeof(struct stat),
							  flags);
	if (callback_return == NULL)
		return 1;
	Py_DECREF(callback_return);
	return 0;
}

static PyObject*
really_call_ftw(PyObject* self, PyObject* args)
{
	const char* dirname = NULL;

	/* We want PyArg_ParseTuple just to extract the first argument directly
	 * as a C string- no more PyString_AsString() necessary.
	 *
	 * We can't effectively check whether the callback is a valid callable,
	 * so we'll just take anything and fail later if it's not.
	 */
	if (PyArg_ParseTuple(args, "sO", &dirname, &callback) == 0)
		return NULL;

	int retval = ftw(dirname, each_item, OPEN_MAX);
	if (retval > 0)
	{
		/* callback raised an error */
		return NULL;
	}
	else if (retval < 0)
	{
		/* ftw had an error */
		PyErr_SetFromErrno(PyExc_OSError);
		return NULL;
	}

	Py_RETURN_NONE;
}

static PyMethodDef FtwMethods[] = {
	{"ftw", really_call_ftw, METH_VARARGS, "Traverse a directory structure."},
	{NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initftw7()
{
	Py_InitModule("ftw7", FtwMethods);
}
