const char *sha1_file_directory = NULL;
+#ifndef O_NOATIME
+#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
+#define O_NOATIME 01000000
+#else
+#define O_NOATIME 0
+#endif
+#endif
+
+static unsigned int sha1_file_open_flag = O_NOATIME;
+
static unsigned hexval(char c)
{
if (c >= '0' && c <= '9')
void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
{
char *filename = sha1_file_name(sha1);
- int fd = open(filename, O_RDONLY);
struct stat st;
void *map;
+ int fd;
+ fd = open(filename, O_RDONLY | sha1_file_open_flag);
if (fd < 0) {
- perror(filename);
- return NULL;
+ /* See if it works without O_NOATIME */
+ switch (sha1_file_open_flag) {
+ default:
+ fd = open(filename, O_RDONLY);
+ if (fd >= 0)
+ break;
+ /* Fallthrough */
+ case 0:
+ perror(filename);
+ return NULL;
+ }
+
+ /* If it failed once, it will probably fail again. Stop using O_NOATIME */
+ sha1_file_open_flag = 0;
}
if (fstat(fd, &st) < 0) {
close(fd);
return NULL;
}
+void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
+ unsigned long *size,
+ unsigned char *tree_sha1_return)
+{
+ char type[20];
+ void *buffer;
+ unsigned long isize;
+ int was_commit = 0;
+ unsigned char tree_sha1[20];
+
+ buffer = read_sha1_file(sha1, type, &isize);
+
+ /*
+ * We might have read a commit instead of a tree, in which case
+ * we parse out the tree_sha1 and attempt to read from there.
+ * (buffer + 5) is because the tree sha1 is always at offset 5
+ * in a commit record ("tree ").
+ */
+ if (buffer &&
+ !strcmp(type, "commit") &&
+ !get_sha1_hex(buffer + 5, tree_sha1)) {
+ free(buffer);
+ buffer = read_sha1_file(tree_sha1, type, &isize);
+ was_commit = 1;
+ }
+
+ /*
+ * Now do we have something and if so is it a tree?
+ */
+ if (!buffer || strcmp(type, "tree")) {
+ free(buffer);
+ return NULL;
+ }
+
+ *size = isize;
+ if (tree_sha1_return)
+ memcpy(tree_sha1_return, was_commit ? tree_sha1 : sha1, 20);
+ return buffer;
+}
+
int write_sha1_file(char *buf, unsigned len, unsigned char *returnsha1)
{
int size;
z_stream stream;
unsigned char sha1[20];
SHA_CTX c;
+ char *filename;
+ int fd;
/* Sha1.. */
SHA1_Init(&c);
SHA1_Update(&c, buf, len);
SHA1_Final(sha1, &c);
+ if (returnsha1)
+ memcpy(returnsha1, sha1, 20);
+
+ filename = sha1_file_name(sha1);
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (fd < 0) {
+ if (errno != EEXIST)
+ return -1;
+
+ /*
+ * We might do collision checking here, but we'd need to
+ * uncompress the old file and check it. Later.
+ */
+ return 0;
+ }
+
/* Set it up */
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, Z_BEST_COMPRESSION);
deflateEnd(&stream);
size = stream.total_out;
- if (write_sha1_buffer(sha1, compressed, size) < 0)
- return -1;
- if (returnsha1)
- memcpy(returnsha1, sha1, 20);
+ if (write(fd, compressed, size) != size)
+ die("unable to write file");
+ close(fd);
+
return 0;
}