Skip to content

Commit

Permalink
Merge branch 'kblees/kb/symlinks'
Browse files Browse the repository at this point in the history
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
dscho authored and Git for Windows Build Agent committed Oct 30, 2024
2 parents e91eb5e + 7590477 commit c61bfe3
Show file tree
Hide file tree
Showing 8 changed files with 528 additions and 165 deletions.
628 changes: 482 additions & 146 deletions compat/mingw.c

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions compat/mingw.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,6 @@ struct utsname {
* trivial stubs
*/

static inline int readlink(const char *path UNUSED, char *buf UNUSED, size_t bufsiz UNUSED)
{ errno = ENOSYS; return -1; }
static inline int symlink(const char *oldpath UNUSED, const char *newpath UNUSED)
{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes UNUSED, mode_t mode UNUSED)
{ errno = ENOSYS; return -1; }
#ifndef __MINGW64_VERSION_MAJOR
Expand Down Expand Up @@ -222,6 +218,8 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out);
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
int link(const char *oldpath, const char *newpath);
int uname(struct utsname *buf);
int symlink(const char *target, const char *link);
int readlink(const char *path, char *buf, size_t bufsiz);

/*
* replacements of existing functions
Expand Down
6 changes: 4 additions & 2 deletions compat/win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include <windows.h>
#endif

static inline int file_attr_to_st_mode (DWORD attr)
static inline int file_attr_to_st_mode (DWORD attr, DWORD tag)
{
int fMode = S_IREAD;
if (attr & FILE_ATTRIBUTE_DIRECTORY)
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) && tag == IO_REPARSE_TAG_SYMLINK)
fMode |= S_IFLNK;
else if (attr & FILE_ATTRIBUTE_DIRECTORY)
fMode |= S_IFDIR;
else
fMode |= S_IFREG;
Expand Down
5 changes: 4 additions & 1 deletion compat/win32/dirent.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
xwcstoutf(ent->d_name, fdata->cFileName, MAX_PATH * 3);

/* Set file type, based on WIN32_FIND_DATA */
if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
if ((fdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
&& fdata->dwReserved0 == IO_REPARSE_TAG_SYMLINK)
ent->d_type = DT_LNK;
else if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ent->d_type = DT_DIR;
else
ent->d_type = DT_REG;
Expand Down
23 changes: 19 additions & 4 deletions compat/win32/fscache.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,13 @@ static struct fsentry *fseentry_create_entry(struct fscache *cache,
fdata->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ?
fdata->EaSize : 0;

fse->st_mode = file_attr_to_st_mode(fdata->FileAttributes);
fse->dirent.d_type = S_ISDIR(fse->st_mode) ? DT_DIR : DT_REG;
fse->u.s.st_size = fdata->EndOfFile.LowPart |
(((off_t)fdata->EndOfFile.HighPart) << 32);
fse->st_mode = file_attr_to_st_mode(fdata->FileAttributes,
fdata->EaSize);
fse->dirent.d_type = S_ISREG(fse->st_mode) ? DT_REG :
S_ISDIR(fse->st_mode) ? DT_DIR : DT_LNK;
fse->u.s.st_size = S_ISLNK(fse->st_mode) ? MAX_LONG_PATH :
fdata->EndOfFile.LowPart |
(((off_t)fdata->EndOfFile.HighPart) << 32);
filetime_to_timespec((FILETIME *)&(fdata->LastAccessTime),
&(fse->u.s.st_atim));
filetime_to_timespec((FILETIME *)&(fdata->LastWriteTime),
Expand Down Expand Up @@ -581,6 +584,18 @@ int fscache_lstat(const char *filename, struct stat *st)
return -1;
}

/*
* Special case symbolic links: FindFirstFile()/FindNextFile() did not
* provide us with the length of the target path.
*/
if (fse->u.s.st_size == MAX_LONG_PATH && S_ISLNK(fse->st_mode)) {
char buf[MAX_LONG_PATH];
int len = readlink(filename, buf, sizeof(buf) - 1);

if (len > 0)
fse->u.s.st_size = len;
}

/* copy stat data */
st->st_ino = 0;
st->st_gid = 0;
Expand Down
4 changes: 2 additions & 2 deletions lockfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ static void trim_last_path_component(struct strbuf *path)
int i = path->len;

/* back up past trailing slashes, if any */
while (i && path->buf[i - 1] == '/')
while (i && is_dir_sep(path->buf[i - 1]))
i--;

/*
* then go backwards until a slash, or the beginning of the
* string
*/
while (i && path->buf[i - 1] != '/')
while (i && !is_dir_sep(path->buf[i - 1]))
i--;

strbuf_setlen(path, i);
Expand Down
11 changes: 11 additions & 0 deletions read-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,17 @@ int ie_modified(struct index_state *istate,
* then we know it is.
*/
if ((changed & DATA_CHANGED) &&
#ifdef GIT_WINDOWS_NATIVE
/*
* Work around Git for Windows v2.27.0 fixing a bug where symlinks'
* target path lengths were not read at all, and instead recorded
* as 4096: now, all symlinks would appear as modified.
*
* So let's just special-case symlinks with a target path length
* (i.e. `sd_size`) of 4096 and force them to be re-checked.
*/
(!S_ISLNK(st->st_mode) || ce->ce_stat_data.sd_size != MAX_LONG_PATH) &&
#endif
(S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0))
return changed;

Expand Down
10 changes: 4 additions & 6 deletions strbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,24 +562,22 @@ ssize_t strbuf_write(struct strbuf *sb, FILE *f)
return sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;
}

#define STRBUF_MAXLINK (2*PATH_MAX)

int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
{
size_t oldalloc = sb->alloc;

if (hint < 32)
hint = 32;

while (hint < STRBUF_MAXLINK) {
for (;;) {
ssize_t len;

strbuf_grow(sb, hint);
len = readlink(path, sb->buf, hint);
strbuf_grow(sb, hint + 1);
len = readlink(path, sb->buf, hint + 1);
if (len < 0) {
if (errno != ERANGE)
break;
} else if (len < hint) {
} else if (len <= hint) {
strbuf_setlen(sb, len);
return 0;
}
Expand Down

0 comments on commit c61bfe3

Please sign in to comment.