File:  [WindowsNT SDKs] / mstools / mfc / src / file.cpp
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:25:09 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-jul-1993, HEAD
Microsoft Windows NT Build 511 (SDK Final Release) 07-24-1993

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// QuickHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#ifdef _WINDOWS
#include "afxwin.h"
#else
#include "afx.h"
#endif
#pragma hdrstop

#include <errno.h>
#include <io.h>
#include <limits.h>
#include <malloc.h>

#ifdef _DOSWIN
#include <sys\types.h>
#include <sys\stat.h>
#endif

#include "dosio_.h"

#ifdef AFX_CORE_SEG
#pragma code_seg(AFX_CORE_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

////////////////////////////////////////////////////////////////////////////

#ifdef _DOSWIN

// DOS INT 21h functions not provided by C Runtimes
// additional Dos calls
#pragma optimize("qgel", off) // assembler cannot be globally optimized

UINT _Afx_seek(UINT hFile, LONG lOff, UINT nMode, DWORD FAR* lpdwNew)
{ 
	UINT res;
	*lpdwNew = -1;
	_asm { 
			mov     bx, hFile
			mov     ax, nMode
			mov     ah, 42h
			mov     dx, word ptr lOff
			mov     cx, word ptr lOff+2
			DOSCALL
			jc      __seek_err
			les     bx, lpdwNew
			mov     word ptr es:[bx], ax
			mov     word ptr es:[bx+2], dx
			xor     ax, ax
	__seek_err:
			mov     res, ax
	}
	return res;
}
		
UINT _Afx_rename(LPCSTR lpszOld, LPCSTR lpszNew)
{ 
	UINT res;
	_asm { 
			mov     bx, ds
			lds     dx, lpszOld
			les     di, lpszNew
			mov     ax, 5600h
			DOSCALL
			jc      __rename_err
			xor     ax, ax
	__rename_err:
			mov     res, ax
			mov     ds, bx
	}
	return res;
}

UINT _Afx_remove(LPCSTR lpsz)  
{ 
	UINT res;
	_asm { 
			mov     bx, ds
			lds     dx, lpsz
			mov     ax, 4100h
			DOSCALL
			jc      __remove_err
			xor     ax, ax
	__remove_err:
			mov     res, ax
			mov     ds, bx
	}
	return res;
}

UINT _Afx_lock(UINT hFile, DWORD dwStart, DWORD dwLen, BOOL bUnlock)
{ 
	UINT res;
	_asm { 
			mov     ax, bUnlock
			mov     ah, 5ch
			mov     bx, hFile
			mov     dx, word ptr dwStart
			mov     cx, word ptr dwStart+2
			mov     di, word ptr dwLen
			mov     si, word ptr dwLen+2
			DOSCALL
			jc      __lock_err1
			xor     ax, ax
	__lock_err1:
			mov     res, ax
			
	}
	return res;
}

#pragma optimize("", on)    // return to default optimizations

#endif // _DOSWIN

/////////////////////////////////////////////////////////////////////////////
// CFileStatus implementation
#ifdef _DEBUG
void
CFileStatus::Dump(CDumpContext& dc) const
{           
	dc << "file status information:";
	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;
}
#endif


////////////////////////////////////////////////////////////////////////////
// CFile implementation
IMPLEMENT_DYNAMIC(CFile, CObject)


CFile::CFile()
{
	m_hFile = hFileNull;
	m_bCloseOnDelete = FALSE;
}

CFile::CFile(int hFile)
{
	m_hFile = hFile;
	m_bCloseOnDelete = FALSE;
}

CFile::CFile(const char* pszFileName, UINT nOpenFlags)
{
	ASSERT(AfxIsValidAddress(pszFileName, strlen(pszFileName), FALSE));

	CFileException e;
	if (!this->Open(pszFileName, nOpenFlags, &e))
		AfxThrowFileException(e.m_cause, e.m_lOsError);
}

CFile::~CFile()
{   
	if (m_hFile != hFileNull && m_bCloseOnDelete)
		Close();
}

CFile*
CFile::Duplicate() const
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);

	CFile* pFile = new CFile(hFileNull);
#ifdef _DOSWIN
	pFile->m_hFile = _dup(this->m_hFile);
#else
	if (!::DuplicateHandle(::GetCurrentProcess(),
		(HANDLE)m_hFile, ::GetCurrentProcess(), 
		(LPHANDLE)&pFile->m_hFile, 0L, TRUE, DUPLICATE_SAME_ACCESS))
	{
		delete pFile;
		CFileException::ThrowOsError(::GetLastError());
	}
#endif
	pFile->m_bCloseOnDelete = this->m_bCloseOnDelete;
	return pFile;
}

BOOL
CFile::Open(const char* pszFileName, UINT nOpenFlags, 
	CFileException* pException /* = NULL */)
{
	ASSERT(AfxIsValidAddress(pszFileName, strlen(pszFileName), FALSE));
	ASSERT(pException == NULL || AfxIsValidAddress(pException, sizeof(CFileException)));
	ASSERT((nOpenFlags & typeText) == 0);

	// CFile objects are always binary and _dos_open does not need flag
	nOpenFlags &= ~(UINT)CFile::typeBinary;

	m_bCloseOnDelete = FALSE;
	m_hFile = hFileNull;


#ifdef _DOSWIN
	ASSERT_VALID(this);

	char szOemPath[_MAX_PATH];
	UINT nErr;

	AnsiToOem(pszFileName, szOemPath);

	if (nOpenFlags & (UINT)CFile::modeCreate)
	{
		if ((nErr = _dos_creat(szOemPath, CFile::normal, (int*)&m_hFile)) != 0)
		{
			if (pException != NULL)
			{
				pException->m_lOsError = nErr;
				pException->m_cause = CFileException::OsErrorToException(nErr);
				return FALSE; // file was not created
			}
		}
		if ((nErr = _dos_close(m_hFile)) != 0)
		{
			// try to delete the file and throw modeCreate exception
			_Afx_remove(szOemPath);
			if (pException != NULL)
			{
				pException->m_lOsError = nErr;
				pException->m_cause = CFileException::OsErrorToException(nErr);
			}
			return FALSE;
		}
	}

	// the file has been modeCreated if needed, now open it
	if ((nErr = _dos_open(szOemPath, nOpenFlags & ~(UINT)CFile::modeCreate, (int*)&m_hFile)) != 0)
	{
		// try to delete the file and throw open exception
		if (pException != NULL)
		{
			pException->m_lOsError = nErr;
			pException->m_cause = CFileException::OsErrorToException(nErr);
		}
		return FALSE;
	}
#endif

#ifdef _NTWIN
	ASSERT_VALID(this);
	ASSERT(sizeof(HFILE) == sizeof(int));
	ASSERT(CFile::shareCompat == 0);

	OFSTRUCT of;

	if (((int)(m_hFile = (int)::OpenFile((LPSTR)pszFileName, &of, nOpenFlags))) < 0)
	{
		if (pException != NULL)
		{
			pException->m_lOsError = of.nErrCode;
			pException->m_cause = CFileException::OsErrorToException((LONG)of.nErrCode);
		}
		return FALSE;
	}
#endif

	m_bCloseOnDelete = TRUE;
	return TRUE;
}


UINT
CFile::Read(void FAR* lpBuf, UINT nCount)
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);
	ASSERT(lpBuf != NULL);
	ASSERT(AfxIsValidAddress(lpBuf, nCount));

	UINT nRead = 0;
	UINT nErr;

	if ((nErr = _dos_read(m_hFile, lpBuf, nCount, &nRead)) != 0)
		CFileException::ThrowOsError(nErr);
		
	return nRead;
}

void
CFile::Write(const void FAR* lpBuf, UINT nCount)
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);
	ASSERT(lpBuf != NULL);
	ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE));

	UINT nWritten = 0;
	UINT nErr;

	if ((nErr = _dos_write(m_hFile, lpBuf, nCount, &nWritten)) != 0)
		CFileException::ThrowOsError(nErr);
	
	if (nCount != nWritten)
		AfxThrowFileException(CFileException::diskFull);
}


LONG
CFile::Seek(LONG lOff, UINT nFrom)
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);
	ASSERT(nFrom == CFile::begin || nFrom == CFile::end || nFrom == CFile::current);

	DWORD dwNew;
	UINT nErr;

	if ((nErr  = _Afx_seek(m_hFile, lOff, nFrom, &dwNew)) != 0)
		CFileException::ThrowOsError(nErr);
	
	return dwNew;
}


DWORD
CFile::GetPosition() const
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);

	DWORD dwPos;
	UINT nErr;

	if ((nErr = _Afx_seek(m_hFile, 0, CFile::current, &dwPos)) != 0)
		CFileException::ThrowOsError(nErr);
	
	return dwPos;
}


#pragma optimize("qgel", off) // assembler cannot be globally optimized
void
CFile::Flush()
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);
	
	UINT nErr;

#ifdef _DOSWIN
	// SmartDrive 4.0 workaround, carry flag incorrectly propogated
		_asm { CLC }
#endif

	if ((nErr = _dos_commit(m_hFile)) != 0)
		CFileException::ThrowOsError(nErr);
}
#pragma optimize("", on)    // return to default optimizations

void
CFile::Close()
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);

	UINT nErr;

	if (m_hFile != hFileNull && (nErr = _dos_close(m_hFile)) != 0)
		CFileException::ThrowOsError(nErr);

	m_hFile = hFileNull;
	m_bCloseOnDelete = FALSE;
}


void
CFile::LockRange(DWORD dwPos, DWORD dwCount)
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);

	UINT nErr;

	if ((nErr = _Afx_lock(m_hFile, dwPos, dwCount, FALSE)) != 0)
		CFileException::ThrowOsError(nErr);
}


void
CFile::UnlockRange(DWORD dwPos, DWORD dwCount)
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);

	UINT nErr;

	if ((nErr = _Afx_lock(m_hFile, dwPos, dwCount, TRUE)) != 0)
		CFileException::ThrowOsError(nErr);
}


void
CFile::SetLength(DWORD dwNewLen)
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);

#ifdef _DOSWIN
	UINT nErr;
	UINT nWritten = 0;

	this->Seek(dwNewLen, CFile::begin);

	if ((nErr = _dos_write(m_hFile, NULL, 0, &nWritten)) != 0)
		CFileException::ThrowOsError(nErr);
#endif
#ifdef _NTWIN
	this->Seek((LONG)dwNewLen, (UINT)CFile::begin);

	if (!::SetEndOfFile((HANDLE)m_hFile))
		CFileException::ThrowOsError((LONG)::GetLastError());
#endif
}

DWORD
CFile::GetLength() const
{
	ASSERT_VALID(this);

	DWORD dwLen, dwCur;
	
	// Seek is a non const operation 
	dwCur = ((CFile*)this)->Seek(0, CFile::current);
	dwLen = ((CFile*)this)->SeekToEnd();
	VERIFY(dwCur == (DWORD)(((CFile*)this)->Seek(dwCur, CFile::begin)));

	return dwLen;
}

BOOL
CFile::GetStatus(CFileStatus& rStatus) const
{
	ASSERT_VALID(this);
	ASSERT(m_hFile != hFileNull);

	//NOTE: cannot return name of file from handle
	rStatus.m_szFullName[0] = '\0';


#ifdef _DOSWIN
	struct _stat s;

	if (_fstat(m_hFile, &s) == 0)
	{
		rStatus.m_ctime = CTime(s.st_atime);
		rStatus.m_atime = rStatus.m_ctime;
		rStatus.m_mtime = rStatus.m_ctime;
		rStatus.m_size = s.st_size;
		rStatus.m_attribute = 0;    // dos won't give us this from
									// just a fd, need the path name
		return TRUE;
	}   
	return FALSE;
#endif
#ifdef _NTWIN
	_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;

	rStatus.m_attribute = 0;		// nt won't give us this from
									// just a fd, need the path name

	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;
#endif
}

void
CFile::Rename(const char* pszOldName, const char* pszNewName)
{
	char szOld[_MAX_PATH];
	char szNew[_MAX_PATH];
	UINT nErr;

	AnsiToOem(pszOldName, szOld);
	AnsiToOem(pszNewName, szNew);

	if ((nErr = _Afx_rename(szOld, szNew)) != 0)
		CFileException::ThrowOsError(nErr);

}

void
CFile::Remove(const char* pszFileName)
{
	UINT nErr;
	char sz[_MAX_PATH];

	AnsiToOem(pszFileName, sz);

	if ((nErr = _Afx_remove(sz)) != 0)
		CFileException::ThrowOsError(nErr);
}


BOOL
CFile::GetStatus(const char* pszFileName, CFileStatus& rStatus)
{

#ifdef _DOSWIN
	char sz[_MAX_PATH];

	// first fill in the full name of the file, undefined if we return FALSE
	if (_fullpath(sz, pszFileName, _MAX_PATH) == NULL)
	{
		rStatus.m_szFullName[0] = '\0';
		return FALSE;
	}
	strncpy(rStatus.m_szFullName, sz, _MAX_PATH);

	// finish filling in the structure
	WORD wAttr = CFile::normal | CFile::readOnly |
				CFile::hidden | CFile::system |
				CFile::directory | CFile::archive;
	struct _find_t find;

	AnsiToOem(pszFileName, sz);

	if (_dos_findfirst(sz, wAttr, &find) == 0)
	{
		rStatus.m_mtime = CTime((WORD)find.wr_date, (WORD)find.wr_time);
		rStatus.m_ctime = rStatus.m_mtime;
		rStatus.m_atime = rStatus.m_mtime;

		rStatus.m_size = find.size;
		rStatus.m_attribute = find.attrib;
		return TRUE;
	}
	else
		return FALSE;
#endif // _DOSWIN
#ifdef _NTWIN
	WIN32_FIND_DATA findFileData;
	OFSTRUCT of;
	HANDLE hFound;

	if ((hFound = FindFirstFile((LPTSTR)pszFileName, &findFileData)) == (HANDLE)(-1))
		return FALSE;

	VERIFY(FindClose(hFound));

	OpenFile((LPSTR)pszFileName, &of, OF_PARSE);
#ifdef _WINDOWS
	VERIFY(OemToCharBuff((LPSTR)of.szPathName, (LPTSTR)rStatus.m_szFullName,
		_MAX_PATH));
#else
	strncpy(rStatus.m_szFullName, (LPTSTR)of.szPathName,
		sizeof(rStatus.m_szFullName)-1);
#endif
	rStatus.m_szFullName[_MAX_PATH-1] = '\0';
	rStatus.m_attribute = (BYTE)(findFileData.dwFileAttributes & ~0x80);

	ASSERT(findFileData.nFileSizeHigh == 0);
	rStatus.m_size = (LONG) findFileData.nFileSizeLow;
	ASSERT(rStatus.m_size >= 0);

	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;
#endif
}

#ifdef _NTWIN
// NOTE: Implementation helper function.
static void NEAR TimeToFileTime(const CTime& time, LPFILETIME pFileTime)
{
	_SYSTEMTIME sysTime;
	sysTime.wYear  = time.GetYear();
	sysTime.wMonth = time.GetMonth();
	sysTime.wDay   = time.GetDay();
	sysTime.wHour = time.GetHour();
	sysTime.wMinute = time.GetMinute();
	sysTime.wSecond = time.GetSecond();
	sysTime.wMilliseconds = 0;

	if (!SystemTimeToFileTime((LPSYSTEMTIME)&sysTime, pFileTime));
		CFileException::ThrowOsError((LONG)::GetLastError());
}
#endif

void
CFile::SetStatus(const char* pszFileName, const CFileStatus& status)
{

#ifdef _DOSWIN
	UINT nErr;
	UINT wAttr;
	char sz[_MAX_PATH];

	AnsiToOem(pszFileName, sz);

	if ((nErr = _dos_getfileattr(sz, &wAttr)) != 0)
		CFileException::ThrowOsError(nErr);

	if (status.m_attribute != wAttr && wAttr & CFile::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 ((nErr = _dos_setfileattr(sz, status.m_attribute)) != 0)
			CFileException::ThrowOsError(nErr);
	}

	if (status.m_mtime.GetTime() != 0)
	{
		WORD wDate, wTime;
		int handle;

		// set the file date/time
		if ((nErr = _dos_open(sz, CFile::modeReadWrite, &handle)) != 0)
			CFileException::ThrowOsError(nErr);

		wDate = (WORD)(((UINT)status.m_mtime.GetYear() - 1980) << 9);
		wDate += (WORD)(((UINT)status.m_mtime.GetMonth()) << 5);
		wDate += (WORD)((UINT)status.m_mtime.GetDay());

		wTime = (WORD)((UINT)(status.m_mtime.GetHour()) << 11);
		wTime += (WORD)((UINT)status.m_mtime.GetMinute() << 5);
		wTime += (WORD)((UINT)status.m_mtime.GetSecond() >> 1);

		if ((nErr = _dos_setftime(handle, wDate, wTime)) != 0)
			CFileException::ThrowOsError(nErr);

		if ((nErr = _dos_close(handle)) != 0)
			CFileException::ThrowOsError(nErr);
	}

	if (status.m_attribute != wAttr && !(wAttr & CFile::readOnly))
	{
		// Set file attribute, only if currently not readonly.
		if ((nErr = _dos_setfileattr(sz, status.m_attribute)) != 0)
			CFileException::ThrowOsError(nErr);
	}

#endif // _DOSWIN
#ifdef _NTWIN
	DWORD wAttr;
	_FILETIME creationTime;
	_FILETIME lastAccessTime;
	_FILETIME lastWriteTime;
	LPFILETIME lpCreationTime = NULL;
	LPFILETIME lpLastAccessTime = NULL;
	LPFILETIME lpLastWriteTime = NULL;

	if ((wAttr = GetFileAttributes((LPTSTR)pszFileName)) == (DWORD)-1L)
		CFileException::ThrowOsError((LONG)GetLastError());

	if ((DWORD)status.m_attribute != wAttr && (wAttr & CFile::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)pszFileName, (DWORD)status.m_attribute))
			CFileException::ThrowOsError((LONG)GetLastError());
	}

	// last modification time
	if (status.m_mtime.GetTime() != 0)
	{
		TimeToFileTime(status.m_mtime, &lastWriteTime);
		lpLastWriteTime = &lastWriteTime;

		// last access time
		if (status.m_atime.GetTime() != 0)
		{
			TimeToFileTime(status.m_atime, &lastAccessTime);
			lpLastAccessTime = &lastAccessTime;
		}
	
		// create time
		if (status.m_ctime.GetTime() != 0)
		{
			TimeToFileTime(status.m_ctime, &creationTime);
			lpCreationTime = &creationTime;
		}
	
		OFSTRUCT of;
		HFILE hFile = OpenFile((LPSTR)pszFileName, &of, OF_READWRITE);

		if (hFile == (HFILE)-1L)
			CFileException::ThrowOsError((LONG)::GetLastError());
	
		if (!SetFileTime((HANDLE)hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime))
			CFileException::ThrowOsError((LONG)::GetLastError());
	
		if (_lclose(hFile) == -1)
			CFileException::ThrowOsError((LONG)::GetLastError());
	
	} // m_mtime != 0

	if ((DWORD)status.m_attribute != wAttr && !(wAttr & CFile::readOnly))
	{
		if (!SetFileAttributes((LPTSTR)pszFileName, (DWORD)status.m_attribute))
			CFileException::ThrowOsError((LONG)GetLastError());
	}
#endif // _NTWIN
}


#ifdef _DEBUG
void
CFile::AssertValid() const
{
	CObject::AssertValid();
	// we permit the descriptor m_hFile to be any value for derived classes
}

void
CFile::Dump(CDumpContext& dc) const
{
	ASSERT_VALID(this);

	CObject::Dump(dc);
	dc << "a " << GetRuntimeClass()->m_pszClassName << " with handle " << m_hFile;
}
#endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.