mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-23 09:10:46 +00:00
windows: Fix Symlink issues
Handle Symlinks if they can be handled in Win32. This is not even compiled. Needs review. The lstat implementation is modified from core Git. The readlink implementation is modified from PHP.
This commit is contained in:
parent
1071c56519
commit
ae496955d2
@ -119,9 +119,9 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
|
|||||||
ssize_t read_len;
|
ssize_t read_len;
|
||||||
|
|
||||||
if (!islnk)
|
if (!islnk)
|
||||||
read_len = read(fd, buffer, sizeof(buffer));
|
read_len = gitfo_read(fd, buffer, sizeof(buffer));
|
||||||
else
|
else
|
||||||
read_len = readlink(full_path, buffer, sizeof(buffer));
|
read_len = gitfo_readlink(full_path, buffer, sizeof(buffer));
|
||||||
|
|
||||||
if (read_len < 0) {
|
if (read_len < 0) {
|
||||||
if (!islnk)
|
if (!islnk)
|
||||||
|
139
src/fileops.c
139
src/fileops.c
@ -175,14 +175,6 @@ int gitfo_exists(const char *path)
|
|||||||
return access(path, F_OK);
|
return access(path, F_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gitfo_shallow_exists(const char *path)
|
|
||||||
{
|
|
||||||
assert(path);
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
return gitfo_lstat(path, &st);
|
|
||||||
}
|
|
||||||
|
|
||||||
git_off_t gitfo_size(git_file fd)
|
git_off_t gitfo_size(git_file fd)
|
||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
@ -609,3 +601,134 @@ int gitfo_getcwd(char *buffer_out, size_t size)
|
|||||||
|
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
static inline time_t filetime_to_time_t(const FILETIME *ft)
|
||||||
|
{
|
||||||
|
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
|
||||||
|
winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
|
||||||
|
winTime /= 10000000; /* Nano to seconds resolution */
|
||||||
|
return (time_t)winTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_lstat(const char *file_name, struct stat *buf)
|
||||||
|
{
|
||||||
|
WIN32_FILE_ATTRIBUTE_DATA fdata;
|
||||||
|
|
||||||
|
if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {
|
||||||
|
int fMode = S_IREAD;
|
||||||
|
|
||||||
|
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
fMode |= S_IFDIR;
|
||||||
|
else
|
||||||
|
fMode |= S_IFREG;
|
||||||
|
|
||||||
|
if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||||
|
fMode |= S_IWRITE;
|
||||||
|
|
||||||
|
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
fMode |= _S_IFLNK;
|
||||||
|
|
||||||
|
buf->st_ino = 0;
|
||||||
|
buf->st_gid = 0;
|
||||||
|
buf->st_uid = 0;
|
||||||
|
buf->st_nlink = 1;
|
||||||
|
buf->st_mode = fMode;
|
||||||
|
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
|
||||||
|
buf->st_dev = buf->st_rdev = (_getdrive() - 1);
|
||||||
|
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
|
||||||
|
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
|
||||||
|
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (GetLastError()) {
|
||||||
|
case ERROR_ACCESS_DENIED:
|
||||||
|
case ERROR_SHARING_VIOLATION:
|
||||||
|
case ERROR_LOCK_VIOLATION:
|
||||||
|
case ERROR_SHARING_BUFFER_EXCEEDED:
|
||||||
|
return GIT_EOSERR;
|
||||||
|
|
||||||
|
case ERROR_BUFFER_OVERFLOW:
|
||||||
|
case ERROR_NOT_ENOUGH_MEMORY:
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return GIT_EINVALIDPATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int gitfo_lstat__w32(const char *file_name, struct stat *buf)
|
||||||
|
{
|
||||||
|
int namelen, error;
|
||||||
|
char alt_name[GIT_PATH_MAX];
|
||||||
|
|
||||||
|
if ((error = do_lstat(file_name, buf)) == GIT_SUCCESS)
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
|
||||||
|
/* if file_name ended in a '/', Windows returned ENOENT;
|
||||||
|
* try again without trailing slashes
|
||||||
|
*/
|
||||||
|
if (error != GIT_EINVALIDPATH)
|
||||||
|
return git__throw(GIT_EOSERR, "Failed to lstat file");
|
||||||
|
|
||||||
|
namelen = strlen(file_name);
|
||||||
|
if (namelen && file_name[namelen-1] != '/')
|
||||||
|
return git__throw(GIT_EOSERR, "Failed to lstat file");
|
||||||
|
|
||||||
|
while (namelen && file_name[namelen-1] == '/')
|
||||||
|
--namelen;
|
||||||
|
|
||||||
|
if (!namelen || namelen >= GIT_PATH_MAX)
|
||||||
|
return git__throw(GIT_ENOMEM, "Failed to lstat file");
|
||||||
|
|
||||||
|
memcpy(alt_name, file_name, namelen);
|
||||||
|
alt_name[namelen] = 0;
|
||||||
|
return do_lstat(alt_name, buf);
|
||||||
|
}
|
||||||
|
int gitfo_readlink__w32(const char *link, char *target, size_t target_len)
|
||||||
|
{
|
||||||
|
HANDLE hFile;
|
||||||
|
DWORD dwRet;
|
||||||
|
|
||||||
|
hFile = CreateFile(link, // file to open
|
||||||
|
GENERIC_READ, // open for reading
|
||||||
|
FILE_SHARE_READ, // share for reading
|
||||||
|
NULL, // default security
|
||||||
|
OPEN_EXISTING, // existing file only
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS, // normal file
|
||||||
|
NULL); // no attr. template
|
||||||
|
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||||||
|
return GIT_EOSERR;
|
||||||
|
|
||||||
|
dwRet = GetFinalPathNameByHandleA(hFile, target, target_len, VOLUME_NAME_DOS);
|
||||||
|
if (dwRet >= target_len)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
|
CloseHandle(hFile);
|
||||||
|
|
||||||
|
if (dwRet > 4) {
|
||||||
|
/* Skip first 4 characters if they are "\\?\" */
|
||||||
|
if (target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') {
|
||||||
|
char tmp[MAXPATHLEN];
|
||||||
|
unsigned int offset = 4;
|
||||||
|
dwRet -= 4;
|
||||||
|
|
||||||
|
/* \??\UNC\ */
|
||||||
|
if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') {
|
||||||
|
offset += 2;
|
||||||
|
dwRet -= 2;
|
||||||
|
target[offset] = '\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(tmp, target + offset, dwRet);
|
||||||
|
memcpy(target, tmp, dwRet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target[dwRet] = '\0';
|
||||||
|
return dwRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -65,7 +65,6 @@ typedef struct { /* file io buffer */
|
|||||||
} gitfo_buf;
|
} gitfo_buf;
|
||||||
|
|
||||||
extern int gitfo_exists(const char *path);
|
extern int gitfo_exists(const char *path);
|
||||||
extern int gitfo_shallow_exists(const char *path);
|
|
||||||
extern int gitfo_open(const char *path, int flags);
|
extern int gitfo_open(const char *path, int flags);
|
||||||
extern int gitfo_creat(const char *path, int mode);
|
extern int gitfo_creat(const char *path, int mode);
|
||||||
extern int gitfo_creat_force(const char *path, int mode);
|
extern int gitfo_creat_force(const char *path, int mode);
|
||||||
@ -95,7 +94,14 @@ extern int gitfo_mv_force(const char *from, const char *to);
|
|||||||
|
|
||||||
#define gitfo_stat(p,b) stat(p, b)
|
#define gitfo_stat(p,b) stat(p, b)
|
||||||
#define gitfo_fstat(f,b) fstat(f, b)
|
#define gitfo_fstat(f,b) fstat(f, b)
|
||||||
|
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
# define gitfo_lstat(p,b) gitfo_lstat__w32(p,b)
|
||||||
|
# define gitfo_readlink(a, b, c) gitfo_readlink__w32(a, b, c)
|
||||||
|
#else
|
||||||
# define gitfo_lstat(p,b) lstat(p,b)
|
# define gitfo_lstat(p,b) lstat(p,b)
|
||||||
|
# define gitfo_readlink(a, b, c) readlink(a, b, c)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define gitfo_unlink(p) unlink(p)
|
#define gitfo_unlink(p) unlink(p)
|
||||||
#define gitfo_rmdir(p) rmdir(p)
|
#define gitfo_rmdir(p) rmdir(p)
|
||||||
|
@ -411,11 +411,8 @@ static int index_init_entry(git_index_entry *entry, git_index *index, const char
|
|||||||
|
|
||||||
git__joinpath(full_path, index->repository->path_workdir, rel_path);
|
git__joinpath(full_path, index->repository->path_workdir, rel_path);
|
||||||
|
|
||||||
if (gitfo_shallow_exists(full_path) < 0)
|
|
||||||
return git__throw(GIT_ENOTFOUND, "Failed to initialize entry. %s does not exist", full_path);
|
|
||||||
|
|
||||||
if (gitfo_lstat(full_path, &st) < 0)
|
if (gitfo_lstat(full_path, &st) < 0)
|
||||||
return git__throw(GIT_EOSERR, "Failed to initialize entry. %s appears to be corrupted", full_path);
|
return git__throw(GIT_EOSERR, "Failed to initialize entry. '%s' cannot be opened", full_path);
|
||||||
|
|
||||||
if (stage < 0 || stage > 3)
|
if (stage < 0 || stage > 3)
|
||||||
return git__throw(GIT_ERROR, "Failed to initialize entry. Invalid stage %i", stage);
|
return git__throw(GIT_ERROR, "Failed to initialize entry. Invalid stage %i", stage);
|
||||||
|
@ -12,10 +12,13 @@
|
|||||||
# define stat _stat64
|
# define stat _stat64
|
||||||
# define fstat _fstat64
|
# define fstat _fstat64
|
||||||
|
|
||||||
|
#define _S_IFLNK 0120000
|
||||||
|
|
||||||
/* stat: file mode type testing macros */
|
/* stat: file mode type testing macros */
|
||||||
# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
||||||
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
||||||
# define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO)
|
# define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO)
|
||||||
|
# define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK)
|
||||||
|
|
||||||
/* case-insensitive string comparison */
|
/* case-insensitive string comparison */
|
||||||
# define strcasecmp _stricmp
|
# define strcasecmp _stricmp
|
||||||
|
Loading…
Reference in New Issue
Block a user