// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #include #include #include #include #ifdef AFX_CORE1_SEG #pragma code_seg(AFX_CORE1_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW //////////////////////////////////////////////////////////////////////////// // Status information for all file classes // In this file so everyone doesn't get the CTime package ///////////////////////////////////////////////////////////////////////////// // CFileStatus diagnostics #ifdef _DEBUG void CFileStatus::Dump(CDumpContext& dc) const { dc << "a CFileStatus at " << (void*)this; dc << "\nm_ctime = " << m_ctime; dc << "\nm_mtime = " << m_mtime; dc << "\nm_atime = " << m_atime; dc << "\nm_size = " << m_size; dc << "\nm_attribute = " << m_attribute; dc << "\nm_szFullName = " << m_szFullName; dc << "\n"; } #endif ///////////////////////////////////////////////////////////////////////////// // CFile name handlers CString CFile::GetFileName() const { ASSERT_VALID(this); CFileStatus status; GetStatus(status); CString strResult; AfxGetFileName(status.m_szFullName, strResult.GetBuffer(_MAX_FNAME), _MAX_FNAME); strResult.ReleaseBuffer(); return strResult; } CString CFile::GetFileTitle() const { ASSERT_VALID(this); CFileStatus status; GetStatus(status); CString strResult; AfxGetFileTitle(status.m_szFullName, strResult.GetBuffer(_MAX_FNAME), _MAX_FNAME); strResult.ReleaseBuffer(); return strResult; } CString CFile::GetFilePath() const { ASSERT_VALID(this); CFileStatus status; GetStatus(status); return status.m_szFullName; } ///////////////////////////////////////////////////////////////////////////// // CFile Status implementation BOOL CFile::GetStatus(CFileStatus& rStatus) const { ASSERT_VALID(this); memset(&rStatus, 0, sizeof(CFileStatus)); // copy file name from cached m_strFileName lstrcpyn(rStatus.m_szFullName, m_strFileName, _countof(rStatus.m_szFullName)); if (m_hFile != hFileNull) { // get time current file size FILETIME ftCreate, ftAccess, ftModify; if (!::GetFileTime((HANDLE)m_hFile, &ftCreate, &ftAccess, &ftModify)) return FALSE; if ((rStatus.m_size = ::GetFileSize((HANDLE)m_hFile, NULL)) == (DWORD)-1L) return FALSE; if (m_strFileName.IsEmpty()) rStatus.m_attribute = 0; else { DWORD dwAttribute = ::GetFileAttributes(m_strFileName); // don't return an error for this because previous versions of MFC didn't if (dwAttribute == 0xFFFFFFFF) rStatus.m_attribute = 0; else { rStatus.m_attribute = (BYTE) dwAttribute; #ifdef _DEBUG // MFC BUG: m_attribute is only a BYTE wide if (dwAttribute & ~0xFF) TRACE0("Warning: CFile::GetStatus() returns m_attribute without high-order flags.\n"); #endif } } // convert times as appropriate rStatus.m_ctime = CTime(ftCreate); rStatus.m_atime = CTime(ftAccess); rStatus.m_mtime = CTime(ftModify); if (rStatus.m_ctime.GetTime() == 0) rStatus.m_ctime = rStatus.m_mtime; if (rStatus.m_atime.GetTime() == 0) rStatus.m_atime = rStatus.m_mtime; } return TRUE; } BOOL PASCAL CFile::GetStatus(LPCTSTR lpszFileName, CFileStatus& rStatus) { // attempt to fully qualify path first if (!AfxFullPath(rStatus.m_szFullName, lpszFileName)) { rStatus.m_szFullName[0] = '\0'; return FALSE; } WIN32_FIND_DATA findFileData; HANDLE hFind = FindFirstFile((LPTSTR)lpszFileName, &findFileData); if (hFind == INVALID_HANDLE_VALUE) return FALSE; VERIFY(FindClose(hFind)); // strip attribute of NORMAL bit, our API doesn't have a "normal" bit. rStatus.m_attribute = (BYTE) (findFileData.dwFileAttributes & ~FILE_ATTRIBUTE_NORMAL); // get just the low DWORD of the file size ASSERT(findFileData.nFileSizeHigh == 0); rStatus.m_size = (LONG)findFileData.nFileSizeLow; // convert times as appropriate rStatus.m_ctime = CTime(findFileData.ftCreationTime); rStatus.m_atime = CTime(findFileData.ftLastAccessTime); rStatus.m_mtime = CTime(findFileData.ftLastWriteTime); if (rStatus.m_ctime.GetTime() == 0) rStatus.m_ctime = rStatus.m_mtime; if (rStatus.m_atime.GetTime() == 0) rStatus.m_atime = rStatus.m_mtime; return TRUE; } void AFX_CDECL AfxTimeToFileTime(const CTime& time, LPFILETIME pFileTime) { SYSTEMTIME sysTime; sysTime.wYear = (WORD)time.GetYear(); sysTime.wMonth = (WORD)time.GetMonth(); sysTime.wDay = (WORD)time.GetDay(); sysTime.wHour = (WORD)time.GetHour(); sysTime.wMinute = (WORD)time.GetMinute(); sysTime.wSecond = (WORD)time.GetSecond(); sysTime.wMilliseconds = 0; // convert system time to local file time FILETIME localTime; if (!SystemTimeToFileTime((LPSYSTEMTIME)&sysTime, &localTime)) CFileException::ThrowOsError((LONG)::GetLastError()); // convert local file time to UTC file time if (!LocalFileTimeToFileTime(&localTime, pFileTime)) CFileException::ThrowOsError((LONG)::GetLastError()); } void PASCAL CFile::SetStatus(LPCTSTR lpszFileName, const CFileStatus& status) { DWORD wAttr; FILETIME creationTime; FILETIME lastAccessTime; FILETIME lastWriteTime; LPFILETIME lpCreationTime = NULL; LPFILETIME lpLastAccessTime = NULL; LPFILETIME lpLastWriteTime = NULL; if ((wAttr = GetFileAttributes((LPTSTR)lpszFileName)) == (DWORD)-1L) CFileException::ThrowOsError((LONG)GetLastError()); if ((DWORD)status.m_attribute != wAttr && (wAttr & readOnly)) { // Set file attribute, only if currently readonly. // This way we will be able to modify the time assuming the // caller changed the file from readonly. if (!SetFileAttributes((LPTSTR)lpszFileName, (DWORD)status.m_attribute)) CFileException::ThrowOsError((LONG)GetLastError()); } // last modification time if (status.m_mtime.GetTime() != 0) { AfxTimeToFileTime(status.m_mtime, &lastWriteTime); lpLastWriteTime = &lastWriteTime; // last access time if (status.m_atime.GetTime() != 0) { AfxTimeToFileTime(status.m_atime, &lastAccessTime); lpLastAccessTime = &lastAccessTime; } // create time if (status.m_ctime.GetTime() != 0) { AfxTimeToFileTime(status.m_ctime, &creationTime); lpCreationTime = &creationTime; } HANDLE hFile = ::CreateFile(lpszFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) CFileException::ThrowOsError((LONG)::GetLastError()); if (!SetFileTime((HANDLE)hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime)) CFileException::ThrowOsError((LONG)::GetLastError()); if (!::CloseHandle(hFile)) CFileException::ThrowOsError((LONG)::GetLastError()); } if ((DWORD)status.m_attribute != wAttr && !(wAttr & readOnly)) { if (!SetFileAttributes((LPTSTR)lpszFileName, (DWORD)status.m_attribute)) CFileException::ThrowOsError((LONG)GetLastError()); } } /////////////////////////////////////////////////////////////////////////////// // CMemFile::GetStatus implementation BOOL CMemFile::GetStatus(CFileStatus& rStatus) const { ASSERT_VALID(this); rStatus.m_ctime = 0; rStatus.m_mtime = 0; rStatus.m_atime = 0; rStatus.m_size = m_nFileSize; rStatus.m_attribute = normal; rStatus.m_szFullName[0] = '\0'; return TRUE; } /////////////////////////////////////////////////////////////////////////////