Skip to content

Commit

Permalink
Merge pull request msysgit#156 from kblees/kb/symlinks
Browse files Browse the repository at this point in the history
Symlink support
  • Loading branch information
dscho committed Aug 30, 2015
2 parents 4262140 + 54c6217 commit 493682e
Show file tree
Hide file tree
Showing 10 changed files with 560 additions and 207 deletions.
655 changes: 480 additions & 175 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 @@ -101,10 +101,6 @@ struct utsname {
* trivial stubs
*/

static inline int readlink(const char *path, char *buf, size_t bufsiz)
{ errno = ENOSYS; return -1; }
static inline int symlink(const char *oldpath, const char *newpath)
{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
#ifndef __MINGW64_VERSION_MAJOR
Expand Down Expand Up @@ -195,6 +191,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
43 changes: 41 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 Expand Up @@ -38,4 +40,41 @@ static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fd
}
}

/* simplify loading of DLL functions */

struct proc_addr {
const char *const dll;
const char *const function;
FARPROC pfunction;
unsigned initialized : 1;
};

/* Declares a function to be loaded dynamically from a DLL. */
#define DECLARE_PROC_ADDR(dll, rettype, function, ...) \
static struct proc_addr proc_addr_##function = \
{ #dll, #function, NULL, 0 }; \
static rettype (WINAPI *function)(__VA_ARGS__)

/*
* Loads a function from a DLL (once-only).
* Returns non-NULL function pointer on success.
* Returns NULL + errno == ENOSYS on failure.
*/
#define INIT_PROC_ADDR(function) (function = get_proc_addr(&proc_addr_##function))

static inline void *get_proc_addr(struct proc_addr *proc)
{
/* only do this once */
if (!proc->initialized) {
proc->initialized = 1;
HANDLE hnd = LoadLibraryA(proc->dll);
if (hnd)
proc->pfunction = GetProcAddress(hnd, proc->function);
}
/* set ENOSYS if DLL or function was not found */
if (!proc->pfunction)
errno = ENOSYS;
return proc->pfunction;
}

#endif
5 changes: 4 additions & 1 deletion compat/win32/dirent.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,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
10 changes: 6 additions & 4 deletions compat/win32/fscache.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ static struct fsentry *fseentry_create_entry(struct fsentry *list,

fse = fsentry_alloc(list, buf, len);

fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes);
fse->st_size = (((off64_t) (fdata->nFileSizeHigh)) << 32)
| fdata->nFileSizeLow;
fse->st_mode = file_attr_to_st_mode(fdata->dwFileAttributes,
fdata->dwReserved0);
fse->st_size = S_ISLNK(fse->st_mode) ? MAX_LONG_PATH :
fdata->nFileSizeLow | (((off_t) fdata->nFileSizeHigh) << 32);
fse->st_atime = filetime_to_time_t(&(fdata->ftLastAccessTime));
fse->st_mtime = filetime_to_time_t(&(fdata->ftLastWriteTime));
fse->st_ctime = filetime_to_time_t(&(fdata->ftCreationTime));
Expand Down Expand Up @@ -456,7 +457,8 @@ static struct dirent *fscache_readdir(DIR *base_dir)
if (!next)
return NULL;
dir->pfsentry = next;
dir->dirent.d_type = S_ISDIR(next->st_mode) ? DT_DIR : DT_REG;
dir->dirent.d_type = S_ISREG(next->st_mode) ? DT_REG :
S_ISDIR(next->st_mode) ? DT_DIR : DT_LNK;
dir->dirent.d_name = (char*) next->name;
return &(dir->dirent);
}
Expand Down
14 changes: 5 additions & 9 deletions compat/winansi.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "../git-compat-util.h"
#include <wingdi.h>
#include <winreg.h>
#include "win32.h"

/*
ANSI codes used by git: m, K
Expand Down Expand Up @@ -35,26 +36,21 @@ typedef struct _CONSOLE_FONT_INFOEX {
#endif
#endif

typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
PCONSOLE_FONT_INFOEX);

static void warn_if_raster_font(void)
{
DWORD fontFamily = 0;
PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
DECLARE_PROC_ADDR(kernel32.dll, BOOL, GetCurrentConsoleFontEx,
HANDLE, BOOL, PCONSOLE_FONT_INFOEX);

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

/* GetCurrentConsoleFontEx is available since Vista */
pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
GetModuleHandle("kernel32.dll"),
"GetCurrentConsoleFontEx");
if (pGetCurrentConsoleFontEx) {
if (INIT_PROC_ADDR(GetCurrentConsoleFontEx)) {
CONSOLE_FONT_INFOEX cfi;
cfi.cbSize = sizeof(cfi);
if (pGetCurrentConsoleFontEx(console, 0, &cfi))
if (GetCurrentConsoleFontEx(console, 0, &cfi))
fontFamily = cfi.FontFamily;
} else {
/* pre-Vista: check default console font in registry */
Expand Down
4 changes: 2 additions & 2 deletions lockfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,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
13 changes: 4 additions & 9 deletions strbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,30 +384,25 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
return sb->len - oldlen;
}

#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 (;; hint *= 2) {
int 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;
}

/* .. the buffer was too small - try again */
hint *= 2;
}
if (oldalloc == 0)
strbuf_release(sb);
Expand Down
8 changes: 8 additions & 0 deletions t/t7800-difftool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ Testing basic diff tool invocation

. ./test-lib.sh

if test_have_prereq MINGW
then
# Avoid posix-to-windows path mangling
pwd () {
builtin pwd
}
fi

difftool_test_setup ()
{
test_config diff.tool test-tool &&
Expand Down
9 changes: 8 additions & 1 deletion t/t9100-git-svn-basic.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ test_expect_success \
(
cd import &&
echo foo >foo &&
ln -s foo foo.link
if test_have_prereq !MINGW
then
ln -s foo foo.link
else
# MSYS libsvn does not support symlinks, so always use cp, even if
# ln -s actually works
cp foo foo.link
fi
mkdir -p dir/a/b/c/d/e &&
echo "deep dir" >dir/a/b/c/d/e/file &&
mkdir bar &&
Expand Down

0 comments on commit 493682e

Please sign in to comment.