Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 320 lines (285 sloc) 7.869 kb
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
1 #include "cache.h"
8e44025 Use blob_, commit_, tag_, and tree_type throughout.
Peter Eriksen authored
2 #include "blob.h"
8ca12c0 @aspotashev add is_dot_or_dotdot inline function
aspotashev authored
3 #include "dir.h"
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
4 #include "streaming.h"
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
5
81a9aa6 create_directories(): remove some memcpy() and strchr() calls
Kjetil Barvik authored
6 static void create_directories(const char *path, int path_len,
7 const struct checkout *state)
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
8 {
81a9aa6 create_directories(): remove some memcpy() and strchr() calls
Kjetil Barvik authored
9 char *buf = xmalloc(path_len + 1);
10 int len = 0;
11
12 while (len < path_len) {
13 do {
14 buf[len] = path[len];
15 len++;
16 } while (len < path_len && path[len] != '/');
17 if (len >= path_len)
18 break;
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
19 buf[len] = 0;
fa2e71c @gitster Do not expect unlink(2) to fail on a directory.
gitster authored
20
bad4a54 lstat_cache(): introduce has_dirs_only_path() function
Kjetil Barvik authored
21 /*
22 * For 'checkout-index --prefix=<dir>', <dir> is
23 * allowed to be a symlink to an existing directory,
24 * and we set 'state->base_dir_len' below, such that
25 * we test the path components of the prefix with the
26 * stat() function instead of the lstat() function.
27 */
5719989 lstat_cache(): swap func(length, string) into func(string, length)
Kjetil Barvik authored
28 if (has_dirs_only_path(buf, len, state->base_dir_len))
fa2e71c @gitster Do not expect unlink(2) to fail on a directory.
gitster authored
29 continue; /* ok, it is already a directory. */
30
31 /*
bad4a54 lstat_cache(): introduce has_dirs_only_path() function
Kjetil Barvik authored
32 * If this mkdir() would fail, it could be that there
33 * is already a symlink or something else exists
34 * there, therefore we then try to unlink it and try
35 * one more time to create the directory.
fa2e71c @gitster Do not expect unlink(2) to fail on a directory.
gitster authored
36 */
f312de0 [PATCH] Let umask do its work upon filesystem object creation.
Junio C Hamano authored
37 if (mkdir(buf, 0777)) {
fa2e71c @gitster Do not expect unlink(2) to fail on a directory.
gitster authored
38 if (errno == EEXIST && state->force &&
691f1a2 @raalkml replace direct calls to unlink(2) with unlink_or_warn
raalkml authored
39 !unlink_or_warn(buf) && !mkdir(buf, 0777))
fa2e71c @gitster Do not expect unlink(2) to fail on a directory.
gitster authored
40 continue;
0721c31 @trast Use die_errno() instead of die() when checking syscalls
trast authored
41 die_errno("cannot create directory at '%s'", buf);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
42 }
43 }
44 free(buf);
45 }
46
47 static void remove_subtree(const char *path)
48 {
49 DIR *dir = opendir(path);
50 struct dirent *de;
51 char pathbuf[PATH_MAX];
52 char *name;
a6080a0 @gitster War on whitespace
gitster authored
53
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
54 if (!dir)
d824cbb @trast Convert existing die(..., strerror(errno)) to die_errno()
trast authored
55 die_errno("cannot opendir '%s'", path);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
56 strcpy(pathbuf, path);
57 name = pathbuf + strlen(path);
58 *name++ = '/';
59 while ((de = readdir(dir)) != NULL) {
60 struct stat st;
8ca12c0 @aspotashev add is_dot_or_dotdot inline function
aspotashev authored
61 if (is_dot_or_dotdot(de->d_name))
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
62 continue;
63 strcpy(name, de->d_name);
64 if (lstat(pathbuf, &st))
d824cbb @trast Convert existing die(..., strerror(errno)) to die_errno()
trast authored
65 die_errno("cannot lstat '%s'", pathbuf);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
66 if (S_ISDIR(st.st_mode))
67 remove_subtree(pathbuf);
68 else if (unlink(pathbuf))
d824cbb @trast Convert existing die(..., strerror(errno)) to die_errno()
trast authored
69 die_errno("cannot unlink '%s'", pathbuf);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
70 }
71 closedir(dir);
72 if (rmdir(path))
d824cbb @trast Convert existing die(..., strerror(errno)) to die_errno()
trast authored
73 die_errno("cannot rmdir '%s'", path);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
74 }
75
d48a72f Fix replacing of a directory with a file/symlink in git-checkout-cache
Linus Torvalds authored
76 static int create_file(const char *path, unsigned int mode)
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
77 {
78 mode = (mode & 0100) ? 0777 : 0666;
781411e @raalkml trivial: O_EXCL makes O_TRUNC redundant
raalkml authored
79 return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
80 }
81
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
82 static void *read_blob_entry(struct cache_entry *ce, unsigned long *size)
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
83 {
84 enum object_type type;
85 void *new = read_sha1_file(ce->sha1, &type, size);
86
87 if (new) {
88 if (type == OBJ_BLOB)
89 return new;
90 free(new);
91 }
92 return NULL;
93 }
94
fd5db55 @gitster write_entry(): separate two helper functions out
gitster authored
95 static int open_output_fd(char *path, struct cache_entry *ce, int to_tempfile)
96 {
97 int symlink = (ce->ce_mode & S_IFMT) != S_IFREG;
98 if (to_tempfile) {
99 strcpy(path, symlink
100 ? ".merge_link_XXXXXX" : ".merge_file_XXXXXX");
101 return mkstemp(path);
102 } else {
103 return create_file(path, !symlink ? ce->ce_mode : 0666);
104 }
105 }
106
107 static int fstat_output(int fd, const struct checkout *state, struct stat *st)
108 {
109 /* use fstat() only when path == ce->name */
110 if (fstat_is_reliable() &&
111 state->refresh_cache && !state->base_dir_len) {
112 fstat(fd, st);
113 return 1;
114 }
115 return 0;
116 }
117
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
118 static int streaming_write_entry(struct cache_entry *ce, char *path,
b669109 @gitster Add streaming filter API
gitster authored
119 struct stream_filter *filter,
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
120 const struct checkout *state, int to_tempfile,
121 int *fstat_done, struct stat *statbuf)
122 {
123 struct git_istream *st;
124 enum object_type type;
125 unsigned long sz;
126 int result = -1;
de6182d @gitster streaming_write_entry(): support files with holes
gitster authored
127 ssize_t kept = 0;
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
128 int fd = -1;
129
b669109 @gitster Add streaming filter API
gitster authored
130 st = open_istream(ce->sha1, &type, &sz, filter);
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
131 if (!st)
132 return -1;
133 if (type != OBJ_BLOB)
134 goto close_and_exit;
135
136 fd = open_output_fd(path, ce, to_tempfile);
137 if (fd < 0)
138 goto close_and_exit;
139
140 for (;;) {
de6182d @gitster streaming_write_entry(): support files with holes
gitster authored
141 char buf[1024 * 16];
142 ssize_t wrote, holeto;
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
143 ssize_t readlen = read_istream(st, buf, sizeof(buf));
144
145 if (!readlen)
146 break;
de6182d @gitster streaming_write_entry(): support files with holes
gitster authored
147 if (sizeof(buf) == readlen) {
148 for (holeto = 0; holeto < readlen; holeto++)
149 if (buf[holeto])
150 break;
151 if (readlen == holeto) {
152 kept += holeto;
153 continue;
154 }
155 }
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
156
de6182d @gitster streaming_write_entry(): support files with holes
gitster authored
157 if (kept && lseek(fd, kept, SEEK_CUR) == (off_t) -1)
158 goto close_and_exit;
159 else
160 kept = 0;
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
161 wrote = write_in_full(fd, buf, readlen);
162
163 if (wrote != readlen)
164 goto close_and_exit;
165 }
de6182d @gitster streaming_write_entry(): support files with holes
gitster authored
166 if (kept && (lseek(fd, kept - 1, SEEK_CUR) == (off_t) -1 ||
167 write(fd, "", 1) != 1))
168 goto close_and_exit;
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
169 *fstat_done = fstat_output(fd, state, statbuf);
170
171 close_and_exit:
172 close_istream(st);
173 if (0 <= fd)
174 result = close(fd);
175 if (result && 0 <= fd)
176 unlink(path);
177 return result;
178 }
179
efbc583 entry.c: Use const qualifier for 'struct checkout' parameters
Luiz Fernando N. Capitulino authored
180 static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
181 {
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
182 unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
e4c7292 write_entry(): use fstat() instead of lstat() when file is open
Kjetil Barvik authored
183 int fd, ret, fstat_done = 0;
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
184 char *new;
185 struct strbuf buf = STRBUF_INIT;
186 unsigned long size;
187 size_t wrote, newsize = 0;
e4c7292 write_entry(): use fstat() instead of lstat() when file is open
Kjetil Barvik authored
188 struct stat st;
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
189
b669109 @gitster Add streaming filter API
gitster authored
190 if (ce_mode_s_ifmt == S_IFREG) {
191 struct stream_filter *filter = get_stream_filter(path, ce->sha1);
192 if (filter &&
193 !streaming_write_entry(ce, path, filter,
194 state, to_tempfile,
195 &fstat_done, &st))
196 goto finish;
197 }
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
198
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
199 switch (ce_mode_s_ifmt) {
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
200 case S_IFREG:
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
201 case S_IFLNK:
202 new = read_blob_entry(ce, &size);
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
203 if (!new)
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
204 return error("unable to read sha1 file of %s (%s)",
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
205 path, sha1_to_hex(ce->sha1));
1a9d7e9 @gitster attr.c: read .gitattributes from index as well.
gitster authored
206
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
207 if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) {
208 ret = symlink(new, path);
209 free(new);
210 if (ret)
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
211 return error("unable to create symlink %s (%s)",
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
212 path, strerror(errno));
213 break;
214 }
215
1a9d7e9 @gitster attr.c: read .gitattributes from index as well.
gitster authored
216 /*
217 * Convert from git internal format to working tree format
218 */
4857c76 write_entry(): cleanup of some duplicated code
Kjetil Barvik authored
219 if (ce_mode_s_ifmt == S_IFREG &&
220 convert_to_working_tree(ce->name, new, size, &buf)) {
1a9d7e9 @gitster attr.c: read .gitattributes from index as well.
gitster authored
221 free(new);
c32f749 Correct some sizeof(size_t) != sizeof(unsigned long) typing errors
René Scharfe authored
222 new = strbuf_detach(&buf, &newsize);
223 size = newsize;
1a9d7e9 @gitster attr.c: read .gitattributes from index as well.
gitster authored
224 }
225
fd5db55 @gitster write_entry(): separate two helper functions out
gitster authored
226 fd = open_output_fd(path, ce, to_tempfile);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
227 if (fd < 0) {
228 free(new);
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
229 return error("unable to create file %s (%s)",
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
230 path, strerror(errno));
231 }
6c510be @torvalds Lazy man's auto-CRLF
torvalds authored
232
93822c2 @awhitcroft short i/o: fix calls to write to use xwrite or write_in_full
awhitcroft authored
233 wrote = write_in_full(fd, new, size);
fd5db55 @gitster write_entry(): separate two helper functions out
gitster authored
234 if (!to_tempfile)
235 fstat_done = fstat_output(fd, state, &st);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
236 close(fd);
237 free(new);
238 if (wrote != size)
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
239 return error("unable to write file %s", path);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
240 break;
302b928 @tali rename dirlink to gitlink.
tali authored
241 case S_IFGITLINK:
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
242 if (to_tempfile)
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
243 return error("cannot create temporary subproject %s", path);
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
244 if (mkdir(path, 0777) < 0)
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
245 return error("cannot create subproject directory %s", path);
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
246 break;
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
247 default:
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
248 return error("unknown file mode for %s in index", path);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
249 }
250
dd8e912 @gitster streaming_write_entry(): use streaming API in write_entry()
gitster authored
251 finish:
6ee67f2 Fix entry.c dependency and compile problem
Linus Torvalds authored
252 if (state->refresh_cache) {
e4c7292 write_entry(): use fstat() instead of lstat() when file is open
Kjetil Barvik authored
253 if (!fstat_done)
254 lstat(ce->name, &st);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
255 fill_stat_cache_info(ce, &st);
256 }
257 return 0;
258 }
259
b6986d8 @torvalds git-checkout: be careful about untracked symlinks
torvalds authored
260 /*
261 * This is like 'lstat()', except it refuses to follow symlinks
da02ca5 @gitster check_path(): allow symlinked directories to checkout-index --prefix
gitster authored
262 * in the path, after skipping "skiplen".
b6986d8 @torvalds git-checkout: be careful about untracked symlinks
torvalds authored
263 */
61b97df @gitster entry.c: mark file-local function static
gitster authored
264 static int check_path(const char *path, int len, struct stat *st, int skiplen)
b6986d8 @torvalds git-checkout: be careful about untracked symlinks
torvalds authored
265 {
da02ca5 @gitster check_path(): allow symlinked directories to checkout-index --prefix
gitster authored
266 const char *slash = path + len;
267
268 while (path < slash && *slash != '/')
269 slash--;
270 if (!has_dirs_only_path(path, slash - path, skiplen)) {
b6986d8 @torvalds git-checkout: be careful about untracked symlinks
torvalds authored
271 errno = ENOENT;
272 return -1;
273 }
274 return lstat(path, st);
275 }
276
efbc583 entry.c: Use const qualifier for 'struct checkout' parameters
Luiz Fernando N. Capitulino authored
277 int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
278 {
095c424 @jonas Use PATH_MAX instead of MAXPATHLEN
jonas authored
279 static char path[PATH_MAX + 1];
de84f99 @spearce Add --temp and --stage=all options to checkout-index.
spearce authored
280 struct stat st;
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
281 int len = state->base_dir_len;
282
de84f99 @spearce Add --temp and --stage=all options to checkout-index.
spearce authored
283 if (topath)
284 return write_entry(ce, topath, state, 1);
285
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
286 memcpy(path, state->base_dir, len);
287 strcpy(path + len, ce->name);
81a9aa6 create_directories(): remove some memcpy() and strchr() calls
Kjetil Barvik authored
288 len += ce_namelen(ce);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
289
da02ca5 @gitster check_path(): allow symlinked directories to checkout-index --prefix
gitster authored
290 if (!check_path(path, len, &st, state->base_dir_len)) {
56cac48 @pclouds ie_match_stat(): do not ignore skip-worktree bit with CE_MATCH_IGNORE_VA...
pclouds authored
291 unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
292 if (!changed)
293 return 0;
294 if (!state->force) {
295 if (!state->quiet)
d43e907 @pclouds entry.c: remove "checkout-index" from error messages
pclouds authored
296 fprintf(stderr, "%s already exists, no checkout\n", path);
4b12dae Return error when not checking out an entry due to dirtiness.
Junio C Hamano authored
297 return -1;
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
298 }
299
300 /*
301 * We unlink the old file, to get the new one with the
302 * right permissions (including umask, which is nasty
303 * to emulate by hand - much easier to let the system
304 * just do the right thing)
305 */
d48a72f Fix replacing of a directory with a file/symlink in git-checkout-cache
Linus Torvalds authored
306 if (S_ISDIR(st.st_mode)) {
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
307 /* If it is a gitlink, leave it alone! */
7a51ed6 @torvalds Make on-disk index representation separate from in-core one
torvalds authored
308 if (S_ISGITLINK(ce->ce_mode))
f0807e6 @torvalds Teach "git-read-tree -u" to check out submodules as a directory
torvalds authored
309 return 0;
d48a72f Fix replacing of a directory with a file/symlink in git-checkout-cache
Linus Torvalds authored
310 if (!state->force)
311 return error("%s is a directory", path);
312 remove_subtree(path);
971f229 @torvalds Fix possible Solaris problem in 'checkout_entry()'
torvalds authored
313 } else if (unlink(path))
314 return error("unable to unlink old '%s' (%s)", path, strerror(errno));
de84f99 @spearce Add --temp and --stage=all options to checkout-index.
spearce authored
315 } else if (state->not_new)
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
316 return 0;
81a9aa6 create_directories(): remove some memcpy() and strchr() calls
Kjetil Barvik authored
317 create_directories(path, len, state);
de84f99 @spearce Add --temp and --stage=all options to checkout-index.
spearce authored
318 return write_entry(ce, path, state, 0);
12dccc1 Make fiel checkout function available to the git library
Linus Torvalds authored
319 }
Something went wrong with that request. Please try again.