Skip to content

Symlink support #156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
May 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
81b096f
strbuf_readlink: don't call readlink twice if hint is the exact link …
kblees May 11, 2015
27c549f
strbuf_readlink: support link targets that exceed PATH_MAX
kblees May 11, 2015
6b1da48
lockfile.c: use is_dir_sep() instead of hardcoded '/' checks
kblees May 11, 2015
643694d
Win32: don't call GetFileAttributes twice in mingw_lstat()
kblees May 12, 2015
b908441
Win32: implement stat() with symlink support
kblees May 15, 2015
5d56517
Win32: remove separate do_lstat() function
kblees May 11, 2015
554a6ca
Win32: let mingw_lstat() error early upon problems with reparse points
kblees May 23, 2015
dd7f51b
Win32: teach fscache and dirent about symlinks
kblees May 11, 2015
9dd538a
Win32: lstat(): return adequate stat.st_size for symlinks
kblees May 15, 2015
f55a25a
Win32: simplify loading of DLL functions
kblees Aug 25, 2014
31a1302
Win32: factor out retry logic
kblees May 19, 2015
d3b84b8
Win32: change default of 'core.symlinks' to false
kblees May 23, 2015
a89cf7f
Win32: add symlink-specific error codes
kblees May 15, 2015
2f6e418
Win32: mingw_unlink: support symlinks to directories
kblees May 23, 2015
ba9786b
Win32: mingw_rename: support renaming symlinks
kblees May 19, 2015
92cfb95
Win32: mingw_chdir: change to symlink-resolved directory
kblees May 23, 2015
e357424
Win32: implement readlink()
kblees May 23, 2015
ec9ce13
Win32: implement basic symlink() functionality (file symlinks only)
kblees May 23, 2015
2c65aca
Win32: symlink: add support for symlinks to directories
kblees May 23, 2015
9298e41
t9100: don't use symlinks with SVN on MINGW
kblees May 20, 2015
7bf1f90
t7800: configure $(pwd) for posix-paths on MINGW
kblees May 20, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
628 changes: 452 additions & 176 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 @@ -93,10 +93,6 @@ struct itimerval {
* 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 @@ -182,6 +178,8 @@ struct passwd *getpwuid(uid_t uid);
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 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