home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK10 / MFC / SRC / FILE.CP$ / file
Encoding:
Text File  |  1992-03-17  |  12.4 KB  |  589 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and Microsoft
  7. // QuickHelp documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #ifdef _WINDOWS
  12. #include "afxwin.h"
  13. #else
  14. #include "afx.h"
  15. #endif
  16. #pragma hdrstop
  17.  
  18. #include <errno.h>
  19. #include <io.h>
  20. #include <limits.h>
  21. #include <malloc.h>
  22.  
  23. #ifdef _DOSWIN
  24. #include <sys\types.h>
  25. #include <sys\stat.h>
  26. #endif
  27.  
  28. #include "dosio_.h"
  29.  
  30. #ifdef AFX_CORE_SEG
  31. #pragma code_seg(AFX_CORE_SEG)
  32. #endif
  33.  
  34. #ifdef _DEBUG
  35. #undef THIS_FILE
  36. static char BASED_CODE THIS_FILE[] = __FILE__;
  37. #endif
  38.  
  39. #define new DEBUG_NEW
  40.  
  41. ////////////////////////////////////////////////////////////////////////////
  42.  
  43. #ifdef _DOSWIN
  44.  
  45. // DOS INT 21h functions not provided by C Runtimes
  46. // additional Dos calls
  47. #pragma optimize("qgel", off) // assembler cannot be globally optimized
  48.  
  49. UINT _Afx_seek(UINT hFile, LONG lOff, UINT nMode, DWORD FAR* lpdwNew)
  50.     UINT res;
  51.     *lpdwNew = -1;
  52.     _asm { 
  53.             mov     bx, hFile
  54.             mov     ax, nMode
  55.             mov     ah, 42h
  56.             mov     dx, word ptr lOff
  57.             mov     cx, word ptr lOff+2
  58.             DOSCALL
  59.             jc      __seek_err
  60.             les     bx, lpdwNew
  61.             mov     word ptr es:[bx], ax
  62.             mov     word ptr es:[bx+2], dx
  63.             xor     ax, ax
  64.     __seek_err:
  65.             mov     res, ax
  66.     }
  67.     return res;
  68. }
  69.         
  70. UINT _Afx_rename(LPCSTR lpszOld, LPCSTR lpszNew)
  71.     UINT res;
  72.     _asm { 
  73.             mov     bx, ds
  74.             lds     dx, lpszOld
  75.             les     di, lpszNew
  76.             mov     ax, 5600h
  77.             DOSCALL
  78.             jc      __rename_err
  79.             xor     ax, ax
  80.     __rename_err:
  81.             mov     res, ax
  82.             mov     ds, bx
  83.     }
  84.     return res;
  85. }
  86.  
  87. UINT _Afx_remove(LPCSTR lpsz)  
  88.     UINT res;
  89.     _asm { 
  90.             mov     bx, ds
  91.             lds     dx, lpsz
  92.             mov     ax, 4100h
  93.             DOSCALL
  94.             jc      __remove_err
  95.             xor     ax, ax
  96.     __remove_err:
  97.             mov     res, ax
  98.             mov     ds, bx
  99.     }
  100.     return res;
  101. }
  102.  
  103. UINT _Afx_lock(UINT hFile, DWORD dwStart, DWORD dwLen, BOOL bUnlock)
  104.     UINT res;
  105.     _asm { 
  106.             mov     ax, bUnlock
  107.             mov     ah, 5ch
  108.             mov     bx, hFile
  109.             mov     dx, word ptr dwStart
  110.             mov     cx, word ptr dwStart+2
  111.             mov     di, word ptr dwLen
  112.             mov     si, word ptr dwLen+2
  113.             DOSCALL
  114.             jc      __lock_err1
  115.             xor     ax, ax
  116.     __lock_err1:
  117.             mov     res, ax
  118.             
  119.     }
  120.     return res;
  121. }
  122.  
  123. #pragma optimize("", on)    // return to default optimizations
  124.  
  125. #endif // _DOSWIN
  126.  
  127. /////////////////////////////////////////////////////////////////////////////
  128. // CFileStatus implementation
  129. #ifdef _DEBUG
  130. void
  131. CFileStatus::Dump(CDumpContext& dc) const
  132. {           
  133.     dc << "file status information:";
  134.     dc << "\nm_ctime = " << m_ctime;
  135.     dc << "\nm_mtime = " << m_mtime;
  136.     dc << "\nm_atime = " << m_atime;
  137.     dc << "\nm_size = " << m_size;
  138.     dc << "\nm_attribute = " << m_attribute;
  139.     dc << "\nm_szFullName = " << m_szFullName;
  140. }
  141. #endif
  142.  
  143.  
  144. ////////////////////////////////////////////////////////////////////////////
  145. // CFile implementation
  146. IMPLEMENT_DYNAMIC(CFile, CObject)
  147.  
  148.  
  149. CFile::CFile()
  150. {
  151.     m_hFile = hFileNull;
  152.     m_bCloseOnDelete = FALSE;
  153. }
  154.  
  155. CFile::CFile(int hFile)
  156. {
  157.     m_hFile = hFile;
  158.     m_bCloseOnDelete = FALSE;
  159. }
  160.  
  161. CFile::CFile(const char* pszFileName, UINT nOpenFlags)
  162. {
  163.     ASSERT(AfxIsValidAddress(pszFileName, strlen(pszFileName), FALSE));
  164.  
  165.     CFileException e;
  166.     if (!this->Open(pszFileName, nOpenFlags, &e))
  167.         AfxThrowFileException(e.m_cause, e.m_lOsError);
  168. }
  169.  
  170. CFile::~CFile()
  171. {   
  172.     if (m_hFile != hFileNull && m_bCloseOnDelete)
  173.         Close();
  174. }
  175.  
  176. CFile*
  177. CFile::Duplicate() const
  178. {
  179.     ASSERT_VALID(this);
  180.     ASSERT(m_hFile != hFileNull);
  181.  
  182.     CFile* pFile = new CFile(hFileNull);
  183.     pFile->m_hFile = _dup(this->m_hFile);
  184.     pFile->m_bCloseOnDelete = this->m_bCloseOnDelete;
  185.     return pFile;
  186. }
  187.  
  188. BOOL
  189. CFile::Open(const char* pszFileName, UINT nOpenFlags, 
  190.     CFileException* pException /* = NULL */)
  191. {
  192.     ASSERT(AfxIsValidAddress(pszFileName, strlen(pszFileName), FALSE));
  193.     ASSERT(pException == NULL || AfxIsValidAddress(pException, sizeof(CFileException)));
  194.     ASSERT((nOpenFlags & typeText) == 0);
  195.  
  196.     // CFile objects are always binary and _dos_open does not need flag
  197.     nOpenFlags &= ~(UINT)CFile::typeBinary;
  198.  
  199.     m_bCloseOnDelete = FALSE;
  200.     m_hFile = hFileNull;
  201.  
  202.  
  203. #ifdef _DOSWIN
  204.     ASSERT_VALID(this);
  205.  
  206.     char szOemPath[_MAX_PATH];
  207.     UINT nErr;
  208.  
  209.     AnsiToOem(pszFileName, szOemPath);
  210.  
  211.     if (nOpenFlags & (UINT)CFile::modeCreate)
  212.     {
  213.         if ((nErr = _dos_creat(szOemPath, CFile::normal, (int*)&m_hFile)) != 0)
  214.         {
  215.             if (pException != NULL)
  216.             {
  217.                 pException->m_lOsError = nErr;
  218.                 pException->m_cause = CFileException::OsErrorToException(nErr);
  219.                 return FALSE; // file was not created
  220.             }
  221.         }
  222.         if ((nErr = _dos_close(m_hFile)) != 0)
  223.         {
  224.             // try to delete the file and throw modeCreate exception
  225.             _Afx_remove(szOemPath);
  226.             if (pException != NULL)
  227.             {
  228.                 pException->m_lOsError = nErr;
  229.                 pException->m_cause = CFileException::OsErrorToException(nErr);
  230.             }
  231.             return FALSE;
  232.         }
  233.     }
  234.  
  235.     // the file has been modeCreated if needed, now open it
  236.     if ((nErr = _dos_open(szOemPath, nOpenFlags & ~(UINT)CFile::modeCreate, (int*)&m_hFile)) != 0)
  237.     {
  238.         // try to delete the file and throw open exception
  239.         _Afx_remove(szOemPath);
  240.         if (pException != NULL)
  241.         {
  242.             pException->m_lOsError = nErr;
  243.             pException->m_cause = CFileException::OsErrorToException(nErr);
  244.         }
  245.         return FALSE;
  246.     }
  247. #endif
  248.  
  249.     m_bCloseOnDelete = TRUE;
  250.     return TRUE;
  251. }
  252.  
  253.  
  254. UINT
  255. CFile::Read(void FAR* lpBuf, UINT nCount)
  256. {
  257.     ASSERT_VALID(this);
  258.     ASSERT(m_hFile != hFileNull);
  259.     ASSERT(lpBuf != NULL);
  260.     ASSERT(AfxIsValidAddress(lpBuf, nCount));
  261.  
  262.     UINT nRead = 0;
  263.     UINT nErr;
  264.  
  265.     if ((nErr = _dos_read(m_hFile, lpBuf, nCount, &nRead)) != 0)
  266.         CFileException::ThrowOsError(nErr);
  267.         
  268.     return nRead;
  269. }
  270.  
  271. void
  272. CFile::Write(const void FAR* lpBuf, UINT nCount)
  273. {
  274.     ASSERT_VALID(this);
  275.     ASSERT(m_hFile != hFileNull);
  276.     ASSERT(lpBuf != NULL);
  277.     ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE));
  278.  
  279.     UINT nWritten = 0;
  280.     UINT nErr;
  281.  
  282.     if ((nErr = _dos_write(m_hFile, lpBuf, nCount, &nWritten)) != 0)
  283.         CFileException::ThrowOsError(nErr);
  284.     
  285.     if (nCount != nWritten)
  286.         AfxThrowFileException(CFileException::diskFull);
  287. }
  288.  
  289.  
  290. LONG
  291. CFile::Seek(LONG lOff, UINT nFrom)
  292. {
  293.     ASSERT_VALID(this);
  294.     ASSERT(m_hFile != hFileNull);
  295.     ASSERT(nFrom == CFile::begin || nFrom == CFile::end || nFrom == CFile::current);
  296.  
  297.     DWORD dwNew;
  298.     UINT nErr;
  299.  
  300.     if ((nErr  = _Afx_seek(m_hFile, lOff, nFrom, &dwNew)) != 0)
  301.         CFileException::ThrowOsError(nErr);
  302.     
  303.     return dwNew;
  304. }
  305.  
  306.  
  307. DWORD
  308. CFile::GetPosition() const
  309. {
  310.     ASSERT_VALID(this);
  311.     ASSERT(m_hFile != hFileNull);
  312.  
  313.     DWORD dwPos;
  314.     UINT nErr;
  315.  
  316.     if ((nErr = _Afx_seek(m_hFile, 0, CFile::current, &dwPos)) != 0)
  317.         CFileException::ThrowOsError(nErr);
  318.     
  319.     return dwPos;
  320. }
  321.  
  322.  
  323. #pragma optimize("qgel", off) // assembler cannot be globally optimized
  324. void
  325. CFile::Flush()
  326. {
  327.     ASSERT_VALID(this);
  328.     ASSERT(m_hFile != hFileNull);
  329.     
  330.     UINT nErr;
  331.  
  332.     // SmartDrive 4.0 workaround, carry flag incorrectly propogated
  333.         _asm { CLC }
  334.  
  335.     if ((nErr = _dos_commit(m_hFile)) != 0)
  336.         CFileException::ThrowOsError(nErr);
  337. }
  338. #pragma optimize("", on)    // return to default optimizations
  339.  
  340. void
  341. CFile::Close()
  342. {
  343.     ASSERT_VALID(this);
  344.     ASSERT(m_hFile != hFileNull);
  345.  
  346.     UINT nErr;
  347.  
  348.     if (m_hFile != hFileNull && (nErr = _dos_close(m_hFile)) != 0)
  349.         CFileException::ThrowOsError(nErr);
  350.  
  351.     m_hFile = hFileNull;
  352.     m_bCloseOnDelete = FALSE;
  353. }
  354.  
  355.  
  356. void
  357. CFile::LockRange(DWORD dwPos, DWORD dwCount)
  358. {
  359.     ASSERT_VALID(this);
  360.     ASSERT(m_hFile != hFileNull);
  361.  
  362.     UINT nErr;
  363.  
  364.     if ((nErr = _Afx_lock(m_hFile, dwPos, dwCount, FALSE)) != 0)
  365.         CFileException::ThrowOsError(nErr);
  366. }
  367.  
  368.  
  369. void
  370. CFile::UnlockRange(DWORD dwPos, DWORD dwCount)
  371. {
  372.     ASSERT_VALID(this);
  373.     ASSERT(m_hFile != hFileNull);
  374.  
  375.     UINT nErr;
  376.  
  377.     if ((nErr = _Afx_lock(m_hFile, dwPos, dwCount, TRUE)) != 0)
  378.         CFileException::ThrowOsError(nErr);
  379. }
  380.  
  381.  
  382. void
  383. CFile::SetLength(DWORD dwNewLen)
  384. {
  385.     ASSERT_VALID(this);
  386.     ASSERT(m_hFile != hFileNull);
  387.  
  388.     UINT nErr;
  389.  
  390. #ifdef _DOSWIN
  391.     UINT nWritten = 0;
  392.  
  393.     this->Seek(dwNewLen, CFile::begin);
  394.  
  395.     if ((nErr = _dos_write(m_hFile, NULL, 0, &nWritten)) != 0)
  396.         CFileException::ThrowOsError(nErr);
  397. #endif
  398. }
  399.  
  400. DWORD
  401. CFile::GetLength() const
  402. {
  403.     ASSERT_VALID(this);
  404.  
  405.     DWORD dwLen, dwCur;
  406.     
  407.     // Seek is a non const operation 
  408.     dwCur = ((CFile*)this)->Seek(0, CFile::current);
  409.     dwLen = ((CFile*)this)->SeekToEnd();
  410.     VERIFY(dwCur == (DWORD)(((CFile*)this)->Seek(dwCur, CFile::begin)));
  411.  
  412.     return dwLen;
  413. }
  414.  
  415. BOOL
  416. CFile::GetStatus(CFileStatus& rStatus) const
  417. {
  418.     ASSERT_VALID(this);
  419.     ASSERT(m_hFile != hFileNull);
  420.  
  421.     //NOTE: cannot return name of file from handle
  422.     rStatus.m_szFullName[0] = '\0';
  423.  
  424.  
  425. #ifdef _DOSWIN
  426.     struct _stat s;
  427.  
  428.     if (_fstat(m_hFile, &s) == 0)
  429.     {
  430.         rStatus.m_ctime = CTime(s.st_atime);
  431.         rStatus.m_atime = rStatus.m_ctime;
  432.         rStatus.m_mtime = rStatus.m_ctime;
  433.         rStatus.m_size = s.st_size;
  434.         rStatus.m_attribute = 0;    // dos won't give us this from
  435.                                     // just a fd, need the path name
  436.         return TRUE;
  437.     }   
  438.     return FALSE;
  439. #endif
  440.  
  441. }
  442.  
  443. void
  444. CFile::Rename(const char* pszOldName, const char* pszNewName)
  445. {
  446.     char szOld[_MAX_PATH];
  447.     char szNew[_MAX_PATH];
  448.     UINT nErr;
  449.  
  450.     AnsiToOem(pszOldName, szOld);
  451.     AnsiToOem(pszNewName, szNew);
  452.  
  453.     if ((nErr = _Afx_rename(szOld, szNew)) != 0)
  454.         CFileException::ThrowOsError(nErr);
  455.  
  456. }
  457.  
  458. void
  459. CFile::Remove(const char* pszFileName)
  460. {
  461.     UINT nErr;
  462.     char sz[_MAX_PATH];
  463.  
  464.     AnsiToOem(pszFileName, sz);
  465.  
  466.     if ((nErr = _Afx_remove(sz)) != 0)
  467.         CFileException::ThrowOsError(nErr);
  468. }
  469.  
  470.  
  471. BOOL
  472. CFile::GetStatus(const char* pszFileName, CFileStatus& rStatus)
  473. {
  474.  
  475. #ifdef _DOSWIN
  476.     char sz[_MAX_PATH];
  477.  
  478.     // first fill in the full name of the file, undefined if we return FALSE
  479.     if (_fullpath(sz, pszFileName, _MAX_PATH) == NULL)
  480.     {
  481.         rStatus.m_szFullName[0] = '\0';
  482.         return FALSE;
  483.     }
  484.     strncpy(rStatus.m_szFullName, sz, _MAX_PATH);
  485.  
  486.     // finish filling in the structure
  487.     WORD wAttr = CFile::normal | CFile::readOnly |
  488.                 CFile::hidden | CFile::system |
  489.                 CFile::directory | CFile::archive;
  490.     struct _find_t find;
  491.  
  492.     AnsiToOem(pszFileName, sz);
  493.  
  494.     if (_dos_findfirst(sz, wAttr, &find) == 0)
  495.     {
  496.         rStatus.m_mtime = CTime((WORD)find.wr_date, (WORD)find.wr_time);
  497.         rStatus.m_ctime = rStatus.m_mtime;
  498.         rStatus.m_atime = rStatus.m_mtime;
  499.  
  500.         rStatus.m_size = find.size;
  501.         rStatus.m_attribute = find.attrib;
  502.         return TRUE;
  503.     }
  504.     else
  505.         return FALSE;
  506. #endif // _DOSWIN
  507. }
  508.  
  509.  
  510. void
  511. CFile::SetStatus(const char* pszFileName, const CFileStatus& status)
  512. {
  513.  
  514. #ifdef _DOSWIN
  515.     UINT nErr;
  516.     UINT wAttr;
  517.     char sz[_MAX_PATH];
  518.  
  519.     AnsiToOem(pszFileName, sz);
  520.  
  521.     if ((nErr = _dos_getfileattr(sz, &wAttr)) != 0)
  522.         CFileException::ThrowOsError(nErr);
  523.  
  524.     if (status.m_attribute != wAttr && wAttr & CFile::readOnly)
  525.     {
  526.         // Set file attribute, only if currently readonly.
  527.         // This way we will be able to modify the time assuming the
  528.         // caller changed the file from readonly.
  529.         if ((nErr = _dos_setfileattr(sz, status.m_attribute)) != 0)
  530.             CFileException::ThrowOsError(nErr);
  531.     }
  532.  
  533.     if (status.m_mtime.GetTime() != 0)
  534.     {
  535.         WORD wDate, wTime;
  536.         int handle;
  537.  
  538.         // set the file date/time
  539.         if ((nErr = _dos_open(sz, CFile::modeReadWrite, &handle)) != 0)
  540.             CFileException::ThrowOsError(nErr);
  541.  
  542.         wDate = (WORD)(((UINT)status.m_mtime.GetYear() - 1980) << 9);
  543.         wDate += (WORD)(((UINT)status.m_mtime.GetMonth()) << 5);
  544.         wDate += (WORD)((UINT)status.m_mtime.GetDay());
  545.  
  546.         wTime = (WORD)((UINT)(status.m_mtime.GetHour()) << 11);
  547.         wTime += (WORD)((UINT)status.m_mtime.GetMinute() << 5);
  548.         wTime += (WORD)((UINT)status.m_mtime.GetSecond() >> 1);
  549.  
  550.         if ((nErr = _dos_setftime(handle, wDate, wTime)) != 0)
  551.             CFileException::ThrowOsError(nErr);
  552.  
  553.         if ((nErr = _dos_close(handle)) != 0)
  554.             CFileException::ThrowOsError(nErr);
  555.     }
  556.  
  557.     if (status.m_attribute != wAttr && !(wAttr & CFile::readOnly))
  558.     {
  559.         // Set file attribute, only if currently not readonly.
  560.         if ((nErr = _dos_setfileattr(sz, status.m_attribute)) != 0)
  561.             CFileException::ThrowOsError(nErr);
  562.     }
  563.  
  564. #endif // _DOSWIN
  565. }
  566.  
  567.  
  568. #ifdef _DEBUG
  569. void
  570. CFile::AssertValid() const
  571. {
  572.     CObject::AssertValid();
  573.     // we permit the descriptor m_hFile to be any value for derived classes
  574. }
  575.  
  576. void
  577. CFile::Dump(CDumpContext& dc) const
  578. {
  579.     ASSERT_VALID(this);
  580.  
  581.     CObject::Dump(dc);
  582.     dc << "a " << GetRuntimeClass()->m_pszClassName << " with handle " << m_hFile;
  583. }
  584. #endif
  585.