Permalink
Browse files

Import trimmed part of ccgfs-0.79

  • Loading branch information...
0 parents commit 39b416a86996be81d9ece8718b06186dab63c51e Vitaly _Vi Shukela committed Jan 3, 2011
Showing with 1,159 additions and 0 deletions.
  1. +2 −0 Makefile
  2. +49 −0 ccgfs.h
  3. +302 −0 packet.c
  4. +138 −0 packet.h
  5. +490 −0 storage.c
  6. +83 −0 xl.c
  7. +9 −0 xl.h
  8. +86 −0 xl_errno.c
2 Makefile
@@ -0,0 +1,2 @@
+all:
+ i586-mingw32msvc-gcc packet.c xl.c xl_errno.c storage.c -o storage.exe
49 ccgfs.h
@@ -0,0 +1,49 @@
+#ifndef _CCGFS_H
+#define _CCGFS_H 1
+
+#include <sys/types.h>
+#include <stdint.h>
+
+/*
+ * min()/max() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x, y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ (void)(&_x == &_y); \
+ (_x < _y) ? _x : _y; })
+
+#define max(x, y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ (void)(&_x == &_y); \
+ (_x > _y) ? _x : _y; \
+})
+
+#ifdef PKTSWAP
+static inline uint32_t swap32(uint32_t x)
+{
+ return ((x & 0x000000FF) << 24) |
+ ((x & 0x0000FF00) << 8) |
+ ((x & 0x00FF0000) >> 8) |
+ ((x & 0xFF000000) >> 24);
+}
+static inline uint64_t swap64(uint64_t x)
+{
+ return ((uint64_t)swap32(x & 0xFFFFFFFF) << 32) |
+ (swap32(x >> 32) & 0xFFFFFFFF);
+}
+# define le32_to_cpu(x) swap32(x)
+# define le64_to_cpu(x) swap64(x)
+# define cpu_to_le32(x) swap32(x)
+# define cpu_to_le64(x) swap64(x)
+#else
+# define le32_to_cpu(x) (x)
+# define le64_to_cpu(x) (x)
+# define cpu_to_le32(x) (x)
+# define cpu_to_le64(x) (x)
+#endif
+
+#endif /* _CCGFS_H */
302 packet.c
@@ -0,0 +1,302 @@
+/*
+ * CC Network Filesystem (ccgfs)
+ *
+ * Copyright © CC Computer Consultants GmbH, 2007
+ * Contact: Jan Engelhardt <jengelh [at] computergmbh de>
+ *
+ * This file is part of CCGFS. CCGFS is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2 or 3 of the License.
+ */
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "packet.h"
+
+/**
+ * @type: type
+ * @length: desired initial length (without header)
+ */
+struct lo_packet *pkt_init(unsigned int type, unsigned int length)
+{
+ struct ccgfs_pkt_header *hdr;
+ struct lo_packet *pkt;
+
+ length += sizeof(*hdr);
+ if ((pkt = malloc(sizeof(*pkt))) == NULL) {
+ fprintf(stderr, "%s: malloc(): %s\n",
+ __func__, strerror(errno));
+ abort();
+ }
+ if ((hdr = pkt->data = malloc(length)) == NULL) {
+ fprintf(stderr, "%s: malloc(): %s\n",
+ __func__, strerror(errno));
+ abort();
+ }
+ pkt->alloc = length;
+ pkt->length = sizeof(*hdr);
+ pkt->shift = sizeof(*hdr);
+ hdr->opcode = cpu_to_le32(type);
+ return pkt;
+}
+
+/**
+ * @size: new size, including header
+ */
+void *pkt_resize(struct lo_packet *pkt, unsigned int size)
+{
+ void *nu = realloc(pkt->data, size);
+ if (nu == NULL) {
+ fprintf(stderr, "%s: realloc(): %s\n",
+ __func__, strerror(errno));
+ abort();
+ }
+ pkt->alloc = size;
+ pkt->data = nu;
+ return nu;
+}
+
+static inline void pkt_resize_plus(struct lo_packet *pkt, unsigned int size)
+{
+ pkt_resize(pkt, pkt->length + size + size / 4);
+}
+
+static inline uint32_t deref_get_32(const void *ptr)
+{
+ uint32_t ret;
+ memcpy(&ret, ptr, sizeof(ret));
+ return ret;
+}
+
+static inline uint64_t deref_get_64(const void *ptr)
+{
+ uint64_t ret;
+ memcpy(&ret, ptr, sizeof(ret));
+ return ret;
+}
+
+static inline void deref_put_32(void *ptr, uint32_t value)
+{
+ memcpy(ptr, &value, sizeof(value));
+}
+
+/**
+ * pkt_push - push an object into the buffer
+ * @pkt: packet buffer to operate on
+ */
+void pkt_push(struct lo_packet *pkt, const void *input_data,
+ unsigned int input_length, unsigned int type)
+{
+ unsigned int nsz;
+ void *dest;
+
+ nsz = input_length + sizeof(uint32_t);
+
+ if (input_length >= 0x7F000000) {
+ fprintf(stderr, "%s: length too big\n", __func__);
+ abort();
+ }
+
+ if (pkt->length + nsz > pkt->alloc)
+ pkt_resize_plus(pkt, nsz);
+
+ dest = pkt->data + pkt->length;
+ switch (type) {
+ case PT_DATA:
+ deref_put_32(dest,
+ cpu_to_le32(input_length | (1 << 31)));
+ memcpy(dest + sizeof(uint32_t), input_data, input_length);
+ break;
+ default:
+ deref_put_32(dest, cpu_to_le32(type));
+ memcpy(dest + sizeof(uint32_t), input_data, input_length);
+ break;
+ }
+ pkt->length += nsz;
+}
+
+/**
+ * pkt_shift_32 - get the next object
+ * @pkt: packet buffer to operate on
+ *
+ * Verifies that the next object is a 32-bit integer object
+ * and returns the value.
+ */
+uint32_t pkt_shift_32(struct lo_packet *pkt)
+{
+ uint32_t *ptr = pkt->data + pkt->shift;
+ if (le32_to_cpu(deref_get_32(ptr)) != PT_32) {
+ fprintf(stderr, "%s: protocol mismatch\n", __func__);
+ abort();
+ }
+ ++ptr;
+ pkt->shift += 2 * sizeof(uint32_t);
+ return le32_to_cpu(deref_get_32(ptr));
+}
+
+/**
+ * pkt_shift_64 - get the next object
+ * @pkt: packet buffer to operate on
+ *
+ * Verifies that the next object is a 64-bit integer object
+ * and returns the value.
+ */
+uint64_t pkt_shift_64(struct lo_packet *pkt)
+{
+ uint32_t *ptr = pkt->data + pkt->shift;
+
+ if (le32_to_cpu(deref_get_32(ptr)) != PT_64) {
+ fprintf(stderr, "%s: protocol mismatch\n", __func__);
+ abort();
+ }
+
+ ++ptr;
+ pkt->shift += sizeof(uint32_t) + sizeof(uint64_t);
+ return le64_to_cpu(deref_get_64(ptr));
+}
+
+/**
+ * pkt_shift_s - get the next object
+ * @pkt: packet buffer to operate on
+ *
+ * Verifies that the next object is a binary blob object and returns a pointer
+ * to it in the transmission buffer. Do not free it.
+ */
+const void *pkt_shift_s(struct lo_packet *pkt)
+{
+ uint32_t *ptr = pkt->data + pkt->shift;
+ uint32_t data = le32_to_cpu(deref_get_32(ptr));
+ uint32_t len = data & ~PT_DATA_BIT;
+
+ if (!(data & PT_DATA_BIT)) {
+ fprintf(stderr, "%s: protocol mismatch\n", __func__);
+ abort();
+ }
+ ++ptr;
+ pkt->shift += sizeof(uint32_t) + len;
+ return ptr;
+}
+
+static ssize_t reliable_write(int fd, void *buf, size_t count)
+{
+ size_t count_left = count;
+ int ret;
+
+ while (count_left > 0) {
+ ret = write(fd, buf, count_left);
+ if (ret > 0) {
+ count_left -= ret;
+ buf += ret;
+ } else if (ret == 0) {
+ return count - count_left;
+ } else if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
+ /* immediate retry */
+ } else {
+ perror("reliable_write unable to recover");
+ return ret;
+ }
+ }
+
+ return count;
+}
+
+static ssize_t reliable_read(int fd, void *buf, size_t count)
+{
+ size_t count_left = count;
+ int ret;
+
+ while (count_left > 0) {
+ ret = read(fd, buf, count_left);
+ if (ret > 0) {
+ count_left -= ret;
+ buf += ret;
+ } else if (ret == 0) {
+ return count - count_left;
+ } else if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
+ /* immediate retry */
+ } else {
+ perror("reliable_read unable to recover");
+ return ret;
+ }
+ }
+
+ return count;
+}
+
+/**
+ * pkt_recv - receive packet
+ * @fd: file descriptor to read
+ *
+ * Reads the next packet from @fd. A new lo_packet is created and returned.
+ * On error, %NULL is returned, in which case the stream (@fd) will be in
+ * an undefined state.
+ */
+struct lo_packet *pkt_recv(int fd)
+{
+ struct ccgfs_pkt_header *hdr;
+ struct lo_packet *pkt;
+ ssize_t ret;
+ int err;
+
+ pkt = pkt_init(0, 0);
+ hdr = pkt->data;
+ ret = reliable_read(fd, hdr, sizeof(*hdr));
+ if (ret != sizeof(*hdr)) {
+ err = errno;
+ pkt_destroy(pkt);
+ errno = err;
+ return NULL;
+ }
+
+ hdr->opcode = le32_to_cpu(hdr->opcode);
+ hdr->length = le32_to_cpu(hdr->length);
+ hdr = pkt_resize(pkt, hdr->length);
+ pkt->length = hdr->length;
+
+ ret = reliable_read(fd, pkt->data + sizeof(*hdr),
+ pkt->length - sizeof(*hdr));
+ if (ret != pkt->length - sizeof(*hdr)) {
+ err = errno;
+ pkt_destroy(pkt);
+ errno = err;
+ return NULL;
+ }
+ return pkt;
+}
+
+static void __pkt_destroy(struct lo_packet *pkt)
+{
+ free(pkt->data);
+ free(pkt);
+}
+
+/**
+ * pkt_send - send packet and destroy
+ * @fd: file descriptor to write it to
+ * @pkt: packet structure
+ *
+ * Writes the packet length into the actual transmission buffer, sends the
+ * packet out to @fd and then destroys it.
+ */
+void pkt_send(int fd, struct lo_packet *pkt)
+{
+ struct ccgfs_pkt_header *hdr = pkt->data;
+ hdr->length = cpu_to_le32(pkt->length);
+ reliable_write(fd, hdr, pkt->length);
+ __pkt_destroy(pkt);
+}
+
+void pkt_destroy(struct lo_packet *pkt)
+{
+ if (pkt->shift != pkt->length) {
+ perror("short packet");
+ fprintf(stderr, "packet %p[%u,%u] has not been "
+ "properly consumed\n",
+ pkt, pkt->shift, pkt->length);
+ }
+ __pkt_destroy(pkt);
+}
138 packet.h
@@ -0,0 +1,138 @@
+/*
+ * CC Network Filesystem (ccgfs)
+ * Mount Daemon
+ *
+ * Copyright © CC Computer Consultants GmbH, 2007
+ * Contact: Jan Engelhardt <jengelh [at] computergmbh de>
+ *
+ * This file is part of CCGFS. CCGFS is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2 or 3 of the License.
+ */
+#ifndef _CCGFS_PKT_H
+#define _CCGFS_PKT_H 1
+
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include "ccgfs.h"
+
+enum {
+ /* Wire protocol */
+ PT_16 = 2,
+ PT_32 = 4,
+ PT_64 = 8,
+ PT_DATA = 255,
+ PT_DATA_BIT = (1 << 31),
+
+ /* Shortcuts for malloc */
+ PV_16 = sizeof(uint32_t) + PT_16,
+ PV_32 = sizeof(uint32_t) + PT_32,
+ PV_64 = sizeof(uint32_t) + PT_64,
+ PV_STRING = sizeof(uint32_t) + PATH_MAX,
+};
+
+enum {
+ CCGFS_CHMOD_REQUEST,
+ CCGFS_CHOWN_REQUEST,
+ CCGFS_CREATE_REQUEST,
+ CCGFS_FGETATTR_REQUEST,
+ CCGFS_FSYNC_REQUEST,
+ CCGFS_FTRUNCATE_REQUEST,
+ CCGFS_GETATTR_REQUEST,
+ CCGFS_GETXATTR_REQUEST,
+ CCGFS_LINK_REQUEST,
+ CCGFS_LISTXATTR_REQUEST,
+ CCGFS_MKDIR_REQUEST,
+ CCGFS_MKNOD_REQUEST,
+ CCGFS_OPEN_REQUEST,
+ CCGFS_OPENDIR_REQUEST,
+ CCGFS_READ_REQUEST,
+ CCGFS_READDIR_REQUEST,
+ CCGFS_READLINK_REQUEST,
+ CCGFS_RELEASE_REQUEST,
+ CCGFS_REMOVEXATTR_REQUEST,
+ CCGFS_RENAME_REQUEST,
+ CCGFS_RMDIR_REQUEST,
+ CCGFS_SETXATTR_REQUEST,
+ CCGFS_STATFS_REQUEST,
+ CCGFS_SYMLINK_REQUEST,
+ CCGFS_TRUNCATE_REQUEST,
+ CCGFS_UNLINK_REQUEST,
+ CCGFS_UTIMENS_REQUEST,
+ CCGFS_WRITE_REQUEST,
+
+ CCGFS_CREATE_RESPONSE,
+ CCGFS_ERRNO_RESPONSE,
+ CCGFS_GETATTR_RESPONSE,
+ CCGFS_GETXATTR_RESPONSE,
+ CCGFS_LISTXATTR_RESPONSE,
+ CCGFS_OPEN_RESPONSE,
+ CCGFS_READ_RESPONSE,
+ CCGFS_READDIR_RESPONSE,
+ CCGFS_READLINK_RESPONSE,
+ CCGFS_STATFS_RESPONSE,
+
+ CCGFS_FSINFO,
+};
+
+/**
+ * local packet
+ * @alloc: allocated size of the data block
+ * @space: used size of the data block
+ * @push_offset: offset for new data
+ * @data: data
+ */
+struct lo_packet {
+ unsigned int alloc, length, shift;
+ void *data;
+};
+
+/**
+ * ccgfs_pkt_header, ccgfs_fsid_header - header common to all packets
+ * @opcode: request/response type
+ * @length: length of total packet, including ccgfs_pkt_header
+ * @fsuid: UID to be used for this request
+ * @fsgid: GID to be used for this request
+ */
+struct ccgfs_pkt_header {
+ uint32_t opcode, length;
+};
+
+struct ccgfs_fsid_header {
+ uint32_t opcode, length;
+ uint32_t fsuid, fsgid;
+};
+
+/* functions */
+extern struct lo_packet *pkt_init(unsigned int, unsigned int);
+extern void *pkt_resize(struct lo_packet *, unsigned int);
+extern void pkt_push(struct lo_packet *, const void *, unsigned int,
+ unsigned int);
+extern uint32_t pkt_shift_32(struct lo_packet *);
+extern uint64_t pkt_shift_64(struct lo_packet *);
+extern const void *pkt_shift_s(struct lo_packet *);
+extern struct lo_packet *pkt_recv(int);
+extern void pkt_send(int, struct lo_packet *);
+extern void pkt_destroy(struct lo_packet *);
+
+/* inline functions */
+static inline void pkt_push_32(struct lo_packet *pkt, uint32_t val)
+{
+ val = cpu_to_le32(val);
+ pkt_push(pkt, &val, sizeof(val), PT_32);
+}
+
+static inline void pkt_push_64(struct lo_packet *pkt, uint64_t val)
+{
+ val = cpu_to_le64(val);
+ pkt_push(pkt, &val, sizeof(val), PT_64);
+}
+
+static inline void pkt_push_s(struct lo_packet *pkt, const char *s)
+{
+ pkt_push(pkt, s, strlen(s) + 1, PT_DATA);
+}
+
+#endif /* _CCGFS_PKT_H */
490 storage.c
@@ -0,0 +1,490 @@
+/*
+ * CC Network Filesystem (ccgfs)
+ * Storage Engine
+ *
+ * Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2008
+ *
+ * This file is part of CCGFS. CCGFS is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2 or 3 of the License.
+ */
+#define _ATFILE_SOURCE 1
+#define _GNU_SOURCE 1
+#include <sys/time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "ccgfs.h"
+#include "packet.h"
+typedef int uid_t;
+typedef int gid_t;
+
+#define b_path(dest, src) /* build path */ \
+ (snprintf(dest, sizeof(dest), "%s%s", root_dir, (src)) >= \
+ sizeof(dest))
+#define perror(s) perror("ccgfs-storage: " s)
+
+enum {
+ LOCALFS_SUCCESS = 0,
+ LOCALFS_STOP,
+};
+
+typedef int (*localfs_func_t)(int, struct lo_packet *);
+
+static __attribute__((pure)) const char *at(const char *in)
+{
+ if (*in != '/')
+ abort();
+ if (in[1] == '\0')
+ return ".";
+ return in + 1;
+}
+
+static int localfs_chmod(int fd, struct lo_packet *rq)
+{
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_chown(int fd, struct lo_packet *rq)
+{
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_create(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ unsigned int rq_flags = pkt_shift_32(rq);
+ mode_t rq_mode = pkt_shift_32(rq);
+ struct lo_packet *rp;
+ int ret;
+
+ ret = open(at(rq_path), arch_openflags(rq_flags), rq_mode);
+ if (ret < 0)
+ return -errno;
+
+ rp = pkt_init(CCGFS_CREATE_RESPONSE, PV_32);
+ pkt_push_32(rp, ret);
+ pkt_send(fd, rp);
+ return LOCALFS_STOP;
+}
+
+static struct lo_packet *getattr_copy_stor(const struct stat *sb)
+{
+ struct lo_packet *rp;
+
+ rp = pkt_init(CCGFS_GETATTR_RESPONSE, 7 * PV_64 + 5 * PV_32);
+ if (rp == NULL)
+ return NULL;
+
+ unsigned long long int fake_st_blksize=1024;
+ unsigned long long int fake_st_blocks=sb->st_size/1024+1;
+
+ pkt_push_64(rp, sb->st_ino);
+ pkt_push_32(rp, sb->st_mode);
+ pkt_push_32(rp, sb->st_nlink);
+ pkt_push_32(rp, sb->st_uid);
+ pkt_push_32(rp, sb->st_gid);
+ pkt_push_32(rp, sb->st_rdev);
+ pkt_push_64(rp, sb->st_size);
+ pkt_push_64(rp, fake_st_blksize);
+ pkt_push_64(rp, fake_st_blocks);
+ pkt_push_64(rp, sb->st_atime);
+ pkt_push_64(rp, sb->st_mtime);
+ pkt_push_64(rp, sb->st_ctime);
+ return rp;
+}
+
+static int localfs_fgetattr(int fd, struct lo_packet *rq)
+{
+ int rq_fd = pkt_shift_32(rq);
+ struct stat sb;
+
+ if (fstat(rq_fd, &sb) < 0)
+ return -errno;
+
+ pkt_send(fd, getattr_copy_stor(&sb));
+ return LOCALFS_STOP;
+}
+
+static int localfs_fsync(int fd, struct lo_packet *rq)
+{
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_ftruncate(int fd, struct lo_packet *rq)
+{
+ int rq_fd = pkt_shift_32(rq);
+ off_t rq_off = pkt_shift_64(rq);
+
+ if (ftruncate(rq_fd, rq_off) < 0)
+ return -errno;
+
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_getattr(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ struct stat sb;
+
+ if (stat(at(rq_path), &sb) < 0)
+ return -errno;
+
+ pkt_send(fd, getattr_copy_stor(&sb));
+ return LOCALFS_STOP;
+}
+
+static int localfs_getxattr(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_link(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_listxattr(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_mkdir(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ mode_t rq_mode = pkt_shift_32(rq);
+
+ (void)rq_mode;
+
+ if (mkdir(at(rq_path)) < 0)
+ return -errno;
+
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_mknod(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_open(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ unsigned int rq_flags = pkt_shift_32(rq);
+ struct lo_packet *rp;
+ int ret;
+
+ ret = open(at(rq_path), arch_openflags(rq_flags));
+ if (ret < 0)
+ return -errno;
+
+ rp = pkt_init(CCGFS_OPEN_RESPONSE, PV_32);
+ pkt_push_32(rp, ret);
+ pkt_send(fd, rp);
+ return LOCALFS_STOP;
+}
+
+static int localfs_opendir_access(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ struct stat sb;
+
+ if (stat(at(rq_path), &sb) < 0)
+ return -errno;
+ if (!S_ISDIR(sb.st_mode))
+ return -ENOTDIR;
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_read(int fd, struct lo_packet *rq)
+{
+ int rq_fd = pkt_shift_32(rq);
+ size_t rq_size = pkt_shift_64(rq);
+ off_t rq_offset = pkt_shift_64(rq);
+
+ struct lo_packet *rp;
+ ssize_t ret;
+ char *buf;
+
+ buf = malloc(rq_size);
+ if (buf == NULL)
+ return -EIO;
+ ret = pread(rq_fd, buf, rq_size, rq_offset);
+ if (ret < 0) {
+ if (errno != ESPIPE) {
+ free(buf);
+ return -errno;
+ }
+ ret = read(rq_fd, buf, rq_size);
+ }
+ if (ret < 0) {
+ free(buf);
+ return -errno;
+ }
+
+ rp = pkt_init(CCGFS_READ_RESPONSE, 2 * PV_STRING);
+ pkt_push_64(rp, ret);
+ pkt_push(rp, buf, ret, PT_DATA);
+ pkt_send(fd, rp);
+ free(buf);
+ return LOCALFS_STOP;
+}
+
+static int localfs_readdir(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ struct dirent *dentry;
+ struct lo_packet *rp;
+ DIR *ptr;
+
+ if ((ptr = opendir(at(rq_path))) == NULL)
+ return -errno;
+
+ while ((dentry = readdir(ptr)) != NULL) {
+ rp = pkt_init(CCGFS_READDIR_RESPONSE,
+ PV_64 + PV_32 + PV_STRING);
+ pkt_push_64(rp, dentry->d_ino);
+ pkt_push_32(rp, 0);
+ pkt_push_s(rp, dentry->d_name);
+ pkt_send(fd, rp);
+ }
+
+ closedir(ptr);
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_readlink(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ char d_linkbuf[PATH_MAX];
+ struct lo_packet *rp;
+
+ memset(d_linkbuf, 0, sizeof(d_linkbuf));
+ if (readlink(at(rq_path), d_linkbuf,
+ sizeof(d_linkbuf) - 1) < 0)
+ return -errno;
+
+ rp = pkt_init(CCGFS_READLINK_RESPONSE, PV_STRING);
+ pkt_push_s(rp, d_linkbuf);
+ pkt_send(fd, rp);
+ return LOCALFS_STOP;
+}
+
+static int localfs_release(int fd, struct lo_packet *rq)
+{
+ if (close(pkt_shift_32(rq)) < 0)
+ return -errno;
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_removexattr(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_rename(int fd, struct lo_packet *rq)
+{
+ const char *rq_oldpath = pkt_shift_s(rq);
+ const char *rq_newpath = pkt_shift_s(rq);
+
+ if (rename(at(rq_oldpath), at(rq_newpath)) < 0)
+ return -errno;
+
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_rmdir(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+
+ if (rmdir(at(rq_path)) < 0)
+ return -errno;
+
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_setxattr(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_symlink(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_statfs(int fd, struct lo_packet *rq)
+{
+ return -ENOSYS;
+}
+
+static int localfs_truncate(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ off_t rq_off = pkt_shift_64(rq);
+
+ if (truncate(at(rq_path), rq_off) < 0)
+ return -errno;
+
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_unlink(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+
+ if (unlink(at(rq_path)) < 0)
+ return -errno;
+
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_utimens(int fd, struct lo_packet *rq)
+{
+ const char *rq_path = pkt_shift_s(rq);
+ struct timeval val[2];
+
+ val[0].tv_sec = pkt_shift_64(rq);
+ val[0].tv_usec = pkt_shift_64(rq) / 1000;
+ val[1].tv_sec = pkt_shift_64(rq);
+ val[1].tv_usec = pkt_shift_64(rq) / 1000;
+ if (futimes(at(rq_path), val) < 0)
+ return -errno;
+
+ return LOCALFS_SUCCESS;
+}
+
+static int localfs_write(int fd, struct lo_packet *rq)
+{
+ int rq_fd = pkt_shift_32(rq);
+ size_t size = pkt_shift_64(rq);
+ off_t offset = pkt_shift_64(rq);
+ const char *data = pkt_shift_s(rq);
+
+ struct lo_packet *rp;
+ ssize_t ret;
+
+ ret = pwrite(rq_fd, data, size, offset);
+ if (ret < 0) {
+ if (errno != ESPIPE)
+ return -errno;
+ ret = write(rq_fd, data, size);
+ }
+ if (ret < 0)
+ return -errno;
+
+ rp = pkt_init(CCGFS_ERRNO_RESPONSE, PV_32);
+ pkt_push_32(rp, ret);
+ pkt_send(fd, rp);
+ return LOCALFS_STOP;
+}
+
+static const localfs_func_t localfs_func_array[] = {
+ [CCGFS_CHMOD_REQUEST] = localfs_chmod,
+ [CCGFS_CHOWN_REQUEST] = localfs_chown,
+ [CCGFS_CREATE_REQUEST] = localfs_create,
+ [CCGFS_FGETATTR_REQUEST] = localfs_fgetattr,
+ [CCGFS_FSYNC_REQUEST] = localfs_fsync,
+ [CCGFS_FTRUNCATE_REQUEST] = localfs_ftruncate,
+ [CCGFS_GETATTR_REQUEST] = localfs_getattr,
+ [CCGFS_GETXATTR_REQUEST] = localfs_getxattr,
+ [CCGFS_LINK_REQUEST] = localfs_link,
+ [CCGFS_LISTXATTR_REQUEST] = localfs_listxattr,
+ [CCGFS_MKDIR_REQUEST] = localfs_mkdir,
+ [CCGFS_MKNOD_REQUEST] = localfs_mknod,
+ [CCGFS_OPEN_REQUEST] = localfs_open,
+ [CCGFS_OPENDIR_REQUEST] = localfs_opendir_access,
+ [CCGFS_READ_REQUEST] = localfs_read,
+ [CCGFS_READDIR_REQUEST] = localfs_readdir,
+ [CCGFS_READLINK_REQUEST] = localfs_readlink,
+ [CCGFS_RELEASE_REQUEST] = localfs_release,
+ [CCGFS_REMOVEXATTR_REQUEST] = localfs_removexattr,
+ [CCGFS_RENAME_REQUEST] = localfs_rename,
+ [CCGFS_RMDIR_REQUEST] = localfs_rmdir,
+ [CCGFS_SETXATTR_REQUEST] = localfs_setxattr,
+ [CCGFS_STATFS_REQUEST] = localfs_statfs,
+ [CCGFS_SYMLINK_REQUEST] = localfs_symlink,
+ [CCGFS_TRUNCATE_REQUEST] = localfs_truncate,
+ [CCGFS_UNLINK_REQUEST] = localfs_unlink,
+ [CCGFS_UTIMENS_REQUEST] = localfs_utimens,
+ [CCGFS_WRITE_REQUEST] = localfs_write,
+};
+
+static int localfs_setfsid(struct lo_packet *rq)
+{
+ uid_t uid = pkt_shift_32(rq);
+ gid_t gid = pkt_shift_32(rq);
+ return -ENOSYS;
+}
+
+static void handle_packet(int fd, struct lo_packet *rq)
+{
+ struct ccgfs_pkt_header *hdr;
+ struct lo_packet *rp;
+ localfs_func_t lf;
+ int ret;
+
+ if (localfs_setfsid(rq) < 0) {
+ rp = pkt_init(CCGFS_ERRNO_RESPONSE, PV_32);
+ pkt_push_32(rp, -EPERM);
+ pkt_send(fd, rp);
+ return;
+ }
+
+ ret = -EIO;
+ hdr = rq->data;
+ lf = localfs_func_array[hdr->opcode];
+ if (lf != NULL)
+ ret = (*lf)(fd, rq);
+
+ if (ret <= 0) {
+ rp = pkt_init(CCGFS_ERRNO_RESPONSE, PV_32);
+ pkt_push_32(rp, generic_errno(ret));
+ pkt_send(fd, rp);
+ }
+}
+
+static void send_fsinfo(int fd)
+{
+ struct lo_packet *rp;
+ char host[1024], buf[65536];
+
+ if (gethostname(host, sizeof(host)) < 0) {
+ strcpy(host, "unknown_host");
+ }
+
+ char cwd[65536];
+ getcwd(cwd,65536);
+
+ snprintf(buf, sizeof(buf), "%s:%s", host, cwd);
+ rp = pkt_init(CCGFS_FSINFO, PV_STRING);
+ pkt_push_s(rp, buf);
+ pkt_send(fd, rp);
+}
+
+int main(int argc, const char **argv)
+{
+ struct lo_packet *rq;
+
+ umask(0);
+ send_fsinfo(STDOUT_FILENO);
+
+ while (true) {
+ rq = pkt_recv(STDIN_FILENO);
+ if (rq == NULL)
+ break;
+ handle_packet(STDOUT_FILENO, rq);
+ pkt_destroy(rq);
+ }
+
+ return EXIT_SUCCESS;
+}
83 xl.c
@@ -0,0 +1,83 @@
+#define _GNU_SOURCE 1
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "xl.h"
+#include "xl_errno.c"
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+enum {
+ OO_READ = 1 << 0,
+ OO_WRITE = 1 << 1,
+ OO_RDWR = (OO_READ | OO_WRITE),
+ OO_ACCMODE = OO_RDWR,
+ OO_CREAT = 1 << 2,
+ OO_EXCL = 1 << 3,
+ OO_TRUNC = 1 << 5,
+ OO_APPEND = 1 << 6,
+};
+
+/* x is always negative or zero */
+int generic_errno(int x)
+{
+ if (x > 0)
+ abort();
+ if (x < -ARRAY_SIZE(arch_to_generic_table))
+ return x;
+ else
+ return arch_to_generic_table[-x];
+}
+
+/* x is always negative or zero */
+int arch_errno(int x)
+{
+ if (x > 0)
+ abort();
+ if (x < -ARRAY_SIZE(generic_to_arch_table))
+ return x;
+ else
+ return generic_to_arch_table[-x];
+}
+
+unsigned int generic_openflags(unsigned int x)
+{
+ unsigned int fl = 0;
+ switch (x & O_ACCMODE) {
+ case O_RDONLY:
+ fl = OO_READ;
+ break;
+ case O_WRONLY:
+ fl = OO_WRITE;
+ break;
+ case O_RDWR:
+ fl = OO_RDWR;
+ break;
+ }
+ if (x & O_CREAT) fl |= OO_CREAT;
+ if (x & O_EXCL) fl |= OO_EXCL;
+ if (x & O_TRUNC) fl |= OO_TRUNC;
+ if (x & O_APPEND) fl |= OO_APPEND;
+ /* No encoding of O_LARGEFILE, will always enable */
+ return fl;
+}
+
+unsigned int arch_openflags(unsigned int x)
+{
+ unsigned int fl = 0;
+ switch (x & OO_ACCMODE) {
+ case OO_READ:
+ fl = O_RDONLY;
+ break;
+ case OO_WRITE:
+ fl = O_WRONLY;
+ break;
+ case OO_RDWR:
+ fl = O_RDWR;
+ break;
+ }
+ if (x & OO_CREAT) fl |= O_CREAT;
+ if (x & OO_EXCL) fl |= O_EXCL;
+ if (x & OO_TRUNC) fl |= O_TRUNC;
+ if (x & OO_APPEND) fl |= O_APPEND;
+ return fl;
+}
9 xl.h
@@ -0,0 +1,9 @@
+#ifndef CCGFS_XL_H
+#define CCGFS_XL_H 1
+
+extern int generic_errno(int);
+extern int arch_errno(int);
+extern unsigned int generic_openflags(unsigned int);
+extern unsigned int arch_openflags(unsigned int);
+
+#endif /* CCGFS_XL_H */
86 xl_errno.c
@@ -0,0 +1,86 @@
+/* Generated by gen_xl_errno.pl */
+#include <errno.h>
+
+static const int arch_to_generic_table[] = {
+ [0] = 0,
+ [EPERM] = -1,
+ [ENOENT] = -2,
+ [ESRCH] = -3,
+ [EINTR] = -4,
+ [EIO] = -5,
+ [ENXIO] = -6,
+ [E2BIG] = -7,
+ [ENOEXEC] = -8,
+ [EBADF] = -9,
+ [ECHILD] = -10,
+ [EAGAIN] = -11,
+ [ENOMEM] = -12,
+ [EACCES] = -13,
+ [EFAULT] = -14,
+ [EBUSY] = -16,
+ [EEXIST] = -17,
+ [EXDEV] = -18,
+ [ENODEV] = -19,
+ [ENOTDIR] = -20,
+ [EISDIR] = -21,
+ [EINVAL] = -22,
+ [ENFILE] = -23,
+ [EMFILE] = -24,
+ [ENOTTY] = -25,
+ [EFBIG] = -27,
+ [ENOSPC] = -28,
+ [ESPIPE] = -29,
+ [EROFS] = -30,
+ [EMLINK] = -31,
+ [EPIPE] = -32,
+ [EDOM] = -33,
+ [ERANGE] = -34,
+ [EDEADLK] = -35,
+ [ENAMETOOLONG] = -36,
+ [ENOLCK] = -37,
+ [ENOSYS] = -38,
+ [ENOTEMPTY] = -39,
+ [EILSEQ] = -84,
+};
+
+static const int generic_to_arch_table[] = {
+ [0] = 0,
+ [1] = -EPERM,
+ [2] = -ENOENT,
+ [3] = -ESRCH,
+ [4] = -EINTR,
+ [5] = -EIO,
+ [6] = -ENXIO,
+ [7] = -E2BIG,
+ [8] = -ENOEXEC,
+ [9] = -EBADF,
+ [10] = -ECHILD,
+ [11] = -EAGAIN,
+ [12] = -ENOMEM,
+ [13] = -EACCES,
+ [14] = -EFAULT,
+ [16] = -EBUSY,
+ [17] = -EEXIST,
+ [18] = -EXDEV,
+ [19] = -ENODEV,
+ [20] = -ENOTDIR,
+ [21] = -EISDIR,
+ [22] = -EINVAL,
+ [23] = -ENFILE,
+ [24] = -EMFILE,
+ [25] = -ENOTTY,
+ [27] = -EFBIG,
+ [28] = -ENOSPC,
+ [29] = -ESPIPE,
+ [30] = -EROFS,
+ [31] = -EMLINK,
+ [32] = -EPIPE,
+ [33] = -EDOM,
+ [34] = -ERANGE,
+ [35] = -EDEADLK,
+ [36] = -ENAMETOOLONG,
+ [37] = -ENOLCK,
+ [38] = -ENOSYS,
+ [39] = -ENOTEMPTY,
+ [84] = -EILSEQ,
+};

0 comments on commit 39b416a

Please sign in to comment.