]>
Commit | Line | Data |
---|---|---|
33db5f4d LT |
1 | /* |
2 | * Check-out files from the "current cache directory" | |
3 | * | |
4 | * Copyright (C) 2005 Linus Torvalds | |
5 | * | |
6 | * Careful: order of argument flags does matter. For example, | |
7 | * | |
8 | * checkout-cache -a -f file.c | |
9 | * | |
10 | * Will first check out all files listed in the cache (but not | |
11 | * overwrite any old ones), and then force-checkout "file.c" a | |
12 | * second time (ie that one _will_ overwrite any old contents | |
13 | * with the same filename). | |
14 | * | |
15 | * Also, just doing "checkout-cache" does nothing. You probably | |
16 | * meant "checkout-cache -a". And if you want to force it, you | |
17 | * want "checkout-cache -f -a". | |
18 | * | |
19 | * Intuitiveness is not the goal here. Repeatability is. The | |
20 | * reason for the "no arguments means no work" thing is that | |
21 | * from scripts you are supposed to be able to do things like | |
22 | * | |
23 | * find . -name '*.h' -print0 | xargs -0 checkout-cache -f -- | |
24 | * | |
25 | * which will force all existing *.h files to be replaced with | |
26 | * their cached copies. If an empty command line implied "all", | |
27 | * then this would force-refresh everything in the cache, which | |
28 | * was not the point. | |
29 | * | |
30 | * Oh, and the "--" is just a good idea when you know the rest | |
31 | * will be filenames. Just so that you wouldn't have a filename | |
32 | * of "-a" causing problems (not possible in the above example, | |
33 | * but get used to it in scripting!). | |
34 | */ | |
35 | #include "cache.h" | |
36 | ||
37 | static int force = 0, quiet = 0; | |
38 | ||
83adac3c LT |
39 | static void create_directories(const char *path) |
40 | { | |
41 | int len = strlen(path); | |
42 | char *buf = malloc(len + 1); | |
43 | const char *slash = path; | |
44 | ||
45 | while ((slash = strchr(slash+1, '/')) != NULL) { | |
46 | len = slash - path; | |
47 | memcpy(buf, path, len); | |
48 | buf[len] = 0; | |
cfd88e2b | 49 | mkdir(buf, 0755); |
83adac3c LT |
50 | } |
51 | } | |
52 | ||
53 | static int create_file(const char *path, unsigned int mode) | |
54 | { | |
e4479470 LT |
55 | int fd; |
56 | ||
fa06d442 | 57 | mode = (mode & 0100) ? 0777 : 0666; |
e4479470 | 58 | fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode); |
83adac3c LT |
59 | if (fd < 0) { |
60 | if (errno == ENOENT) { | |
61 | create_directories(path); | |
e4479470 | 62 | fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode); |
83adac3c LT |
63 | } |
64 | } | |
83adac3c LT |
65 | return fd; |
66 | } | |
67 | ||
65bb4914 | 68 | static int write_entry(struct cache_entry *ce, const char *path) |
33db5f4d LT |
69 | { |
70 | int fd; | |
71 | void *new; | |
72 | unsigned long size; | |
73 | long wrote; | |
8d3af1d5 | 74 | char type[20]; |
33db5f4d | 75 | |
8d3af1d5 LT |
76 | new = read_sha1_file(ce->sha1, type, &size); |
77 | if (!new || strcmp(type, "blob")) { | |
2de381f9 | 78 | return error("checkout-cache: unable to read sha1 file of %s (%s)", |
65bb4914 | 79 | path, sha1_to_hex(ce->sha1)); |
33db5f4d | 80 | } |
65bb4914 | 81 | fd = create_file(path, ntohl(ce->ce_mode)); |
33db5f4d | 82 | if (fd < 0) { |
33db5f4d | 83 | free(new); |
2de381f9 | 84 | return error("checkout-cache: unable to create %s (%s)", |
65bb4914 | 85 | path, strerror(errno)); |
33db5f4d LT |
86 | } |
87 | wrote = write(fd, new, size); | |
88 | close(fd); | |
89 | free(new); | |
2de381f9 | 90 | if (wrote != size) |
65bb4914 | 91 | return error("checkout-cache: unable to write %s", path); |
2de381f9 | 92 | return 0; |
33db5f4d LT |
93 | } |
94 | ||
65bb4914 | 95 | static int checkout_entry(struct cache_entry *ce, const char *base_dir) |
33db5f4d | 96 | { |
29d76d4b | 97 | struct stat st; |
65bb4914 LT |
98 | static char path[MAXPATHLEN+1]; |
99 | int len = strlen(base_dir); | |
100 | ||
101 | memcpy(path, base_dir, len); | |
102 | strcpy(path + len, ce->name); | |
33db5f4d | 103 | |
65bb4914 | 104 | if (!stat(path, &st)) { |
29d76d4b LT |
105 | unsigned changed = cache_match_stat(ce, &st); |
106 | if (!changed) | |
107 | return 0; | |
108 | if (!force) { | |
109 | if (!quiet) | |
65bb4914 | 110 | fprintf(stderr, "checkout-cache: %s already exists\n", path); |
f7391ce3 | 111 | return 0; |
33db5f4d | 112 | } |
e4479470 LT |
113 | |
114 | /* | |
115 | * We unlink the old file, to get the new one with the | |
116 | * right permissions (including umask, which is nasty | |
117 | * to emulate by hand - much easier to let the system | |
118 | * just do the right thing) | |
119 | */ | |
65bb4914 | 120 | unlink(path); |
33db5f4d | 121 | } |
65bb4914 | 122 | return write_entry(ce, path); |
33db5f4d LT |
123 | } |
124 | ||
65bb4914 | 125 | static int checkout_file(const char *name, const char *base_dir) |
33db5f4d LT |
126 | { |
127 | int pos = cache_name_pos(name, strlen(name)); | |
128 | if (pos < 0) { | |
a38800fd JH |
129 | if (!quiet) { |
130 | pos = -pos - 1; | |
131 | fprintf(stderr, | |
132 | "checkout-cache: %s is %s.\n", | |
133 | name, | |
134 | (pos < active_nr && | |
135 | !strcmp(active_cache[pos]->name, name)) ? | |
136 | "unmerged" : "not in the cache"); | |
137 | } | |
33db5f4d LT |
138 | return -1; |
139 | } | |
65bb4914 | 140 | return checkout_entry(active_cache[pos], base_dir); |
33db5f4d LT |
141 | } |
142 | ||
65bb4914 | 143 | static int checkout_all(const char *base_dir) |
33db5f4d LT |
144 | { |
145 | int i; | |
146 | ||
147 | for (i = 0; i < active_nr ; i++) { | |
148 | struct cache_entry *ce = active_cache[i]; | |
d9f98eeb LT |
149 | if (ce_stage(ce)) |
150 | continue; | |
65bb4914 | 151 | if (checkout_entry(ce, base_dir) < 0) |
33db5f4d LT |
152 | return -1; |
153 | } | |
154 | return 0; | |
155 | } | |
156 | ||
157 | int main(int argc, char **argv) | |
158 | { | |
159 | int i, force_filename = 0; | |
65bb4914 | 160 | const char *base_dir = ""; |
33db5f4d LT |
161 | |
162 | if (read_cache() < 0) { | |
2de381f9 | 163 | die("invalid cache"); |
33db5f4d LT |
164 | } |
165 | ||
166 | for (i = 1; i < argc; i++) { | |
167 | const char *arg = argv[i]; | |
168 | if (!force_filename) { | |
169 | if (!strcmp(arg, "-a")) { | |
65bb4914 | 170 | checkout_all(base_dir); |
33db5f4d LT |
171 | continue; |
172 | } | |
173 | if (!strcmp(arg, "--")) { | |
174 | force_filename = 1; | |
175 | continue; | |
176 | } | |
177 | if (!strcmp(arg, "-f")) { | |
178 | force = 1; | |
179 | continue; | |
180 | } | |
181 | if (!strcmp(arg, "-q")) { | |
182 | quiet = 1; | |
183 | continue; | |
184 | } | |
65bb4914 LT |
185 | if (!memcmp(arg, "--prefix=", 9)) { |
186 | base_dir = arg+9; | |
187 | continue; | |
188 | } | |
33db5f4d | 189 | } |
65bb4914 | 190 | checkout_file(arg, base_dir); |
33db5f4d LT |
191 | } |
192 | return 0; | |
193 | } |