/* do_stat is a common implementation for cygwin_lstat and cygwin_stat. * * To simplify its logic, in the case of cygwin symlinks, this implementation * falls back to the cygwin version of stat/lstat, which is provided as the * last argument. */ static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat) { WIN32_FILE_ATTRIBUTE_DATA fdata; if (file_name[0] == '/') return cygstat (file_name, buf); if (!(errno = get_file_attr(file_name, &fdata))) { /* * If the system attribute is set and it is not a directory then * it could be a symbol link created in the nowinsymlinks mode. * Normally, Cygwin works in the winsymlinks mode, so this situation * is very unlikely. For the sake of simplicity of our code, let's * Cygwin to handle it. */ if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) return cygstat(file_name, buf); /* fill out the stat structure */ buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_ino = 0; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); buf->st_nlink = 1; buf->st_uid = buf->st_gid = 0; #ifdef __CYGWIN_USE_BIG_TYPES__ buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow; #else buf->st_size = (off_t)fdata.nFileSizeLow; #endif buf->st_blocks = size_to_blocks(buf->st_size); filetime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim); filetime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim); filetime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim); return 0; } else if (errno == ENOENT) { /* * In the winsymlinks mode (which is the default), Cygwin * emulates symbol links using Windows shortcut files. These * files are formed by adding .lnk extension. So, if we have * not found the specified file name, it could be that it is * a symbol link. Let's Cygwin to deal with that. */ return cygstat(file_name, buf); } return -1; }
/* * Allocate and initialize an fsentry from a FILE_FULL_DIR_INFORMATION structure. */ static struct fsentry *fseentry_create_entry(struct fscache *cache, struct fsentry *list, PFILE_FULL_DIR_INFORMATION fdata) { char buf[MAX_PATH * 3]; int len; struct fsentry *fse; len = xwcstoutfn(buf, ARRAY_SIZE(buf), fdata->FileName, fdata->FileNameLength / sizeof(wchar_t)); fse = fsentry_alloc(cache, list, buf, len); /* * On certain Windows versions, host directories mapped into * Windows Containers ("Volumes", see https://docs.docker.com/storage/volumes/) * look like symbolic links, but their targets are paths that * are valid only in kernel mode. * * Let's work around this by detecting that situation and * telling Git that these are *not* symbolic links. */ if (fdata->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && fdata->EaSize == IO_REPARSE_TAG_SYMLINK && sizeof(buf) > (list ? list->len + 1 : 0) + fse->len + 1 && is_inside_windows_container()) { size_t off = 0; if (list) { memcpy(buf, list->name, list->len); buf[list->len] = '/'; off = list->len + 1; } memcpy(buf + off, fse->name, fse->len); buf[off + fse->len] = '\0'; } fse->st_mode = file_attr_to_st_mode(fdata->FileAttributes, fdata->EaSize, buf); fse->st_size = S_ISLNK(fse->st_mode) ? MAX_LONG_PATH : fdata->EndOfFile.LowPart | (((off_t)fdata->EndOfFile.HighPart) << 32); filetime_to_timespec((FILETIME *)&(fdata->LastAccessTime), &(fse->st_atim)); filetime_to_timespec((FILETIME *)&(fdata->LastWriteTime), &(fse->st_mtim)); filetime_to_timespec((FILETIME *)&(fdata->CreationTime), &(fse->st_ctim)); return fse; }
/* * Allocate and initialize an fsentry from a WIN32_FIND_DATA structure. */ static struct fsentry *fseentry_create_entry(struct fsentry *list, const WIN32_FIND_DATAW *fdata) { char buf[MAX_PATH * 3]; int len; struct fsentry *fse; len = xwcstoutf(buf, fdata->cFileName, ARRAY_SIZE(buf)); fse = fsentry_alloc(list, buf, len); 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); filetime_to_timespec(&(fdata->ftLastAccessTime), &(fse->st_atim)); filetime_to_timespec(&(fdata->ftLastWriteTime), &(fse->st_mtim)); filetime_to_timespec(&(fdata->ftCreationTime), &(fse->st_ctim)); return fse; }