зеркало из https://github.com/microsoft/git.git
git-apply: be a lot more careful when writing files
We write them under another name and rename them to their destination, so that if something bad happens in the middle, we won't have caused any bigger harm. Also, this makes the writing be NFS "intr" safe, and as a side effects makes sure that if the target is hardlinked (or symlinked) we will have broken the link.
This commit is contained in:
Родитель
dda2d79af2
Коммит
1b668341db
84
apply.c
84
apply.c
|
@ -1245,31 +1245,65 @@ static void create_subdirectories(const char *path)
|
|||
free(buf);
|
||||
}
|
||||
|
||||
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (S_ISLNK(mode))
|
||||
return symlink(buf, path);
|
||||
fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC, (mode & 0100) ? 0777 : 0666);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
while (size) {
|
||||
int written = write(fd, buf, size);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
die("writing file %s: %s", path, strerror(errno));
|
||||
}
|
||||
if (!written)
|
||||
die("out of space writing file %s", path);
|
||||
buf += written;
|
||||
size -= written;
|
||||
}
|
||||
if (close(fd) < 0)
|
||||
die("closing file %s: %s", path, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We optimistically assume that the directories exist,
|
||||
* which is true 99% of the time anyway. If they don't,
|
||||
* we create them and try again.
|
||||
*/
|
||||
static int create_regular_file(const char *path, unsigned int mode)
|
||||
static void create_one_file(const char *path, unsigned mode, const char *buf, unsigned long size)
|
||||
{
|
||||
int ret = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
if (!try_create_file(path, mode, buf, size))
|
||||
return;
|
||||
|
||||
if (ret < 0 && errno == ENOENT) {
|
||||
if (errno == ENOENT) {
|
||||
create_subdirectories(path);
|
||||
ret = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
if (!try_create_file(path, mode, buf, size))
|
||||
return;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int create_symlink(const char *buf, const char *path)
|
||||
{
|
||||
int ret = symlink(buf, path);
|
||||
if (errno == EEXIST) {
|
||||
unsigned int nr = getpid();
|
||||
|
||||
if (ret < 0 && errno == ENOENT) {
|
||||
create_subdirectories(path);
|
||||
ret = symlink(buf, path);
|
||||
for (;;) {
|
||||
const char *newpath;
|
||||
newpath = mkpath("%s~%u", path, nr);
|
||||
if (!try_create_file(newpath, mode, buf, size)) {
|
||||
if (!rename(newpath, path))
|
||||
return;
|
||||
unlink(newpath);
|
||||
break;
|
||||
}
|
||||
if (errno != EEXIST)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
die("unable to write file %s mode %o", path, mode);
|
||||
}
|
||||
|
||||
static void create_file(struct patch *patch)
|
||||
|
@ -1281,28 +1315,8 @@ static void create_file(struct patch *patch)
|
|||
|
||||
if (!mode)
|
||||
mode = S_IFREG | 0644;
|
||||
if (S_ISREG(mode)) {
|
||||
int fd;
|
||||
mode = (mode & 0100) ? 0777 : 0666;
|
||||
fd = create_regular_file(path, mode);
|
||||
if (fd < 0)
|
||||
die("unable to create file %s (%s)", path, strerror(errno));
|
||||
if (write(fd, buf, size) != size)
|
||||
die("unable to write file %s", path);
|
||||
close(fd);
|
||||
add_index_file(path, mode, buf, size);
|
||||
return;
|
||||
}
|
||||
if (S_ISLNK(mode)) {
|
||||
if (size && buf[size-1] == '\n')
|
||||
size--;
|
||||
buf[size] = 0;
|
||||
if (create_symlink(buf, path) < 0)
|
||||
die("unable to write symlink %s", path);
|
||||
add_index_file(path, mode, buf, size);
|
||||
return;
|
||||
}
|
||||
die("unable to write file mode %o", mode);
|
||||
create_one_file(path, mode, buf, size);
|
||||
add_index_file(path, mode, buf, size);
|
||||
}
|
||||
|
||||
static void write_out_one_result(struct patch *patch)
|
||||
|
|
Загрузка…
Ссылка в новой задаче