Skip to content

Commit

Permalink
Make fiel checkout function available to the git library
Browse files Browse the repository at this point in the history
The merge stuff will want it soon, and we don't want to
duplicate all the work..
  • Loading branch information
Linus Torvalds committed Jun 6, 2005
1 parent 76f3834 commit 12dccc1
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 174 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ install: $(PROG) $(SCRIPTS)
$(INSTALL) $(PROG) $(SCRIPTS) $(dest)$(bin)

LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
tag.o delta.o date.o index.o diff-delta.o patch-delta.o
tag.o delta.o date.o index.o diff-delta.o patch-delta.o entry.o
LIB_FILE=libgit.a
LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h

Expand Down
11 changes: 11 additions & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,15 @@ static inline void *xcalloc(size_t nmemb, size_t size)
return ret;
}

struct checkout {
const char *base_dir;
int base_dir_len;
unsigned force:1,
quiet:1,
not_new:1,
refresh_cache:1;
};

extern int checkout_entry(struct cache_entry *ce, struct checkout *state);

#endif /* CACHE_H */
193 changes: 20 additions & 173 deletions checkout-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,175 +32,22 @@
* of "-a" causing problems (not possible in the above example,
* but get used to it in scripting!).
*/
#include <sys/types.h>
#include <dirent.h>
#include "cache.h"

static int force = 0, quiet = 0, not_new = 0, refresh_cache = 0;
static const char *base_dir = "";
static int base_dir_len = 0;

static void create_directories(const char *path)
{
int len = strlen(path);
char *buf = xmalloc(len + 1);
const char *slash = path;

while ((slash = strchr(slash+1, '/')) != NULL) {
len = slash - path;
memcpy(buf, path, len);
buf[len] = 0;
if (mkdir(buf, 0755)) {
if (errno == EEXIST) {
struct stat st;
if (len > base_dir_len && force && !unlink(buf) && !mkdir(buf, 0755))
continue;
if (!stat(buf, &st) && S_ISDIR(st.st_mode))
continue; /* ok */
}
die("cannot create directory at %s", buf);
}
}
free(buf);
}

static void remove_subtree(const char *path)
{
DIR *dir = opendir(path);
struct dirent *de;
char pathbuf[PATH_MAX];
char *name;

if (!dir)
die("cannot opendir %s", path);
strcpy(pathbuf, path);
name = pathbuf + strlen(path);
*name++ = '/';
while ((de = readdir(dir)) != NULL) {
struct stat st;
if ((de->d_name[0] == '.') &&
((de->d_name[1] == 0) ||
((de->d_name[1] == '.') && de->d_name[2] == 0)))
continue;
strcpy(name, de->d_name);
if (lstat(pathbuf, &st))
die("cannot lstat %s", pathbuf);
if (S_ISDIR(st.st_mode))
remove_subtree(pathbuf);
else if (unlink(pathbuf))
die("cannot unlink %s", pathbuf);
}
closedir(dir);
if (rmdir(path))
die("cannot rmdir %s", path);
}

static int create_file(const char *path, unsigned int mode)
{
int fd;

mode = (mode & 0100) ? 0777 : 0666;
create_directories(path);
fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
if (fd < 0) {
if (errno == EISDIR && force) {
remove_subtree(path);
fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
}
}
return fd;
}

static int write_entry(struct cache_entry *ce, const char *path)
{
int fd;
void *new;
unsigned long size;
long wrote;
char type[20];
char target[1024];

new = read_sha1_file(ce->sha1, type, &size);
if (!new || strcmp(type, "blob")) {
if (new)
free(new);
return error("git-checkout-cache: unable to read sha1 file of %s (%s)",
path, sha1_to_hex(ce->sha1));
}
switch (ntohl(ce->ce_mode) & S_IFMT) {
case S_IFREG:
fd = create_file(path, ntohl(ce->ce_mode));
if (fd < 0) {
free(new);
return error("git-checkout-cache: unable to create file %s (%s)",
path, strerror(errno));
}
wrote = write(fd, new, size);
close(fd);
free(new);
if (wrote != size)
return error("git-checkout-cache: unable to write file %s", path);
break;
case S_IFLNK:
memcpy(target, new, size);
target[size] = '\0';
create_directories(path);
if (symlink(target, path)) {
free(new);
return error("git-checkout-cache: unable to create symlink %s (%s)",
path, strerror(errno));
}
free(new);
break;
default:
free(new);
return error("git-checkout-cache: unknown file mode for %s", path);
}

if (refresh_cache) {
struct stat st;
lstat(ce->name, &st);
fill_stat_cache_info(ce, &st);
}
return 0;
}

static int checkout_entry(struct cache_entry *ce)
{
struct stat st;
static char path[MAXPATHLEN+1];
int len = base_dir_len;

memcpy(path, base_dir, len);
strcpy(path + len, ce->name);

if (!lstat(path, &st)) {
unsigned changed = ce_match_stat(ce, &st);
if (!changed)
return 0;
if (!force) {
if (!quiet)
fprintf(stderr, "git-checkout-cache: %s already exists\n", path);
return 0;
}

/*
* We unlink the old file, to get the new one with the
* right permissions (including umask, which is nasty
* to emulate by hand - much easier to let the system
* just do the right thing)
*/
unlink(path);
} else if (not_new)
return 0;
return write_entry(ce, path);
}
static struct checkout state = {
.base_dir = "",
.base_dir_len = 0,
.force = 0,
.quiet = 0,
.not_new = 0,
.refresh_cache = 0,
};

static int checkout_file(const char *name)
{
int pos = cache_name_pos(name, strlen(name));
if (pos < 0) {
if (!quiet) {
if (!state.quiet) {
pos = -pos - 1;
fprintf(stderr,
"git-checkout-cache: %s is %s.\n",
Expand All @@ -211,7 +58,7 @@ static int checkout_file(const char *name)
}
return -1;
}
return checkout_entry(active_cache[pos]);
return checkout_entry(active_cache[pos], &state);
}

static int checkout_all(void)
Expand All @@ -222,7 +69,7 @@ static int checkout_all(void)
struct cache_entry *ce = active_cache[i];
if (ce_stage(ce))
continue;
if (checkout_entry(ce) < 0)
if (checkout_entry(ce, &state) < 0)
return -1;
}
return 0;
Expand Down Expand Up @@ -250,19 +97,19 @@ int main(int argc, char **argv)
continue;
}
if (!strcmp(arg, "-f")) {
force = 1;
state.force = 1;
continue;
}
if (!strcmp(arg, "-q")) {
quiet = 1;
state.quiet = 1;
continue;
}
if (!strcmp(arg, "-n")) {
not_new = 1;
state.not_new = 1;
continue;
}
if (!strcmp(arg, "-u")) {
refresh_cache = 1;
state.refresh_cache = 1;
if (newfd < 0)
newfd = hold_index_file_for_update
(&cache_file,
Expand All @@ -272,20 +119,20 @@ int main(int argc, char **argv)
continue;
}
if (!memcmp(arg, "--prefix=", 9)) {
base_dir = arg+9;
base_dir_len = strlen(base_dir);
state.base_dir = arg+9;
state.base_dir_len = strlen(state.base_dir);
continue;
}
}
if (base_dir_len) {
if (state.base_dir_len) {
/* when --prefix is specified we do not
* want to update cache.
*/
if (refresh_cache) {
if (state.refresh_cache) {
close(newfd); newfd = -1;
rollback_index_file(&cache_file);
}
refresh_cache = 0;
state.refresh_cache = 0;
}
checkout_file(arg);
}
Expand Down
Loading

0 comments on commit 12dccc1

Please sign in to comment.