Skip to content

Instantly share code, notes, and snippets.

@ghostmansd
Created February 19, 2015 18:30
Show Gist options
  • Save ghostmansd/a0b6402fa22475b45243 to your computer and use it in GitHub Desktop.
Save ghostmansd/a0b6402fa22475b45243 to your computer and use it in GitHub Desktop.
dirpath(3) and fdirpath(3)
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
size_t fdirpath(int fd, char *buffer, size_t size)
{
int mfd = -1;
pid_t pid = 0;
int status = 0;
size_t msize = 0;
char *mdata = NULL;
char mpath[] = "/tmp/dirpath/XXXXXX";
int const mflags = MAP_SHARED;
int const mprot = (PROT_READ | PROT_WRITE);
size_t *total = NULL;
if ((fd == -1)
|| ((buffer == NULL) && (size != 0))
|| ((buffer != NULL) && (size == 0))) {
errno = EINVAL;
return (size_t)-1;
}
pthread_mutex_lock(&mutex);
if (mkdir("/tmp/dirpath", 0755) == -1) {
if (errno != EEXIST) {
return (size_t)-1;
}
}
if ((mfd = mkstemp(mpath)) == -1) {
return (size_t)-1;
}
pthread_mutex_unlock(&mutex);
msize += sizeof(size_t);
msize += size;
if (ftruncate(mfd, (off_t)msize)) {
status = errno;
close(mfd);
unlink(mpath);
errno = status;
return (size_t)-1;
}
if ((mdata = mmap(NULL, msize, mprot, mflags, mfd, 0)) == MAP_FAILED) {
status = errno;
close(mfd);
unlink(mpath);
errno = status;
return (size_t)-1;
}
total = (size_t*)mdata;
mdata += sizeof(size_t);
if (buffer != NULL) {
memcpy(mdata, buffer, size);
}
mdata -= sizeof(size_t);
if ((pid = fork()) == 0) {
size_t len = 64;
char *path = NULL;
void *temp = NULL;
if (fchdir(fd) == -1) {
exit(errno);
}
total = (size_t*)mdata;
while (temp == NULL) {
temp = path;
path = realloc(path, len);
if (path == NULL) {
free(temp);
exit(ENOMEM);
}
memset(path, 0, len);
temp = getcwd(path, len);
if (temp == NULL) {
if (errno != ERANGE) {
free(path);
exit(errno);
}
temp = NULL;
len *= 2;
}
}
*total = strlen(path);
if (buffer != NULL) {
mdata += sizeof(size_t);
size = ((*total > size) ? size : *total);
memcpy(mdata, path, size);
}
free(path);
exit(0);
} else if (pid == -1) {
status = errno;
close(mfd);
unlink(mpath);
errno = status;
return (size_t)-1;
}
waitpid(pid, &status, 0);
if (status != 0) {
close(mfd);
unlink(mpath);
munmap(mdata, msize);
errno = status;
return (size_t)-1;
}
if (buffer != NULL) {
mdata += sizeof(size_t);
size = ((*total > size) ? size : *total);
memcpy(buffer, mdata, size);
mdata -= sizeof(size_t);
}
size = *total;
if (close(mfd) == -1) {
status = errno;
unlink(mpath);
munmap(mdata, msize);
errno = status;
return (size_t)-1;
}
if (unlink(mpath) == -1) {
status = errno;
munmap(mdata, msize);
errno = status;
return (size_t)-1;
}
if (munmap(mdata, msize) == -1) {
return (size_t)-1;
}
pthread_mutex_lock(&mutex);
if (rmdir("/tmp/dirpath") == -1) {
#if defined(ENOEMPTY) && (ENOEMPTY != EEXIST)
if ((errno != EEXIST) && (errno != ENOEMPTY)) {
return (size_t)-1;
}
#else
if (errno != EEXIST) {
return (size_t)-1;
}
#endif
}
pthread_mutex_unlock(&mutex);
return size;
}
size_t dirpath(DIR *dir, char *buffer, size_t size)
{
int fd = -1;
if (dir == NULL) {
errno = EINVAL;
return (size_t)-1;
}
if ((fd = dirfd(dir)) == -1) {
return (size_t)-1;
}
return fdirpath(fd, buffer, size);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment