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 == '/')
+ pos++;
while (pos) {
pos = strchr(pos, '/');
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++;
return 0;
}
-struct packed_git *add_packed_git(char *path, int path_len)
+struct packed_git *add_packed_git(char *path, int path_len, int local)
{
struct stat st;
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_base = 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;
}
packed_git = pack;
}
-static void prepare_packed_git_one(char *objdir)
+static void prepare_packed_git_one(char *objdir, int local)
{
char path[PATH_MAX];
int len;
/* we have .idx. Is it a file we can map? */
strcpy(path + len, de->d_name);
- p = add_packed_git(path, len + namelen);
+ p = add_packed_git(path, len + namelen, local);
if (!p)
continue;
p->next = packed_git;
if (run_once)
return;
- prepare_packed_git_one(get_object_directory());
+ prepare_packed_git_one(get_object_directory(), 1);
prepare_alt_odb();
for (alt = alt_odb_list; alt; alt = alt->next) {
- alt->name[0] = 0;
- prepare_packed_git_one(alt->base);
+ 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;
int move_temp_to_file(const char *tmpfile, char *filename)
{
int ret = link_temp_to_file(tmpfile, filename);
- if (ret) {
- /*
- * Coda hack - coda doesn't like cross-directory links,
- * so we fall back to a rename, which will mean that it
- * won't be able to check collisions, but that's not a
- * big deal.
- *
- * When this succeeds, we just return 0. We have nothing
- * left to unlink.
- */
- if (ret == EXDEV && !rename(tmpfile, filename))
+
+ /*
+ * Coda hack - coda doesn't like cross-directory links,
+ * so we fall back to a rename, which will mean that it
+ * won't be able to check collisions, but that's not a
+ * big deal.
+ *
+ * The same holds for FAT formatted media.
+ *
+ * When this succeeds, we just return 0. We have nothing
+ * left to unlink.
+ */
+ if (ret && ret != EEXIST) {
+ if (!rename(tmpfile, filename))
return 0;
+ ret = errno;
}
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;