Skip to content

Commit 0457432

Browse files
committed
Merge pull request #156 from kblees/kb/symlinks
Symlink support
2 parents c67def3 + d6d6327 commit 0457432

File tree

8 files changed

+506
-207
lines changed

8 files changed

+506
-207
lines changed

compat/mingw.c

Lines changed: 442 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
@@ -110,10 +110,6 @@ struct utsname {
110110
* trivial stubs
111111
*/
112112

113-
static inline int readlink(const char *path, char *buf, size_t bufsiz)
114-
{ errno = ENOSYS; return -1; }
115-
static inline int symlink(const char *oldpath, const char *newpath)
116-
{ errno = ENOSYS; return -1; }
117113
static inline int fchmod(int fildes, mode_t mode)
118114
{ errno = ENOSYS; return -1; }
119115
#ifndef __MINGW64_VERSION_MAJOR
@@ -204,6 +200,8 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out);
204200
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
205201
int link(const char *oldpath, const char *newpath);
206202
int uname(struct utsname *buf);
203+
int symlink(const char *target, const char *link);
204+
int readlink(const char *path, char *buf, size_t bufsiz);
207205

208206
/*
209207
* 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
@@ -17,14 +17,14 @@ static void trim_last_path_component(struct strbuf *path)
1717
int i = path->len;
1818

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

2323
/*
2424
* then go backwards until a slash, or the beginning of the
2525
* string
2626
*/
27-
while (i && path->buf[i - 1] != '/')
27+
while (i && !is_dir_sep(path->buf[i - 1]))
2828
i--;
2929

3030
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);

0 commit comments

Comments
 (0)