#include "GbMakePath.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>


int makePath(const char *path, int mode) {
	//first check if the path already exist
	struct stat st;
	if(stat(path,&st)==0) {
		if(S_ISDIR(st.st_mode))
			return 0; //excellent
		else {
			errno = ENOTDIR;
			return -1;
		}
	}
	
	//loop over the components in the path, creating them if necessary
	const char *path_end = path+strlen(path);
	for(const char *component_start = path; component_start<path_end; ) {
		const char *component_end = strchr(component_start+1,'/');
		if(!component_end) {
			component_end = component_start;
			while(*component_end)
				component_end++;
		}
		char buf[1024];
		memcpy(buf, path, (size_t)(component_end-path));
		buf[component_end-path] = '\0';
		if(stat(buf,&st)==0) {
			if(!S_ISDIR(st.st_mode)) {
				errno = ENOTDIR;
				return -1;
			}
		} else {
			int rc = mkdir(buf, mode);
			if(rc!=0)
				return -1;
		}
		
		component_start = component_end;
		if(*component_start=='/')
			component_start++;
	}

	return 0;	
}


#ifdef UNITTEST
#include <assert.h>

int main(void) {
	rmdir("/tmp/GbMakePath/dir1/dir2");
	rmdir("/tmp/GbMakePath/dir1");
	rmdir("/tmp/GbMakePath");

	assert(makePath("/tmp/GbMakePath/dir1/dir2",0777)==0);
	assert(access("/tmp/GbMakePath/dir1/dir2",X_OK)==0);
	rmdir("/tmp/GbMakePath/dir1/dir2");
	rmdir("/tmp/GbMakePath/dir1");
	rmdir("/tmp/GbMakePath");

	assert(makePath("/tmp/GbMakePath//dir1//dir2",0777)==0);
	assert(access("/tmp/GbMakePath/dir1/dir2",X_OK)==0);
	rmdir("/tmp/GbMakePath/dir1/dir2");
	rmdir("/tmp/GbMakePath/dir1");
	rmdir("/tmp/GbMakePath");

	assert(makePath("/tmp/GbMakePath/dir1/dir2",0777)==0);
	assert(makePath("/tmp/GbMakePath/dir1/dir2",0777)==0);
	assert(makePath("/tmp/GbMakePath/dir1",0777)==0);

	assert(makePath("/proc/foobooblarg",0777)!=0);

	return 0;
}
#endif