mirror of
https://github.com/git/git.git
synced 2026-01-19 15:09:01 +00:00
Win32: implement stat() with symlink support
With respect to symlinks, the current stat() implementation is almost the same as lstat(): except for the file type (st_mode & S_IFMT), it returns information about the link rather than the target. Implement stat by opening the file with as little permissions as possible and calling GetFileInformationByHandle on it. This way, all link resoltion is handled by the Windows file system layer. If symlinks are disabled, use lstat() as before, but fail with ELOOP if a symlink would have to be resolved. Signed-off-by: Karsten Blees <blees@dcon.de>
This commit is contained in:
committed by
Jameson Miller
parent
daff13a0e2
commit
76d630d0ca
@@ -723,16 +723,60 @@ int mingw_lstat(const char *file_name, struct stat *buf)
|
||||
{
|
||||
return do_lstat(0, file_name, buf);
|
||||
}
|
||||
|
||||
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION fdata;
|
||||
if (!GetFileInformationByHandle(hnd, &fdata)) {
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
buf->st_ino = 0;
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_gid = buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow | (((off_t) fdata.nFileSizeHigh) << 32);
|
||||
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 0;
|
||||
}
|
||||
|
||||
int mingw_stat(const char *file_name, struct stat *buf)
|
||||
{
|
||||
return do_lstat(1, file_name, buf);
|
||||
wchar_t wfile_name[MAX_LONG_PATH];
|
||||
HANDLE hnd;
|
||||
int result;
|
||||
|
||||
/* if symlinks are disabled, use lstat() (without following links) */
|
||||
if (!has_symlinks) {
|
||||
result = lstat(file_name, buf);
|
||||
if (!result && S_ISLNK(buf->st_mode)) {
|
||||
errno = ELOOP;
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* otherwise just open the file and let Windows resolve the links */
|
||||
if (xutftowcs_long_path(wfile_name, file_name) < 0)
|
||||
return -1;
|
||||
hnd = CreateFileW(wfile_name, 0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (hnd == INVALID_HANDLE_VALUE) {
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
result = get_file_info_by_handle(hnd, buf);
|
||||
CloseHandle(hnd);
|
||||
return result;
|
||||
}
|
||||
|
||||
int mingw_fstat(int fd, struct stat *buf)
|
||||
{
|
||||
HANDLE fh = (HANDLE)_get_osfhandle(fd);
|
||||
BY_HANDLE_FILE_INFORMATION fdata;
|
||||
|
||||
if (fh == INVALID_HANDLE_VALUE) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
@@ -741,20 +785,8 @@ int mingw_fstat(int fd, struct stat *buf)
|
||||
if (GetFileType(fh) != FILE_TYPE_DISK)
|
||||
return _fstati64(fd, buf);
|
||||
|
||||
if (GetFileInformationByHandle(fh, &fdata)) {
|
||||
buf->st_ino = 0;
|
||||
buf->st_gid = 0;
|
||||
buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow |
|
||||
(((off_t)fdata.nFileSizeHigh)<<32);
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
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));
|
||||
if (!get_file_info_by_handle(fh, buf))
|
||||
return 0;
|
||||
}
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user