1 #include "git-compat-util.h"
8 int copy_fd(int ifd
, int ofd
)
12 ssize_t len
= xread(ifd
, buffer
, sizeof(buffer
));
16 return COPY_READ_ERROR
;
17 if (write_in_full(ofd
, buffer
, len
) < 0)
18 return COPY_WRITE_ERROR
;
23 static int copy_times(const char *dst
, const char *src
)
27 if (stat(src
, &st
) < 0)
29 times
.actime
= st
.st_atime
;
30 times
.modtime
= st
.st_mtime
;
31 if (utime(dst
, ×
) < 0)
36 int copy_file(const char *dst
, const char *src
, int mode
)
40 mode
= (mode
& 0111) ? 0777 : 0666;
41 if ((fdi
= open(src
, O_RDONLY
)) < 0)
43 if ((fdo
= open(dst
, O_WRONLY
| O_CREAT
| O_EXCL
, mode
)) < 0) {
47 status
= copy_fd(fdi
, fdo
);
50 error_errno("copy-fd: read returned");
52 case COPY_WRITE_ERROR
:
53 error_errno("copy-fd: write returned");
58 return error_errno("%s: close error", dst
);
60 if (!status
&& adjust_shared_perm(dst
))
66 int copy_file_with_time(const char *dst
, const char *src
, int mode
)
68 int status
= copy_file(dst
, src
, mode
);
70 return copy_times(dst
, src
);
74 static int do_symlinks_match(const char *path1
, const char *path2
)
76 struct strbuf buf1
= STRBUF_INIT
, buf2
= STRBUF_INIT
;
79 if (!strbuf_readlink(&buf1
, path1
, 0) &&
80 !strbuf_readlink(&buf2
, path2
, 0))
81 ret
= !strcmp(buf1
.buf
, buf2
.buf
);
83 strbuf_release(&buf1
);
84 strbuf_release(&buf2
);
88 int do_files_match(const char *path1
, const char *path2
)
91 int fd1
= -1, fd2
= -1, ret
= 1;
92 char buf1
[8192], buf2
[8192];
94 if ((fd1
= open_nofollow(path1
, O_RDONLY
)) < 0 ||
95 fstat(fd1
, &st1
) || !S_ISREG(st1
.st_mode
)) {
96 if (fd1
< 0 && errno
== ELOOP
)
97 /* maybe this is a symbolic link? */
98 return do_symlinks_match(path1
, path2
);
100 } else if ((fd2
= open_nofollow(path2
, O_RDONLY
)) < 0 ||
101 fstat(fd2
, &st2
) || !S_ISREG(st2
.st_mode
)) {
106 /* to match, neither must be executable, or both */
107 ret
= !(st1
.st_mode
& 0111) == !(st2
.st_mode
& 0111);
110 ret
= st1
.st_size
== st2
.st_size
;
113 ssize_t len1
= read_in_full(fd1
, buf1
, sizeof(buf1
));
114 ssize_t len2
= read_in_full(fd2
, buf2
, sizeof(buf2
));
116 if (len1
< 0 || len2
< 0 || len1
!= len2
)
117 ret
= 0; /* read error or different file size */
118 else if (!len1
) /* len2 is also 0; hit EOF on both */
119 break; /* ret is still true */
121 ret
= !memcmp(buf1
, buf2
, len1
);