smplfsys.cpp
Upload User: dangjiwu
Upload Date: 2013-07-19
Package Size: 42019k
Code Size: 81k
Category:

Symbian

Development Platform:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: smplfsys.cpp,v 1.3.8.5 2004/07/09 02:04:08 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. /////////////////////////////////////////////////////////////////////////////
  50. //
  51. //  Simple File System for simple synchronous local files
  52. //
  53. //  This is a very simple file system, it just calls basic standard lib
  54. //  calls for open, seek, read, etc...
  55. //
  56. #define INITGUID    1
  57. #include "hxcom.h"
  58. #include "hxtypes.h"
  59. #include "../smplfsys.ver"
  60. #include "hxcomm.h"
  61. #include "ihxpckts.h"
  62. #include "hxfiles.h"
  63. #include "hxplugn.h"
  64. #include "hxengin.h"
  65. #include "hxcore.h"
  66. #include "hxprefs.h"
  67. #include "hxrendr.h"
  68. #include "hxmon.h"
  69. #include "hxauth.h"
  70. #include "hxauthn.h"
  71. #include "hxplgns.h"
  72. #include "hxdataf.h"
  73. #include "hxtick.h"
  74. #include "debug.h"
  75. #undef INITGUID
  76. #include "hxathsp.h"
  77. #include "hxcorsp.h"
  78. #include "hxpktsp.h"
  79. #include "hxcomsp.h"
  80. #include "hxplnsp.h"
  81. #include "hxspriv.h"
  82. #include "hlxosstr.h"
  83. #include "timeval.h"
  84. #include "tparse.h"
  85. #include "dbcs.h" // for HXCompareStrings
  86. #include "hxstring.h" // for CHXString
  87. #include "hxxfile.h" // for HXXFile::GetReasonableLocalFileName()
  88. #include "hxstrutl.h"
  89. #include "hxver.h"
  90. #include "chxpckts.h"
  91. #include "hxurl.h"
  92. #include "hxperf.h"
  93. #include "hxcbobj.h"
  94. #include "hxdir.h"
  95. #include <stdio.h>
  96. #include <string.h>
  97. #ifdef _MACINTOSH
  98. #include <fcntl.h>
  99. #include "chxdataf.h" // Macintosh file i/o
  100. #include "macasyncfile.h"  // Macintosh interrupt file i/o
  101. #ifdef _MAC_MACHO
  102. #include <sys/stat.h>
  103. #include "hlxclib/fcntl.h"
  104. #include <unistd.h> // for unlink
  105. #else
  106. #include <unix.h> // for unlink
  107. #endif
  108. #ifdef _UNIX /* including unix.h defines _UNIX */
  109. #undef _UNIX
  110. #endif
  111. #elif (defined (_WINDOWS ) || defined (_WIN32)) && !defined(WIN32_PLATFORM_PSPC)
  112. #include <direct.h>
  113. #include "datffact.h"
  114. #else
  115. #include "hlxclib/sys/types.h"
  116. #include "hlxclib/sys/stat.h"
  117. #include "hlxclib/fcntl.h"
  118. #include "datffact.h"
  119. #endif
  120. #include "findfile.h"
  121. #include "smplmlog.h"
  122. #include "baseobj.h"
  123. #if defined(HELIX_FEATURE_PROGDOWN)
  124. #include "progdown.h"
  125. #include "microsleep.h"
  126. #endif
  127. #include "smplfsys.h"
  128. #include "hxperf.h"
  129. #ifdef _AIX
  130. #include "hxtbuf.h"
  131. #include "dllpath.h"
  132. ENABLE_MULTILOAD_DLLACCESS_PATHS(Smplfsys);
  133. #endif
  134. // same for all the platforms...may need to tweak it, if necessary
  135. #define MAX_ITERATION_COUNT    200
  136. #include "hxheap.h"
  137. #ifdef _DEBUG
  138. #undef HX_THIS_FILE
  139. static const char HX_THIS_FILE[] = __FILE__;
  140. #endif
  141. #ifndef HELIX_CONFIG_NOSTATICS
  142. INT32 smpl_nRefCount = 0;
  143. #endif // HELIX_CONFIG_NOSTATICS
  144. HX_ENABLE_CHECKPOINTS_FOR_MODULE( "SmplFsys", "SmplFsysPerf.log" )
  145. const char* const CSimpleFileSystem::zm_pDescription = "RealNetworks Local File System";
  146. const char* const CSimpleFileSystem::zm_pCopyright = HXVER_COPYRIGHT;
  147. const char* const CSimpleFileSystem::zm_pMoreInfoURL = HXVER_MOREINFO;
  148. const char* const CSimpleFileSystem::zm_pShortName = "pn-local";
  149. const char* const CSimpleFileSystem::zm_pProtocol = "file";
  150. /****************************************************************************
  151.  *
  152.  *  Function:
  153.  *
  154.  * HXCreateInstance()
  155.  *
  156.  *  Purpose:
  157.  *
  158.  * Function implemented by all plugin DLL's to create an instance of
  159.  * any of the objects supported by the DLL. This method is similar to
  160.  * Window's CoCreateInstance() in its purpose, except that it only
  161.  * creates objects from this plugin DLL.
  162.  *
  163.  * NOTE: Aggregation is never used. Therefore and outer unknown is
  164.  * not passed to this function, and you do not need to code for this
  165.  * situation.
  166.  *
  167.  */
  168. STDAPI ENTRYPOINT(HXCREATEINSTANCE)
  169. (
  170.     IUnknown**  /*OUT*/ ppIUnknown
  171. )
  172. {
  173.     // Do NOT check for expiration.  Needed for Auto Upgrade.
  174.     *ppIUnknown = (IUnknown*)(IHXPlugin*)new CSimpleFileSystem();
  175.     if (*ppIUnknown)
  176.     {
  177. (*ppIUnknown)->AddRef();
  178. return HXR_OK;
  179.     }
  180.     return HXR_OUTOFMEMORY;
  181. }
  182. /****************************************************************************
  183.  *
  184.  *  Function:
  185.  *
  186.  * CanUnload()
  187.  *
  188.  *  Purpose:
  189.  *
  190.  * Function implemented by all plugin DLL's if it returns HXR_OK
  191.  * then the pluginhandler can unload the DLL
  192.  *
  193.  */
  194. STDAPI ENTRYPOINT(CanUnload)(void)
  195. {
  196. #ifdef HELIX_CONFIG_NOSTATICS
  197.     return HXR_FAIL;
  198. #else // HELIX_CONFIG_NOSTATICS
  199.     return (smpl_nRefCount ? HXR_FAIL : HXR_OK);
  200. #endif // HELIX_CONFIG_NOSTATICS
  201. }
  202. /****************************************************************************
  203.  *
  204.  *  Function:
  205.  *
  206.  * HXShutdown()
  207.  *
  208.  *  Purpose:
  209.  *
  210.  * Function implemented by all plugin DLL's to free any *global*
  211.  * resources. This method is called just before the DLL is unloaded.
  212.  *
  213.  */
  214. STDAPI ENTRYPOINT(HXSHUTDOWN)(void)
  215. {
  216.     return HXR_OK;
  217. }
  218. CSimpleFileSystem::CSimpleFileSystem()
  219.     : m_lRefCount(0)
  220.     , m_pContext(0)
  221.     , m_options(NULL)
  222.     , m_ulMaxIterationLevel(MAX_ITERATION_COUNT)
  223.     , m_pCommonObj(NULL)
  224.     , m_bDisableMemoryMappedIO(FALSE)
  225.     , m_bEnableFileLocking(FALSE)
  226.     , m_ulChunkSize(0)
  227. {
  228. #ifndef HELIX_CONFIG_NOSTATICS
  229.     smpl_nRefCount++;
  230. #endif // HELIX_CONFIG_NOSTATICS
  231. }
  232. CSimpleFileSystem::~CSimpleFileSystem()
  233. {
  234. #ifndef HELIX_CONFIG_NOSTATICS
  235.     smpl_nRefCount--;
  236. #endif // HELIX_CONFIG_NOSTATICS
  237.     if (m_pContext)
  238.     {
  239. m_pContext->Release();
  240. m_pContext = 0;
  241.     }
  242.     if(m_options)
  243.     {
  244. m_options->Release();
  245. m_options = 0;
  246.     }
  247.     HX_RELEASE(m_pCommonObj);
  248. }
  249. /************************************************************************
  250.  *  Method:
  251.  *    IHXPlugin::InitPlugin
  252.  *  Purpose:
  253.  *    Initializes the plugin for use. This interface must always be
  254.  *    called before any other method is called. This is primarily needed
  255.  *    so that the plugin can have access to the context for creation of
  256.  *    IHXBuffers and IMalloc.
  257.  */
  258. STDMETHODIMP CSimpleFileSystem::InitPlugin(IUnknown* /*IN*/ pContext)
  259. {
  260.     HX_LOG_BLOCK( "CSimpleFileSystem::InitPlugin" );
  261.     HX_RESULT lResult;
  262.     IHXPreferences* prefs = 0;
  263.     IHXBuffer* base_path_buf = 0;
  264.     if (pContext && !m_pContext)
  265.     {
  266.         m_pContext = pContext;
  267. m_pContext->AddRef();
  268. IHXRegistry* pReg = NULL;
  269. if (m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pReg) == HXR_OK)
  270. {
  271.     INT32 lCS = 0;
  272.     if (HXR_OK == pReg->GetIntByName("config.MMapChunkSize", lCS) && lCS)
  273.     {
  274. m_ulChunkSize = lCS;
  275.     }
  276.     pReg->Release();
  277. }
  278. if(!m_options ||
  279.    (HXR_OK != m_options->GetPropertyBuffer("BasePath", base_path_buf)))
  280. {
  281.     lResult = pContext->QueryInterface(IID_IHXPreferences,
  282.        (void**) &prefs);
  283.     if (lResult == HXR_OK)
  284.     {
  285. lResult = prefs->ReadPref("BasePath", base_path_buf);
  286. if (lResult == HXR_OK)
  287. {
  288.     m_base_path = CHXString((char*)base_path_buf->GetBuffer());
  289. }
  290.     }
  291. }
  292. else
  293. {
  294.     m_base_path = CHXString((char*)base_path_buf->GetBuffer());
  295. }
  296.     }
  297.     if (prefs)
  298.     {
  299. prefs->Release();
  300. prefs = 0;
  301.     }
  302.     if (base_path_buf)
  303.     {
  304. base_path_buf->Release();
  305. base_path_buf = 0;
  306.     }
  307.     IHXGetRecursionLevel* pGet;
  308.     lResult = pContext->QueryInterface(IID_IHXGetRecursionLevel,
  309.        (void**) &pGet);
  310.     if (lResult == HXR_OK)
  311.     {
  312. m_ulMaxIterationLevel = pGet->GetRecursionLevel();
  313. pGet->Release();
  314.     }
  315.     return HXR_OK;
  316. }
  317. /************************************************************************
  318.  *  Method:
  319.  *    IHXPlugin::GetPluginInfo
  320.  *  Purpose:
  321.  *    Returns the basic information about this plugin. Including:
  322.  *
  323.  *    unInterfaceCount the number of standard RMA interfaces
  324.  * supported by this plugin DLL.
  325.  *    pIIDList array of IID's for standard RMA interfaces
  326.  * supported by this plugin DLL.
  327.  *    bLoadMultiple whether or not this plugin DLL can be loaded
  328.  * multiple times. All File Formats must set
  329.  * this value to TRUE.
  330.  *    pDescription which is used in about UIs (can be NULL)
  331.  *    pCopyright which is used in about UIs (can be NULL)
  332.  *    pMoreInfoURL which is used in about UIs (can be NULL)
  333.  */
  334. STDMETHODIMP CSimpleFileSystem::GetPluginInfo
  335. (
  336.     REF(BOOL)        /*OUT*/ bLoadMultiple,
  337.     REF(const char*) /*OUT*/ pDescription,
  338.     REF(const char*) /*OUT*/ pCopyright,
  339.     REF(const char*) /*OUT*/ pMoreInfoURL,
  340.     REF(ULONG32)     /*OUT*/ ulVersionNumber
  341. )
  342. {
  343.     bLoadMultiple = TRUE;
  344.     pDescription    = zm_pDescription;
  345.     pCopyright     = zm_pCopyright;
  346.     pMoreInfoURL    = zm_pMoreInfoURL;
  347.     ulVersionNumber = TARVER_ULONG32_VERSION;
  348.     return HXR_OK;
  349. }
  350. // *** IUnknown methods ***
  351. /////////////////////////////////////////////////////////////////////////
  352. //  Method:
  353. // IUnknown::QueryInterface
  354. //  Purpose:
  355. // Implement this to export the interfaces supported by your
  356. // object.
  357. //
  358. STDMETHODIMP CSimpleFileSystem::QueryInterface(REFIID riid, void** ppvObj)
  359. {
  360.     QInterfaceList qiList[] =
  361.     {
  362. { GET_IIDHANDLE(IID_IUnknown), this },
  363. { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*) this },
  364. { GET_IIDHANDLE(IID_IHXFileSystemObject), (IHXFileSystemObject*) this },
  365.     };
  366.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  367. }
  368. /////////////////////////////////////////////////////////////////////////
  369. //  Method:
  370. // IUnknown::AddRef
  371. //  Purpose:
  372. // Everyone usually implements this the same... feel free to use
  373. // this implementation.
  374. //
  375. STDMETHODIMP_(ULONG32) CSimpleFileSystem::AddRef()
  376. {
  377.     return InterlockedIncrement(&m_lRefCount);
  378. }
  379. /////////////////////////////////////////////////////////////////////////
  380. //  Method:
  381. // IUnknown::Release
  382. //  Purpose:
  383. // Everyone usually implements this the same... feel free to use
  384. // this implementation.
  385. //
  386. STDMETHODIMP_(ULONG32) CSimpleFileSystem::Release()
  387. {
  388.     if (InterlockedDecrement(&m_lRefCount) > 0)
  389.     {
  390.         return m_lRefCount;
  391.     }
  392.     delete this;
  393.     return 0;
  394. }
  395. STDMETHODIMP CSimpleFileSystem::GetFileSystemInfo
  396. (
  397.     REF(const char*) /*OUT*/ pShortName,
  398.     REF(const char*) /*OUT*/ pProtocol
  399. )
  400. {
  401.     pShortName = zm_pShortName;
  402.     pProtocol = zm_pProtocol;
  403.     return HXR_OK;
  404. }
  405. STDMETHODIMP
  406. CSimpleFileSystem::InitFileSystem(IHXValues* options)
  407. {
  408.     HX_LOG_BLOCK( "CSimpleFileSystem::InitFileSystem" );
  409.     IHXBuffer* base_path_buf = 0;
  410.     m_options = options;
  411.     if (m_options)
  412.     {
  413. m_options->AddRef();
  414. if (HXR_OK == m_options->GetPropertyBuffer("BasePath", base_path_buf))
  415. {
  416.     m_base_path = CHXString((char*)base_path_buf->GetBuffer());
  417. }
  418. ULONG32 ulTemp = 0;
  419. BOOL bLog = FALSE;
  420. /*
  421.          *  XXX PM this is weak.  I need a way to show these options
  422.  *  but only if explicitly asked to do so.  Ideally we would
  423.  *  use the IRMErrorMessages with HXLOG_DEBUG and --sdm for
  424.  *  server but I can't here because no context gets passed
  425.  *  to file system object until its first connection.
  426.  *  Can you believe that?
  427.  */
  428. m_options->GetPropertyULONG32("LogOptionalParams",
  429. ulTemp);
  430. bLog = ulTemp ? TRUE : FALSE;
  431. ulTemp = 0;
  432. m_options->GetPropertyULONG32("DisableMemoryMappedIO",
  433.     ulTemp);
  434. m_bDisableMemoryMappedIO = ulTemp ? TRUE : FALSE;
  435. ulTemp = 0;
  436. m_options->GetPropertyULONG32("EnableFileLocking",
  437. ulTemp);
  438. m_bEnableFileLocking = ulTemp ? TRUE : FALSE;
  439. ulTemp = 0;
  440. m_options->GetPropertyULONG32("MaxIterationLevel", ulTemp);
  441. if (ulTemp)
  442. {
  443.             m_ulMaxIterationLevel = ulTemp;
  444. }
  445. if (bLog)
  446. {
  447.     char pNumericMount[50]; /* Flawfinder: ignore */
  448.     IHXBuffer* pBuffer = 0;
  449.     const char* pMount;
  450.     m_options->GetPropertyCString("MountPoint", pBuffer);
  451.     if (!pBuffer)
  452.     {
  453. m_options->GetPropertyBuffer("MountPoint", pBuffer);
  454. if (!pBuffer)
  455. {
  456.     m_options->GetPropertyULONG32("MountPount", ulTemp);
  457. }
  458.     }
  459.     if (pBuffer)
  460.     {
  461. pMount = (const char*)pBuffer->GetBuffer();
  462.     }
  463.     else
  464.     {
  465. pMount = pNumericMount;
  466. sprintf(pNumericMount, "%lu", ulTemp); /* Flawfinder: ignore */
  467.     }
  468.     printf("Optional smplfsys (pn-local) parameters for"
  469.     " MountPoint: %sn", pMount);
  470.     HX_RELEASE(pBuffer);
  471.     printf("DisableMemoryMappedIO: %sn",
  472.     m_bDisableMemoryMappedIO ? "TRUE" : "FALSE");
  473.     printf("EnableFileLocking: %sn",
  474.     m_bEnableFileLocking ? "TRUE" : "FALSE");
  475.     printf("MaxIterationLevel: %lun",
  476.     m_ulMaxIterationLevel);
  477.     ulTemp = 0;
  478.     m_options->GetPropertyULONG32("MMapChunkSize", ulTemp);
  479.     if (ulTemp)
  480.     {
  481. printf("MMapChunkSize: %lun", ulTemp);
  482.     }
  483. }
  484.     }
  485.     if (base_path_buf)
  486.     {
  487. base_path_buf->Release();
  488.     }
  489.     return HXR_OK;
  490. }
  491. /////////////////////////////////////////////////////////////////////////
  492. //  Method:
  493. // IHXFileSystemObject::CreateFile
  494. //  Purpose:
  495. // TBD
  496. //
  497. STDMETHODIMP CSimpleFileSystem::CreateFile
  498. (
  499.     IUnknown** /*OUT*/ ppFileObject
  500. )
  501. {
  502.     HX_LOG_BLOCK( "CSimpleFileSystem::CreateFile" );
  503.     CSimpleFileObject* pFileObj =
  504. new CSimpleFileObject(m_base_path,
  505.       this,
  506.       m_pContext,
  507.       m_ulMaxIterationLevel);
  508.     if (pFileObj)
  509.     {
  510. if (HXR_OK == pFileObj->QueryInterface(IID_IUnknown,
  511.     (void**)ppFileObject))
  512. {
  513.     return HXR_OK;
  514. }
  515. return HXR_UNEXPECTED;
  516.     }
  517.     return HXR_OUTOFMEMORY;
  518. }
  519. /////////////////////////////////////////////////////////////////////////
  520. //  Method:
  521. // CSimpleFileSystem::CreateDir
  522. //  Purpose:
  523. // TBD
  524. //
  525. STDMETHODIMP CSimpleFileSystem::CreateDir
  526. (
  527.     IUnknown** /*OUT*/ ppDirObject
  528. )
  529. {
  530.     return HXR_NOTIMPL;
  531. }
  532. CSimpleFileObject::CSimpleFileObject(CHXString& base_path,
  533.      CSimpleFileSystem *pFS,
  534.      IUnknown* pContext,
  535.      UINT32 ulMaxIterationLevel)
  536.     : m_lRefCount(0)
  537.     , m_ulFlags(0)
  538.     , m_bLocalClose(FALSE)
  539.     , m_pContext(pContext)
  540.     , m_pCommonClassFactory(NULL)
  541.     , m_pFileResponse(NULL)
  542.     , m_pFileSystem(pFS)
  543.     , m_pFilename(NULL)
  544.     , m_pRequest(0)
  545.     , m_pDescriptorReg(0)
  546.     , m_pDirResponse(NULL)
  547.     , m_pDirList(NULL)
  548.     , m_pScheduler(NULL)
  549.     , m_pStackCallback(NULL)
  550.     , m_bInRead(FALSE)
  551.     , m_bReadPending(FALSE)
  552.     , m_bAsyncReadPending(FALSE)
  553.     , m_ulPendingReadCount(0)
  554.     , m_ulSize(0)
  555.     , m_ulPos(0)
  556.     , m_bAsyncAccess(TRUE)
  557.     , m_bCanBeReOpened(0)
  558. #ifdef _MACINTOSH
  559.     , m_pDataFile(NULL)
  560.     , m_pAsyncFileResponse(NULL)
  561.     , m_pInterruptState(NULL)
  562.     , m_pFileStatResponse(NULL)
  563.     , m_eSeekReason(EXTERNAL_SEEK)
  564.     , m_ulPreSeekPosition(0)
  565.     , m_bFileToBeClosed(FALSE)
  566. #endif
  567.     , m_nFd(-1)
  568.     , m_ulMaxIterationLevel(ulMaxIterationLevel)
  569.     , m_pUnknownUserContext(NULL)
  570.     , m_ulPendingSeekOffset(0)
  571.     , m_usPendingSeekWhence(SEEK_SET)
  572. #if defined(HELIX_FEATURE_PROGDOWN)
  573.     , m_pProgDownMon(NULL)
  574.     , m_ulCallbackState(CallbackStateUnknown)
  575.     , m_bProgDownEnabled(TRUE)
  576. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  577. {
  578.     MLOG_LEAK("CON CSimpleFileObject this=0x%08xn", this);
  579. #ifndef HELIX_CONFIG_NOSTATICS
  580.     smpl_nRefCount++;
  581. #endif //  HELIX_CONFIG_NOSTATICS
  582.     m_base_path = base_path;
  583.     if (m_pFileSystem)
  584.     {
  585. m_pFileSystem->AddRef();
  586.     }
  587.     if (m_pContext)
  588.     {
  589. m_pContext->AddRef();
  590. #ifdef USE_THREADSAFE_SCHEDULER
  591. m_pContext->QueryInterface(IID_IHXThreadSafeScheduler, (void**) &m_pScheduler);
  592. if (!m_pScheduler)
  593. {
  594.     m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  595. }
  596. #else
  597. m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  598. #endif //USE_THREADSAFE_SCHEDULER
  599. #if !defined _MACINTOSH
  600. IHXDataFileFactory* pDFFact = new HXDataFileFactory;;
  601. pDFFact->AddRef();
  602. {
  603.     DPRINTF(0x5d000000, ("CSFO::CSFO() -- after QIn"));
  604.     {
  605. pDFFact->CreateFile(m_pDataFile, m_pContext,
  606.     pFS->m_pCommonObj, pFS->m_bDisableMemoryMappedIO,
  607.     pFS->m_ulChunkSize, pFS->m_bEnableFileLocking,
  608.     TRUE);  // Always prefer async I/O
  609. if (!m_pDataFile)
  610. {
  611. #ifndef _WIN16
  612.     DPRINTF(0x5d000000, ("Internal Error s/546n"));
  613. #endif
  614.     pDFFact->Release();
  615.     return;
  616. }
  617.     }
  618. }
  619. pDFFact->Release();
  620. #endif /* !defined _MACINTOSH */
  621. m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  622.    (void **)&m_pCommonClassFactory);
  623.     }
  624.     m_pStackCallback = new CHXGenericCallback(this, CSimpleFileObject::StackCallback);
  625.     if (m_pStackCallback)
  626.     {
  627.         m_pStackCallback->AddRef();
  628.     }
  629. #if defined (_MACINTOSH)
  630.     m_pAsyncFileResponse = new SMPLAsyncResponse(this);
  631.     if (m_pContext)
  632.     {
  633. m_pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
  634.     }
  635. #endif
  636. #if defined(HELIX_FEATURE_PROGDOWN)
  637.     m_pProgDownMon = new CProgressiveDownloadMonitor();
  638. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  639. };
  640. CSimpleFileObject::~CSimpleFileObject()
  641. {
  642.     MLOG_LEAK("DES CSimpleFileObject this=0x%08xn", this);
  643. #ifndef HELIX_CONFIG_NOSTATICS
  644.     smpl_nRefCount--;
  645. #endif  // HELIX_CONFIG_NOSTATICS
  646.     m_bLocalClose = TRUE;
  647.     Close();
  648. };
  649. // *** IUnknown methods ***
  650. /////////////////////////////////////////////////////////////////////////
  651. //  Method:
  652. // IUnknown::QueryInterface
  653. //  Purpose:
  654. // Implement this to export the interfaces supported by your
  655. //   object.
  656. //
  657. STDMETHODIMP CSimpleFileObject::QueryInterface(REFIID riid, void** ppvObj)
  658. {
  659.     QInterfaceList qiList[] =
  660.     {
  661. { GET_IIDHANDLE(IID_IUnknown), this },
  662. { GET_IIDHANDLE(IID_IHXFileObject), (IHXFileObject*) this },
  663. { GET_IIDHANDLE(IID_IHXDirHandler), (IHXDirHandler*) this },
  664. { GET_IIDHANDLE(IID_IHXFileStat), (IHXFileStat*) this },
  665. { GET_IIDHANDLE(IID_IHXFileExists), (IHXFileExists*) this },
  666. { GET_IIDHANDLE(IID_IHXGetFileFromSamePool), (IHXGetFileFromSamePool*) this },
  667. { GET_IIDHANDLE(IID_IHXRequestHandler), (IHXRequestHandler*) this },
  668. { GET_IIDHANDLE(IID_IHXFileRename), (IHXFileRename*) this },
  669. { GET_IIDHANDLE(IID_IHXFileRemove), (IHXFileRemove*) this },
  670. { GET_IIDHANDLE(IID_IHXFileMove), (IHXFileMove*) this },
  671. { GET_IIDHANDLE(IID_IHXThreadSafeMethods), (IHXThreadSafeMethods*) this },
  672.     };
  673.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  674. }
  675. /////////////////////////////////////////////////////////////////////////
  676. //  Method:
  677. // IUnknown::AddRef
  678. //  Purpose:
  679. // Everyone usually implements this the same... feel free to use
  680. // this implementation.
  681. //
  682. STDMETHODIMP_(ULONG32) CSimpleFileObject::AddRef()
  683. {
  684.     return InterlockedIncrement(&m_lRefCount);
  685. }
  686. /////////////////////////////////////////////////////////////////////////
  687. //  Method:
  688. // IUnknown::Release
  689. //  Purpose:
  690. // Everyone usually implements this the same... feel free to use
  691. // this implementation.
  692. //
  693. STDMETHODIMP_(ULONG32) CSimpleFileObject::Release()
  694. {
  695.     if (InterlockedDecrement(&m_lRefCount) > 0)
  696.     {
  697. return m_lRefCount;
  698.     }
  699.     delete this;
  700.     return 0;
  701. }
  702. /************************************************************************
  703.  *  Method:
  704.  * IHXFileObject::Init
  705.  *  Purpose:
  706.  * Associates a file object with the file response object it should
  707.  * notify of operation completness. This method should also check
  708.  * for validity of the object (for example by opening it if it is
  709.  * a local file).
  710.  */
  711. STDMETHODIMP
  712. CSimpleFileObject::Init
  713. (
  714.     ULONG32 /*IN*/ ulFlags,
  715.     IHXFileResponse*   /*IN*/ pFileResponse
  716. )
  717. {
  718.     MLOG_GEN(NULL, "CSimpleFileObject::Init(0x%08x,0x%08x) this=0x%08xn",
  719.              ulFlags, pFileResponse, this);
  720.     HX_LOG_BLOCK( "CSimpleFileObject::Init" );
  721.     DPRINTF(0x5d000000, ("CSFO::Init(flags(0x%x), pFileResponse(%p)) "
  722.     "-- fd(%d)n", ulFlags, pFileResponse, m_nFd));
  723.     HX_RESULT lReturnVal = HXR_OK;
  724.     HX_RESULT resultInitDone = HXR_OK;
  725.     IHXRequestContext* pIHXRequestContextCurrent = NULL;
  726.     if (!pFileResponse) return HXR_INVALID_PARAMETER;
  727.     if (!m_pRequest) return HXR_INVALID_PARAMETER;
  728.     /* Release any previous reponses */
  729.     if (m_pFileResponse)
  730.     {
  731. m_pFileResponse->Release();
  732.     }
  733.     m_pFileResponse = pFileResponse;
  734.     m_pFileResponse->AddRef();
  735.     /* have we already opened/created a file */
  736.     if (m_nFd != -1)
  737.     {
  738. m_bReadPending      = FALSE;
  739. m_ulPendingReadCount = 0;
  740. /* remove any pending callbacks */
  741.         if (m_pStackCallback) m_pStackCallback->Cancel(m_pScheduler);
  742. /* if flags are same, then we are all set and there
  743.  * is no need to do anything further
  744.  */
  745. if (m_ulFlags == ulFlags || ulFlags == 0)
  746. {
  747.     /* If we have already opened a file, then seek back
  748.      * to zero during re-initialization
  749.      */
  750. #ifndef _MACINTOSH
  751.     HX_RESULT result = m_pDataFile->Seek(0, SEEK_SET);
  752.     m_pFileResponse->InitDone(result);
  753.     return result;
  754. #else
  755.     BOOL bAtInterrupt = FALSE;
  756.     if (m_pInterruptState)
  757.     {
  758. bAtInterrupt = m_pInterruptState->AtInterruptTime();
  759.     }
  760.     /* I want to know if we ever reach here at interrupt time
  761.      * Please e-mail me a repro case if you hit this assert
  762.      * - RA
  763.      */
  764.     HX_ASSERT(bAtInterrupt == FALSE);
  765.     m_eSeekReason = REINIT_SEEK;
  766.     HX_RESULT theResult = m_pDataFile->SafeSeek(0, SEEK_SET, bAtInterrupt);
  767.     if (theResult != HXR_OK)
  768.     {
  769. m_pFileResponse->InitDone(HXR_FAIL);
  770.     }
  771.     return theResult;
  772. #endif
  773.     /*
  774.     m_pFileResponse->InitDone(HXR_OK);
  775.     return HXR_OK;
  776.     */
  777. }
  778. #ifdef _MACINTOSH
  779. HX_RELEASE(m_pDataFile);
  780. m_pDataFile = NULL;
  781. #else
  782. DPRINTF(0x5d000000, ("CSFO::Init() -- m_pDataFile->Close()n"));
  783.         if (m_pDescriptorReg)
  784. {
  785.     m_pDescriptorReg->UnRegisterDescriptors(1);
  786. }
  787.         m_pDataFile->Close();
  788. m_nFd = -1;
  789. #endif
  790.     }
  791.     m_ulFlags = ulFlags;
  792.     if (!m_pCommonClassFactory)
  793.     {
  794. m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  795.                                     (void **)&m_pCommonClassFactory);
  796.     }
  797.     HX_RELEASE(m_pUnknownUserContext);
  798.     if (m_pRequest && SUCCEEDED(m_pRequest->QueryInterface(
  799. IID_IHXRequestContext, (void**)&pIHXRequestContextCurrent)))
  800.     {
  801. pIHXRequestContextCurrent->GetUserContext(m_pUnknownUserContext);
  802. pIHXRequestContextCurrent->Release();
  803.     }
  804.     DPRINTF(0x5d000000, ("CSFO::Init() -- (2) _OpenFile()n"));
  805.     lReturnVal = _OpenFile(ulFlags);
  806.     DPRINTF(0x5d000000, ("CSFO::Init(flags(0x%x), pFileResponse(%p)) "
  807.     "-- result(0x%x), m_nFd(%d)n",
  808.     ulFlags, pFileResponse, lReturnVal, m_nFd));
  809.     if ((m_nFd == -1 || FAILED(lReturnVal)))
  810.     {
  811. // XXXSSH -- probably obsolete
  812. if (lReturnVal != HXR_NOT_AUTHORIZED)
  813. {
  814.     lReturnVal = HXR_DOC_MISSING;
  815. }
  816.     }
  817.     else
  818.     {
  819. lReturnVal = HXR_OK;
  820.     }
  821. #if defined(HELIX_FEATURE_PROGDOWN)
  822.     // If we are writing to the file, then disable
  823.     // the progressive download features
  824.     m_bProgDownEnabled = (m_ulFlags & HX_FILE_WRITE ? FALSE : TRUE);
  825.     if (m_pProgDownMon && m_bProgDownEnabled)
  826.     {
  827.         m_pProgDownMon->Init(m_pContext, m_pDataFile, this);
  828.     }
  829. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  830.     resultInitDone =
  831. m_pFileResponse->InitDone(lReturnVal);
  832.     lReturnVal = resultInitDone;
  833.     DPRINTF(0x5d000000, ("CSFO::Init() "
  834.     "-- resultInitDone(0x%x), m_nFd(%d)n",
  835.     resultInitDone, m_nFd));
  836.     return (lReturnVal);
  837. }
  838. /************************************************************************
  839.  *  Method:
  840.  *      IHXFileObject::GetFilename
  841.  *  Purpose:
  842.  *      Returns the filename (without any path information) associated
  843.  *      with a file object.
  844.  */
  845. STDMETHODIMP CSimpleFileObject::GetFilename
  846. (
  847.     REF(const char*) /*OUT*/ pFilename
  848. )
  849. {
  850.     UpdateFileNameMember();
  851.     // Find the separator character before the file name
  852.     pFilename = ::strrchr(m_pFilename, OS_SEPARATOR_CHAR);
  853.     if (pFilename != NULL) // Found
  854.     {
  855. // File name starts after the separator charactor
  856. pFilename++;
  857.     }
  858.     else // Not found
  859.     {
  860. pFilename = m_pFilename;
  861.     }
  862.     return HXR_OK;
  863. }
  864. /************************************************************************
  865.  *  Method:
  866.  * IHXFileObject::Close
  867.  *  Purpose:
  868.  * Closes the file resource and releases all resources associated
  869.  * with the object.
  870.  */
  871. STDMETHODIMP CSimpleFileObject::Close()
  872. {
  873.     MLOG_GEN(NULL, "CSimpleFileObject::Close() this=0x%08xn", this);
  874.     HX_LOG_BLOCK( "CSimpleFileObject::Close" );
  875.     // If there is a pending callback, be sure to remove it!
  876.     if (m_pStackCallback) m_pStackCallback->Cancel(m_pScheduler);
  877.     HX_RELEASE(m_pStackCallback);
  878.     HX_RELEASE(m_pScheduler);
  879.     HX_RELEASE(m_pUnknownUserContext);
  880.     if (m_pContext)
  881.     {
  882. m_pContext->Release();
  883. m_pContext = NULL;
  884.     }
  885.     if (m_pCommonClassFactory)
  886.     {
  887. m_pCommonClassFactory->Release();
  888. m_pCommonClassFactory = NULL;
  889.     }
  890.     if (m_pFileSystem)
  891.     {
  892. m_pFileSystem->Release();
  893. m_pFileSystem = NULL;
  894.     }
  895.     if (m_pRequest)
  896.     {
  897. m_pRequest->Release();
  898. m_pRequest = NULL;
  899.     }
  900.     if (m_pDescriptorReg && (m_nFd != -1))
  901.     {
  902. m_pDescriptorReg->UnRegisterDescriptors(1);
  903. m_pDescriptorReg->Release();
  904. m_pDescriptorReg = 0;
  905.     }
  906. #if defined(HELIX_FEATURE_PROGDOWN)
  907.     // XXXMEH
  908.     // IMPORTANT!!
  909.     // Since the progressive download monitor does now not
  910.     // hold a ref on m_pDataFile, then we MUST make sure
  911.     // and call m_pProgDownMon->Close() BEFORE we close
  912.     // and release m_pDataFile. This is because there could
  913.     // be pending callbacks which will attempt to use
  914.     // the IHXDataFile. Callling m_pProgDownMon->Close()
  915.     // will cancel these pending callbacks.
  916.     if (m_pProgDownMon)
  917.     {
  918.         // Close the progressive download monitor. Closing
  919.         // also cancels any pending callbacks
  920.         m_pProgDownMon->Close();
  921.     }
  922.     HX_DELETE(m_pProgDownMon);
  923. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  924.     if (m_pDataFile)
  925.     {
  926. #if defined _MACINTOSH
  927.     HX_RELEASE(m_pDataFile);
  928.     HX_DELETE(m_pAsyncFileResponse);
  929.     HX_RELEASE(m_pInterruptState);
  930.     HX_RELEASE(m_pFileStatResponse);
  931. #else
  932. DPRINTF(0x5d000000, ("CSFO::Close() -- m_pDataFile->Close()n"));
  933. m_pDataFile->Close();
  934. HX_RELEASE(m_pDataFile);
  935. #endif
  936.     }
  937.     m_nFd = -1;
  938.     if(m_pFilename)
  939.     {
  940. HX_VECTOR_DELETE(m_pFilename);
  941. m_pFilename = NULL;
  942.     }
  943.     if (m_pDirResponse)
  944.     {
  945. m_pDirResponse->Release();
  946. m_pDirResponse = NULL;
  947.     }
  948.     if (m_pDirList)
  949.     {
  950. delete m_pDirList;
  951. m_pDirList = NULL;
  952.     }
  953.     // Make sure we do not attempt to schedule any more replies which
  954.     // would result in a crash after this point
  955.     m_bReadPending = FALSE;
  956. // It is vitally important that the CloseDone be the last step in
  957.     // this method, as the last reference to this object may be
  958.     // released inside CloseDone!  Do not place code after this if block!
  959.     // MBO: Access to stack variables after CloseDone is OK.
  960.     if (!m_bLocalClose)
  961.     {
  962. if(m_pFileResponse)
  963. {
  964.     // This keeps us from getting into an infinite loop when
  965.     // CSimpleFileObject::Close() calls m_pFileResponse->Release()
  966.     // which calls ~CRIFFReader() which calls Close() and so on,
  967.     // never hitting the line that sets m_pFileResponse to NULL...
  968.     IHXFileResponse* pTempFileResponse = m_pFileResponse;
  969.     m_pFileResponse = NULL;
  970.     pTempFileResponse->CloseDone(HXR_OK);
  971.     pTempFileResponse->Release();
  972.         }
  973.     }
  974.     else if (m_pFileResponse)
  975.     {
  976. m_pFileResponse->Release();
  977. m_pFileResponse = NULL;
  978.     }
  979.     return HXR_OK;
  980. }
  981. /************************************************************************
  982.  *  Method:
  983.  * IHXFileObject::Read
  984.  *  Purpose:
  985.  * Reads a buffer of data of the specified length from the file
  986.  * and asynchronously returns it to the caller via the
  987.  * IHXFileResponse interface passed in to Init.
  988.  */
  989. STDMETHODIMP CSimpleFileObject::Read(ULONG32 ulCount)
  990. {
  991.     MLOG_GEN(NULL, "CSimpleFileObject::Read(%lu) this=0x%08x tick=%lun",
  992.              ulCount, this, HX_GET_BETTERTICKCOUNT());
  993.     HX_LOG_BLOCK( "CSimpleFileObject::Read" );
  994.     // XXXBHG, For now, you cant read more than 1MB at a time!
  995.     if (ulCount > 0x000FFFFF)
  996.     {
  997. //Force the system to recognize a failed Read so infinite
  998. // buffering does not occur with the core waiting for EOF:
  999. ActualAsyncReadDone(HXR_FAIL, NULL);
  1000. return HXR_INVALID_PARAMETER;
  1001.     }
  1002.     if((m_nFd == -1) && m_bCanBeReOpened)
  1003.     {
  1004. DPRINTF(0x5d000000, ("CSFO::Read() -- _OpenFile()n"));
  1005. _OpenFile(m_ulFlags);
  1006. m_bCanBeReOpened = FALSE;
  1007. #ifndef _MACINTOSH
  1008. m_pDataFile->Seek(m_ulPos, SEEK_SET);
  1009. #endif
  1010.     }
  1011.     if (m_nFd != -1)
  1012.     {
  1013. if(!(m_ulFlags & HX_FILE_READ))
  1014.     return HXR_UNEXPECTED;
  1015. if (m_bReadPending)
  1016. {
  1017.     return HXR_UNEXPECTED;
  1018. }
  1019. m_bReadPending = TRUE;
  1020. m_ulPendingReadCount = ulCount;
  1021. if (m_bInRead && m_bAsyncAccess)
  1022. {
  1023.     return HXR_OK;
  1024. }
  1025. m_bInRead = TRUE;
  1026. HX_RESULT theErr = HXR_OK;
  1027. UINT16 uIterationCount;
  1028. uIterationCount = 0;
  1029. AddRef(); // Make sure we do not destruct in ReadDone()
  1030.         BOOL bProgFail = FALSE;
  1031. do
  1032. {
  1033.             bProgFail = FALSE;
  1034.     theErr = DoRead(bProgFail);
  1035.     uIterationCount++;
  1036. } while (m_bReadPending && !m_bAsyncReadPending && !theErr && uIterationCount < m_ulMaxIterationLevel && !bProgFail);
  1037. /* have we exceeded our iteration count? */
  1038. if (m_bReadPending && !m_bAsyncReadPending && !theErr && m_bAsyncAccess && !bProgFail)
  1039. {
  1040.             MLOG_PD(NULL, "tScheduling stack callbackn");
  1041.     HX_ASSERT(!m_pStackCallback->IsCallbackPending() &&
  1042.      uIterationCount >= m_ulMaxIterationLevel);
  1043.             // Schedule a callback if there is not one already scheduled
  1044.             m_pStackCallback->ScheduleRelative(m_pScheduler, 0);
  1045. }
  1046. m_bInRead = FALSE;
  1047. Release();
  1048. return theErr;
  1049.     }
  1050.     return HXR_UNEXPECTED;
  1051. }
  1052. HX_RESULT
  1053. CSimpleFileObject::DoRead(REF(BOOL) rbProgFail)
  1054. {
  1055.     MLOG_PD(NULL, "CSimpleFileObject::DoRead() this=0x%08x tick=%lu curoffset=%lun",
  1056.             this, HX_GET_BETTERTICKCOUNT(), m_ulPos);
  1057.     HX_LOG_BLOCK( "CSimpleFileObject::DoRead" );
  1058.     HX_ASSERT(m_bReadPending);
  1059.     HX_RESULT theErr = HXR_OK;
  1060.     UINT32 ulCount = m_ulPendingReadCount;
  1061. #ifndef _MACINTOSH
  1062.     // Create buffer object here, notice that we call the
  1063.     // CreateInstance method of the controller, but we could
  1064.     // have implemented our own object that exposed the IHXBuffer
  1065.     // interface.
  1066.     IHXBuffer* pBuffer = NULL;
  1067.     ULONG32 actual = m_pDataFile->Read(pBuffer, ulCount);
  1068. #if defined(HELIX_FEATURE_PROGDOWN)
  1069.     MLOG_PD(NULL, "tulCount = %lu actual = %lun", ulCount, actual);
  1070.     // Sanity check. Unlikely we'd even make it here
  1071.     // if we failed to allocate m_pProgDownMon, but 
  1072.     // if so, then just behave like HELIX_FEATURE_PROGDOWN
  1073.     // is not defined
  1074.     if (m_pProgDownMon && m_bProgDownEnabled)
  1075.     {
  1076.         // Did we read all the bytes we were asked for?
  1077.         if (actual < ulCount)
  1078.         {
  1079.             MLOG_PD(NULL, "tt******** FAILED to read requested bytesn");
  1080.             // The read failed to read all the requested bytes
  1081.             //
  1082.             // Do we have a history of progressive download
  1083.             // with this file?
  1084.             if (m_pProgDownMon->HasBeenProgressive())
  1085.             {
  1086.                 MLOG_PD(NULL, "tttFile HAS been progressiven");
  1087.                 // This file has been progressive sometime in
  1088.                 // the past. However, we need to
  1089.                 // check the *current* state.
  1090.                 if (m_pProgDownMon->IsProgressive())
  1091.                 {
  1092.                     MLOG_PD(NULL, "ttttFile currently IS progressiven");
  1093.                     // The file is still currently downloading.
  1094.                     //
  1095.                     // Can we callback asynchronously?
  1096.                     if (m_bAsyncAccess)
  1097.                     {
  1098.                         // Set the flag saying we failed due to
  1099.                         // progressive download
  1100.                         rbProgFail = TRUE;
  1101.                         // Schedule the callback
  1102.                         return FinishDoReadWithCallback(actual);
  1103.                     }
  1104.                     else
  1105.                     {
  1106.                         // Try synchronously
  1107.                         return FinishDoReadWithoutCallback(actual);
  1108.                     }
  1109.                 }
  1110.                 else
  1111.                 {
  1112.                     MLOG_PD(NULL, "ttttFile currently is NOT progressiven");
  1113.                     // The file has been progressive in the past
  1114.                     // but the current state is NOT progressive.
  1115.                     // That could mean that either the download has
  1116.                     // finished or that the download agent is paused.
  1117.                     // With our current implementation we can't tell
  1118.                     // the difference (we would need to know the "true"
  1119.                     // file size to know for sure). Therefore, we will
  1120.                     // ask the fileformat whether or not it would "expect"
  1121.                     // a failure at this point. The fileformat should have
  1122.                     // knowledge to know whether or not a failure of this
  1123.                     // read would indicate failure or not. Sometimes fileformats
  1124.                     // read in large chunks and *expect* to get a failure.
  1125.                     // On the other hand, file formats sometimes do a read
  1126.                     // and are NOT expecting it to fail.
  1127.                     if (RequireFullRead())
  1128.                     {
  1129.                         MLOG_PD(NULL, "ttttFileResponse requires full readsn");
  1130.                         // The response says it requires full reads
  1131.                         //
  1132.                         // Can we callback asynchronously?
  1133.                         if (m_bAsyncAccess)
  1134.                         {
  1135.                             // Set the flag saying we failed due to
  1136.                             // progressive download
  1137.                             rbProgFail = TRUE;
  1138.                             // Schedule the callback
  1139.                             return FinishDoReadWithCallback(actual);
  1140.                         }
  1141.                         else
  1142.                         {
  1143.                             // Try synchronously
  1144.                             return FinishDoReadWithoutCallback(actual);
  1145.                         }
  1146.                     }
  1147.                     else if (m_pProgDownMon->GetFormerProgressiveRetryCount() > 0)
  1148.                     {
  1149.                         MLOG_PD(NULL, "ttttRetrying former progressive, count = %lun",
  1150.                                 m_pProgDownMon->GetFormerProgressiveRetryCount());
  1151.                         // We do not require a full read, but we are going
  1152.                         // to retry a certain number of times before calling
  1153.                         // back with ReadDone().
  1154.                         //
  1155.                         // Decrement the retry count. If the file becomes
  1156.                         // progressive again, then this count gets reset.
  1157.                         m_pProgDownMon->DecrementFormerProgressiveRetryCount();
  1158.                         // Can we callback asynchronously?
  1159.                         if (m_bAsyncAccess)
  1160.                         {
  1161.                             // Set the flag saying we failed due to
  1162.                             // progressive download
  1163.                             rbProgFail = TRUE;
  1164.                             // Schedule the callback
  1165.                             return FinishDoReadWithCallback(actual);
  1166.                         }
  1167.                         else
  1168.                         {
  1169.                             // Try synchronously
  1170.                             return FinishDoReadWithoutCallback(actual);
  1171.                         }
  1172.                     }
  1173.                     else
  1174.                     {
  1175.                         MLOG_PD(NULL, "ttttCannot retry former progressive any moren");
  1176.                         // We have retried on this formerly progressive
  1177.                         // file as long as we can, so just call back
  1178.                         // with ReadDone().
  1179.                         //
  1180.                         // Clear the progressive download failure flag
  1181.                         rbProgFail = FALSE;
  1182.                         // Finish the DoRead
  1183.                         return FinishDoRead(actual, pBuffer);
  1184.                     }
  1185.                 }
  1186.             }
  1187.             else /* if (m_pProgDownMon->HasBeenProgressive()) */
  1188.             {
  1189.                 MLOG_PD(NULL, "tttFile has NOT been progressive, checking file sizen");
  1190.                 // This file has never yet been progressive
  1191.                 //
  1192.                 // Do a filesize check. This will check
  1193.                 // the filesize against the filesize at
  1194.                 // the time that m_pProgDownMon->Init()
  1195.                 // was called. If the filesize has changed,
  1196.                 // then the m_pProgDownMon->HasBeenProgressive()
  1197.                 // flag will change.
  1198.                 m_pProgDownMon->MonitorFileSize();
  1199.                 // Has the filesize changed?
  1200.                 if (m_pProgDownMon->HasBeenProgressive())
  1201.                 {
  1202.                     MLOG_PD(NULL, "ttttFile size HAS changed, beginning size monitoring and retryingn");
  1203.                     // The filesize has indeed changed.
  1204.                     //
  1205.                     // Begin the monitoring of the file size
  1206.                     m_pProgDownMon->BeginSizeMonitoring();
  1207.                     // Can we callback asynchronously?
  1208.                     if (m_bAsyncAccess)
  1209.                     {
  1210.                         // Set the flag saying we failed due to
  1211.                         // progressive download
  1212.                         rbProgFail = TRUE;
  1213.                         // Schedule the callback
  1214.                         return FinishDoReadWithCallback(actual);
  1215.                     }
  1216.                     else
  1217.                     {
  1218.                         // Try synchronously
  1219.                         return FinishDoReadWithoutCallback(actual);
  1220.                     }
  1221.                 }
  1222.                 else
  1223.                 {
  1224.                     MLOG_PD(NULL, "ttttFile size has NOT changed.n");
  1225.                     // The filesize has NOT changed. This is most likely
  1226.                     // just a normal file and the fileformat has attempted
  1227.                     // to read past the end of the file. However, we will
  1228.                     // first ask the fileformat if it expected a failure.
  1229.                     if (RequireFullRead() &&
  1230.                         m_pProgDownMon->GetNotProgressiveRetryCount() > 0)
  1231.                     {
  1232.                         MLOG_PD(NULL, "tttttRetrying not progressive, count = %lun",
  1233.                                 m_pProgDownMon->GetNotProgressiveRetryCount());
  1234.                         // Decrement the retry count. If the file becomes
  1235.                         // progressive, then this count gets reset.
  1236.                         m_pProgDownMon->DecrementNotProgressiveRetryCount();
  1237.                         // The fileformat had the Advise interface and 
  1238.                         // said it did not expect a failure here. Also,
  1239.                         // we have not retried our maximum number of attempts
  1240.                         // yet, so we will retry the read.
  1241.                         //
  1242.                         // Can we callback asynchronously?
  1243.                         if (m_bAsyncAccess)
  1244.                         {
  1245.                             // Set the flag saying we failed due to
  1246.                             // progressive download
  1247.                             rbProgFail = TRUE;
  1248.                             // Schedule the callback
  1249.                             return FinishDoReadWithCallback(actual);
  1250.                         }
  1251.                         else
  1252.                         {
  1253.                             // Try synchronously
  1254.                             return FinishDoReadWithoutCallback(actual);
  1255.                         }
  1256.                     }
  1257.                     else
  1258.                     {
  1259.                         // Either:
  1260.                         // a) the fileformat either didn't have the Advise interface;
  1261.                         // b) the fileformat did have the interface and said it
  1262.                         //    was expecting a failure; or
  1263.                         // c) the fileformat had the Advise interface and said it
  1264.                         //    wasn't expecting a failure, but we've retried all the
  1265.                         //    times we can.
  1266.                         //
  1267.                         // Clear the progressive download failure flag
  1268.                         rbProgFail = FALSE;
  1269.                         // Finish the DoRead
  1270.                         return FinishDoRead(actual, pBuffer);
  1271.                     }
  1272.                 }
  1273.             } /* if (m_pProgDownMon->HasBeenProgressive()) else */
  1274.         }
  1275.         else /* if (actual < ulCount) */
  1276.         {
  1277.             // The read succeeded
  1278.             //
  1279.             // Reset the not progressive retry count
  1280.             m_pProgDownMon->ResetNotProgressiveRetryCount();
  1281.             // Clear the progressive download failure flag
  1282.             rbProgFail = FALSE;
  1283.             // Finish the DoRead
  1284.             return FinishDoRead(actual, pBuffer);
  1285.         }
  1286.     }
  1287.     else /* if (m_pProgDownMon) */
  1288. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  1289.     {
  1290.         // Clear the progressive download failure flag
  1291.         rbProgFail = FALSE;
  1292.         // Finish the DoRead
  1293.         return FinishDoRead(actual, pBuffer);
  1294.     }
  1295. #else /* #ifndef _MACINTOSH */
  1296.     BOOL bAtInterrupt = FALSE;
  1297.     if (m_pInterruptState)
  1298.     {
  1299. bAtInterrupt = m_pInterruptState->AtInterruptTime();
  1300.     }
  1301.     m_bAsyncReadPending = TRUE;
  1302.     theErr = m_pDataFile->SafeRead(ulCount, bAtInterrupt);
  1303. #endif /* #ifndef _MACINTOSH #else */
  1304.     return theErr;
  1305. }
  1306. /************************************************************************
  1307.  *  Method:
  1308.  * IHXFileObject::Write
  1309.  *  Purpose:
  1310.  * Writes a buffer of data to the file and asynchronously notifies
  1311.  * the caller via the IHXFileResponse interface passed in to Init,
  1312.  * of the completeness of the operation.
  1313.  */
  1314. STDMETHODIMP CSimpleFileObject::Write(IHXBuffer* pBuffer)
  1315. {
  1316.     if (m_nFd == -1 || !(m_ulFlags & HX_FILE_WRITE))
  1317.     {
  1318. return HXR_UNEXPECTED;
  1319.     }
  1320.     pBuffer->AddRef();
  1321. #ifdef _MACINTOSH
  1322. BOOL bAtInterrupt = FALSE;
  1323. if (m_pInterruptState)
  1324. {
  1325.     bAtInterrupt = m_pInterruptState->AtInterruptTime();
  1326. }
  1327.     UINT32 actual = m_pDataFile->SafeWrite(pBuffer, bAtInterrupt);
  1328. #else
  1329.     UINT32 actual = m_pDataFile->Write(pBuffer);
  1330. #endif
  1331.     pBuffer->Release();
  1332.     if (actual > 0)
  1333.     {
  1334. m_ulPos += actual;
  1335.     }
  1336.     if(actual == pBuffer->GetSize())
  1337. m_pFileResponse->WriteDone(HXR_OK);
  1338.     else
  1339. m_pFileResponse->WriteDone(HXR_FAILED);
  1340.     return HXR_OK;
  1341. }
  1342. /************************************************************************
  1343.  *  Method:
  1344.  * IHXFileObject::Seek
  1345.  *  Purpose:
  1346.  * Seeks to an offset in the file and asynchronously notifies
  1347.  * the caller via the IHXFileResponse interface passed in to Init,
  1348.  * of the completeness of the operation.
  1349.  */
  1350. STDMETHODIMP CSimpleFileObject::Seek(ULONG32 ulOffset, BOOL bRelative)
  1351. {
  1352.     MLOG_GEN(NULL, "CSimpleFileObject::Seek(%lu,%lu) this=0x%08x tick=%lun",
  1353.              ulOffset, bRelative, this, HX_GET_BETTERTICKCOUNT());
  1354.     HX_LOG_BLOCK( "CSimpleFileObject::Seek" );
  1355.     if((m_nFd == -1) && m_bCanBeReOpened)
  1356.     {
  1357. DPRINTF(0x5d000000, ("CSFO::Seek() -- _OpenFile()n"));
  1358. _OpenFile(m_ulFlags);
  1359.     }
  1360.     if (m_nFd != -1)
  1361.     {
  1362. /* remove any pending callbacks */
  1363.         if (m_pStackCallback) m_pStackCallback->Cancel(m_pScheduler);
  1364. #if defined(HELIX_FEATURE_PROGDOWN)
  1365.         // Seeks can interrupt other seeks, and cancel them
  1366.         // out. Therefore, if we had scheduled a callback to
  1367.         // handle a failed seek or a failed read, then we need
  1368.         // to cancel that callback.
  1369.         if (m_pProgDownMon && m_pProgDownMon->IsCallbackPending())
  1370.         {
  1371.             m_pProgDownMon->CancelCallback();
  1372.         }
  1373. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  1374. AddRef(); // Make sure we do not destruct on possible ReadDone
  1375. /*
  1376.  *  Seek cancels pending Reads.
  1377.  */
  1378. if (m_bReadPending)
  1379. {
  1380.     ActualAsyncReadDone(HXR_CANCELLED, NULL);
  1381. }
  1382. int whence = SEEK_SET;
  1383. if(bRelative)
  1384.     whence = SEEK_CUR;
  1385. #ifndef _MACINTOSH
  1386.         // Save the pending seek parameters
  1387.         m_ulPendingSeekOffset = ulOffset;
  1388.         m_usPendingSeekWhence = (UINT16) whence;
  1389.         // Do the seek
  1390.         HX_RESULT seekDoneResult = HXR_OK;
  1391.         HX_RESULT result = DoSeek(seekDoneResult);
  1392.         // Undo the AddRef();
  1393.         Release();
  1394. return ((result == HXR_OK) ? seekDoneResult : result);
  1395. #else
  1396. BOOL bAtInterrupt = FALSE;
  1397. if (m_pInterruptState)
  1398. {
  1399.     bAtInterrupt = m_pInterruptState->AtInterruptTime();
  1400. }
  1401. m_eSeekReason = EXTERNAL_SEEK;
  1402. HX_RESULT seekDoneResult = m_pDataFile->SafeSeek(ulOffset, whence, bAtInterrupt);
  1403. Release();
  1404. return seekDoneResult;
  1405. #endif
  1406.     }
  1407.     return HXR_UNEXPECTED;
  1408. }
  1409. HX_RESULT CSimpleFileObject::DoSeek(REF(HX_RESULT) rSeekDoneResult)
  1410. {
  1411.     MLOG_PD(NULL, "CSimpleFileObject::DoSeek() this=0x%08x tick=%lu offset=%lu whence=%un",
  1412.             this, HX_GET_BETTERTICKCOUNT(), m_ulPendingSeekOffset, m_usPendingSeekWhence);
  1413.     HX_RESULT result = m_pDataFile->Seek(m_ulPendingSeekOffset,
  1414.                                          m_usPendingSeekWhence);
  1415.     if (result == HXR_OK)
  1416.     {
  1417. if (m_usPendingSeekWhence == SEEK_SET)
  1418. {
  1419.     m_ulPos = m_ulPendingSeekOffset;
  1420. }
  1421. else
  1422. {
  1423.     m_ulPos += m_ulPendingSeekOffset;
  1424. }
  1425.     }
  1426. #if defined(HELIX_FEATURE_PROGDOWN)
  1427.     // For the purposes of progressive download, we
  1428.     // will assume that seeking never fails. We will
  1429.     // add the assert below to catch anytime it does.
  1430.     // If we are finding that this assert is tripping,
  1431.     // then we need to add equivalent support in DoSeek()
  1432.     // for progressive download that we have in DoRead().
  1433.     HX_ASSERT(SUCCEEDED(result));
  1434. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  1435.     rSeekDoneResult = ActualAsyncSeekDone(result);
  1436.     return result;
  1437. }
  1438. void CSimpleFileObject::SeekBackwards(UINT32 ulNumBytes)
  1439. {
  1440.     if (m_pDataFile && ulNumBytes)
  1441.     {
  1442.         // Get the current offset
  1443.         UINT32 ulCurOffset = m_pDataFile->Tell();
  1444.         // Make sure the number of bytes we 
  1445.         // are supposed to back up is not greater
  1446.         // than the current offset
  1447.         if (ulNumBytes > ulCurOffset) ulNumBytes = ulCurOffset;
  1448.         // Compute the new absolute offset
  1449.         UINT32 ulNewOffset = ulCurOffset - ulNumBytes;
  1450.         // Seek the data file to this offset
  1451.         m_pDataFile->Seek(ulNewOffset, SEEK_SET);
  1452.     }
  1453. }
  1454. HX_RESULT CSimpleFileObject::FinishDoRead(UINT32 actual, REF(IHXBuffer*) pBuffer)
  1455. {
  1456.     /*
  1457.      * If they get to the end of the file, then close it and reset.
  1458.      */
  1459.     if (actual > 0 && pBuffer)
  1460.     {
  1461.         m_ulPos += actual;
  1462.     }
  1463. #if defined(HELIX_FEATURE_PROGDOWN)
  1464.     if (m_ulSize && (!m_bProgDownEnabled || (m_pProgDownMon && !m_pProgDownMon->HasBeenProgressive())))
  1465. #else
  1466.     if (m_ulSize)
  1467. #endif
  1468.     {
  1469.         if(m_ulPos >= m_ulSize)
  1470.         {
  1471.     DPRINTF(0x5d000000, ("CSFO::Read() -- m_pDataFile->Close()n"));
  1472.     m_pDataFile->Close();
  1473.     m_nFd = -1;
  1474.     if (m_pDescriptorReg)
  1475.     {
  1476.         m_pDescriptorReg->UnRegisterDescriptors(1);
  1477.     }
  1478.     m_bCanBeReOpened = 1;
  1479.         }
  1480.     }
  1481.     /* ignore return value from readdone! */
  1482.     ActualAsyncReadDone((actual > 0 && pBuffer) ? HXR_OK : HXR_FAILED, pBuffer);
  1483.     // Release our reference on the buffer!
  1484.     HX_RELEASE(pBuffer);
  1485.     return HXR_OK;
  1486. }
  1487. STDMETHODIMP CSimpleFileObject::InitDirHandler
  1488. (
  1489.     IHXDirHandlerResponse*    /*IN*/  pDirResponse
  1490. )
  1491. {
  1492.     m_pDirResponse = pDirResponse;
  1493.     m_pDirResponse->AddRef();
  1494.     m_pDirResponse->InitDirHandlerDone(HXR_OK);
  1495.     return HXR_OK;
  1496. }
  1497. STDMETHODIMP CSimpleFileObject::CloseDirHandler()
  1498. {
  1499.     // Members must not be accessed after async ...Done() response
  1500.     if (m_pDirResponse)
  1501.     {
  1502. IHXDirHandlerResponse *pTmpDirResponse = m_pDirResponse;
  1503. m_pDirResponse = NULL;
  1504. pTmpDirResponse->CloseDirHandlerDone(HXR_OK);
  1505. pTmpDirResponse->Release();
  1506.     }
  1507.     return HXR_OK;
  1508. }
  1509. STDMETHODIMP CSimpleFileObject::MakeDir()
  1510. {
  1511.     CHXString strFileName;
  1512.     HX_RESULT retVal = HXR_OK;
  1513.     UpdateFileNameMember();
  1514.     GetFullPathname(m_pFilename, &strFileName);
  1515. #if defined (_WINDOWS ) || defined (_WIN32)
  1516.     if (CreateDirectory(OS_STRING((const char*) strFileName), 0) == 0)
  1517.     {
  1518. retVal = HXR_FAIL;
  1519.     }
  1520. #elif defined (_UNIX)
  1521.     if (mkdir((const char*) strFileName, 0755) < 0)
  1522.     {
  1523. retVal = HXR_FAIL;
  1524.     }
  1525. #elif defined (_MACINTOSH)
  1526.     //XXXGH...don't know how to do this on Mac
  1527.     retVal = HXR_FAIL;
  1528. #else
  1529.     XHXDirectory* pHXDirectory = XHXDirectory::Construct(&m_pFileSystem->m_pCommonObj);
  1530.     retVal = HXR_OUTOFMEMORY;
  1531.     if (pHXDirectory)
  1532.     {
  1533. retVal = HXR_FAIL;
  1534. pHXDirectory->SetPath((const char*) strFileName);
  1535. if (pHXDirectory->Create())
  1536. {
  1537.     retVal = HXR_OK;
  1538. }
  1539. delete pHXDirectory;
  1540.     }
  1541. #endif
  1542.     m_pDirResponse->MakeDirDone(retVal);
  1543.     return HXR_OK;
  1544. }
  1545. STDMETHODIMP CSimpleFileObject::ReadDir()
  1546. {
  1547.     const char* pDirname = 0;
  1548.     if (!m_pDirList)
  1549.     {
  1550. CHXString strFileName;
  1551. UpdateFileNameMember();
  1552. GetFullPathname(m_pFilename, &strFileName);
  1553. m_pDirList =
  1554.     CFindFile::CreateFindFile((const char*)strFileName, 0, "*");
  1555. if (!m_pDirList)
  1556. {
  1557.     m_pDirResponse->ReadDirDone(HXR_FAIL, 0);
  1558.     return HXR_OK;
  1559. }
  1560. pDirname = m_pDirList->FindFirst();
  1561.     }
  1562.     else
  1563.     {
  1564. pDirname = m_pDirList->FindNext();
  1565.     }
  1566.     if (!pDirname)
  1567.     {
  1568. delete m_pDirList;
  1569. m_pDirList = 0;
  1570. m_pDirResponse->ReadDirDone(HXR_FILE_NOT_FOUND, 0);
  1571. return HXR_OK;
  1572.     }
  1573.     HX_RESULT result;
  1574.     if (!m_pCommonClassFactory)
  1575.     {
  1576. result = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  1577.                                     (void **)&m_pCommonClassFactory);
  1578. if (HXR_OK != result)
  1579. {
  1580.     return result;
  1581. }
  1582.     }
  1583.     IHXBuffer* pBuffer = 0;
  1584.     result = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
  1585.                                                    (void**)&pBuffer);
  1586.     if (HXR_OK != result)
  1587.     {
  1588. return result;
  1589.     }
  1590.     pBuffer->Set((Byte*)pDirname, strlen(pDirname)+1);
  1591.     m_pDirResponse->ReadDirDone(HXR_OK, pBuffer);
  1592.     pBuffer->Release();
  1593.     return HXR_OK;
  1594. }
  1595. /************************************************************************
  1596.  * Method:
  1597.  * IHXFileObject::Stat
  1598.  * Purpose:
  1599.  * Collects information about the file that is returned to the
  1600.  * caller in an IHXStat object
  1601.  */
  1602. STDMETHODIMP CSimpleFileObject::Stat(IHXFileStatResponse* pFileStatResponse)
  1603. {
  1604.     MLOG_GEN(NULL, "CSimpleFileObject::Stat(0x%08x) this=0x%08xn", pFileStatResponse, this);
  1605.     HX_LOG_BLOCK( "CSimpleFileObject::Stat" );
  1606.     struct stat StatBuffer;
  1607.     CHXString strFileName;
  1608. #ifdef _MACINTOSH
  1609.         // if fstat fails
  1610. #ifdef _MAC_MACHO
  1611. GetFullPathname(m_pFilename, &strFileName);
  1612.         int res = stat(strFileName, &StatBuffer);
  1613. #else
  1614.         int res = stat(m_pFilename, &StatBuffer);
  1615. #endif
  1616. if ( res != 0 )
  1617. {
  1618. // return failure code
  1619. return HXR_FAIL;
  1620. }
  1621. #else
  1622.     if(m_nFd == -1)
  1623.     {
  1624. CHXString   strURL;
  1625. UpdateFileNameMember();
  1626. strURL = m_pFilename;
  1627. GetFullPathname(strURL, &strFileName);
  1628. m_pDataFile->Bind((const char *)strFileName);
  1629.     }
  1630.     if (m_pDataFile->Stat(&StatBuffer) != HXR_OK)
  1631.     {
  1632. pFileStatResponse->StatDone(HXR_FAIL,
  1633.     0,
  1634.     0,
  1635.     0,
  1636.     0,
  1637.     0);
  1638. return HXR_OK;
  1639.     }
  1640. #endif
  1641.     /*
  1642.      * XXXSMP:
  1643.      *    We we need this because RealPix opens up tons of files
  1644.      *    just to stat them.  If you are reading this comment
  1645.      *    and the date is past July 31, then please yell at
  1646.      *    Sujal.
  1647.      */
  1648. #if !defined(_MACINTOSH)
  1649.     if(m_nFd != -1)
  1650.     {
  1651. DPRINTF(0x5d000000, ("CSFO::Stat() -- m_pDataFile->Close()n"));
  1652. if (m_pDescriptorReg)
  1653. {
  1654.     m_pDescriptorReg->UnRegisterDescriptors(1);
  1655. }
  1656. m_pDataFile->Close();
  1657. m_nFd = -1;
  1658. m_bCanBeReOpened = 1;
  1659.     }
  1660. #endif
  1661.     m_ulSize = StatBuffer.st_size;
  1662.     pFileStatResponse->StatDone(HXR_OK,
  1663. StatBuffer.st_size,
  1664. StatBuffer.st_ctime,
  1665. StatBuffer.st_atime,
  1666. StatBuffer.st_mtime,
  1667. StatBuffer.st_mode);
  1668.     return HXR_OK;
  1669. }
  1670. /************************************************************************
  1671.  *  Method:
  1672.  * IHXFileObject::Advise
  1673.  *  Purpose:
  1674.  * To pass information to the File Object
  1675.  */
  1676. STDMETHODIMP CSimpleFileObject::Advise(ULONG32 ulInfo)
  1677. {
  1678.     MLOG_GEN(NULL, "CSimpleFileObject::Advise(%s) this=0x%08xn",
  1679.              (ulInfo == HX_FILEADVISE_RANDOMACCESS ? "HX_FILEADVISE_RANDOMACCESS" :
  1680.                 (ulInfo == HX_FILEADVISE_SYNCACCESS ? "HX_FILEADVISE_SYNCACCESS" :
  1681.                    (ulInfo == HX_FILEADVISE_ASYNCACCESS ? "HX_FILEADVISE_ASYNCACCESS" :
  1682.                       (ulInfo == HX_FILEADVISE_RANDOMACCESSONLY ? "HX_FILEADVISE_RANDOMACCESSONLY" :
  1683.                          (ulInfo == HX_FILEADVISE_ANYACCESS ? "HX_FILEADVISE_ANYACCESS" : "Unknown"))))),
  1684.              this);
  1685.     HX_RESULT retVal = HXR_FAIL;
  1686. #ifndef _MACINTOSH
  1687.     if (ulInfo == HX_FILEADVISE_SYNCACCESS)
  1688.     {
  1689. m_bAsyncAccess = FALSE;
  1690. retVal = HXR_OK;
  1691.     }
  1692.     else if (ulInfo == HX_FILEADVISE_ASYNCACCESS)
  1693.     {
  1694. m_bAsyncAccess = TRUE;
  1695. retVal = HXR_OK;
  1696.     }
  1697. #if defined(HELIX_FEATURE_PROGDOWN)
  1698.     else if (ulInfo == HX_FILEADVISE_RANDOMACCESS)
  1699.     {
  1700.         retVal = HXR_OK;
  1701.         if (m_pProgDownMon && m_bProgDownEnabled)
  1702.         {
  1703.             // Has this file ever been progressive?
  1704.             if (m_pProgDownMon->HasBeenProgressive())
  1705.             {
  1706.                 // It has been in the past, but
  1707.                 // is it currently progressive?
  1708.                 if (m_pProgDownMon->IsProgressive())
  1709.                 {
  1710.                     // Set the linear return value
  1711.                     retVal = HXR_ADVISE_PREFER_LINEAR;
  1712.                 }
  1713.             }
  1714.             else
  1715.             {
  1716.                 // Manually monitor the file size. This
  1717.                 // will trigger HasBeenProgressive() to 
  1718.                 // be true if the file is progressive
  1719.                 m_pProgDownMon->MonitorFileSize();
  1720.                 // Are we now progressive?
  1721.                 if (m_pProgDownMon->HasBeenProgressive())
  1722.                 {
  1723.                     // Set the linear return value
  1724.                     retVal = HXR_ADVISE_PREFER_LINEAR;
  1725.                     // Begin the monitoring of the file size
  1726.                     m_pProgDownMon->BeginSizeMonitoring();
  1727.                 }
  1728.             }
  1729.         }
  1730.     }
  1731. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  1732. #endif // _MACINTOSH
  1733.     MLOG_GEN(NULL, "treturn %sn",
  1734.              (retVal == HXR_OK ? "HXR_OK" :
  1735.                 (retVal == HXR_FAIL ? "HXR_FAIL" :
  1736.                    (retVal == HXR_ADVISE_PREFER_LINEAR ? "HXR_ADVISE_PREFER_LINEAR" :
  1737.                       "Unknown"))));
  1738.     return retVal;
  1739. }
  1740. /************************************************************************
  1741.  * Method:
  1742.  *     IHXFileObject::GetFileObjectFromPool
  1743.  * Purpose:
  1744.  *      To get another FileObject from the same pool.
  1745.  */
  1746. STDMETHODIMP CSimpleFileObject::GetFileObjectFromPool (
  1747.     IHXGetFileFromSamePoolResponse* response
  1748. )
  1749. {
  1750.     HX_RESULT lReturnVal = HXR_FAILED;
  1751.     CSimpleFileObject* pFileObject = 0;
  1752.     CHXString new_path;
  1753.     CHXString strFileName;
  1754.     CHXString strURL;
  1755.     IUnknown* pUnknown = 0;
  1756.     char* pNewPath    = 0;
  1757.     char* pSeparator  = 0;
  1758.     UpdateFileNameMember();
  1759.     if(!m_pFilename)
  1760.     {
  1761. pNewPath = new char[strlen(m_base_path) + 1];
  1762. strcpy(pNewPath, m_base_path); /* Flawfinder: ignore */
  1763.     }
  1764.     else
  1765.     {
  1766. strURL = m_pFilename;
  1767. // Make a nice local file name from the URL!
  1768. GetFullPathname(strURL, &strFileName);
  1769. pNewPath = new char[strlen(strFileName) + 1];
  1770. strcpy(pNewPath, (const char*)strFileName); /* Flawfinder: ignore */
  1771. pSeparator = ::strrchr(pNewPath, OS_SEPARATOR_CHAR);
  1772. if(pSeparator)
  1773. {
  1774.     /* Separator will be added in seturl */
  1775.     *pSeparator = 0;
  1776. }
  1777. else
  1778. {
  1779.     // started w/filename. no separator implies no path
  1780.     pNewPath[0] = 0;
  1781. }
  1782.     }
  1783.     new_path = pNewPath;
  1784.     if (pNewPath)
  1785.     {
  1786. delete [] pNewPath;
  1787. pNewPath = 0;
  1788.     }
  1789.     pFileObject = new CSimpleFileObject(new_path,
  1790. m_pFileSystem,
  1791. m_pContext,
  1792. m_ulMaxIterationLevel);
  1793.     if (!pFileObject)
  1794.     {
  1795. return HXR_OUTOFMEMORY;
  1796.     }
  1797.     lReturnVal = pFileObject->QueryInterface(IID_IUnknown,
  1798.      (void**)&pUnknown);
  1799.     response->FileObjectReady(lReturnVal == HXR_OK ?
  1800.       HXR_OK : HXR_FAILED,
  1801.       pUnknown);
  1802.     if(pUnknown)
  1803.     {
  1804. pUnknown->Release();
  1805. pUnknown = NULL;
  1806.     }
  1807.     return lReturnVal;
  1808. }
  1809. // IHXFileExists interface
  1810. /************************************************************************
  1811.  * Method:
  1812.  *     IHXFileExists::DoesExist
  1813.  * Purpose:
  1814.  */
  1815. STDMETHODIMP CSimpleFileObject::DoesExist(const char* /*IN*/  pPath,
  1816. IHXFileExistsResponse* /*IN*/  pFileResponse)
  1817. {
  1818.     BOOL bExists = FALSE;
  1819.     BOOL bPlusURL = FALSE;
  1820.     CHXString   strFileName;
  1821.     CHXString strPath;
  1822.     CHXString   plusFileName;
  1823.     CHXString   plusPath;
  1824.     strPath = pPath;
  1825.     bPlusURL = HXXFile::IsPlusURL(pPath);
  1826.     if (bPlusURL)
  1827.     {
  1828. INT32 index = strPath.ReverseFind('+');
  1829. plusFileName = strPath.Right(strPath.GetLength() - (index+1));
  1830. strPath = strPath.Left(index);
  1831. index = strPath.ReverseFind('/');
  1832. if (index >= 0)
  1833. {
  1834.     plusPath = strPath.Left(index+1);
  1835.     plusPath = plusPath + plusFileName;
  1836. }
  1837. else
  1838. {
  1839.     plusPath = plusFileName;
  1840. }
  1841. HXXFile::GetReasonableLocalFileName(plusPath);
  1842. GetFullPathname(plusPath, &plusFileName);
  1843.     }
  1844.     // Make a nice local file name from the URL!
  1845.     HXXFile::GetReasonableLocalFileName(strPath);
  1846.     GetFullPathname(strPath, &strFileName);
  1847. #ifdef _MACINTOSH
  1848.     CHXDataFile*     pDataFile = 0; /* cross-platform file object */
  1849.     pDataFile = CHXDataFile::Construct();
  1850.     if (pDataFile->Open((const char*)strFileName,O_RDONLY) == HXR_OK)
  1851.     {
  1852. if (bPlusURL)
  1853. {
  1854.     if (pDataFile->Open((const char*)plusFileName,O_RDONLY) == HXR_OK)
  1855.     {
  1856. bExists = TRUE;
  1857.     }
  1858. }
  1859. else
  1860. {
  1861.     bExists = TRUE;
  1862. }
  1863.     }
  1864.     delete pDataFile;
  1865. #else
  1866.     struct stat statbuf;
  1867.     m_pDataFile->Bind((const char *)strFileName);
  1868.     if (m_pDataFile->Stat(&statbuf) == 0)
  1869.     {
  1870. if (bPlusURL)
  1871. {
  1872.     m_pDataFile->Bind((const char *)plusFileName);
  1873.     if (m_pDataFile->Stat(&statbuf) == 0)
  1874.     {
  1875. DPRINTF(0x5d000000, ("CSFO::DoesExist() -- both r TRUEn"));
  1876. bExists = TRUE;
  1877.     }
  1878. }
  1879. else
  1880. {
  1881.     DPRINTF(0x5d000000, ("CSFO::DoesExist() -- TRUEn"));
  1882.     bExists = TRUE;
  1883. }
  1884.     }
  1885.     else
  1886. DPRINTF(0x5d000000, ("CSFO::DoesExist() -- FALSEn"));
  1887. #endif
  1888.     pFileResponse->DoesExistDone(bExists);
  1889.     return HXR_OK;
  1890. }
  1891. /************************************************************************
  1892.  * Method:
  1893.  *     Private interface::OpenFile
  1894.  * Purpose:
  1895.  *     This common method is used from Init() and GetFileObjectFromPool()
  1896.  */
  1897. STDMETHODIMP CSimpleFileObject::_OpenFile(ULONG32     ulFlags)
  1898. {
  1899.     HX_LOG_BLOCK( "CSimpleFileObject::_OpenFile" );
  1900.     DPRINTF(0x5d000000, ("CSFO::_OpenFile(%lu)n", ulFlags));
  1901.     HX_RESULT lReturnVal = HXR_OK;
  1902.     IHXUserImpersonation* pUserImpersonationThis = NULL;
  1903.     CHXString strFileName;
  1904.     CHXString strURL;
  1905.     m_ulFlags = ulFlags;
  1906.     UpdateFileNameMember();
  1907.     strURL = m_pFilename;
  1908.     // Make a nice local file name from the URL!
  1909.     GetFullPathname(strURL, &strFileName);
  1910.     if (m_pUnknownUserContext)
  1911.     {
  1912. m_pUnknownUserContext->QueryInterface(IID_IHXUserImpersonation,
  1913.     (void**)&pUserImpersonationThis);
  1914.     }
  1915.     if (pUserImpersonationThis)
  1916.     {
  1917. // see ntauth plugin
  1918. pUserImpersonationThis->Start();
  1919.     }
  1920.     UINT16 flags = 0;
  1921. #ifdef _MACINTOSH
  1922.     // use native modes
  1923.     if (ulFlags & HX_FILE_READ)
  1924. flags |= O_RDONLY;
  1925.     if (ulFlags & HX_FILE_WRITE)
  1926. flags |= O_WRONLY;
  1927.     if (ulFlags & HX_FILE_BINARY)
  1928. flags |= O_BINARY;
  1929.     if (!ulFlags)
  1930.     {
  1931. flags = O_RDONLY | O_BINARY;
  1932. m_ulFlags = HX_FILE_READ | HX_FILE_BINARY;
  1933.     }
  1934.     // XXXGH must do HX_FILE_REPLACE for MAC
  1935.     m_pDataFile = (CMacAsyncFile*) CMacAsyncFile::Construct();
  1936.     m_pDataFile->SetAsyncResponse(m_pAsyncFileResponse);
  1937.     BOOL bAtInterrupt = FALSE;
  1938.     if (m_pInterruptState)
  1939.     {
  1940.          bAtInterrupt = m_pInterruptState->AtInterruptTime();
  1941.     }
  1942.     m_nFd = m_pDataFile->SafeOpen((const char*)strFileName,flags, 0, bAtInterrupt);
  1943. #else
  1944.     if (ulFlags & HX_FILE_READ)
  1945. flags |= HX_FILEFLAG_READ;
  1946.     if (ulFlags & HX_FILE_WRITE)
  1947. flags |= HX_FILEFLAG_WRITE;
  1948.     if (ulFlags & HX_FILE_BINARY)
  1949. flags |= HX_FILEFLAG_BINARY;
  1950.     if (!ulFlags)
  1951.     {
  1952. flags = HX_FILEFLAG_READ | HX_FILEFLAG_BINARY;
  1953. m_ulFlags = HX_FILE_READ | HX_FILE_BINARY;
  1954.     }
  1955.     DPRINTF(0x5d000000, ("CSFO::_OpenFile() -- flags(%u)n", flags));
  1956.     HX_ASSERT(m_pDataFile);
  1957.     MLOG_GEN(NULL, "CSimpleFileObject::_OpenFile() this=0x%08x tick=%lu filename=%sn",
  1958.              this, HX_GET_BETTERTICKCOUNT(), (const char*) strFileName);
  1959.     m_pDataFile->Bind((const char *)strFileName);
  1960.     if (HXR_OK == m_pDataFile->Open((UINT16)m_ulFlags))
  1961.     {
  1962. m_nFd = m_pDataFile->GetFd();
  1963. DPRINTF(0x5d000000, ("CSFO::_OpenFile() "
  1964. "-- fd(%d), filename(%s)n", m_nFd,
  1965. ((const char *)strFileName) ? (const char *)strFileName : "NULL"));
  1966.     }
  1967.     else
  1968.     {
  1969. m_nFd = -1;
  1970.     }
  1971. #endif
  1972.     if (pUserImpersonationThis)
  1973.     {
  1974. pUserImpersonationThis->Stop();
  1975.     }
  1976.     /* InitDone may result in close/destruction of this object.Mime mapper
  1977.      * is only interested in the mimetype. This is the sequence of events:
  1978.      * InitDone->FinishSetup->Close MimeMapper.. Release it. load right ff
  1979.      * hand over file system to the file format.
  1980.      * So by the time control returns back here, this object may already be
  1981.      * closed, resulting in m_nFd = -1
  1982.      */
  1983.     if (m_nFd != -1)
  1984.     {
  1985. lReturnVal = HXR_OK;
  1986.     }
  1987.     else if (pUserImpersonationThis)
  1988.     {
  1989. lReturnVal = HXR_NOT_AUTHORIZED;
  1990.     }
  1991.     else
  1992.     {
  1993. DPRINTF(0x5d000000, ("Error: file missingn"));
  1994. lReturnVal = HXR_DOC_MISSING;
  1995.     }
  1996.     HX_RELEASE(pUserImpersonationThis);
  1997.     if (lReturnVal == HXR_OK)
  1998.     {
  1999. if (!m_pDescriptorReg)
  2000. {
  2001.     m_pContext->QueryInterface(IID_IHXDescriptorRegistration,
  2002. (void **)&m_pDescriptorReg);
  2003. }
  2004. if (m_pDescriptorReg)
  2005. {
  2006.     m_pDescriptorReg->RegisterDescriptors(1);
  2007. }
  2008.     }
  2009.     return lReturnVal;
  2010. }
  2011. void
  2012. CSimpleFileObject::UpdateFileNameMember()
  2013. {
  2014.     const char* pURL;
  2015.     if (m_base_path.GetLength() > 0)
  2016.     {
  2017.        /* Running on the Server, do this without wasting CPU! */
  2018.        if (m_pRequest->GetURL(pURL) != HXR_OK)
  2019.        {
  2020.    HX_VECTOR_DELETE(m_pFilename);
  2021.    return;
  2022.        }
  2023.        UINT32 ulIndex = 0;
  2024.        while (pURL[ulIndex] != 0)
  2025.        {
  2026.    // HP - allow '$' in directory/file names
  2027.    //
  2028.    // still need to take care of that obsolete $ sign option:
  2029.    // rtsp://moe.cr.prognet.com/ambush.rm$1:00
  2030.    // time after the $ is assumed to be the start time.
  2031.    //
  2032.    // the solution is to compare the string following the $ to
  2033.    // a properly formed time. If the string is a time and only
  2034.    // a time, then we know its the old-style start-time option
  2035.    // otherwise, '$' is part of the directory/file name and we
  2036.    // will keep it.
  2037.    if (pURL[ulIndex] == '$')
  2038.    {
  2039.        const char* pszOption = &pURL[ulIndex + 1];
  2040.        if (::TimeParse(pszOption))
  2041.        {
  2042.    goto strip_and_duplicate;
  2043.        }
  2044.    }
  2045.    else
  2046.    {
  2047. #if !defined(_MACINTOSH) && !defined(_MAC_UNIX) // ? # and + are legal in Mac file names and shouldn't be stripped (yes, we're seeing a file name, not a URL here)
  2048.        switch (pURL[ulIndex])
  2049.        {
  2050.        case '?':
  2051.        case '#':
  2052.        case '+':
  2053.    goto strip_and_duplicate;
  2054.        default:
  2055.    break;
  2056.        }
  2057. #endif
  2058.    }
  2059.    ulIndex++;
  2060.        }
  2061.        HX_VECTOR_DELETE(m_pFilename);
  2062. #if defined(_MACINTOSH) || defined(_MAC_UNIX)
  2063.        m_pFilename = new_string(pURL); // on Mac, new_path_string mangles legal filenames which have / or  in them
  2064. #else
  2065.        m_pFilename = new_path_string(pURL);
  2066. #endif
  2067.        return;
  2068. strip_and_duplicate:
  2069.        HX_VECTOR_DELETE(m_pFilename);
  2070. #if defined(_MACINTOSH) || defined(_MAC_UNIX)
  2071.        m_pFilename = new_string(pURL); // on Mac, new_path_string mangles legal filenames which have / or  in them
  2072. #else
  2073.        m_pFilename = new_path_string(pURL);
  2074. #endif
  2075.        m_pFilename[ulIndex] = 0;
  2076.        return;
  2077.     }
  2078.     pURL = 0;
  2079.     if (m_pRequest)
  2080.     {
  2081. if (m_pRequest->GetURL(pURL) != HXR_OK)
  2082. {
  2083.     HX_VECTOR_DELETE(m_pFilename);
  2084.     m_pFilename = 0;
  2085. }
  2086. IHXValues* pReqHeader = NULL;
  2087. BOOL bVerbatimFileName = FALSE;
  2088. if (SUCCEEDED(m_pRequest->GetRequestHeaders(pReqHeader)) &&
  2089.     pReqHeader)
  2090. {
  2091.     ULONG32 ulVal = 0;
  2092.     if (SUCCEEDED(pReqHeader->GetPropertyULONG32("VerbatimFileName",
  2093.  ulVal)))
  2094.     {
  2095. bVerbatimFileName = (ulVal ? TRUE : FALSE);
  2096.     }
  2097. }
  2098. HX_RELEASE(pReqHeader);
  2099. CHXString strFilename;
  2100. if (bVerbatimFileName)
  2101. {
  2102.     if (pURL)
  2103.     {
  2104. strFilename = pURL;
  2105.     }
  2106. }
  2107. else
  2108. {
  2109.     CHXURL* pCHXURL = new CHXURL(pURL, m_pCommonClassFactory);
  2110.     if (pCHXURL)
  2111.     {
  2112. IHXValues* pHeader = pCHXURL->GetProperties();
  2113. if(pHeader)
  2114. {
  2115.     IHXBuffer* pUrlBuffer = NULL;
  2116.     if(HXR_OK == pHeader->GetPropertyBuffer(PROPERTY_URL, pUrlBuffer) &&
  2117. pUrlBuffer)
  2118.     {
  2119. strFilename = (const char*)pUrlBuffer->GetBuffer();
  2120. HX_RELEASE(pUrlBuffer);
  2121.     }
  2122.     HX_RELEASE(pHeader);
  2123. }
  2124. delete pCHXURL;
  2125.     }
  2126.     /*
  2127.     * Strip off the parameters
  2128.     */
  2129.     INT32 index = strFilename.Find('?');
  2130.     if (index >= 0)
  2131.     {
  2132. strFilename = strFilename.Left(index);
  2133.     }
  2134.     if (HXXFile::IsPlusURL(pURL))
  2135.     {
  2136. index = strFilename.ReverseFind('+');
  2137. if (index >= 0)
  2138. {
  2139.     strFilename = strFilename.Left(index);
  2140. }
  2141.     }
  2142. }
  2143. HXXFile::GetReasonableLocalFileName(strFilename);
  2144. HX_VECTOR_DELETE(m_pFilename);
  2145. #if defined(_CARBON) || defined(_MAC_UNIX)
  2146. // Under Carbon, GetReasonableLocalFileName returns a proper Mac path, possibly including
  2147. // slashes which shouldn't be mucked with.
  2148. m_pFilename = new_string((const char *) strFilename);
  2149. #else
  2150. m_pFilename = new_path_string((const char*)strFilename);
  2151. #endif
  2152.     }
  2153. }
  2154. STDMETHODIMP CSimpleFileObject::SetRequest
  2155. (
  2156.     IHXRequest* pRequest
  2157. )
  2158. {
  2159.     if (!pRequest)
  2160.     {
  2161. return HXR_INVALID_PARAMETER;
  2162.     }
  2163.     HX_RELEASE(m_pRequest);
  2164.     m_pRequest = pRequest;
  2165.     m_pRequest->AddRef();
  2166.     UpdateFileNameMember();
  2167.     return HXR_OK;
  2168. }
  2169. STDMETHODIMP CSimpleFileObject::GetRequest
  2170. (
  2171.     REF(IHXRequest*) pRequest
  2172. )
  2173. {
  2174.     pRequest = m_pRequest;
  2175.     if (pRequest)
  2176.     {
  2177. pRequest->AddRef();
  2178.     }
  2179.     return HXR_OK;
  2180. }
  2181. static BOOL DoRename(const char* pOldName,
  2182.      const char* pNewName,
  2183.      IUnknown** ppCommonObj)
  2184. {
  2185.     BOOL ret = FALSE;
  2186. #if defined(_MACINTOSH) || defined(_SYMBIAN)
  2187.     XHXDirectory* pHXDir =  XHXDirectory::Construct(ppCommonObj);
  2188.     if (pHXDir)
  2189.     {
  2190. if (SUCCEEDED(pHXDir->Rename(pOldName, pNewName)))
  2191. {
  2192.     ret = TRUE;
  2193. }
  2194. delete pHXDir;
  2195.     }
  2196. #elif defined(WIN32_PLATFORM_PSPC)
  2197.     if (MoveFile(OS_STRING(pOldName), OS_STRING(pNewName)) != 0)
  2198.     {
  2199. ret = TRUE;
  2200.     }
  2201. #else
  2202.     if (rename(pOldName, pNewName) == 0)
  2203.     {
  2204. ret = TRUE;
  2205.     }
  2206. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  2207.     return ret;
  2208. }
  2209. STDMETHODIMP CSimpleFileObject::Rename
  2210. (
  2211.     const char* pFilename
  2212. )
  2213. {
  2214.     CHXString strFilename;
  2215.     CHXString newFilename;
  2216.     UpdateFileNameMember();
  2217.     strFilename = m_pFilename;
  2218.     INT32 index = strFilename.ReverseFind(OS_SEPARATOR_CHAR);
  2219.     if (index != -1)
  2220.     {
  2221. newFilename = strFilename.Left(index+1);
  2222. newFilename += pFilename;
  2223.     }
  2224.     else
  2225.     {
  2226. newFilename = pFilename;
  2227.     }
  2228.     GetFullPathname((const char*)newFilename, &newFilename);
  2229.     GetFullPathname((const char*)strFilename, &strFilename);
  2230.     if (DoRename(strFilename, newFilename, &m_pFileSystem->m_pCommonObj) == FALSE)
  2231.     {
  2232. return HXR_FAIL;
  2233.     }
  2234.     return HXR_OK;
  2235. }
  2236. STDMETHODIMP CSimpleFileObject::Move
  2237. (
  2238.     const char* pFilename
  2239. )
  2240. {
  2241.     CHXString strFilename;
  2242.     CHXString newFilename;
  2243.     HX_RESULT retVal = HXR_OK;
  2244.     UpdateFileNameMember();
  2245.     newFilename = pFilename;
  2246.     HXXFile::GetReasonableLocalFileName(newFilename);
  2247.     GetFullPathname((const char*) newFilename, &newFilename);
  2248.     GetFullPathname(m_pFilename, &strFilename);
  2249.     if (DoRename(strFilename, newFilename, &m_pFileSystem->m_pCommonObj) == FALSE)
  2250.     {
  2251. #ifdef _UNIX
  2252. // We'll attempt to move the file manually since on UNIX
  2253. // rename accross devices (file systems) is not supported
  2254. FILE* pSource = fopen((const char*) strFilename, "rb");
  2255. FILE* pTarget = fopen((const char*) newFilename, "rb");
  2256. retVal = HXR_FAIL;
  2257. if (pTarget)
  2258. {
  2259.     // Target file already exists -> fail.
  2260.     fclose(pTarget);
  2261.     pTarget = NULL;
  2262. }
  2263. else
  2264. {
  2265.     pTarget = fopen((const char*) newFilename, "wb");
  2266. }
  2267. if (pSource && pTarget)
  2268. {
  2269.     retVal = HXR_OK;
  2270. }
  2271. if (retVal == HXR_OK)
  2272. {
  2273.     const ULONG32 COPY_BUF_SIZE = 1024;
  2274.     UINT8 pBuffer[COPY_BUF_SIZE];
  2275.     size_t bufLen;
  2276.     do
  2277.     {
  2278. bufLen = fread(pBuffer, 1, COPY_BUF_SIZE, pSource);
  2279. if (bufLen > 0)
  2280. {
  2281.     if (fwrite(pBuffer, 1, bufLen, pTarget) != bufLen)
  2282.     {
  2283. retVal = HXR_FAIL;
  2284. break;
  2285.     }
  2286. }
  2287.     } while (bufLen == COPY_BUF_SIZE);
  2288. }
  2289. // Make sure no erorrs occured
  2290. if (retVal == HXR_OK)
  2291. {
  2292.     retVal = HXR_FAIL;
  2293.     if (feof(pSource) &&
  2294. (ferror(pSource) == 0) &&
  2295. (ferror(pTarget) == 0))
  2296.     {
  2297. retVal = HXR_OK;
  2298.     }
  2299. }
  2300. if (pSource)
  2301. {
  2302.     fclose(pSource);
  2303.     pSource = NULL;
  2304. }
  2305. // Remove the source file - only if copied OK
  2306. if (retVal == HXR_OK)
  2307. {
  2308.     if (remove((const char*) strFilename) != 0)
  2309.     {
  2310. retVal = HXR_FAIL;
  2311.     }
  2312. }
  2313. if (pTarget)
  2314. {
  2315.     fclose(pTarget);
  2316.     pTarget = NULL;
  2317.     // In case of failure, remove the target
  2318.     if (retVal != HXR_OK)
  2319.     {
  2320. remove((const char*) newFilename);
  2321.     }
  2322. }
  2323. #else // _UNIX
  2324. retVal = HXR_FAIL;
  2325. #endif // _UNIX
  2326.     }
  2327.     return retVal;
  2328. }
  2329. STDMETHODIMP
  2330. CSimpleFileObject::Remove()
  2331. {
  2332. #ifdef _MACINTOSH
  2333.     CHXString strFilename;
  2334.     UpdateFileNameMember();
  2335.     strFilename = m_pFilename;
  2336.     GetFullPathname((const char*)strFilename, &strFilename);
  2337.     if (unlink((const char*)strFilename) != 0)
  2338.     {
  2339. return HXR_FAIL;
  2340.     }
  2341.     return HXR_OK;
  2342. #else
  2343.     UpdateFileNameMember();
  2344.     CHXString strFileName;
  2345.     CHXString strUrl = m_pFilename;
  2346.     // Make a nice local file name from the URL!
  2347.     HXXFile::GetReasonableLocalFileName(strUrl);
  2348.     GetFullPathname(strUrl, &strFileName);
  2349.     m_pDataFile->Bind((const char*)strFileName);
  2350.     HX_RESULT res = m_pDataFile->Delete();
  2351.     if (res == HXR_OK)
  2352.     {
  2353. m_nFd = -1;
  2354.     }
  2355.     return res;
  2356. #endif
  2357. }
  2358. void
  2359. CSimpleFileObject::GetFullPathname(const char* pPath, CHXString* pPathname)
  2360. {
  2361.     if (m_base_path.GetLength() > 0)
  2362.     {
  2363. INT32 lLevel = 0;
  2364. for (const char* pTemp = pPath; *pTemp; pTemp++)
  2365. {
  2366.     /*
  2367.      * Increment directory level if we have a slash, and it's
  2368.      * not a leading slash, and it's not right after a slash
  2369.      * (doesn't count on most OSes).
  2370.      */
  2371.     if (((*pTemp == OS_SEPARATOR_CHAR) ||
  2372.          (*pTemp == '/')) && (pTemp != pPath) &&
  2373.       ((*(pTemp-1)) != OS_SEPARATOR_CHAR) &&
  2374.       ((*(pTemp-1)) != '/'))
  2375.     {
  2376. lLevel++;
  2377.     }
  2378.     if ((pTemp != pPath) &&
  2379.      (*pTemp == '.') &&
  2380.      (*(pTemp - 1) == '.'))
  2381.     {
  2382. lLevel--;
  2383. if (((*(pTemp + 1)) == OS_SEPARATOR_CHAR) ||
  2384.     ((*(pTemp + 1)) == '/'))
  2385. {
  2386.     pTemp++;
  2387. }
  2388. if (lLevel < 0)
  2389. {
  2390.     *pPathname = "!$InvalidPath";
  2391.     return;
  2392. }
  2393.     }
  2394. }
  2395. if (*pPath)
  2396. {
  2397. #if defined(_MACINTOSH) && !defined(_CARBON)
  2398.     CHXString strPath;
  2399.     CHXURL::decodeURL(pPath, strPath);
  2400.             pPath = (const char*)strPath;
  2401.             UINT32 ulPathLen = strPath.GetLength();
  2402. #else
  2403.             UINT32 ulPathLen = strlen(pPath);
  2404. #endif
  2405.             UINT32 ulBaseLen = m_base_path.GetLength();
  2406.             char* pStr = new char[ulBaseLen + ulPathLen + 2];
  2407.             char* pTmp = pStr;
  2408.             if (ulBaseLen)
  2409.             {
  2410.                 memcpy(pTmp, (const char*)m_base_path, ulBaseLen); /* Flawfinder: ignore */
  2411.                 pTmp += ulBaseLen;
  2412.             }
  2413.             *pTmp = OS_SEPARATOR_CHAR;
  2414.             pTmp++;
  2415.             memcpy(pTmp, pPath, ulPathLen + 1); /* Flawfinder: ignore */
  2416.             CHXString strResult(pStr, ulBaseLen + ulPathLen + 2);
  2417.             *pPathname = strResult;
  2418.             delete[] pStr;
  2419. }
  2420. else
  2421. {
  2422.     *pPathname = m_base_path;
  2423. }
  2424.     }
  2425.     else
  2426.     {
  2427. #if defined (_MACINTOSH) && !defined(_CARBON)
  2428.         CHXString strPath;
  2429.         CHXURL::decodeURL(pPath, strPath);
  2430. #else
  2431.         CHXString strPath(pPath, strlen(pPath));
  2432. #endif
  2433.         *pPathname = strPath;
  2434.     }
  2435. }
  2436. HX_RESULT
  2437. CSimpleFileObject::ActualAsyncReadDone(HX_RESULT result, IHXBuffer* pBuffer)
  2438. {
  2439.     MLOG_PD(NULL, "CSimpleFileObject::ActualAsyncReadDone(0x%08x,0x%08x) tick=%lun",
  2440.             result, pBuffer, HX_GET_BETTERTICKCOUNT());
  2441.     HX_LOG_BLOCK( "CSimpleFileObject::ActualAsyncReadDone" );
  2442.     m_bReadPending = FALSE;
  2443.     m_bAsyncReadPending = FALSE;
  2444.     // Let the file response sink know about the buffer...
  2445.     HX_RESULT rv = m_pFileResponse->ReadDone(result, pBuffer);
  2446.     MLOG_PD(NULL, "treturning 0x%08x from ActualAsyncReadDone() tick=%lun",
  2447.             rv, HX_GET_BETTERTICKCOUNT());
  2448.     return rv;
  2449. }
  2450. HX_RESULT
  2451. CSimpleFileObject::ActualAsyncSeekDone(HX_RESULT result)
  2452. {
  2453. #ifndef _MACINTOSH
  2454.     MLOG_PD(NULL, "CSimpleFileObject::ActualAsyncSeekDone(0x%08x) tick=%lun",
  2455.             result, HX_GET_BETTERTICKCOUNT());
  2456.     HX_RESULT rv = m_pFileResponse->SeekDone(result);
  2457.     MLOG_PD(NULL, "treturning 0x%08x from ActualAsyncSeekDone() tick=%lun",
  2458.             rv, HX_GET_BETTERTICKCOUNT());
  2459.     return rv;
  2460. #else
  2461.     switch (m_eSeekReason)
  2462.     {
  2463. case REINIT_SEEK:
  2464.     return m_pFileResponse->InitDone(!result ? HXR_OK : HXR_FAIL);
  2465. case EXTERNAL_SEEK:
  2466.     return m_pFileResponse->SeekDone(result);
  2467. case PRE_TELL_SEEK:
  2468.     {
  2469. m_ulSize = m_pDataFile->Tell();
  2470. BOOL bAtInterrupt = FALSE;
  2471. if (m_pInterruptState)
  2472. {
  2473.     bAtInterrupt = m_pInterruptState->AtInterruptTime();
  2474. }
  2475. m_eSeekReason = POST_TELL_SEEK;
  2476. /* If we need to close the file, why waste time in seeking back
  2477.  * to the original position
  2478.  */
  2479. if (!m_bFileToBeClosed)
  2480. {
  2481.     m_pDataFile->SafeSeek(m_ulPreSeekPosition,SEEK_SET);
  2482. }
  2483. else
  2484. {
  2485.     ActualAsyncSeekDone(result);
  2486. }
  2487.     }
  2488.     break;
  2489. case POST_TELL_SEEK:
  2490.     {
  2491. if (m_bFileToBeClosed && m_pDataFile)
  2492. {
  2493.     m_bFileToBeClosed = FALSE;
  2494.     HX_RELEASE(m_pDataFile);
  2495.     m_pDataFile = NULL;
  2496.     m_nFd = -1;
  2497. }
  2498. struct stat StatBuffer;
  2499. StatBuffer.st_size = m_ulSize;
  2500. StatBuffer.st_ctime = 0;
  2501. StatBuffer.st_atime = 0;
  2502. StatBuffer.st_mtime = 0;
  2503. StatBuffer.st_mode = 0;
  2504. if (m_pFileStatResponse)
  2505. {
  2506.     // Access to members after async ..Done() call is invalid
  2507.     IHXFileStatResponse *pTmpFileStatResponse = m_pFileStatResponse;
  2508.     m_pFileStatResponse = NULL;
  2509.     pTmpFileStatResponse->StatDone( HXR_OK,
  2510.     StatBuffer.st_size,
  2511.     StatBuffer.st_ctime,
  2512.     StatBuffer.st_atime,
  2513.     StatBuffer.st_mtime,
  2514.     StatBuffer.st_mode);
  2515.     pTmpFileStatResponse->Release();
  2516. }
  2517.     }
  2518.     break;
  2519. default:
  2520.     HX_ASSERT(FALSE);
  2521.     return HXR_FAIL;
  2522.     }
  2523.     return HXR_OK;
  2524. #endif
  2525. }
  2526. STDMETHODIMP_(UINT32)
  2527. CSimpleFileObject::IsThreadSafe()
  2528. {
  2529.     return HX_THREADSAFE_METHOD_FS_READ;
  2530. }
  2531. #ifdef _MACINTOSH
  2532. // SMPLAsyncResponse
  2533. CSimpleFileObject::SMPLAsyncResponse::SMPLAsyncResponse(CSimpleFileObject* pFileObject)
  2534. {
  2535.     m_pSMPLFileObject = pFileObject;
  2536. }
  2537. CSimpleFileObject::SMPLAsyncResponse::~SMPLAsyncResponse()
  2538. {
  2539. }
  2540. HX_RESULT
  2541. CSimpleFileObject::SMPLAsyncResponse::AsyncReadDone (HX_RESULT result, IHXBuffer* pBuffer)
  2542. {
  2543.     m_pSMPLFileObject->ActualAsyncReadDone(result, pBuffer);
  2544.     return HXR_OK;
  2545. }
  2546. HX_RESULT
  2547. CSimpleFileObject::SMPLAsyncResponse::AsyncSeekDone (HX_RESULT result)
  2548. {
  2549.     m_pSMPLFileObject->ActualAsyncSeekDone(result);
  2550.     return HXR_OK;
  2551. }
  2552. #endif /*_MACINTOSH*/
  2553. #if defined(HELIX_FEATURE_PROGDOWN)
  2554. STDMETHODIMP CSimpleFileObject::ProgressiveCallback()
  2555. {
  2556.     if (m_ulCallbackState == CallbackStateSeek)
  2557.     {
  2558.         MLOG_PD(NULL, "CSimpleFileObject::ProgressiveCallback() this=0x%08x tick=%lu state=%sn",
  2559.                 this, HX_GET_BETTERTICKCOUNT(), "CallbackStateSeek");
  2560.         // Make sure we do not destruct during SeekDone()
  2561.         AddRef();
  2562.         // Do the seek
  2563.         HX_RESULT seekDoneResult = HXR_OK;
  2564.         DoSeek(seekDoneResult);
  2565.         // Undo the AddRef();
  2566.         Release();
  2567.     }
  2568.     else if (m_ulCallbackState == CallbackStateRead)
  2569.     {
  2570.         MLOG_PD(NULL, "CSimpleFileObject::ProgressiveCallback() this=0x%08x tick=%lu state=%sn",
  2571.                 this, HX_GET_BETTERTICKCOUNT(), "CallbackStateRead");
  2572.         // Make sure we do not destruct in ReadDone()
  2573.         AddRef();
  2574.         // Call DoRead()
  2575.         BOOL bProgFail = FALSE;
  2576.         DoRead(bProgFail);
  2577.         // Undo the AddRef()
  2578.         Release();
  2579.     }
  2580.     return HXR_OK;
  2581. }
  2582. BOOL CSimpleFileObject::RequireFullRead()
  2583. {
  2584.     BOOL bRet = FALSE;
  2585.     if (m_pFileResponse)
  2586.     {
  2587.         // QueryInterface for the IHXAdvise interface
  2588.         IHXAdvise* pAdvise = NULL;
  2589.         m_pFileResponse->QueryInterface(IID_IHXAdvise, (void**) &pAdvise);
  2590.         if (pAdvise)
  2591.         {
  2592.             if (SUCCEEDED(pAdvise->Advise(HX_FILERESPONSEADVISE_REQUIREFULLREAD)))
  2593.             {
  2594.                 bRet = TRUE;
  2595.             }
  2596.         }
  2597.         HX_RELEASE(pAdvise);
  2598.     }
  2599.     return bRet;
  2600. }
  2601. HX_RESULT CSimpleFileObject::FinishDoReadWithCallback(UINT32 actual)
  2602. {
  2603.     // Seek backwards if necessary
  2604.     SeekBackwards(actual);
  2605.     // Set the callback state
  2606.     m_ulCallbackState = CallbackStateRead;
  2607.     // Schedule a callback to try the read again
  2608.     m_pProgDownMon->ScheduleCallback();
  2609.     return HXR_OK;
  2610. }
  2611. HX_RESULT CSimpleFileObject::FinishDoReadWithoutCallback(UINT32 actual)
  2612. {
  2613.     // Seek backwards if necessary
  2614.     SeekBackwards(actual);
  2615.     // Since we can't employ callback when m_bAsyncAccess is FALSE,
  2616.     // then we must sleep. We'll sleep for 100ms (or 100000 microsec)
  2617.     microsleep(100000);
  2618.     return HXR_OK;
  2619. }
  2620. #endif /* #if defined(HELIX_FEATURE_PROGDOWN) */
  2621. void CSimpleFileObject::StackCallback(void* pArg)
  2622. {
  2623.     MLOG_PD(NULL, "CSimpleFileObject::StackCallback() tick=%lun", HX_GET_BETTERTICKCOUNT());
  2624.     if (pArg)
  2625.     {
  2626.         CSimpleFileObject* pFileObject = (CSimpleFileObject*) pArg;
  2627.         pFileObject->AddRef();
  2628.         BOOL bProgFail = FALSE;
  2629.         pFileObject->DoRead(bProgFail);
  2630.         pFileObject->Release();
  2631.     }
  2632. }