chxavfilestore.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:38k
源码类别:

Symbian

开发平台:

C/C++

  1. /************************************************************************
  2.  * chxavfilestore.cpp
  3.  * ------------------
  4.  *
  5.  * Synopsis:
  6.  * simple file system abstraction for manipulating files and folders;
  7.  * maintains 'root' (relative to true filesystem) 'current' folder
  8.  * state
  9.  *
  10.  * root path is stored in full form, e.g.: c:realmedia
  11.  * folder is stored in relative form, fully specified, e.g.:
  12.  *     = root
  13.  * music     = subfolder music
  14.  *
  15.  * the term 'item' (as used in this class) refers to a file or folder
  16.  * that is in the current entry list; the entry list contains a list
  17.  * of files and folders within the current folder
  18.  *
  19.  * Target:
  20.  * Symbian OS
  21.  *
  22.  *
  23.  * (c) 1995-2003 RealNetworks, Inc. Patents pending. All rights reserved.
  24.  *
  25.  ************************************************************************/
  26. // Symbian includes...
  27. #include <coeutils.h>
  28. #include <eikfutil.h>
  29. #include <f32file.h> // TSwitch, CFileMan
  30. // Helix includes...
  31. // Include from this project...
  32. #include "chxavfilestore.h"
  33. #include "chxavdirectoryreader.h"
  34. #include "chxavfileutil.h"
  35. #include "chxavutil.h"
  36. #include "chxavmisc.h"
  37. #include "chxavstringutils.h"
  38. #include "hxsym_leaveutil.h"
  39. #include "hxsym_debug.h"
  40. CHXAvFileStore::CHXAvFileStore()
  41. : m_pFullPath(0)
  42. , m_bNeedRefresh(true)
  43. , m_pFileMan(0)
  44. , m_pObserver(0)
  45. , m_cbFileOp(0)
  46. , m_suspendRefreshSem(0)
  47. , m_bHaveOutstandingFileSystemEvent(false)
  48. {
  49. }
  50. CHXAvFileStore::~CHXAvFileStore()
  51. {
  52.     HX_DELETE(m_pFullPath);
  53.     HX_DELETE(m_pFileMan);
  54. #if defined(ASYNC_COPYMOVE)
  55.     CancelAsyncFileOp();
  56. #endif
  57.     m_apaLsSess.Close();
  58. }
  59. ////////////////////////////////////////////////////////////
  60. //
  61. void CHXAvFileStore::ConstructL(const TDesC& root,
  62.                              const TDesC& path,
  63.                              bool bAutoCreateRoot)
  64. {
  65.     m_apaLsSess.Connect();
  66.     m_fsWatcher.ConstructL();
  67.      // set callback for receiving fs event notifications
  68.     m_fsWatcher.SetEventActionL
  69. (
  70. MakeCommand(this, &CHXAvFileStore::OnFileSystemEvent)
  71. );
  72. #if defined(ASYNC_COPYMOVE)
  73.     // active object to run on asynch completion of file op
  74.     m_pFileOpCompletion =
  75. new (ELeave) CHXAvActiveDisp<CHXAvFileStore>(this,
  76.     &CHXAvFileStore::OnFileOpAsyncComplete,
  77.     &CHXAvFileStore::OnFileOpAsyncCancel);
  78.     CActiveScheduler::Add(m_pFileOpCompletion.raw_ptr());
  79. #endif
  80.     // create, fill out and activate the listbox
  81.     SetRootL(root, bAutoCreateRoot);
  82.     SetCurrentPathL(path);
  83.     RefreshEntryInfoL();
  84.     RFs& fs = CCoeEnv::Static()->FsSession();
  85.     m_pFileMan = CFileMan::NewL(fs, this /*observer*/);
  86. }
  87. ////////////////////////////////////////////////////////////
  88. // paths can be provided as relative to root (e.g., /media/myfolder/foo.rm)
  89. // or absolute ('e:/videos/)
  90. //
  91. // this decides which and returns a fully specified path with drive
  92. //
  93. //
  94. TFileName* CHXAvFileStore::AllocFullPathL(const TDesC& path,
  95.                                        const TDesC& name,
  96.                                        CHXAvFile::NameType type)
  97. {
  98.     TFileName* pPath = 0;
  99.     TInt idxDrive = CHXAvFile::GetDriveIndex(path);
  100.     if(-1 != idxDrive)
  101.     {
  102.         // path has a drive; it is absolute
  103.         pPath = CHXAvFile::AllocFileNameL(path, name, type);
  104.     }
  105.     else
  106.     {
  107.         // path is relative
  108.         pPath = CHXAvFile::AllocFileNameL(GetRoot(), path, CHXAvFile::ntFolder);
  109.         CHXAvFile::AppendPath(*pPath, name, type);
  110.     }
  111.     return pPath;
  112. }
  113. //////////////////////////////////////////////////////////////
  114. // return true if fullPathChild is path to file or folder immediately
  115. // under current path
  116. bool CHXAvFileStore::IsImmediateChild(const TDesC& fullPathChild)
  117. {
  118.     TPtrC ptrFolder = CHXAvFile::GetParentFolder(fullPathChild);
  119.     return (0 == ptrFolder.CompareF(*m_pFullPath));
  120. }
  121. //////////////////////////////////////////////////////////////
  122. // return true if fullPathParent is a parent of the current
  123. //
  124. bool CHXAvFileStore::IsParent(const TDesC& fullPathParent)
  125. {
  126.     return  CHXAvFile::IsSubPath(fullPathParent, *m_pFullPath);
  127. }
  128. ////////////////////////////////////////////////////////////
  129. // return true if the destination path matches the
  130. // path for the given item within the current path
  131. //
  132. // pathDest         - relative or absolute path
  133. // idxItem          - item in current path
  134. //
  135. bool CHXAvFileStore::IsSamePathL(const TDesC& pathDest, TInt idxItem)
  136. {
  137.     bool bIsSame = false;
  138.     // form "pathdest" + "name associated with item in current path"
  139.     TFileName* pSrcPath = AllocFullPathL(idxItem);
  140.     AUTO_PUSH_POP_DEL(pSrcPath);
  141.     TFileName* pDestPath = AllocFullTargetPathL(pathDest, idxItem);
  142.     AUTO_PUSH_POP_DEL(pDestPath);
  143.     bIsSame = ( pSrcPath->CompareF(*pDestPath) == 0 );
  144.     return bIsSame;
  145. }
  146. ////////////////////////////////////////////////////////////
  147. // called when fs watcher detects an event
  148. void CHXAvFileStore::OnFileSystemEvent()
  149. {
  150.     DPRINTF(SYMP_FILE, ("FileStore::OnFileSystemEvent(): suspend count = %ldn", m_suspendRefreshSem));
  151.     // flag that entry list is out of data
  152.     m_bNeedRefresh = true;
  153.     if(m_suspendRefreshSem > 0)
  154.     {
  155.        // keep track of fact that we got file system event while locked; we'll defer
  156.        // notifying observer until we become unlocked
  157.        m_bHaveOutstandingFileSystemEvent = true;
  158.     }
  159.     else
  160.     {
  161.         m_bHaveOutstandingFileSystemEvent = false;
  162.         m_eventHandler.Execute();
  163.     }
  164.    
  165. }
  166. ////////////////////////////////////////////////////////////
  167. // path must be fully qualified absolute root path, e.g., something like:
  168. //
  169. // 'e:realnetworksmedia'
  170. // 'c:media'
  171. //
  172. // * trailing slash required
  173. // * drive letter required
  174. //
  175. // can be called more than once
  176. //
  177. void CHXAvFileStore::SetRootL(const TDesC& path, bool bAutoCreateRoot)
  178. {
  179.     RFs& fs = CCoeEnv::Static()->FsSession();
  180.     TInt idxDrive = CHXAvFile::GetDriveIndex(path);
  181.     if(idxDrive == -1 || !CHXAvFile::HasFolderSuffix(path))
  182.     {
  183.         // caller should ensure path suffix and valid drive
  184.         HXSYM_LEAVE(KErrBadName);
  185.     }
  186.     TInt errExist = KErrPathNotFound;
  187.     if( bAutoCreateRoot )
  188.     {
  189.         TRAP(errExist, BaflUtils::EnsurePathExistsL(fs, path));
  190.     }
  191.     else if(BaflUtils::PathExists(fs, path))
  192.     {
  193.         errExist = KErrNone;
  194.     }
  195.     // make sure root is valid by now
  196.     HXSYM_LEAVE_IF_ERR(errExist);  // drive doesn't exist?
  197.     TFileName* pFullPath = new (ELeave) TFileName;
  198.     AUTO_PUSH_POP_DEL(pFullPath);
  199.     HXSYM_LEAVE_IF_ERR(CHXAvFile::GetFullPath(fs, path, *pFullPath));
  200.     m_root.Set(*pFullPath, 0, 0);
  201.     UpdateFullPathL();
  202.     HX_ASSERT(CHXAvFile::HasFolderSuffix(m_root.FullName()));
  203.     // watch for fs events; this resets watch path if we were watching previously
  204.     if( m_root.FullName().Length() > 3 )
  205.     {
  206. m_fsWatcher.SetWatchPathL(m_root.FullName());
  207.     }
  208.     else
  209.     {
  210.         //
  211.         // specifying a root drive path like 'c:' fails for some reason so watch
  212.         // everything in this case
  213.         //
  214.         m_fsWatcher.SetWatchPathL(KNullDesC);
  215.     }
  216.     m_fsWatcher.SetNotifyType(TNotifyType(ENotifyDir | ENotifyFile | ENotifyEntry));
  217.     m_fsWatcher.StartWatching();
  218.     m_bNeedRefresh = true;
  219. }
  220. ////////////////////////////////////////////
  221. // path             -  relative to current root path;
  222. //                     leading and trailing path delimiter is optional
  223. //
  224. //
  225. void CHXAvFileStore::SetCurrentPathL(const TDesC& path)
  226. {
  227.     // we want to make sure it looks like '/folder/'
  228.     m_curPath.SetLength(0);
  229.     CHXAvFile::AppendPath(m_curPath, path, CHXAvFile::ntFolder);
  230.     DPRINTF(SYMP_FILE, ("FileStore::SetCurrentPathL(): current path '%s'n", dbg::CharPtr(path)()));
  231.     TInt err = EikFileUtils::CheckFolder(UpdateFullPathL());
  232.     HXSYM_LEAVE_IF_ERR(err); // leave if path not found
  233.     
  234.     m_bNeedRefresh = true;
  235.     HX_ASSERT(CHXAvFile::HasFolderPrefix(m_curPath));
  236.     HX_ASSERT(CHXAvFile::HasFolderSuffix(m_curPath));
  237. }
  238. ////////////////////////////////////////////////////////////
  239. // make sure full path refers to current folder
  240. const TDesC& CHXAvFileStore::UpdateFullPathL()
  241. {
  242.     // alloc fully qualified folder base path
  243.     if(!m_pFullPath)
  244.     {
  245. m_pFullPath = CHXAvFile::AllocFileNameL(m_root.FullName(), m_curPath, CHXAvFile::ntFolder);
  246.     }
  247.     else
  248.     {
  249. m_pFullPath->Copy(m_root.FullName());
  250. CHXAvFile::AppendPath(*m_pFullPath, m_curPath, CHXAvFile::ntFolder);
  251.     }
  252.     return *m_pFullPath;
  253. }
  254. ////////////////////////////////////////////
  255. // count files (not folders) in the in the
  256. // current entries list
  257. TInt CHXAvFileStore::GetCurrentFolderFileCount() const
  258. {
  259.     TInt itemCount = m_entryInfo.Nelements();
  260.     TInt fileCount = 0;
  261.     for(TInt idx = 0; idx < itemCount; ++idx)
  262.     {
  263. if(!m_entryInfo[idx].m_entry.IsDir())
  264. {
  265.     ++fileCount;
  266. }
  267.     }
  268.     return fileCount;
  269. }
  270. ////////////////////////////////////////////////////
  271. // add relevant file entries to list info
  272. //
  273. void CHXAvFileStore::RefreshEntryInfoHelper(const CDir* pFiles, bool bIncludeFolders)
  274. {
  275.     HX_ASSERT(pFiles != 0);
  276.     TInt count = pFiles->Count();
  277.     for( TInt idx = 0; idx < count; ++idx )
  278.     {
  279. const TEntry& entry = (*pFiles)[idx];
  280. // don't add special (system, hidden) files
  281. if(!CHXAvUtil::ShouldHideFromUser(entry)) //XXXLCM 'filter policy'
  282. {
  283.     // note: entry.iName is stripped, e.g., 'folder'
  284.     if(entry.IsDir() && bIncludeFolders)
  285.     {
  286.         // add directory
  287.         CHXAvUtil::Append(m_entryInfo, CHXAvFile::FileInfo(entry, CHXAvFile::ftFolder));
  288.     }
  289.     else
  290.     {
  291.         // only add filetypes that we can play(e.g., 'file.rm')
  292.         TFileName* pPath = CHXAvFile::AllocFileNameL(GetFullPath(),
  293.           entry.iName);
  294.         AUTO_PUSH_POP_DEL(pPath);
  295.         CHXAvFile::FileType type = CHXAvFile::GetFileType(*pPath);
  296.         if (CHXAvFile::IsNanoPlayerFileType(type)) //XXXLCM 'filter policy'
  297.                 {
  298.     CHXAvUtil::Append(m_entryInfo, CHXAvFile::FileInfo(entry, type));
  299.                 }
  300.     }
  301.         }
  302.     }
  303. }
  304. // for RefreshSuspenderL
  305. void CHXAvFileStore::CleanupSuspendRefresh(TAny* p)
  306. {
  307.     CHXAvFileStore* pFs = reinterpret_cast<CHXAvFileStore*>(p);
  308.     pFs->SuspendRefresh(false);
  309. }
  310. ////////////////////////////////////////////////////////////
  311. //
  312. // Call with 'true' to temporarily prevent file and dir list updates as
  313. // well as filesystem event notifications being forwarded. This
  314. // 'locks' the file and dir entry lists so that any indexes associated with
  315. // current lists that are held by client remain valid.
  316. //
  317. // Useful in cases where you are holding on to an index while, say,
  318. // waiting for user input before acting on the index.
  319. //
  320. // An alternative is to use CopyEntriesL()
  321. //
  322. void CHXAvFileStore::SuspendRefresh(bool bSuspend)
  323. {
  324.     if( bSuspend )
  325.     {
  326.         ++m_suspendRefreshSem;
  327.     }
  328.     else
  329.     {
  330.         --m_suspendRefreshSem;
  331.     }
  332.     DPRINTF(SYMP_FILE, ("FileStore::SuspendRefresh('%s'): suspend count = %dn", dbg::Bool(bSuspend), m_suspendRefreshSem));
  333.     HX_ASSERT(m_suspendRefreshSem >= 0); // calls must be balanced
  334.     
  335.     if(0 == m_suspendRefreshSem)
  336.     {
  337.         DPRINTF(SYMP_FILE, ("FileStore::SuspendRefresh(): exiting suspendn"));
  338.         // we are no longer suspended; now we can forward deferred filesystem
  339.         // event notifications to observes
  340.         if( m_bHaveOutstandingFileSystemEvent )
  341.         {
  342.             DPRINTF(SYMP_FILE, ("FileStore::SuspendRefresh(): sending deferred file system event notificationn"));
  343.             OnFileSystemEvent();
  344.         }  
  345.     }
  346. }
  347. ////////////////////////////////////////////////////////////
  348. // fill out entry info based on current path
  349. //
  350. void CHXAvFileStore::RefreshEntryInfoL()
  351. {
  352.     if( 0 == m_suspendRefreshSem )
  353.     {
  354.         TInt err = KErrNone;
  355.         CHXAvDirectoryReader reader;
  356.         if(reader.SetToPath(GetFullPath()))
  357.         {
  358.     m_bNeedRefresh = false;
  359.     m_entryInfo.Resize(0);
  360.     const bool bIncludeChildFolders = true;
  361.     RefreshEntryInfoHelper(reader.GetFiles(), bIncludeChildFolders);
  362.     RefreshEntryInfoHelper(reader.GetDirs(), bIncludeChildFolders);
  363.         }
  364.         else
  365.         {
  366.     // path invalid? external delete?
  367.     err = reader.GetLastError();
  368.         }
  369.         HXSYM_LEAVE_IF_ERR(err);
  370.     }
  371. }
  372. ////////////////////////////////////////////////////////////
  373. // path                    -  relative to root or absolute
  374. // name                    -  relative to given path
  375. //
  376. // caller must close file object
  377. //
  378. FILE* CHXAvFileStore::OpenFileL(const TDesC& path,
  379.      const TDesC& fileName,
  380.      const char* pMode)
  381. {
  382.     HX_ASSERT(pMode);
  383.     TFileName* pPath = AllocFullPathL(path, fileName);
  384.     AUTO_PUSH_POP_DEL(pPath);
  385.     CHXAvFile::EnsureClearReadOnlyAttributeL(*pPath);
  386.     FILE* pFile = ::fopen( CHXAvStringUtils::DescToString(*pPath), pMode);
  387.     return pFile;
  388. }
  389. ////////////////////////////////////////////////////////////
  390. // returns KErrDiskFull if there is not enough disk space to
  391. // make the copy
  392. //
  393. // Epoc copy-file APIs normally require that EFileShareReadersOnly flag was used
  394. // to open the source file; fopen(..., "r") apparently does not result in
  395. // EFileShareReadersOnly being set (probably only EFileRead);
  396. // here's a work-around
  397. //
  398. // call this after copyfile fails with KErrInUse
  399. //
  400. // args:
  401. //
  402. //   pathDest             - path relative to root or absoluted
  403. //   fileNameDest         - name relative to pathDest
  404. //
  405. TInt CHXAvFileStore::CopyFileAlternateL(const TDesC& pathDest,
  406.     const TDesC& fileNameDest,
  407.     const TDesC& fullPathSource,
  408.                     bool bAllowOverwrite)
  409. {
  410.     TFileName* pFullPathDest = AllocFullPathL(pathDest, fileNameDest);
  411.     AUTO_PUSH_POP_DEL(pFullPathDest);
  412.     DPRINTF(SYMP_FILE, ("FileStore::CopyFileAlternateL(): copying '%s' -> '%s'n", dbg::CharPtr(fullPathSource)(), dbg::CharPtr(*pFullPathDest)()));
  413.     TInt idxDestDrive = CHXAvFile::GetDriveIndex(*pFullPathDest);
  414.     TInt err = CHXAvFile::CheckDiskSpaceForCopyL(fullPathSource, idxDestDrive);
  415.     if(KErrNone == err)
  416.     {
  417.         RFile source;
  418.         RFile target;
  419.         // buffer for reading source file data
  420.         const TUint k_cbCopyBuffer = 64 * 1024; // 64K buffer (mimics CFileMan copy)
  421.         HBufC8* pCopyBuffer = HBufC8::NewL(k_cbCopyBuffer);
  422.         AUTO_PUSH_POP_DEL(pCopyBuffer);
  423.         CEikonEnv* pEnv = CEikonEnv::Static();
  424.         // open source
  425.         err = source.Open(pEnv->FsSession(), fullPathSource, EFileRead|EFileShareAny);
  426.         if(KErrNone == err)
  427.         {
  428.             CleanupClosePushL(source);
  429.             if( bAllowOverwrite && CHXAvFile::PathExists(*pFullPathDest) )
  430.             {
  431.                 // make sure file is deleted (so create will succeed)
  432.                 HXSYM_LEAVE_IF_ERR(DeleteFileL(*pFullPathDest));
  433.             }
  434.             // (re-)create target; fails if file exists
  435.             err = target.Create(pEnv->FsSession(), *pFullPathDest, EFileWrite|EFileShareExclusive);
  436.             if(KErrNone == err)
  437.             {
  438.                 CleanupClosePushL(target);
  439.                 m_cbFileOp = 0;
  440.                 OnFileOpStart(FileStoreOperationObserver::otCopy, fullPathSource, *pFullPathDest);
  441.                 // copy bits
  442.                 TPtr8 ptr = pCopyBuffer->Des();
  443.                 err =  source.Read(ptr);
  444.                 if( KErrNone == err )
  445.                 {
  446.     while(pCopyBuffer->Length() != 0)
  447.     {
  448.         err = target.Write(*pCopyBuffer);
  449.                         if( KErrNone != err )
  450.                         {
  451.                             break;
  452.                         }
  453.                         m_cbFileOp += pCopyBuffer->Length();
  454.                         // notify observer each time we copy a chunk; provide chance to cancel operation
  455.                         bool bContinue  =  OnFileOpTick(FileStoreOperationObserver::otCopy, fullPathSource, *pFullPathDest, m_cbFileOp);
  456.                         if( !bContinue )
  457.                         {
  458.                             // user cancel
  459.                             err = KErrCancel;
  460.                             break;
  461.                         }
  462.                         err = source.Read(ptr);
  463.                         if( KErrNone != err )
  464.                         {
  465.                             break;
  466.                         }
  467.     }
  468.                     if( KErrNone == err )
  469.                     {
  470.                         err = target.Flush();
  471.                     }
  472.                 }
  473.                 target.Close();
  474.                 CleanupStack::PopAndDestroy(); // target
  475.                 if( KErrNone != err )
  476.                 {
  477.                     DPRINTF(SYMP_FILE, ("FileStore::CopyFileAlternateL(): failed; deleting target file (err = 0x%08xn)", err));
  478.                     // delete destination - copy was not completed
  479.                     HXSYM_LEAVE_IF_ERR(DeleteFileL(*pFullPathDest));
  480.                 }
  481.                 else
  482.                 {
  483.                     // succeded - set file attributes
  484.                     HXSYM_LEAVE_IF_ERR(m_pFileMan->Attribs(*pFullPathDest,
  485.                                                         KEntryAttNormal/*set*/,
  486.                                                         KEntryAttReadOnly/*clear*/, TTime(0)));
  487.                 }
  488.                 OnFileOpEnd(FileStoreOperationObserver::otCopy, err, fullPathSource, *pFullPathDest);
  489.             }
  490.             CleanupStack::PopAndDestroy(); // source
  491.         }
  492.     }
  493.     return err;
  494. }
  495. ////////////////////////////////////////////////////////////
  496. // returns KErrDiskFull if there is not enough disk space to
  497. // make the copy
  498. //
  499. // args:
  500. //
  501. //   pathDest             - path relative to root or absolute
  502. //   fileNameDest         - name relative to pathDest
  503. //
  504. TInt CHXAvFileStore::CopyFileL(const TDesC& pathDest,
  505.     const TDesC& fileNameDest,
  506.     const TDesC& fullPathSource,
  507.     bool bAllowOverwrite)
  508. {
  509.     TFileName* pFullPathDest = AllocFullPathL(pathDest, fileNameDest);
  510.     AUTO_PUSH_POP_DEL(pFullPathDest);
  511.     TUint flag = (bAllowOverwrite ? CFileMan::EOverWrite : 0);
  512.     DPRINTF(SYMP_FILE, ("FileStore::CopyFileL(): copying '%s' -> '%s'n", dbg::CharPtr(fullPathSource)(), dbg::CharPtr(*pFullPathDest)()));
  513.     TInt err = KErrGeneral;
  514.     if( 0 == pFullPathDest->CompareF(fullPathSource) )
  515.     {
  516.         // copy to self; nothing to do; ignore
  517.         err = KErrNone;
  518.     }
  519.     else
  520.     {
  521.         TInt idxDestDrive = CHXAvFile::GetDriveIndex(*pFullPathDest);
  522.         err = CHXAvFile::CheckDiskSpaceForCopyL(fullPathSource, idxDestDrive);
  523.         if( err == KErrNone )
  524.         {
  525.             // fileman copy fails (KErrInUse) if file not opened with EFileShareReadersOnly
  526. #if defined(ASYNC_COPYMOVE)
  527.             err = m_pFileMan->Copy(fullPathSource, *pFullPathDest, flag, m_pFileOpCompletion->Status());
  528.             m_pFileOpCompletion->Activate();
  529. #else
  530.             err = m_pFileMan->Copy(fullPathSource, *pFullPathDest, flag);
  531. #endif
  532.         }
  533.     }
  534.     return err;
  535. }
  536. ////////////////////////////////////////////////////////////
  537. // folder       -  folder relative to current path;
  538. //                 leading path delimiter is optional
  539. //
  540. TInt CHXAvFileStore::CreateChildFolderL(const TDesC& folder, bool bAllowOverwrite)
  541. {
  542.     // alloc fully qualified folder name
  543.     TFileName* pName = CHXAvFile::AllocFileNameL(GetFullPath(), folder, CHXAvFile::ntFolder);
  544.     AUTO_PUSH_POP_DEL(pName);
  545.     if( bAllowOverwrite && CHXAvFile::PathExists(*pName) )
  546.     {
  547.         // make sure existing folder is deleted (so create will succeed)
  548.         HXSYM_LEAVE_IF_ERR(DeleteFileL(*pName));
  549.     }
  550.     RFs& fs = CCoeEnv::Static()->FsSession();
  551.     TInt err = fs.MkDir(*pName); //note: see also MkDirAll
  552.     if(KErrNone == err)
  553.     {
  554. // just in case (we should get event notification from the fs watcher)
  555. m_bNeedRefresh = true;
  556.     }
  557.     return err;
  558. }
  559. ////////////////////////////////////////////
  560. // folder       -  folder relative to current path;
  561. //                 path delimiters (prefix and suffix) are optional
  562. //
  563. void CHXAvFileStore::SwitchToChildFolderL(const TDesC& folder)
  564. {
  565.     DPRINTF(SYMP_FILE, ("FileStore::SwitchToChildFolderL(): '%s'n", dbg::CharPtr(folder)()));
  566.     TFileName* pPath = CHXAvFile::AllocFileNameL(m_curPath, folder, CHXAvFile::ntFolder);
  567.     AUTO_PUSH_POP_DEL(pPath);
  568.     SetCurrentPathL(*pPath);
  569. }
  570. ////////////////////////////////////////////////////////////
  571. // switch current path to parent folder
  572. void CHXAvFileStore::SwitchToParentFolderL()
  573. {
  574.     DPRINTF(SYMP_FILE, ("FileStore::SwitchToParentFolderL()n"));
  575.     HX_ASSERT(!IsAtRoot());
  576.     TPtrC parent = CHXAvFile::GetParentFolder(m_curPath);
  577.     SetCurrentPathL(parent);
  578. }
  579. ////////////////////////////////////////////////////////////
  580. //
  581. TInt CHXAvFileStore::DeleteFileL(const TDesC& fullPath, CHXAvFile::NameType type)
  582. {
  583.     return DeleteFileL(fullPath, KNullDesC, type);
  584. }
  585. ////////////////////////////////////////////////////////////
  586. // delete a file or folder from disk; if successful, mark
  587. // current list as needing refresh
  588. //
  589. //  pathDest    -   full or relative base path
  590. //  name        -   name of file or folder to append
  591. //  type        -   type of file system entry; ntUnspecified if type can safely be deduced from 'name'
  592. //
  593. TInt CHXAvFileStore::DeleteFileL(const TDesC& pathDest, const TDesC& name, CHXAvFile::NameType type)
  594. {
  595.     TInt err = KErrGeneral;
  596.     TFileName* pFullPath = AllocFullPathL(pathDest, name);
  597.     AUTO_PUSH_POP_DEL(pFullPath);
  598.     bool bIsFolder = false;
  599.     if( type == CHXAvFile::ntFolder )
  600.     {
  601.         bIsFolder = true;
  602.         CHXAvFile::EnsureFolderSuffix(*pFullPath);
  603.     }
  604.     else if( type == CHXAvFile::ntUnspecified )
  605.     {
  606.         bIsFolder = CHXAvFile::HasFolderSuffix(*pFullPath);
  607.     }
  608.     CHXAvFile::EnsureClearReadOnlyAttributeL(*pFullPath);
  609.     if( bIsFolder )
  610.     {
  611.         HX_ASSERT(CHXAvFile::HasFolderSuffix(*pFullPath));
  612. err = m_pFileMan->RmDir(*pFullPath);
  613.     }
  614.     else
  615.     {
  616.         HX_ASSERT(!CHXAvFile::HasFolderSuffix(*pFullPath));
  617. err = m_pFileMan->Delete(*pFullPath);
  618.     }
  619.     if(KErrNone == err)
  620.     {
  621.         // just in case (we should get event notification from the fs watcher)
  622.         m_bNeedRefresh = IsImmediateChild(*pFullPath) || IsParent(*pFullPath);
  623.     }
  624.     return err;
  625. }
  626. ////////////////////////////////////////////////////////////
  627. // delete a file or folder from disk; if successful, markd current
  628. // list as needing refresh
  629. //
  630. // idxItem                - index of item in current folder path
  631. //
  632. TInt CHXAvFileStore::DeleteItemL(TInt idxItem)
  633. {
  634.     TInt err = KErrGeneral;
  635.     TFileName* pFullPath = AllocFullPathL(idxItem);
  636.     AUTO_PUSH_POP_DEL(pFullPath);
  637.     CHXAvFile::EnsureClearReadOnlyAttributeL(*pFullPath);
  638.     HX_ASSERT(idxItem < m_entryInfo.Nelements());
  639.     const TEntry& entry = m_entryInfo[idxItem].m_entry;
  640.     if( entry.IsDir() )
  641.     {
  642.         HX_ASSERT(CHXAvFile::HasFolderSuffix(*pFullPath));
  643. err = m_pFileMan->RmDir(*pFullPath);
  644.     }
  645.     else
  646.     {
  647.         HX_ASSERT(!CHXAvFile::HasFolderSuffix(*pFullPath));
  648. err = m_pFileMan->Delete(*pFullPath);
  649.     }
  650.     if(KErrNone == err)
  651.     {
  652. // just in case (we should get event notification from the fs watcher)
  653. m_bNeedRefresh = true;
  654.     }
  655.     return err;
  656. }
  657. ////////////////////////////////////////////////////////////
  658. // path                   - relative to root or absolute (if drive specified)
  659. // idxItem                - index of item in _current_ folder path
  660. //
  661. // * call this before certain unchecking methods
  662. //
  663. // return: true if fully qualified filename formed from
  664. //         input parameters would fit safely in a TFileName buffer
  665. //
  666. bool CHXAvFileStore::IsSafeFileNameLengthL(const TDesC& path, TInt idxItem)
  667. {
  668.     TFileName* pPath = AllocFullPathL(path, KNullDesC, CHXAvFile::ntFolder);
  669.     AUTO_PUSH_POP_DEL(pPath);
  670.     HX_ASSERT(idxItem < m_entryInfo.Nelements());
  671.     const TEntry& entry = m_entryInfo[idxItem].m_entry;
  672.     TInt cchRequired = pPath->Length() + entry.iName.Length();
  673.     if( entry.IsDir() )
  674.     {
  675.         cchRequired += 1; // account for folder suffix that will need to be added
  676.     }
  677.     return cchRequired <= KMaxFileName;
  678. }
  679. ////////////////////////////////////////////////////////////
  680. // see IsSafeFileNameLengthL() override
  681. bool CHXAvFileStore::IsSafeFileNameLengthL(const TDesC& path,
  682.                                         const TDesC& name,
  683.                                         CHXAvFile::NameType type)
  684. {
  685.     TFileName* pPath = AllocFullPathL(path, KNullDesC, CHXAvFile::ntFolder);
  686.     AUTO_PUSH_POP_DEL(pPath);
  687.     TInt cchRequired = pPath->Length() + name.Length();
  688.     if( (CHXAvFile::ntFolder == type) && !CHXAvFile::HasFolderSuffix(name) )
  689.     {
  690.         cchRequired += 1; // account for folder suffix that will need to be added
  691.     }
  692.     return cchRequired <= KMaxFileName;
  693. }
  694. ////////////////////////////////////////////////////////////
  695. //
  696. // Allocate full path (file or folder) for given item in
  697. // current path
  698. //
  699. // idxItem      - index to an existing item (folder or file)
  700. //
  701. TFileName* CHXAvFileStore::AllocFullPathL(TInt idxItem)
  702. {
  703.     HX_ASSERT(idxItem < m_entryInfo.Nelements());
  704.     const TEntry& entry = m_entryInfo[idxItem].m_entry;
  705.     // allocate fully qualified file or folder name
  706.     TFileName* pPath = CHXAvFile::AllocFileNameL(GetFullPath(),
  707.     entry.iName, (entry.IsDir() ? CHXAvFile::ntFolder : CHXAvFile::ntFile) );
  708.     return pPath;
  709. }
  710. ////////////////////////////////////////////////////////////
  711. //
  712. // Allocate full destination path (file or folder) matching
  713. // the given item
  714. //
  715. // targetPath   - absolute or relative target folder path
  716. // idxItem      - index to an existing item (folder or file)
  717. // targetName   - name of target file or folder; zero-length indicates
  718. //                use same name as file/folder at given index in current folder
  719. //
  720. //
  721. TFileName* CHXAvFileStore::AllocFullTargetPathL(const TDesC& targetPath,
  722.                                                  TInt idxItem, const TDesC& targetName)
  723. {
  724.     HX_ASSERT(idxItem < m_entryInfo.Nelements());
  725.     const TEntry& entry = m_entryInfo[idxItem].m_entry;
  726.     CHXAvFile::NameType type = ( entry.IsDir() ? CHXAvFile::ntFolder : CHXAvFile::ntFile );
  727.     TFileName* pPath = 0;
  728.     if( 0 == targetName.Length() )
  729.     {
  730.         // no target name, use same name
  731.         pPath = AllocFullPathL(targetPath, entry.iName, type);
  732.     }
  733.     else
  734.     {
  735.         pPath = AllocFullPathL(targetPath, targetName, type);
  736.     }
  737.     return pPath;
  738. }
  739. ////////////////////////////////////////////////////////////
  740. //does file or folder matching name associated with item exist in target path
  741. //
  742. // path                   - relative to root or absolute (if drive specified)
  743. // idxItem                - index of item in _current_ folder path
  744. //
  745. //
  746. bool CHXAvFileStore::NameExistsInTargetPathL(const TDesC& targetPath, TInt idxItem)
  747. {
  748.     // alloc full file path matching the name associated with the given entry index
  749.     HX_ASSERT(idxItem < m_entryInfo.Nelements());
  750.     const TEntry& entry = m_entryInfo[idxItem].m_entry;
  751.     return NameExistsInTargetPathL(targetPath, entry.iName);
  752. }
  753. ////////////////////////////////////////////////////////////
  754. // does file or folder exist with given name in path
  755. //
  756. // * use before moving/renaming an item to the target folder
  757. //
  758. // path                   - relative to root or absolute (if drive specified)
  759. // name                   - file or folder name (ok to have folder trailing slash)
  760. //
  761. //
  762. bool CHXAvFileStore::NameExistsInTargetPathL(const TDesC& targetPath, const TDesC& name)
  763. {
  764.     // alloc full file path matching the name associated with the given entry index
  765.     TFileName* pName = AllocFullPathL(targetPath, name, CHXAvFile::ntFile);
  766.     AUTO_PUSH_POP_DEL(pName);
  767.     // see if file with given name exists
  768.     bool bExists = CHXAvFile::PathExists(*pName);
  769.     if( !bExists )
  770.     {
  771.         // see if folder with given name exists
  772.         CHXAvFile::EnsureFolderSuffix(*pName);
  773.         bExists = CHXAvFile::PathExists(*pName);
  774.     }
  775.     return bExists;
  776. }
  777. ////////////////////////////////////////////////////////////
  778. // does file or folder (specified) matching name associated with item exists in target path
  779. //
  780. // return true if target path has folder or file having same name
  781. // as entry at given index idxItem in current path 
  782. //
  783. bool CHXAvFileStore::NameExistsInTargetPathL(const TDesC& targetPath, TInt idxItem, CHXAvFile::NameType type)
  784. {
  785.     HX_ASSERT(idxItem < m_entryInfo.Nelements());
  786.     const TEntry& entry = m_entryInfo[idxItem].m_entry;
  787.     return PathExistsL(targetPath, entry.iName, type);
  788. }
  789. ////////////////////////////////////////////////////////////
  790. // does path exist as file or folder (specified or dedecude based on name)
  791. //
  792. // return true if target path has file or folder having given name
  793. //
  794. bool CHXAvFileStore::PathExistsL(const TDesC& targetPath, const TDesC& name, CHXAvFile::NameType type)
  795. {
  796.     TFileName* pName = AllocFullPathL(targetPath, name, type);
  797.     AUTO_PUSH_POP_DEL(pName);
  798.     return CHXAvFile::PathExists(*pName);
  799. }
  800. ////////////////////////////////////////////////////////////
  801. //
  802. TInt CHXAvFileStore::MoveItemL(TInt idxItem,
  803.                             const TDesC& newName,
  804.                             bool bAllowOverwrite, bool bRename)
  805. {
  806.     return MoveItemL(idxItem, KNullDesC, newName, bAllowOverwrite, bRename);
  807. }
  808. ////////////////////////////////////////////////////////////
  809. // move item
  810. //
  811. // return:
  812. //          KErrNone if file is moved;
  813. //          KErrDiskFull if insufficient space on target
  814. //
  815. // idxItem                - index of item in current folder path
  816. // targetPath             - relative to root or absolute (or KNullDesC to move within current path, i.e., rename)
  817. // targetName             - new name for file or folder;
  818. //                          for folders, trailing '' optional
  819. // bRename                - uses underlying rename api; doesn't check disk space for copy (probably no difference from move)
  820. //
  821. TInt CHXAvFileStore::MoveItemL(TInt idxItem,
  822. const TDesC& targetPath,
  823. const TDesC& targetName,
  824. bool bAllowOverwrite, bool bRename)
  825. {
  826.     // source path
  827.     TFileName* pOldPath = AllocFullPathL(idxItem);
  828.     AUTO_PUSH_POP_DEL(pOldPath);
  829.     // target path
  830.     TFileName* pNewPath = 0;
  831.     if( targetPath.Length() != 0 )
  832.     {
  833.         pNewPath = AllocFullTargetPathL(targetPath, idxItem, targetName);
  834.     }
  835.     else
  836.     {
  837.         // use current path for target
  838.         pNewPath = AllocFullTargetPathL(GetCurrentPath(), idxItem, targetName);
  839.     }
  840.     AUTO_PUSH_POP_DEL(pNewPath);
  841.     TInt err = KErrNone;
  842.     if( 0 != pOldPath->CompareF(*pNewPath)) // else, move to self - nothing to do
  843.     {
  844.         if(!bRename)
  845.         {
  846.             // see if we are moving across drives...
  847.             TInt idxDestDrive = CHXAvFile::GetDriveIndex(*pNewPath);
  848.             TInt idxSourceDrive = CHXAvFile::GetDriveIndex(*pOldPath);
  849.             if(idxDestDrive != idxSourceDrive)
  850.             {
  851.                 // need to check for disk space on destination drive
  852.                 err =  CHXAvFile::CheckDiskSpaceForCopyL(*pOldPath, idxDestDrive);
  853.             }
  854.         }
  855.         if(KErrNone == err)
  856.         {
  857.             DPRINTF(SYMP_FILE, ("FileStore::MoveItemL(): moving '%s' -> '%s'n", dbg::CharPtr(*pOldPath)(), dbg::CharPtr(*pNewPath)()));
  858.             TUint flag = CFileMan::ERecurse;
  859.             // clear ro attributes for source and dest
  860.             CHXAvFile::EnsureClearReadOnlyAttributeL(*pOldPath);
  861.             if(PathExistsL(*pNewPath, KNullDesC) && bAllowOverwrite)
  862.             {
  863.                 flag |= CFileMan::EOverWrite;
  864.                 CHXAvFile::EnsureClearReadOnlyAttributeL(*pNewPath);
  865.             }
  866.             // folder suffixes cause errors
  867.             CHXAvFile::TrimFolderSuffix(pOldPath);
  868.             CHXAvFile::TrimFolderSuffix(pNewPath);
  869.             if( bRename )
  870.             {
  871.                 err =  m_pFileMan->Rename(*pOldPath, *pNewPath, flag);
  872.             }
  873.             else
  874.             {
  875. #if defined(ASYNC_COPYMOVE)
  876.                 err = m_pFileMan->Move(*pOldPath, *pNewPath, flag, m_pFileOpCompletion->Status());
  877.                 m_pFileOpCompletion->Activate();
  878. #else
  879.                 err = m_pFileMan->Move(*pOldPath, *pNewPath, flag);
  880. #endif
  881.             }
  882.             DPRINTF(SYMP_FILE_UI, ("CHXAvFileStore::MoveItemL: result = %ldn", err));
  883.             if(KErrNone == err)
  884.             {
  885.                 if(PathExistsL(*pOldPath, KNullDesC))
  886.                 {
  887.                     DPRINTF(SYMP_FILE_UI, ("CHXAvFileStore::MoveItemL: old path still exists! deleting old itemn"));
  888.                     // just in case - in case where we overwrite an existing folder the source
  889.                     // folder is not deleted
  890.                     HXSYM_LEAVE_IF_ERR(DeleteFileL(*pOldPath));
  891.                 }
  892.         // just in case (we should get event notification from the fs watcher)
  893.         m_bNeedRefresh = true;
  894.             }
  895.         }
  896.     }
  897.     return err;
  898. }
  899. //////////////////////////////////
  900. //
  901. FileStoreOperationObserver::OperationType
  902. FileStoreOperationObserver::TranslateFileManAction(CFileMan::TAction action)
  903. {
  904.     if(action == CFileMan::ECopy)
  905.     {
  906.         return otCopy;
  907.     }
  908.     else if(action == CFileMan::EMove)
  909.     {
  910.         return otMove;
  911.     }
  912.     else if(action == CFileMan::ERename)
  913.     {
  914.         return otMove;
  915.     }
  916.     return otWhoCares;
  917. }
  918. //////////////////////////////////
  919. // called when fileman begins a file operation
  920. //
  921. // called on separate thread if async fileman operations are used
  922. //
  923. MFileManObserver::TControl CHXAvFileStore::NotifyFileManStarted()
  924. {
  925.     DPRINTF(SYMP_FILE, ("FileStore::NotifyFileManStarted()n"));
  926.     FileStoreOperationObserver::OperationType type = TranslateFileManAction(m_pFileMan->CurrentAction());
  927.     if( type != FileStoreOperationObserver::otWhoCares )
  928.     {
  929.         TFileName source, dest;
  930.         m_pFileMan->GetCurrentSource(source);
  931.         m_pFileMan->GetCurrentTarget(dest);
  932.         m_cbFileOp = 0;
  933.         OnFileOpStart(type, source, dest);
  934.     }
  935.     // ECopy, EMove, EDelete, ERename, ERmDir
  936.     return EContinue;
  937. }
  938. //////////////////////////////////
  939. // called when fileman completes copying a chunk of data (move, copy)
  940. //
  941. // called on separate thread if async fileman operations are used
  942. //
  943. // we can return EContinue,ERetry,EAbort,ECancel
  944. MFileManObserver::TControl CHXAvFileStore::NotifyFileManOperation()
  945. {
  946.     DPRINTF(SYMP_FILE, ("FileStore::NotifyFileManOperation()n"));
  947.     MFileManObserver::TControl controlAction = EContinue;
  948.     FileStoreOperationObserver::OperationType type = TranslateFileManAction(m_pFileMan->CurrentAction());
  949.     if( type != FileStoreOperationObserver::otWhoCares )
  950.     {
  951.         TFileName source, dest;
  952.         m_pFileMan->GetCurrentSource(source);
  953.         m_pFileMan->GetCurrentTarget(dest);
  954.         TInt cbCopied = m_pFileMan->BytesTransferredByCopyStep();
  955.         m_cbFileOp += cbCopied;
  956.         bool bContinue = OnFileOpTick(type, source, dest, m_cbFileOp);
  957.         if( !bContinue )
  958.         {
  959.             controlAction = ECancel;
  960.         }
  961.     }
  962.     return controlAction;
  963. }
  964. //////////////////////////////////
  965. // called when fileman completes an operation
  966. //
  967. // called on separate thread if async fileman operations are used
  968. //
  969. MFileManObserver::TControl CHXAvFileStore::NotifyFileManEnded()
  970. {
  971.     DPRINTF(SYMP_FILE, ("FileStore::NotifyFileManEnded()n"));
  972.     FileStoreOperationObserver::OperationType type = TranslateFileManAction(m_pFileMan->CurrentAction());
  973.     if( type != FileStoreOperationObserver::otWhoCares )
  974.     {
  975.         TFileName source, dest;
  976.         m_pFileMan->GetCurrentSource(source);
  977.         m_pFileMan->GetCurrentTarget(dest);
  978.         //TInt cbCopied = m_pFileMan->BytesTransferredByCopyStep();
  979.         OnFileOpEnd(type, KErrNone, source, dest);
  980.     }
  981.     return EContinue;
  982. }
  983. #if defined(ASYNC_COPYMOVE)
  984. ////////////////////////////////////////
  985. // called when async fileman request completes
  986. void CHXAvFileStore::OnFileOpAsyncComplete(TInt status)
  987. {
  988.     DPRINTF(SYMP_FILE, ("FileStore::OnFileOpAsyncComplete(): status = %dn", status));
  989. }
  990. ////////////////////////////////////////
  991. // called when async fileman request is cancelled
  992. void CHXAvFileStore::OnFileOpAsyncCancel(TInt status)
  993. {
  994.     DPRINTF(SYMP_FILE, ("FileStore::OnFileOpAsyncCancel(): status = %dn", status));
  995. }
  996. ////////////////////////////////////////
  997. // called to abort/cancel async fileman request
  998. void CHXAvFileStore::CancelAsyncFileOp()
  999. {
  1000.     DPRINTF(SYMP_FILE, ("FileStore::CancelAsyncFileOp()n"));
  1001.     if( m_pFileOpCompletion && m_pFileOpCompletion->IsActive() )
  1002.     {
  1003. m_pFileOpCompletion->Cancel();
  1004.     }
  1005. }
  1006. #endif // ASYNC_COPYMOVE
  1007. void CHXAvFileStore::OnFileOpStart(FileStoreOperationObserver::OperationType type, const TDesC& source, const TDesC& target)
  1008. {
  1009.     DPRINTF(SYMP_FILE, ("FileStore::OnFileOpStart(): op = %d; src = '%s'; dst = '%s'n", type,  dbg::CharPtr(source)(), dbg::CharPtr(target)()));
  1010.     if(m_pObserver)
  1011.     {
  1012.         m_pObserver->OnFileOpStart(type, source, target);
  1013.     }
  1014. }
  1015. bool CHXAvFileStore::OnFileOpTick(FileStoreOperationObserver::OperationType type, const TDesC& source, const TDesC& target, TInt64 cbCopied)
  1016. {
  1017.     DPRINTF(SYMP_FILE, ("FileStore::OnFileOpTick(): op = %d; src = '%s'; dst = '%s'; cb = %lun", type,  dbg::CharPtr(source)(), dbg::CharPtr(target)(), cbCopied.Low()));
  1018.     if(m_pObserver)
  1019.     {
  1020.         return m_pObserver->OnFileOpTick(type, source, target, m_cbFileOp);
  1021.     }
  1022.     return true;
  1023. }
  1024. void CHXAvFileStore::OnFileOpEnd(FileStoreOperationObserver::OperationType type, TInt err, const TDesC& source, const TDesC& target)
  1025. {
  1026.     DPRINTF(SYMP_FILE, ("FileStore::OnFileOpEnd(): op = %d; err = %d, src = '%s'; dst = '%s'n", type, err, dbg::CharPtr(source)(), dbg::CharPtr(target)()));
  1027.     if(m_pObserver)
  1028.     {
  1029.         m_pObserver->OnFileOpEnd(type, err, source, target);
  1030.     }
  1031. }