Skip to content

Instantly share code, notes, and snippets.

@yoursunny
Created Aug 28, 2021
Embed
What would you like to do?
Today I Learned: openat() https://yoursunny.com/t/2021/openat/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <unistd.h>
typedef struct KV
{
char* dir;
} KV;
bool
KV_Open(KV* kv, const char* dir)
{
struct stat st;
if (stat(dir, &st) != 0 || !S_ISDIR(st.st_mode)) {
return false;
}
kv->dir = strdup(dir);
return true;
}
bool
KV_Close(KV* kv)
{
free(kv->dir);
return true;
}
ssize_t
KV_Load(KV* kv, const char* key, uint8_t* buffer, size_t limit)
{
char pathname[PATH_MAX];
int res = snprintf(pathname, sizeof(pathname), "%s/%s", kv->dir, key);
if (res < 0 || res >= (int)sizeof(pathname)) {
return -1;
}
int fd = open(pathname, O_RDONLY);
if (fd < 0) {
return -1;
}
ssize_t size = read(fd, buffer, limit);
close(fd);
return size;
}
bool
KV_Save(KV* kv, const char* key, const uint8_t* value, size_t size)
{
char pathname[PATH_MAX];
int res = snprintf(pathname, sizeof(pathname), "%s/%s", kv->dir, key);
if (res < 0 || res >= (int)sizeof(pathname)) {
return false;
}
int fd = open(pathname, O_WRONLY | O_CREAT, 0644);
if (fd < 0) {
return false;
}
ssize_t written = write(fd, value, size);
close(fd);
return (size_t)written == size;
}
bool
KV_Delete(KV* kv, const char* key)
{
char pathname[PATH_MAX];
int res = snprintf(pathname, sizeof(pathname), "%s/%s", kv->dir, key);
if (res < 0 || res >= (int)sizeof(pathname)) {
return false;
}
return unlink(pathname) == 0;
}
int
main()
{
KV kv;
if (!KV_Open(&kv, "/tmp")) {
fprintf(stderr, "KV_Open error\n");
return 1;
}
const char* key = "yoursunny";
uint8_t value[] = { 0x61, 0x77, 0x65, 0x73, 0x6F, 0x6D, 0x65 };
if (!KV_Save(&kv, key, value, sizeof(value))) {
fprintf(stderr, "KV_Save error\n");
return 1;
}
char buffer[16];
ssize_t size = KV_Load(&kv, key, (uint8_t*)buffer, sizeof(buffer) - 1);
if (size < 0) {
fprintf(stderr, "KV_Load error\n");
return 1;
}
buffer[size] = '\0';
printf("%s = %s\n", key, buffer);
if (!KV_Delete(&kv, key)) {
fprintf(stderr, "KV_Delete error\n");
return 1;
}
if (!KV_Close(&kv)) {
fprintf(stderr, "KV_Close error\n");
return 1;
}
return 0;
}
#define _POSIX_C_SOURCE 200809L
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <unistd.h>
typedef struct KV
{
int dirfd;
} KV;
bool
KV_Open(KV* kv, const char* dir)
{
kv->dirfd = open(dir, O_RDONLY | O_DIRECTORY);
return kv->dirfd >= 0;
}
bool
KV_Close(KV* kv)
{
close(kv->dirfd);
return true;
}
ssize_t
KV_Load(KV* kv, const char* key, uint8_t* buffer, size_t limit)
{
int fd = openat(kv->dirfd, key, O_RDONLY);
if (fd < 0) {
return false;
}
ssize_t size = read(fd, buffer, limit);
close(fd);
return size;
}
bool
KV_Save(KV* kv, const char* key, const uint8_t* value, size_t size)
{
int fd = openat(kv->dirfd, key, O_WRONLY | O_CREAT, 0644);
if (fd < 0) {
return false;
}
ssize_t written = write(fd, value, size);
close(fd);
return (size_t)written == size;
}
bool
KV_Delete(KV* kv, const char* key)
{
return unlinkat(kv->dirfd, key, 0) == 0;
}
int
main()
{
KV kv;
if (!KV_Open(&kv, "/tmp")) {
fprintf(stderr, "KV_Open error\n");
return 1;
}
const char* key = "yoursunny";
uint8_t value[] = { 0x61, 0x77, 0x65, 0x73, 0x6F, 0x6D, 0x65 };
if (!KV_Save(&kv, key, value, sizeof(value))) {
fprintf(stderr, "KV_Save error\n");
return 1;
}
char buffer[16];
ssize_t size = KV_Load(&kv, key, (uint8_t*)buffer, sizeof(buffer) - 1);
if (size < 0) {
fprintf(stderr, "KV_Load error\n");
return 1;
}
buffer[size] = '\0';
printf("%s = %s\n", key, buffer);
if (!KV_Delete(&kv, key)) {
fprintf(stderr, "KV_Delete error\n");
return 1;
}
if (!KV_Close(&kv)) {
fprintf(stderr, "KV_Close error\n");
return 1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment