DirEntList list_dir ( const std::wstring &directory, const UnaryCallback <const DirEnt &, bool> &filter, const BinaryCallback <const DirEnt &, const DirEnt &, bool> &comp ) { DirEntList filelist; std::string dirname = wstring_to_mbs (directory); if (DIR *dir = ::opendir (dirname.c_str ())) { DirEnt tmp_ent; if (*c(dirname).rbegin() != '/') { dirname += '/'; } while (struct dirent *ent = readdir (dir)) { tmp_ent.name = mbs_to_wstring (ent->d_name); tmp_ent.attr = get_file_attr (dirname + ent->d_name); if (!filter (tmp_ent)) { filelist.push_back (std::move (tmp_ent)); } } closedir (dir); // Sort them filelist.sort (wrap (comp)); } return filelist; }
std::string find_executable (const std::string &exe) { std::string result; if (exe.empty ()) { // Empty input. Return empty string } else if (memchr (exe.data (), '/', exe.length ())) { // exe is a full/relative pathname if (exe[0] == '~') { result = home_expand_pathname (exe); } else { result = exe; } if ((get_file_attr (result) & (FILE_ATTR_DIRECTORY|FILE_ATTR_EXECUTABLE)) != FILE_ATTR_EXECUTABLE) { result.clear (); } } else if (const char *path = getenv ("PATH")) { // exe is a "bare" filename for (;;) { const char *colon = strchrnul (path, ':'); if (path == colon) { result = '.'; } else { result.assign (path, colon); } result += '/'; result += exe; if ((get_file_attr (result) & (FILE_ATTR_DIRECTORY|FILE_ATTR_EXECUTABLE)) == FILE_ATTR_EXECUTABLE) { break; } if (*colon != ':') { result.clear (); break; } path = colon+1; } } return result; }
/* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. * * If follow is true then act like stat() and report on the link * target. Otherwise report on the link itself. */ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) { int err; WIN32_FILE_ATTRIBUTE_DATA fdata; if (!(err = get_file_attr(file_name, &fdata))) { int len = strlen(file_name); buf->st_ino = 0; buf->st_uid = DEFAULT_UID; buf->st_gid = DEFAULT_GID; buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); if (len > 4 && (!strcasecmp(file_name+len-4, ".exe") || !strcasecmp(file_name+len-4, ".com"))) buf->st_mode |= S_IEXEC; buf->st_size = fdata.nFileSizeLow | (((off64_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 (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { WIN32_FIND_DATAA findbuf; HANDLE handle = FindFirstFileA(file_name, &findbuf); if (handle != INVALID_HANDLE_VALUE) { if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); } else { buf->st_mode = S_IFLNK; } buf->st_mode |= S_IREAD; if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) buf->st_mode |= S_IWRITE; } FindClose(handle); } } /* * Assume a block is 4096 bytes and calculate number of 512 byte * sectors. */ buf->st_blksize = 4096; buf->st_blocks = ((buf->st_size+4095)>>12)<<3; return 0; }
/* 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; }
/* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. */ static int do_lstat(const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; if (!(errno = get_file_attr(file_name, &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; /* Can't use nFileSizeHigh, since it's not a stat64 */ 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)); return 0; } return -1; }
/* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. * * If follow is true then act like stat() and report on the link * target. Otherwise report on the link itself. */ static int do_lstat(int follow, const char *file_name, struct stat *buf) { int err; WIN32_FILE_ATTRIBUTE_DATA fdata; if (!(err = get_file_attr(file_name, &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 (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { WIN32_FIND_DATAA findbuf; HANDLE handle = FindFirstFileA(file_name, &findbuf); if (handle != INVALID_HANDLE_VALUE) { if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); } else { buf->st_mode = S_IFLNK; } buf->st_mode |= S_IREAD; if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) buf->st_mode |= S_IWRITE; } FindClose(handle); } } return 0; } errno = err; return -1; }
unsigned get_file_attr (const wchar_t *name) { return get_file_attr (wstring_to_mbs (name).c_str ()); }