do not edit — generated by btf.
git.druid.rocksindexdruid520qsrc/fstree.c

src/fstree.c


#include "config.h"
 
#ifdef OS_NETBSD_C
#define _NETBSD_SOURCE 1
#endif
#define _POSIX_C_SOURCE 200809L
 
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
 
#include "q.h"
 
/* walk a prefix, recording only WHICH paths exist (a plain presence
 * list) -- the manifest diff only needs presence, so there's no type,
 * mtime, symlink-target, or device bookkeeping. appends into an
 * in-memory snap rather than a stream. */
void
walktree(struct snap* s, const char* base, const char* rel)
{
	DIR* d;
	struct dirent* e;
	char full[MAXPATH];
	char nrel[MAXPATH];
	struct stat st;
 
	if(pathjoin(full, sizeof(full), base, rel) == 0)
	{
		die("path too long");
		return;
	}
	d = opendir(full);
	if(d == NULL)
	{
		return;
	}
	e = readdir(d);
	while(e != NULL)
	{
		if(strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0)
		{
			if(rel[0] != '\0')
			{
				if(pathjoin(nrel, sizeof(nrel), rel, e->d_name) == 0)
				{
					die("path too long");
					return;
				}
			}
			else
			{
				size_t dn = strlen(e->d_name);
 
				if(dn > sizeof(nrel) - 1)
				{
					die("path too long");
					return;
				}
				memcpy(nrel, e->d_name, dn);
				nrel[dn] = '\0';
			}
			if(pathjoin(full, sizeof(full), base, nrel) == 0)
			{
				die("path too long");
				return;
			}
			if(lstat(full, &st) == 0)
			{
				snap_add(s, nrel);
				/* descend only real directories, never symlinks -- lstat
				 * reports the link itself, so S_ISDIR is false for a
				 * symlink-to-directory and the walk can't loop. */
				if(S_ISDIR(st.st_mode))
				{
					walktree(s, base, nrel);
				}
			}
		}
		e = readdir(d);
	}
	closedir(d);
}
 
/* best-effort recursive remove: a leftover file from a too-long path is
 * a small harm next to blocking the whole removal. falls back to unlink
 * when the path isn't a directory. */
void
rmtree(const char* path)
{
	DIR* d;
	struct dirent* e;
	char sub[MAXPATH];
	struct stat st;
 
	d = opendir(path);
	if(d == NULL)
	{
		unlink(path);
		return;
	}
	e = readdir(d);
	while(e != NULL)
	{
		if(strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0
		    && pathjoin(sub, sizeof(sub), path, e->d_name) != 0)
		{
			if(lstat(sub, &st) == 0)
			{
				if(S_ISDIR(st.st_mode))
				{
					rmtree(sub);
				}
				else
				{
					unlink(sub);
				}
			}
		}
		e = readdir(d);
	}
	closedir(d);
	rmdir(path);
}
 
/* mkdir -p, leaf included: creates every component of path (itself a
 * directory, not a file whose ancestors need making). EEXIST is the
 * common case (an ancestor already there); anything else is fatal. */
void
makedirs(const char* path)
{
	char buf[MAXPATH];
	size_t n = strlen(path);
	size_t i;
 
	if(n >= sizeof(buf))
	{
		die("path too long");
		return;
	}
	memcpy(buf, path, n + 1);
	for(i = 1; i < n; i = i + 1)
	{
		if(buf[i] == '/')
		{
			buf[i] = '\0';
			if(mkdir(buf, 0755) != 0 && errno != EEXIST)
			{
				die("failed creating directory");
				return;
			}
			buf[i] = '/';
		}
	}
	if(mkdir(buf, 0755) != 0 && errno != EEXIST)
	{
		die("failed creating directory");
		return;
	}
}
powered by btf.