Logo Search packages:      
Sourcecode: filezilla version File versions

directorycache.cpp

#include "FileZilla.h"
#include "directorycache.h"

int CDirectoryCache::m_nRefCount = 0;
std::list<CDirectoryCache::CCacheEntry> CDirectoryCache::m_CacheList;

CDirectoryCache::CDirectoryCache()
{
      m_nRefCount++;
}

CDirectoryCache::~CDirectoryCache()
{
      m_nRefCount--;
}

void CDirectoryCache::Store(const CDirectoryListing &listing, const CServer &server, CServerPath parentPath /*=CServerPath()*/, wxString subDir /*=_T("")*/)
{
      // First check for existing entry in cache and update if it neccessary
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            CCacheEntry &entry = *iter;
            if (entry.server != server || entry.listing.path != listing.path)
                  continue;
            
            entry.modificationTime = CTimeEx::Now();
            entry.createTime = entry.modificationTime.GetTime();

            entry.listing = listing;

            if (!parentPath.IsEmpty() && subDir != _T(""))
            {
                  // Search for parents
                  for (tParentsIter parentsIter = entry.parents.begin(); parentsIter != entry.parents.end(); parentsIter++)
                  {
                        const CCacheEntry::t_parent &parent = *parentsIter;
                        if (parent.path == parentPath && parent.subDir == subDir)
                              return;
                  }
      
                  // Store parent
                  CCacheEntry::t_parent parent;
                  parent.path = parentPath;
                  parent.subDir = subDir;
                  entry.parents.push_front(parent);
            }

            return;
      }

      // Create new entry and store listing in cache
      CCacheEntry entry;
      entry.modificationTime = CTimeEx::Now();
      entry.createTime = entry.modificationTime.GetTime();
      entry.listing = listing;
      entry.server = server;

      if (!parentPath.IsEmpty() && subDir != _T(""))
      {
            // Store parent
            CCacheEntry::t_parent parent;
            parent.path = parentPath;
            parent.subDir = subDir;
            entry.parents.push_front(parent);
      }

      m_CacheList.push_front(entry);
}

bool CDirectoryCache::Lookup(CDirectoryListing &listing, const CServer &server, const CServerPath &path, bool allowUnsureEntries)
{
      return Lookup(listing, server, path, _T(""), allowUnsureEntries);
}

bool CDirectoryCache::Lookup(CDirectoryListing &listing, const CServer &server, const CServerPath &path, wxString subDir, bool allowUnsureEntries)
{
      if (subDir != _T(".."))
      {
            for (tCacheConstIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
            {
                  const CCacheEntry &entry = *iter;
                  if (entry.server != server)
                        continue;

                  if (subDir == _T(""))
                  {
                        if (entry.listing.path == path)
                        {
                              if (!allowUnsureEntries && entry.listing.m_hasUnsureEntries)
                                    return false;

                              listing = entry.listing;
                              return true;
                        }
                  }
                  else
                  {
                        for (tParentsConstIter parentsIter = entry.parents.begin(); parentsIter != entry.parents.end(); parentsIter++)
                        {
                              const CCacheEntry::t_parent &parent = *parentsIter;
                              if (parent.path != path || parent.subDir != subDir)
                                    continue;

                              if (!allowUnsureEntries && entry.listing.m_hasUnsureEntries)
                                    return false;

                              listing = entry.listing;
                              return true;
                        }
                  }
            }
      }
      else
      {
            // Search own entry
            tCacheConstIter iter;
            for (iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
            {
                  if (iter->server != server)
                        continue;

                  const CCacheEntry &entry = *iter;

                  tParentsConstIter parentsIter;
                  for (parentsIter = entry.parents.begin(); parentsIter != entry.parents.end(); parentsIter++)
                  {
                        if (parentsIter->subDir == _T("..") && parentsIter->path == path)
                              break;
                  }
                  if (parentsIter != entry.parents.end())
                        break;
            }
            if (iter == m_CacheList.end())
                  return false;

            bool res = Lookup(listing, server, iter->listing.path, _T(""), allowUnsureEntries);
            return res;
      }
      return false;
}

bool CDirectoryCache::DoesExist(const CServer &server, const CServerPath &path, wxString subDir, int &hasUnsureEntries)
{
      if (subDir != _T(".."))
      {
            for (tCacheConstIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
            {
                  const CCacheEntry &entry = *iter;
                  if (entry.server != server)
                        continue;

                  if (subDir == _T(""))
                  {
                        if (entry.listing.path == path)
                        {
                              hasUnsureEntries = entry.listing.m_hasUnsureEntries;
                              return true;
                        }
                  }
                  else
                  {
                        for (tParentsConstIter parentsIter = entry.parents.begin(); parentsIter != entry.parents.end(); parentsIter++)
                        {
                              const CCacheEntry::t_parent &parent = *parentsIter;
                              if (parent.path != path || parent.subDir != subDir)
                                    continue;

                              hasUnsureEntries = entry.listing.m_hasUnsureEntries;
                              return true;
                        }
                  }
            }
      }
      else
      {
            // Search own entry
            tCacheConstIter iter;
            for (iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
            {
                  if (iter->server != server)
                        continue;

                  const CCacheEntry &entry = *iter;

                  tParentsConstIter parentsIter;
                  for (parentsIter = entry.parents.begin(); parentsIter != entry.parents.end(); parentsIter++)
                  {
                        if (parentsIter->subDir == _T("..") && parentsIter->path == path)
                              break;
                  }
                  if (parentsIter != entry.parents.end())
                        break;
            }
            if (iter == m_CacheList.end())
                  return false;

            bool res = DoesExist(server, iter->listing.path, _T(""), hasUnsureEntries);
            return res;
      }
      return false;
}

bool CDirectoryCache::LookupFile(CDirentry &entry, const CServer &server, const CServerPath &path, const wxString& file, bool &dirDidExist, bool &matchedCase)
{
      for (tCacheConstIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            const CCacheEntry &cacheEntry = *iter;
            if (cacheEntry.server != server)
                  continue;

            if (cacheEntry.listing.path == path)
            {
                  dirDidExist = true;

                  const CDirectoryListing &listing = cacheEntry.listing;

                  bool found = false;
                  for (unsigned int i = 0; i < listing.GetCount(); i++)
                  {
                        if (!listing[i].name.CmpNoCase(file))
                        {
                              if (listing[i].name == file)
                              {
                                    entry = listing[i];
                                    matchedCase = true;
                                    return true;
                              }
                              if (!found)
                              {
                                    found = true;
                                    entry = listing[i];
                              }
                        }
                  }
                  if (found)
                  {
                        matchedCase = false;
                        return true;
                  }

                  return false;
            }
      }

      dirDidExist = false;
      return false;
}

CDirectoryCache::CCacheEntry& CDirectoryCache::CCacheEntry::operator=(const CDirectoryCache::CCacheEntry &a)
{
      listing = a.listing;
      server = a.server;
      createTime = a.createTime;
      modificationTime = a.modificationTime;
      parents = a.parents;

      return *this;
}

CDirectoryCache::CCacheEntry::CCacheEntry(const CDirectoryCache::CCacheEntry &entry)
{
      listing = entry.listing;
      server = entry.server;
      createTime = entry.createTime;
      modificationTime = entry.modificationTime;
      parents = entry.parents;
}

bool CDirectoryCache::InvalidateFile(const CServer &server, const CServerPath &path, const wxString& filename, bool *wasDir /*=false*/)
{
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            CCacheEntry &entry = *iter;
            if (entry.server != server || path.CmpNoCase(entry.listing.path))
                  continue;

            //bool matchCase = false;
            for (unsigned int i = 0; i < entry.listing.GetCount(); i++)
            {
                  if (!filename.CmpNoCase(((const CCacheEntry&)entry).listing[i].name))
                  {
                        if (wasDir)
                              *wasDir = entry.listing[i].dir;
                        entry.listing[i].unsure = true;
                        //if (entry.listing[i].name == filename)
                              //matchCase = true;
                  }                       
            }
            entry.listing.m_hasUnsureEntries |= UNSURE_UNSURE;
            entry.modificationTime = CTimeEx::Now();
      }

      return true;
}

bool CDirectoryCache::UpdateFile(const CServer &server, const CServerPath &path, const wxString& filename, bool mayCreate, enum Filetype type /*=file*/, int size /*=-1*/)
{
      bool updated = false;

      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            CCacheEntry &entry = *iter;
            const CCacheEntry &cEntry = *iter;
            if (entry.server != server || path.CmpNoCase(entry.listing.path))
                  continue;

            bool matchCase = false;
            for (unsigned int i = 0; i < entry.listing.GetCount(); i++)
            {
                  if (!filename.CmpNoCase(cEntry.listing[i].name))
                  {
                        if (cEntry.listing[i].name == filename)
                              matchCase = true;
                        entry.listing[i].unsure = true;
                  }                       
            }
            if (!matchCase && type != unknown && mayCreate)
            {
                  const unsigned int count = entry.listing.GetCount();
                  entry.listing.SetCount(count + 1);
                  CDirentry& direntry = entry.listing[count];
                  direntry.name = filename;
                  direntry.hasDate = false;
                  direntry.hasTime = false;
                  direntry.size = size;
                  direntry.dir = (type == dir);
                  direntry.link = 0;
                  direntry.unsure = true;
                  entry.listing.m_hasUnsureEntries |= UNSURE_ADD;
            }
            else
                  entry.listing.m_hasUnsureEntries |= UNSURE_CHANGE;
            entry.modificationTime = CTimeEx::Now();

            updated = true;
      }

      return updated;
}

bool CDirectoryCache::RemoveFile(const CServer &server, const CServerPath &path, const wxString& filename)
{
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            const CCacheEntry &entry = *iter;
            if (entry.server != server || path.CmpNoCase(entry.listing.path))
                  continue;

            bool matchCase = false;
            for (unsigned int i = 0; i < entry.listing.GetCount(); i++)
            {
                  if (entry.listing[i].name == filename)
                        matchCase = true;
            }
            
            if (matchCase)
            {
                  unsigned int i;
                  for (i = 0; i < entry.listing.GetCount(); i++)
                        if (entry.listing[i].name == filename)
                              break;
                  wxASSERT(i != entry.listing.GetCount());

                  CDirectoryListing& listing = iter->listing;
                  listing.RemoveEntry(i);
            }
            else
            {
                  for (unsigned int i = 0; i < entry.listing.GetCount(); i++)
                  {
                        if (!filename.CmpNoCase(entry.listing[i].name))
                        {
                              iter->listing[i].unsure = true;
                        }                       
                  }
                  iter->listing.m_hasUnsureEntries |= UNSURE_CONFUSED;
            }
            iter->modificationTime = CTimeEx::Now();
      }

      return true;
}

void CDirectoryCache::InvalidateServer(const CServer& server)
{
      std::list<CCacheEntry> newCache;
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            const CCacheEntry &entry = *iter;
            if (entry.server != server)
                  newCache.push_back(entry);
      }
      m_CacheList = newCache;
}

bool CDirectoryCache::HasChanged(CTimeEx since, const CServer &server, const CServerPath &path) const
{
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            CCacheEntry &entry = *iter;
            if (entry.server != server)
                  continue;
            
            if (entry.listing.path != path)
                  continue;

            if (entry.modificationTime > since)
                  return true;
            else
                  return false;
      }

      return false;
}

bool CDirectoryCache::GetChangeTime(CTimeEx& time, const CServer &server, const CServerPath &path) const
{
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            CCacheEntry &entry = *iter;
            if (entry.server != server)
                  continue;
            
            if (entry.listing.path != path)
                  continue;

            time = entry.modificationTime;
            return true;
      }

      return false;
}

void CDirectoryCache::RemoveDir(const CServer& server, const CServerPath& path, const wxString& filename)
{
      // TODO: This is not 100% foolproof and may not work properly
      // Perhaps just throw away the complete cache?

      CServerPath absolutePath = path;
      if (!absolutePath.AddSegment(filename))
            absolutePath.Clear();

      std::list<CCacheEntry> newList;
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            CCacheEntry &entry = *iter;
            if (entry.server != server)
            {
                  // Don't delete items from different server
                  newList.push_back(*iter);
                  continue;
            }

            // Delete exact matches and subdirs
            if (!absolutePath.IsEmpty() && (entry.listing.path == absolutePath || absolutePath.IsParentOf(entry.listing.path, true)))
                  continue;

            tParentsIter parentsIter;
            for (parentsIter = entry.parents.begin(); parentsIter != entry.parents.end(); parentsIter++)
            {
                  const CCacheEntry::t_parent &parent = *parentsIter;
                  if (parent.path == path && parent.subDir == filename)
                        break;
            }
            if (parentsIter != entry.parents.end())
                  continue;

            newList.push_back(*iter);
      }
      
      m_CacheList = newList;

      RemoveFile(server, path, filename);
}

void CDirectoryCache::Rename(const CServer& server, const CServerPath& pathFrom, const wxString& fileFrom, const CServerPath& pathTo, const wxString& fileTo)
{
      CDirectoryListing listing;
      bool found = Lookup(listing, server, pathFrom, true);
      if (found)
      {
            unsigned int i;
            for (i = 0; i < listing.GetCount(); i++)
            {
                  if (listing[i].name == fileFrom)
                        break;
            }
            if (i != listing.GetCount())
            {
                  if (listing[i].dir)
                  {
                        RemoveDir(server, pathFrom, fileFrom);
                        UpdateFile(server, pathTo, fileTo, true, dir);
                  }
                  else
                  {
                        RemoveFile(server, pathFrom, fileFrom);
                        UpdateFile(server, pathTo, fileTo, true, file);
                  }
            }
            else
            {
                  // Be on the safe side, invalidate everything.
                  InvalidateServer(server);
            }
      }
      else
      {
            // We know nothing, invalidate everything.
            InvalidateServer(server);
      }
}

void CDirectoryCache::AddParent(const CServer& server, const CServerPath& path, const CServerPath& parentPath, const wxString subDir)
{
      for (tCacheIter iter = m_CacheList.begin(); iter != m_CacheList.end(); iter++)
      {
            CCacheEntry &entry = *iter;
            if (entry.server != server)
                  continue;

            if (entry.listing.path != path)
                  continue;

            // Search for parents
            for (tParentsIter parentsIter = entry.parents.begin(); parentsIter != entry.parents.end(); parentsIter++)
            {
                  const CCacheEntry::t_parent &parent = *parentsIter;
                  if (parent.path == parentPath && parent.subDir == subDir)
                        return;
            }

            // Store parent
            CCacheEntry::t_parent parent;
            parent.path = parentPath;
            parent.subDir = subDir;
            entry.parents.push_front(parent);
      }
}

Generated by  Doxygen 1.6.0   Back to index