int lisp_fstat(HANDLE hfile, struct __stat64 *buf) { int filetype; filetype = GetFileType(hfile) & ~FILE_TYPE_REMOTE; if (filetype == FILE_TYPE_UNKNOWN) { errno = EBADF; return -1; } memset(buf, 0, sizeof(*buf)); buf->st_nlink = 1; switch(filetype) { case FILE_TYPE_CHAR: case FILE_TYPE_PIPE: if (filetype == FILE_TYPE_CHAR) { buf->st_mode = _S_IFCHR; } else { buf->st_mode = _S_IFIFO; } break; case FILE_TYPE_DISK: { BY_HANDLE_FILE_INFORMATION info; if (!GetFileInformationByHandle(hfile, &info)) { _dosmaperr(GetLastError()); return -1; } if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { buf->st_mode = STAT_READONLY; } else { buf->st_mode = STAT_READWRITE; } buf->st_mode |= _S_IFREG; buf->st_size = ((((__int64)(info.nFileSizeHigh))<<32LL) | ((__int64)(info.nFileSizeLow))); buf->st_mtime = filetime_to_unix_time(&info.ftLastWriteTime); buf->st_atime = filetime_to_unix_time(&info.ftLastAccessTime); buf->st_ctime = filetime_to_unix_time(&info.ftCreationTime); } break; case FILE_TYPE_UNKNOWN: default: errno = EBADF; return -1; } return 0; }
static void stat_to_sys_path_info(DWORD attributes, DWORD size_low, DWORD size_high, FILETIME const* mtime, tr_sys_path_info* info) { TR_ASSERT(mtime != NULL); TR_ASSERT(info != NULL); if (attributes & FILE_ATTRIBUTE_DIRECTORY) { info->type = TR_SYS_PATH_IS_DIRECTORY; } else if (!(attributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_VIRTUAL))) { info->type = TR_SYS_PATH_IS_FILE; } else { info->type = TR_SYS_PATH_IS_OTHER; } info->size = size_high; info->size <<= 32; info->size |= size_low; info->last_modified_at = filetime_to_unix_time(mtime); }
int ty_stat(const char *path, ty_file_info *info, bool follow) { TY_UNUSED(follow); assert(path && path[0]); assert(info); HANDLE h; BY_HANDLE_FILE_INFORMATION attr; int r; // FIXME: check error handling h = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) { switch (GetLastError()) { case ERROR_ACCESS_DENIED: return ty_error(TY_ERROR_ACCESS, "Permission denied for '%s'", path); case ERROR_NOT_READY: return ty_error(TY_ERROR_IO, "I/O error while stating '%s'", path); case ERROR_FILE_NOT_FOUND: return ty_error(TY_ERROR_NOT_FOUND, "Path '%s' does not exist", path); case ERROR_PATH_NOT_FOUND: return ty_error(TY_ERROR_NOT_FOUND, "Part of '%s' is not a directory", path); } // Let's lie a little, error will be clearer this way return ty_error(TY_ERROR_SYSTEM, "GetFileAttributesEx('%s') failed: %s", path, ty_win32_strerror(0)); } r = GetFileInformationByHandle(h, &attr); if (!r) return ty_error(TY_ERROR_SYSTEM, "GetFileInformationByHandle('%s') failed: %s", path, ty_win32_strerror(0)); if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { info->type = TY_FILE_DIRECTORY; } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { info->type = TY_FILE_SPECIAL; } else { info->type = TY_FILE_REGULAR; } info->size = ((uint64_t)attr.nFileSizeHigh << 32) | attr.nFileSizeLow; info->mtime = filetime_to_unix_time(&attr.ftLastWriteTime); return 0; }