@@ -0,0 +1,139 @@
+#include "refs.h"
+#include "cache.h"
+
+#include <errno.h>
+
+static char *split_ref_file_name(const char *dir, const char *name)
+{
+ char *base = get_refs_directory();
+ int baselen = strlen(base);
+ int dirlen = strlen(dir);
+ int namelen = strlen(name);
+ char *ret;
+ if (dir[0] == '.')
+ return NULL;
+ if (strchr(dir, '/'))
+ return NULL;
+ if (strchr(name, '/'))
+ return NULL;
+ ret = xmalloc(baselen + 3 + dirlen + namelen);
+ strcpy(ret, base);
+ ret[baselen] = '/';
+ strcpy(ret + baselen + 1, dir);
+ ret[baselen + 1 + dirlen] = '/';
+ strcpy(ret + baselen + 2 + dirlen, name);
+ ret[baselen + 2 + dirlen + namelen] = '\0';
+ return ret;
+}
+
+static char *ref_file_name(const char *ref)
+{
+ char *base = get_refs_directory();
+ int baselen = strlen(base);
+ int reflen = strlen(ref);
+ char *ret;
+ char *check;
+ if (ref[0] == '.')
+ return NULL;
+ check = strchr(ref, '/');
+ if (!check)
+ return NULL;
+ if (strchr(check + 1, '/'))
+ return NULL;
+ ret = xmalloc(baselen + 2 + reflen);
+ strcpy(ret, base);
+ ret[baselen] = '/';
+ strcpy(ret + baselen + 1, ref);
+ ret[baselen + 1 + reflen] = '\0';
+ return ret;
+}
+
+static int read_ref_file(char *filename, unsigned char *sha1) {
+ int fd = open(filename, O_RDONLY);
+ char hex[41];
+ if (fd < 0) {
+ return error("Couldn't open %s\n", filename);
+ }
+ if ((read(fd, hex, 41) < 41) ||
+ (hex[40] != '\n') ||
+ get_sha1_hex(hex, sha1)) {
+ error("Couldn't read a hash from %s\n", filename);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
+int get_split_ref_sha1(const char *dir, const char *name, unsigned char *sha1)
+{
+ char *filename = split_ref_file_name(dir, name);
+ int retval;
+ if (!filename)
+ return -1;
+ retval = read_ref_file(filename, sha1);
+ free(filename);
+ return retval;
+}
+
+int get_ref_sha1(const char *ref, unsigned char *sha1)
+{
+ char *filename = ref_file_name(ref);
+ int retval;
+ if (!filename)
+ return -1;
+ retval = read_ref_file(filename, sha1);
+ free(filename);
+ return retval;
+}
+
+int write_split_ref_sha1(const char *dir, const char *name,
+ unsigned char *sha1)
+{
+ char *filename = split_ref_file_name(dir, name);
+ char *hex = sha1_to_hex(sha1);
+ char term = '\n';
+ int fd;
+ if (!filename)
+ return -1;
+ unlink(filename);
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (fd < 0 && errno == ENOENT) {
+ char *dirname = split_ref_file_name(dir, "");
+ mkdir(dirname, 0755);
+ free(dirname);
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ }
+ if (fd < 0) {
+ error("Couldn't open for writing %s: %s\n", filename,
+ strerror(errno));
+ free(filename);
+ return -1;
+ }
+ if (write(fd, hex, 40) < 40 ||
+ write(fd, &term, 1) < 1) {
+ error("Couldn't write %s\n", filename);
+ free(filename);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 0;
+
+}
+
+int split_ref(char **dir, char **name, const char *ref)
+{
+ char *middle = strchr(ref, '/');
+ if (ref[0] == '.')
+ return -1;
+ if (!middle)
+ return -1;
+ if (strchr(middle + 1, '/'))
+ return -1;
+ *dir = xmalloc(middle - ref + 1);
+ *name = strdup(middle + 1);
+ (*dir)[middle - ref] = '\0';
+ memcpy(*dir, ref, middle - ref);
+ return 0;
+}