return 0;
}
+int adjust_shared_perm(const char *path)
+{
+ struct stat st;
+ int mode;
+
+ if (!shared_repository)
+ return 0;
+ if (lstat(path, &st) < 0)
+ return -1;
+ mode = st.st_mode;
+ if (mode & S_IRUSR)
+ mode |= S_IRGRP;
+ if (mode & S_IWUSR)
+ mode |= S_IWGRP;
+ if (mode & S_IXUSR)
+ mode |= S_IXGRP;
+ if (S_ISDIR(mode))
+ mode |= S_ISGID;
+ if (chmod(path, mode) < 0)
+ return -2;
+ return 0;
+}
+
int safe_create_leading_directories(char *path)
{
char *pos = path;
if (!pos)
break;
*pos = 0;
- if (mkdir(path, 0777) < 0)
+ if (mkdir(path, 0777) < 0) {
if (errno != EEXIST) {
*pos = '/';
return -1;
}
+ }
+ else if (adjust_shared_perm(path)) {
+ *pos = '/';
+ return -2;
+ }
*pos++ = '/';
}
return 0;
*buf++ = hex[val >> 4];
*buf++ = hex[val & 0xf];
}
+ *buf = '\0';
+
return buffer;
}
* alternate_object_database. The elements on this list come from
* non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
* environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
- * whose contents is exactly in the same format as that environment
- * variable. Its base points at a statically allocated buffer that
+ * whose contents is similar to that environment variable but can be
+ * LF separated. Its base points at a statically allocated buffer that
* contains "/the/directory/corresponding/to/.git/objects/...", while
* its name points just after the slash at the end of ".git/objects/"
* in the example above, and has enough space to hold 40-byte hex
{
const char *cp, *last;
struct alternate_object_database *ent;
+ const char *objdir = get_object_directory();
int base_len = -1;
last = alt;
for ( ; cp < ep && *cp != sep; cp++)
;
if (last != cp) {
+ struct alternate_object_database *alt;
/* 43 = 40-byte + 2 '/' + terminating NUL */
int pfxlen = cp - last;
int entlen = pfxlen + 43;
pfxlen += base_len;
}
ent = xmalloc(sizeof(*ent) + entlen);
- *alt_odb_tail = ent;
- alt_odb_tail = &(ent->next);
- ent->next = NULL;
+
if (*last != '/' && relative_base) {
memcpy(ent->base, relative_base, base_len - 1);
ent->base[base_len - 1] = '/';
ent->name = ent->base + pfxlen + 1;
ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
ent->base[entlen-1] = 0;
+
+ /* Prevent the common mistake of listing the same
+ * thing twice, or object directory itself.
+ */
+ for (alt = alt_odb_list; alt; alt = alt->next)
+ if (!memcmp(ent->base, alt->base, pfxlen))
+ goto bad;
+ if (!memcmp(ent->base, objdir, pfxlen)) {
+ bad:
+ free(ent);
+ }
+ else {
+ *alt_odb_tail = ent;
+ alt_odb_tail = &(ent->next);
+ ent->next = NULL;
+ }
}
while (cp < ep && *cp == sep)
cp++;
static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
void **idx_map_)
{
+ SHA_CTX ctx;
+ unsigned char sha1[20];
void *idx_map;
unsigned int *index;
unsigned long idx_size;
int nr, i;
- int fd = open(path, O_RDONLY);
+ int fd;
struct stat st;
+
+ fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
if (fstat(fd, &st)) {
if (idx_size != 4*256 + nr * 24 + 20 + 20)
return error("wrong index file size");
+ /*
+ * File checksum.
+ */
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, idx_map, idx_size-20);
+ SHA1_Final(sha1, &ctx);
+
+ if (memcmp(sha1, idx_map + idx_size - 20, 20))
+ return error("index checksum mismatch");
+
return 0;
}
struct packed_git *p;
unsigned long idx_size;
void *idx_map;
+ unsigned char sha1[20];
if (check_packed_git_idx(path, &idx_size, &idx_map))
return NULL;
p->pack_last_used = 0;
p->pack_use_cnt = 0;
p->pack_local = local;
+ if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
+ memcpy(p->sha1, sha1, 20);
return p;
}
prepare_packed_git_one(get_object_directory(), 1);
prepare_alt_odb();
for (alt = alt_odb_list; alt; alt = alt->next) {
- alt->name[0] = 0;
+ alt->name[-1] = 0;
prepare_packed_git_one(alt->base, 0);
+ alt->name[-1] = '/';
}
run_once = 1;
}
if (dir) {
*dir = 0;
mkdir(filename, 0777);
+ if (adjust_shared_perm(filename))
+ return -2;
*dir = '/';
if (!link(tmpfile, filename))
return 0;
unlink(tmpfile);
if (ret) {
if (ret != EEXIST) {
- fprintf(stderr, "unable to write sha1 filename %s: %s", filename, strerror(ret));
+ fprintf(stderr, "unable to write sha1 filename %s: %s\n", filename, strerror(ret));
return -1;
}
/* FIXME!!! Collision check here ? */
}
if (errno != ENOENT) {
- fprintf(stderr, "sha1 file %s: %s", filename, strerror(errno));
+ fprintf(stderr, "sha1 file %s: %s\n", filename, strerror(errno));
return -1;
}
fd = mkstemp(tmpfile);
if (fd < 0) {
- fprintf(stderr, "unable to create temporary sha1 filename %s: %s", tmpfile, strerror(errno));
+ fprintf(stderr, "unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno));
return -1;
}
size = write(fd, buf + posn, objsize - posn);
if (size <= 0) {
if (!size) {
- fprintf(stderr, "write closed");
+ fprintf(stderr, "write closed\n");
} else {
perror("write ");
}
return find_sha1_file(sha1, &st) ? 1 : 0;
}
+int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
+{
+ unsigned long size = 4096;
+ char *buf = malloc(size);
+ int iret, ret;
+ unsigned long off = 0;
+ unsigned char hdr[50];
+ int hdrlen;
+ do {
+ iret = read(fd, buf + off, size - off);
+ if (iret > 0) {
+ off += iret;
+ if (off == size) {
+ size *= 2;
+ buf = realloc(buf, size);
+ }
+ }
+ } while (iret > 0);
+ if (iret < 0) {
+ free(buf);
+ return -1;
+ }
+ if (!type)
+ type = "blob";
+ if (write_object)
+ ret = write_sha1_file(buf, off, type, sha1);
+ else {
+ write_sha1_file_prepare(buf, off, type, sha1, hdr, &hdrlen);
+ ret = 0;
+ }
+ free(buf);
+ return ret;
+}
+
int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type)
{
unsigned long size = st->st_size;