Skip to content

Commit 49b9363

Browse files
committed
Merge pull request #156 from kblees/kb/symlinks
Symlink support
2 parents 9c9dc30 + 7bf1f90 commit 49b9363

File tree

10 files changed

+532
-208
lines changed

10 files changed

+532
-208
lines changed

compat/mingw.c

Lines changed: 452 additions & 176 deletions
Large diffs are not rendered by default.

compat/mingw.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,6 @@ struct itimerval {
9393
* trivial stubs
9494
*/
9595

96-
static inline int readlink(const char *path, char *buf, size_t bufsiz)
97-
{ errno = ENOSYS; return -1; }
98-
static inline int symlink(const char *oldpath, const char *newpath)
99-
{ errno = ENOSYS; return -1; }
10096
static inline int fchmod(int fildes, mode_t mode)
10197
{ errno = ENOSYS; return -1; }
10298
#ifndef __MINGW64_VERSION_MAJOR
@@ -182,6 +178,8 @@ struct passwd *getpwuid(uid_t uid);
182178
int setitimer(int type, struct itimerval *in, struct itimerval *out);
183179
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
184180
int link(const char *oldpath, const char *newpath);
181+
int symlink(const char *target, const char *link);
182+
int readlink(const char *path, char *buf, size_t bufsiz);
185183

186184
/*
187185
* replacements of existing functions

compat/win32.h

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
#include <windows.h>
77
#endif
88

9-
static inline int file_attr_to_st_mode (DWORD attr)
9+
static inline int file_attr_to_st_mode (DWORD attr, DWORD tag)
1010
{
1111
int fMode = S_IREAD;
12-
if (attr & FILE_ATTRIBUTE_DIRECTORY)
12+
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) && tag == IO_REPARSE_TAG_SYMLINK)
13+
fMode |= S_IFLNK;
14+
else if (attr & FILE_ATTRIBUTE_DIRECTORY)
1315
fMode |= S_IFDIR;
1416
else
1517
fMode |= S_IFREG;
@@ -38,4 +40,41 @@ static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fd
3840
}
3941
}
4042

43+
/* simplify loading of DLL functions */
44+
45+
struct proc_addr {
46+
const char *const dll;
47+
const char *const function;
48+
FARPROC pfunction;
49+
unsigned initialized : 1;
50+
};
51+
52+
/* Declares a function to be loaded dynamically from a DLL. */
53+
#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \
54+
static struct proc_addr proc_addr_##function = \
55+
{ #dll, #function, NULL, 0 }; \
56+
static rettype (WINAPI *function)(__VA_ARGS__)
57+
58+
/*
59+
* Loads a function from a DLL (once-only).
60+
* Returns non-NULL function pointer on success.
61+
* Returns NULL + errno == ENOSYS on failure.
62+
*/
63+
#define INIT_PROC_ADDR(function) (function = get_proc_addr(&proc_addr_##function))
64+
65+
static inline void *get_proc_addr(struct proc_addr *proc)
66+
{
67+
/* only do this once */
68+
if (!proc->initialized) {
69+
proc->initialized = 1;
70+
HANDLE hnd = LoadLibraryA(proc->dll);
71+
if (hnd)
72+
proc->pfunction = GetProcAddress(hnd, proc->function);
73+
}
74+
/* set ENOSYS if DLL or function was not found */
75+
if (!proc->pfunction)
76+
errno = ENOSYS;
77+
return proc->pfunction;
78+
}
79+
4180
#endif

compat/win32/dirent.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAW *fdata)
1616
xwcstoutf(ent->d_name, fdata->cFileName, MAX_PATH * 3);
1717

1818
/* Set file type, based on WIN32_FIND_DATA */
19-
if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
19+
if ((fdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
20+
&& fdata->dwReserved0 == IO_REPARSE_TAG_SYMLINK)
21+
ent->d_type = DT_LNK;
22+
else if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2023
ent->d_type = DT_DIR;
2124
else
2225
ent->d_type = DT_REG;

compat/win32/fscache.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,10 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,
147147

148148
fse = fsentry_alloc(list, buf, len);
149149

150-
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes);
151-
fse->st_size = (((off64_t) (fdata->nFileSizeHigh)) << 32)
152-
| fdata->nFileSizeLow;
150+
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes,
151+
fdata->dwReserved0);
152+
fse->st_size = S_ISLNK(fse->st_mode) ? MAX_LONG_PATH :
153+
fdata->nFileSizeLow | (((off_t) fdata->nFileSizeHigh) << 32);
153154
fse->st_atime = filetime_to_time_t(&(fdata->ftLastAccessTime));
154155
fse->st_mtime = filetime_to_time_t(&(fdata->ftLastWriteTime));
155156
fse->st_ctime = filetime_to_time_t(&(fdata->ftCreationTime));
@@ -456,7 +457,8 @@ static struct dirent *fscache_readdir(DIR *base_dir)
456457
if (!next)
457458
return NULL;
458459
dir->pfsentry = next;
459-
dir->dirent.d_type = S_ISDIR(next->st_mode) ? DT_DIR : DT_REG;
460+
dir->dirent.d_type = S_ISREG(next->st_mode) ? DT_REG :
461+
S_ISDIR(next->st_mode) ? DT_DIR : DT_LNK;
460462
dir->dirent.d_name = (char*) next->name;
461463
return &(dir->dirent);
462464
}

compat/winansi.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../git-compat-util.h"
77
#include <wingdi.h>
88
#include <winreg.h>
9+
#include "win32.h"
910

1011
/*
1112
ANSI codes used by git: m, K
@@ -35,26 +36,21 @@ typedef struct _CONSOLE_FONT_INFOEX {
3536
#endif
3637
#endif
3738

38-
typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
39-
PCONSOLE_FONT_INFOEX);
40-
4139
static void warn_if_raster_font(void)
4240
{
4341
DWORD fontFamily = 0;
44-
PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
42+
DECLARE_PROC_ADDR(kernel32.dll, BOOL, GetCurrentConsoleFontEx,
43+
HANDLE, BOOL, PCONSOLE_FONT_INFOEX);
4544

4645
/* don't bother if output was ascii only */
4746
if (!non_ascii_used)
4847
return;
4948

5049
/* GetCurrentConsoleFontEx is available since Vista */
51-
pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
52-
GetModuleHandle("kernel32.dll"),
53-
"GetCurrentConsoleFontEx");
54-
if (pGetCurrentConsoleFontEx) {
50+
if (INIT_PROC_ADDR(GetCurrentConsoleFontEx)) {
5551
CONSOLE_FONT_INFOEX cfi;
5652
cfi.cbSize = sizeof(cfi);
57-
if (pGetCurrentConsoleFontEx(console, 0, &cfi))
53+
if (GetCurrentConsoleFontEx(console, 0, &cfi))
5854
fontFamily = cfi.FontFamily;
5955
} else {
6056
/* pre-Vista: check default console font in registry */

lockfile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ static void trim_last_path_component(struct strbuf *path)
4646
int i = path->len;
4747

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

5252
/*
5353
* then go backwards until a slash, or the beginning of the
5454
* string
5555
*/
56-
while (i && path->buf[i - 1] != '/')
56+
while (i && !is_dir_sep(path->buf[i - 1]))
5757
i--;
5858

5959
strbuf_setlen(path, i);

strbuf.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -384,30 +384,25 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
384384
return sb->len - oldlen;
385385
}
386386

387-
#define STRBUF_MAXLINK (2*PATH_MAX)
388-
389387
int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
390388
{
391389
size_t oldalloc = sb->alloc;
392390

393391
if (hint < 32)
394392
hint = 32;
395393

396-
while (hint < STRBUF_MAXLINK) {
394+
for (;; hint *= 2) {
397395
int len;
398396

399-
strbuf_grow(sb, hint);
400-
len = readlink(path, sb->buf, hint);
397+
strbuf_grow(sb, hint + 1);
398+
len = readlink(path, sb->buf, hint + 1);
401399
if (len < 0) {
402400
if (errno != ERANGE)
403401
break;
404-
} else if (len < hint) {
402+
} else if (len <= hint) {
405403
strbuf_setlen(sb, len);
406404
return 0;
407405
}
408-
409-
/* .. the buffer was too small - try again */
410-
hint *= 2;
411406
}
412407
if (oldalloc == 0)
413408
strbuf_release(sb);

t/t7800-difftool.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ Testing basic diff tool invocation
1010

1111
. ./test-lib.sh
1212

13+
if test_have_prereq MINGW
14+
then
15+
# Avoid posix-to-windows path mangling
16+
pwd () {
17+
builtin pwd
18+
}
19+
fi
20+
1321
difftool_test_setup ()
1422
{
1523
test_config diff.tool test-tool &&

t/t9100-git-svn-basic.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ test_expect_success \
2525
(
2626
cd import &&
2727
echo foo >foo &&
28-
ln -s foo foo.link
28+
if test_have_prereq !MINGW
29+
then
30+
ln -s foo foo.link
31+
else
32+
# MSYS libsvn does not support symlinks, so always use cp, even if
33+
# ln -s actually works
34+
cp foo foo.link
35+
fi
2936
mkdir -p dir/a/b/c/d/e &&
3037
echo "deep dir" >dir/a/b/c/d/e/file &&
3138
mkdir bar &&

0 commit comments

Comments
 (0)