Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
MinGW: Allow passing the symlink target type from index information.
Browse files Browse the repository at this point in the history
Required for msysgit which needs to know whether the target of a symbolic link
is a directory or file.

Signed-off-by: Michael Geddes <michael@frog.wheelycreek.net>
  • Loading branch information
frogonwheels committed May 14, 2014
1 parent 29272bc commit fa9215f
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 1 deletion.
125 changes: 124 additions & 1 deletion entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,126 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path,
return result;
}

/*
* Does 'match' match the given name?
* A match is found if
*
* (1) the 'match' string is leading directory of 'name', or
* (2) the 'match' string is exactly the same as 'name'.
*
* and the return value tells which case it was.
*
* It returns 0 when there is no match.
*
* Preserved and simplified from dir.c for use here (without glob special matching)
*/
static int match_one(const char *match, const char *name, int namelen)
{
int matchlen;

/* If the match was just the prefix, we matched */
if (!*match)
return MATCHED_RECURSIVELY;

if (ignore_case) {
for (;;) {
unsigned char c1 = tolower(*match);
unsigned char c2 = tolower(*name);
if (c1 == '\0' )
break;
if (c1 != c2)
return 0;
match++;
name++;
namelen--;
}
/* We don't match the matchstring exactly, */
matchlen = strlen(match);
if (strncmp_icase(match, name, matchlen))
return 0;
} else {
for (;;) {
unsigned char c1 = *match;
unsigned char c2 = *name;
if (c1 == '\0' )
break;
if (c1 != c2)
return 0;
match++;
name++;
namelen--;
}
/* We don't match the matchstring exactly, */
matchlen = strlen(match);
if (strncmp(match, name, matchlen))
return 0;
}

if (namelen == matchlen)
return MATCHED_EXACTLY;
if (match[matchlen-1] == '/' || name[matchlen] == '/')
return MATCHED_RECURSIVELY;
return 0;
}

static enum git_target_type get_symlink_type( const char *filepath, const char *symlinkpath )
{
/* For certain O/S and file-systems, symlinks need to know before-hand whether it
* is a directory or a file being pointed to.
*
* This allows us to use index information for relative paths that lie
* within the working directory.
*
* This function is not interested in interrogating the file-system.
*/
char *sanitized;
const char *fpos, *last;
enum git_target_type ret;
int len, pos;

/* This is an absolute path, so git doesn't know.
*/
if (is_absolute_path(symlinkpath))
return GIT_TARGET_UNKNOWN;

/* Work on a sanitized version of the path that can be
* matched against the index.
*/
last = NULL;
for (fpos = filepath; *fpos; ++fpos)
if (is_dir_sep(*fpos))
last = fpos;

if (last) {
len = (1+last-filepath);
sanitized = xmalloc(len + strlen(symlinkpath)+1);
memcpy(sanitized, filepath, 1+last-filepath);
} else {
len = 0;
sanitized = xmalloc(strlen(symlinkpath)+1);
}
strcpy(sanitized+len, symlinkpath);

ret = GIT_TARGET_UNKNOWN;
if (!normalize_path_copy(sanitized, sanitized)) {
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
switch (match_one(sanitized, ce->name, ce_namelen(ce))) {
case MATCHED_EXACTLY:
case MATCHED_FNMATCH:
ret = GIT_TARGET_ISFILE;
break;
case MATCHED_RECURSIVELY:
ret = GIT_TARGET_ISDIR;
break;
}
}
}

free(sanitized);
return ret;
}

static int write_entry(struct cache_entry *ce,
char *path, const struct checkout *state, int to_tempfile)
{
Expand Down Expand Up @@ -165,7 +285,10 @@ static int write_entry(struct cache_entry *ce,
path, sha1_to_hex(ce->sha1));

if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) {
ret = symlink(new, path);
/* Note that symlink_with_type is a macro, and that for filesystems that
* don't care, get_symlink_type will not be called.
*/
ret = symlink_with_type(new, path, get_symlink_type(path, new));
free(new);
if (ret)
return error("unable to create symlink %s (%s)",
Expand Down
10 changes: 10 additions & 0 deletions git-compat-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@
#define _NETBSD_SOURCE 1
#define _SGI_SOURCE 1

/* default is not to pass type - mingw needs this */
#define symlink_with_type(a,b,c) symlink((a),(b))

/* Used for 'Target Type' Parameter for symlink_with_type */
enum git_target_type {
GIT_TARGET_UNKNOWN,
GIT_TARGET_ISFILE,
GIT_TARGET_ISDIR
};

#if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0502
Expand Down

0 comments on commit fa9215f

Please sign in to comment.