]>
Commit | Line | Data |
---|---|---|
12dccc16 | 1 | #include "cache.h" |
8e440259 | 2 | #include "blob.h" |
8ca12c0d | 3 | #include "dir.h" |
12dccc16 | 4 | |
efbc5831 | 5 | static void create_directories(const char *path, const struct checkout *state) |
12dccc16 LT |
6 | { |
7 | int len = strlen(path); | |
8 | char *buf = xmalloc(len + 1); | |
9 | const char *slash = path; | |
10 | ||
11 | while ((slash = strchr(slash+1, '/')) != NULL) { | |
12 | len = slash - path; | |
13 | memcpy(buf, path, len); | |
14 | buf[len] = 0; | |
fa2e71c9 | 15 | |
bad4a54f KB |
16 | /* |
17 | * For 'checkout-index --prefix=<dir>', <dir> is | |
18 | * allowed to be a symlink to an existing directory, | |
19 | * and we set 'state->base_dir_len' below, such that | |
20 | * we test the path components of the prefix with the | |
21 | * stat() function instead of the lstat() function. | |
22 | */ | |
23 | if (has_dirs_only_path(len, buf, state->base_dir_len)) | |
fa2e71c9 JH |
24 | continue; /* ok, it is already a directory. */ |
25 | ||
26 | /* | |
bad4a54f KB |
27 | * If this mkdir() would fail, it could be that there |
28 | * is already a symlink or something else exists | |
29 | * there, therefore we then try to unlink it and try | |
30 | * one more time to create the directory. | |
fa2e71c9 | 31 | */ |
f312de01 | 32 | if (mkdir(buf, 0777)) { |
fa2e71c9 JH |
33 | if (errno == EEXIST && state->force && |
34 | !unlink(buf) && !mkdir(buf, 0777)) | |
35 | continue; | |
12dccc16 LT |
36 | die("cannot create directory at %s", buf); |
37 | } | |
38 | } | |
39 | free(buf); | |
40 | } | |
41 | ||
42 | static void remove_subtree(const char *path) | |
43 | { | |
44 | DIR *dir = opendir(path); | |
45 | struct dirent *de; | |
46 | char pathbuf[PATH_MAX]; | |
47 | char *name; | |
a6080a0a | 48 | |
12dccc16 | 49 | if (!dir) |
cc2903fc | 50 | die("cannot opendir %s (%s)", path, strerror(errno)); |
12dccc16 LT |
51 | strcpy(pathbuf, path); |
52 | name = pathbuf + strlen(path); | |
53 | *name++ = '/'; | |
54 | while ((de = readdir(dir)) != NULL) { | |
55 | struct stat st; | |
8ca12c0d | 56 | if (is_dot_or_dotdot(de->d_name)) |
12dccc16 LT |
57 | continue; |
58 | strcpy(name, de->d_name); | |
59 | if (lstat(pathbuf, &st)) | |
cc2903fc | 60 | die("cannot lstat %s (%s)", pathbuf, strerror(errno)); |
12dccc16 LT |
61 | if (S_ISDIR(st.st_mode)) |
62 | remove_subtree(pathbuf); | |
63 | else if (unlink(pathbuf)) | |
cc2903fc | 64 | die("cannot unlink %s (%s)", pathbuf, strerror(errno)); |
12dccc16 LT |
65 | } |
66 | closedir(dir); | |
67 | if (rmdir(path)) | |
cc2903fc | 68 | die("cannot rmdir %s (%s)", path, strerror(errno)); |
12dccc16 LT |
69 | } |
70 | ||
d48a72f3 | 71 | static int create_file(const char *path, unsigned int mode) |
12dccc16 | 72 | { |
12dccc16 | 73 | mode = (mode & 0100) ? 0777 : 0666; |
781411ed | 74 | return open(path, O_WRONLY | O_CREAT | O_EXCL, mode); |
12dccc16 LT |
75 | } |
76 | ||
f0807e62 LT |
77 | static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned long *size) |
78 | { | |
79 | enum object_type type; | |
80 | void *new = read_sha1_file(ce->sha1, &type, size); | |
81 | ||
82 | if (new) { | |
83 | if (type == OBJ_BLOB) | |
84 | return new; | |
85 | free(new); | |
86 | } | |
87 | return NULL; | |
88 | } | |
89 | ||
efbc5831 | 90 | static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile) |
12dccc16 LT |
91 | { |
92 | int fd; | |
12dccc16 | 93 | long wrote; |
12dccc16 | 94 | |
7a51ed66 | 95 | switch (ce->ce_mode & S_IFMT) { |
5ecd293d PH |
96 | char *new; |
97 | struct strbuf buf; | |
a2d7c6c6 | 98 | unsigned long size; |
6c510bee | 99 | |
12dccc16 | 100 | case S_IFREG: |
f0807e62 LT |
101 | new = read_blob_entry(ce, path, &size); |
102 | if (!new) | |
7e44c935 | 103 | return error("git checkout-index: unable to read sha1 file of %s (%s)", |
f0807e62 | 104 | path, sha1_to_hex(ce->sha1)); |
1a9d7e9b JH |
105 | |
106 | /* | |
107 | * Convert from git internal format to working tree format | |
108 | */ | |
5ecd293d PH |
109 | strbuf_init(&buf, 0); |
110 | if (convert_to_working_tree(ce->name, new, size, &buf)) { | |
c32f749f | 111 | size_t newsize = 0; |
1a9d7e9b | 112 | free(new); |
c32f749f RS |
113 | new = strbuf_detach(&buf, &newsize); |
114 | size = newsize; | |
1a9d7e9b JH |
115 | } |
116 | ||
de84f99c SP |
117 | if (to_tempfile) { |
118 | strcpy(path, ".merge_file_XXXXXX"); | |
119 | fd = mkstemp(path); | |
120 | } else | |
7a51ed66 | 121 | fd = create_file(path, ce->ce_mode); |
12dccc16 LT |
122 | if (fd < 0) { |
123 | free(new); | |
7e44c935 | 124 | return error("git checkout-index: unable to create file %s (%s)", |
12dccc16 LT |
125 | path, strerror(errno)); |
126 | } | |
6c510bee | 127 | |
93822c22 | 128 | wrote = write_in_full(fd, new, size); |
12dccc16 LT |
129 | close(fd); |
130 | free(new); | |
131 | if (wrote != size) | |
7e44c935 | 132 | return error("git checkout-index: unable to write file %s", path); |
12dccc16 LT |
133 | break; |
134 | case S_IFLNK: | |
f0807e62 LT |
135 | new = read_blob_entry(ce, path, &size); |
136 | if (!new) | |
7e44c935 | 137 | return error("git checkout-index: unable to read sha1 file of %s (%s)", |
f0807e62 | 138 | path, sha1_to_hex(ce->sha1)); |
78a8d641 JS |
139 | if (to_tempfile || !has_symlinks) { |
140 | if (to_tempfile) { | |
141 | strcpy(path, ".merge_link_XXXXXX"); | |
142 | fd = mkstemp(path); | |
143 | } else | |
144 | fd = create_file(path, 0666); | |
de84f99c SP |
145 | if (fd < 0) { |
146 | free(new); | |
7e44c935 | 147 | return error("git checkout-index: unable to create " |
de84f99c SP |
148 | "file %s (%s)", path, strerror(errno)); |
149 | } | |
93822c22 | 150 | wrote = write_in_full(fd, new, size); |
de84f99c SP |
151 | close(fd); |
152 | free(new); | |
153 | if (wrote != size) | |
7e44c935 | 154 | return error("git checkout-index: unable to write file %s", |
de84f99c SP |
155 | path); |
156 | } else { | |
157 | wrote = symlink(new, path); | |
12dccc16 | 158 | free(new); |
de84f99c | 159 | if (wrote) |
7e44c935 | 160 | return error("git checkout-index: unable to create " |
de84f99c | 161 | "symlink %s (%s)", path, strerror(errno)); |
12dccc16 | 162 | } |
12dccc16 | 163 | break; |
302b9282 | 164 | case S_IFGITLINK: |
f0807e62 | 165 | if (to_tempfile) |
7e44c935 | 166 | return error("git checkout-index: cannot create temporary subproject %s", path); |
f0807e62 | 167 | if (mkdir(path, 0777) < 0) |
7e44c935 | 168 | return error("git checkout-index: cannot create subproject directory %s", path); |
f0807e62 | 169 | break; |
12dccc16 | 170 | default: |
7e44c935 | 171 | return error("git checkout-index: unknown file mode for %s", path); |
12dccc16 LT |
172 | } |
173 | ||
6ee67f26 | 174 | if (state->refresh_cache) { |
12dccc16 LT |
175 | struct stat st; |
176 | lstat(ce->name, &st); | |
177 | fill_stat_cache_info(ce, &st); | |
178 | } | |
179 | return 0; | |
180 | } | |
181 | ||
efbc5831 | 182 | int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath) |
12dccc16 | 183 | { |
095c424d | 184 | static char path[PATH_MAX + 1]; |
de84f99c | 185 | struct stat st; |
12dccc16 LT |
186 | int len = state->base_dir_len; |
187 | ||
de84f99c SP |
188 | if (topath) |
189 | return write_entry(ce, topath, state, 1); | |
190 | ||
12dccc16 LT |
191 | memcpy(path, state->base_dir, len); |
192 | strcpy(path + len, ce->name); | |
193 | ||
194 | if (!lstat(path, &st)) { | |
4bd5b7da | 195 | unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID); |
12dccc16 LT |
196 | if (!changed) |
197 | return 0; | |
198 | if (!state->force) { | |
199 | if (!state->quiet) | |
215a7ad1 | 200 | fprintf(stderr, "git-checkout-index: %s already exists\n", path); |
4b12dae6 | 201 | return -1; |
12dccc16 LT |
202 | } |
203 | ||
204 | /* | |
205 | * We unlink the old file, to get the new one with the | |
206 | * right permissions (including umask, which is nasty | |
207 | * to emulate by hand - much easier to let the system | |
208 | * just do the right thing) | |
209 | */ | |
d48a72f3 | 210 | if (S_ISDIR(st.st_mode)) { |
f0807e62 | 211 | /* If it is a gitlink, leave it alone! */ |
7a51ed66 | 212 | if (S_ISGITLINK(ce->ce_mode)) |
f0807e62 | 213 | return 0; |
d48a72f3 LT |
214 | if (!state->force) |
215 | return error("%s is a directory", path); | |
216 | remove_subtree(path); | |
971f229c LT |
217 | } else if (unlink(path)) |
218 | return error("unable to unlink old '%s' (%s)", path, strerror(errno)); | |
de84f99c | 219 | } else if (state->not_new) |
12dccc16 LT |
220 | return 0; |
221 | create_directories(path, state); | |
de84f99c | 222 | return write_entry(ce, path, state, 0); |
12dccc16 | 223 | } |