OSDN Git Service

PATCH: [ 1589563 ] Fix crash with weird filetimes (and cleanup the code)
authorKimmo Varis <kimmov@gmail.com>
Fri, 3 Nov 2006 19:52:27 +0000 (19:52 +0000)
committerKimmo Varis <kimmov@gmail.com>
Fri, 3 Nov 2006 19:52:27 +0000 (19:52 +0000)
Src/Changes.txt
Src/DiffFileInfo.cpp
Src/DiffFileInfo.h
Src/DirScan.cpp
Src/DirViewColHandler.cpp
Src/DirViewColItems.cpp
Src/FileInfo.cpp
Src/FileInfo.h

index bff9c6b..d53a54f 100644 (file)
@@ -7,6 +7,9 @@ Add new items to top.
   Src: ProjectFile.cpp
  PATCH: [ 1589438 ] Add read-only info to ProjectFile dialog
   Src: MainFrm.cpp
+ PATCH: [ 1589563 ] Fix crash with weird filetimes (and cleanup the code)
+  Src: DiffFileInfo.cpp DiffFileInfo.h DirScan.cpp DirViewColHandler.cpp
+   DirViewColItems.cpp FileInfo.cpp FileInfo.h
 
 2006-11-03 Tim
  PATCH: [ 1589601 ] Add "ReDim" keyword to Visual Basic highlighter
index c5f7021..840e18c 100644 (file)
 #include "unicoder.h"
 
 /**
- * @brief Convert a FILETIME to a long (standard time)
- */
-static __int64 FileTimeToInt64(FILETIME & ft)
-{
-       return CTime(ft).GetTime();
-}
-
-/**
- * @brief Update fileinfo from given file
- * @param [in] sFilePath Full path to file/directory to update
- * @return TRUE if file exists
- */
-BOOL DiffFileInfo::Update(LPCTSTR sFilePath)
-{
-       // CFileFind doesn't expose the attributes
-       // CFileStatus doesn't expose 64 bit size
-       BOOL Update = FALSE;
-       WIN32_FIND_DATA wfd;
-       HANDLE h = FindFirstFile(sFilePath, &wfd);
-       __int64 mtime64 = 0;
-       size = -1;
-       flags.reset();
-       mtime = 0;
-       if (h != INVALID_HANDLE_VALUE)
-       {
-               mtime64 = FileTimeToInt64(wfd.ftLastWriteTime);
-               flags.attributes = wfd.dwFileAttributes;
-
-               // Folders don't have a size (size remains as -1)
-               if ((flags.attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
-                       size = FileInfo::GetSizeFromFindData(wfd);
-               FindClose(h);
-               Update = TRUE;
-       }
-       mtime = mtime64;
-       return Update;
-}
-
-/**
  * @brief Clears FileInfo data.
  */
 void DiffFileInfo::Clear()
@@ -77,7 +38,6 @@ void DiffFileInfo::Clear()
        m_textStats.clear();
 }
 
-
 /**
  * @brief Return true if file is in any Unicode encoding
  */
index 8143790..f3a6483 100644 (file)
@@ -84,7 +84,9 @@ struct DiffFileFlags : public FileFlags
 
 
 /**
- * @brief Information for file
+ * @brief Information for file.
+ * This class expands FileInfo class with encoding information and
+ * text stats information.
  */
 struct DiffFileInfo : public FileInfo
 {
@@ -100,7 +102,6 @@ struct DiffFileInfo : public FileInfo
 // methods
 
        DiffFileInfo() { Clear(); }
-       BOOL Update(LPCTSTR sFilePath);
        void Clear();
        bool IsEditableEncoding() const;
 };
index c042a97..1ad7790 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "stdafx.h"
 #include <shlwapi.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include "DirScan.h"
 #include "CompareStats.h"
 #include "common/unicoder.h"
@@ -36,13 +38,11 @@ static char THIS_FILE[] = __FILE__;
  */
 struct fentry
 {
-       CString name;
-       // storing __time_t if MSVC6 (__MSC_VER<1300)
-       // storing __time64_t if MSVC7 (VC.NET)
+       CString name; /**< Item name */
        __int64 mtime; /**< Last modify time */
        __int64 ctime; /**< Creation modify time */
-       __int64 size;
-       int attrs;
+       __int64 size; /**< File size */
+       int attrs; /**< Item attributes */
 };
 typedef CArray<fentry, fentry&> fentryArray;
 
@@ -356,6 +356,8 @@ void UpdateDiffItem(DIFFITEM & di, BOOL & bExists, CDiffContext *pCtxt)
  *
  * @param [in] di DiffItem to compare
  * @param [in,out] pCtxt Compare context: contains difflist, encoding info etc.
+ * @todo For date compare, maybe we should use creation date if modification
+ * date is missing?
  */
 void CompareDiffItem(DIFFITEM di, CDiffContext * pCtxt)
 {
@@ -405,19 +407,33 @@ void CompareDiffItem(DIFFITEM di, CDiffContext * pCtxt)
                                pCtxt->m_nCompMethod == CMP_DATE_SIZE)
                        {
                                // Compare by modified date
-                               __int64 nTimeDiff = di.left.mtime - di.right.mtime;
-                               // Remove sign
-                               nTimeDiff = (nTimeDiff > 0 ? nTimeDiff : -nTimeDiff);
-                               if (pCtxt->m_bIgnoreSmallTimeDiff)
+                               // Check that we have both filetimes
+                               if (di.left.mtime != 0 && di.right.mtime != 0)
                                {
-                                       // If option to ignore small timediffs (couple of seconds)
-                                       // is set, decrease absolute difference by allowed diff
-                                       nTimeDiff -= SmallTimeDiff;
+                                       __int64 nTimeDiff = di.left.mtime - di.right.mtime;
+                                       // Remove sign
+                                       nTimeDiff = (nTimeDiff > 0 ? nTimeDiff : -nTimeDiff);
+                                       if (pCtxt->m_bIgnoreSmallTimeDiff)
+                                       {
+                                               // If option to ignore small timediffs (couple of seconds)
+                                               // is set, decrease absolute difference by allowed diff
+                                               nTimeDiff -= SmallTimeDiff;
+                                       }
+                                       if (nTimeDiff <= 0)
+                                               di.diffcode |= DIFFCODE::TEXT | DIFFCODE::SAME;
+                                       else
+                                               di.diffcode |= DIFFCODE::TEXT | DIFFCODE::DIFF;
                                }
-                               if (nTimeDiff <= 0)
-                                       di.diffcode |= DIFFCODE::TEXT | DIFFCODE::SAME;
                                else
-                                       di.diffcode |= DIFFCODE::TEXT | DIFFCODE::DIFF;
+                               {
+                                       // Filetimes for item(s) could not be read. So we have to
+                                       // set error status, unless we have DATE_SIZE -compare
+                                       // when we have still hope for size compare..
+                                       if (pCtxt->m_nCompMethod == CMP_DATE_SIZE)
+                                               di.diffcode |= DIFFCODE::TEXT | DIFFCODE::SAME;
+                                       else
+                                               di.diffcode |= DIFFCODE::TEXT | DIFFCODE::CMPERR;
+                               }
                                
                                // This is actual CMP_DATE_SIZE method..
                                // If file sizes differ mark them different
@@ -472,7 +488,16 @@ void LoadAndSortFiles(const CString & sDir, fentryArray * dirs, fentryArray * fi
 }
 
 /**
- * @brief Load arrays with all directories & files in specified dir
+ * @brief Find files and subfolders from given folder.
+ * This function saves all files and subfolders in given folder to arrays.
+ * We use 64-bit version of stat() to get times since find doesn't return
+ * valid times for very old files (around year 1970). Even stat() seems to
+ * give negative time values but we can live with that. Those around 1970
+ * times can happen when file is created so that it  doesn't get valid
+ * creation or modificatio dates.
+ * @param [in] sDir Base folder for files and subfolders.
+ * @param [in, out] dirs Array where subfolders are stored.
+ * @param [in, out] files Array where files are stored.
  */
 void LoadFiles(const CString & sDir, fentryArray * dirs, fentryArray * files)
 {
@@ -489,14 +514,28 @@ void LoadFiles(const CString & sDir, fentryArray * dirs, fentryArray * files)
                        DWORD dwIsDirectory = ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
                        if (dwIsDirectory && StrStr(_T(".."), ff.cFileName))
                                continue;
+
                        fentry ent;
-                       // Save filetimes as seconds since January 1, 1970
-                       ent.ctime = CTime(ff.ftCreationTime).GetTime();
-                       ent.mtime = CTime(ff.ftLastWriteTime).GetTime();
-                       if (!dwIsDirectory)
-                               ent.size = FileInfo::GetSizeFromFindData(ff);
-                       else
-                               ent.size = -1;  // No size for directories
+                       CString fullpath = paths_ConcatPath(sDir, ff.cFileName);
+                       struct _stati64 fstats;
+                       if (_tstati64(fullpath, &fstats) == 0)
+                       {
+                               // Save filetimes as seconds since January 1, 1970
+                               // Note that times can be < 0 if they are around that 1970..
+                               // Anyway that is not sensible case for normal files so we can
+                               // just use zero for their time.
+                               ent.ctime = fstats.st_ctime;
+                               if (ent.ctime < 0)
+                                       ent.ctime = 0;
+                               ent.mtime = fstats.st_mtime;
+                               if (ent.mtime < 0)
+                                       ent.mtime = 0;
+
+                               if (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                                       ent.size = -1;  // No size for directories
+                               else
+                                       ent.size = fstats.st_size;
+                       }
                        ent.name = ff.cFileName;
                        ent.attrs = ff.dwFileAttributes;
                        (dwIsDirectory ? dirs : files) -> Add(ent);
index 38d7264..0a3b072 100644 (file)
@@ -199,7 +199,7 @@ void CDirView::ReflectGetdispinfo(NMLVDISPINFO *pParam)
        int nIdx = pParam->item.iItem;
        int i = ColPhysToLog(pParam->item.iSubItem);
        POSITION key = GetItemKey(nIdx);
-       if (key == (POSITION) SPECIAL_ITEM_POS)
+       if (key == SPECIAL_ITEM_POS)
        {
                if (IsColName(i))
                {
@@ -215,13 +215,13 @@ void CDirView::ReflectGetdispinfo(NMLVDISPINFO *pParam)
        {
                CString s = ColGetTextToDisplay(&ctxt, i, di);
                // Add '*' to newer time field
-               if
-               (
-                       (IsColLmTime(i) && di.left.mtime > di.right.mtime) // Left modification time
-               ||      (IsColRmTime(i) && di.left.mtime < di.right.mtime) // Right modification time
-               )
+               if (di.left.mtime != 0 || di.right.mtime != 0)
                {
-                       s.Insert(0, _T("* "));
+                       if ((IsColLmTime(i) && di.left.mtime > di.right.mtime) ||
+                               (IsColRmTime(i) && di.left.mtime < di.right.mtime))
+                       {
+                               s.Insert(0, _T("* "));
+                       }
                }
                // Don't show result for folderitems appearing both sides
                if ((IsColStatus(i) || IsColStatusAbbr(i)) &&
index 611c3a8..53fe23c 100644 (file)
@@ -66,10 +66,10 @@ static int sign64(__int64 val)
 }
 /**
  * @brief Function to compare two diffcodes for a sort
+ * @todo How shall we order diff statuses?
  */
 static int cmpdiffcode(int diffcode1, int diffcode2)
 {
-       // TODO: How shall we order these ?
        return diffcode1-diffcode2;     
 }
 /**
index ce048af..740a0c1 100644 (file)
 // $Id$
 
 #include "stdafx.h"
+#include <sys/types.h>
+#include <sys/stat.h>
 #include "FileInfo.h"
 
 /**
- * @brief Convert a FILETIME to a long (standard time)
- */
-static __int64 FileTimeToInt64(FILETIME & ft)
-{
-       return CTime(ft).GetTime();
-}
-
-/**
  * @brief Update fileinfo from given file
  * @param [in] sFilePath Full path to file/directory to update
+ * @return TRUE if information was updated (item was found).
  */
-void FileInfo::Update(CString sFilePath)
+BOOL FileInfo::Update(CString sFilePath)
 {
-       // CFileFind doesn't expose the attributes
-       // CFileStatus doesn't expose 64 bit size
-
-       WIN32_FIND_DATA wfd;
-       HANDLE h = FindFirstFile(sFilePath, &wfd);
+       struct _stati64 fstats;
        __int64 mtime64 = 0;
+       BOOL retVal = FALSE;
+
        size = -1;
        flags.reset();
        mtime = 0;
-       if (h != INVALID_HANDLE_VALUE)
+
+       if (_tstati64(sFilePath, &fstats) == 0)
        {
-               mtime64 = FileTimeToInt64(wfd.ftLastWriteTime);
-               flags.attributes = wfd.dwFileAttributes;
+               // There can be files without modification date.
+               // Then we must use creation date. Of course we assume
+               // creation date then exists...
+               if (fstats.st_mtime == 0)
+                       mtime64 = fstats.st_ctime;
+               else
+                       mtime64 = fstats.st_mtime;
 
-               // No size for directory ( size remains as -1)$
+               flags.attributes = GetFileAttributes(sFilePath);
+
+               // No size for directory ( size remains as -1)
                if ((flags.attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
-                       size = FileInfo::GetSizeFromFindData(wfd);
-               FindClose(h);
+                       size = fstats.st_size;
+
+               retVal = TRUE;
        }
        mtime = mtime64;
+       return retVal;
 }
 
 /**
@@ -72,28 +75,3 @@ void FileInfo::Clear()
        version.Empty();
        flags.reset();
 }
-
-/**
- * @brief Returns 64-bit filesize from Windows Find Data.
- * This function calculates 64-bit filesize from given find-data where
- * filesize is in two variables.
- * @param [in] findData Find-data to get filesize.
- * @return 64-bit filesize.
- */
-__int64 FileInfo::GetSizeFromFindData(const WIN32_FIND_DATA & findData)
-{
-       __int64 tmpSize = 0;
-       // Get file's size. If more than 31 bits is needed then we need to
-       // calculate full 64 bits. Since size is signed variable.
-       if (findData.nFileSizeHigh > 0 || findData.nFileSizeLow > INT_MAX)
-       {
-               tmpSize = findData.nFileSizeHigh;
-               tmpSize = tmpSize << 32;
-               tmpSize += findData.nFileSizeLow;
-       }
-       else
-       {
-               tmpSize = findData.nFileSizeLow;
-       }
-       return tmpSize;
-}
index 2d6650e..f98420a 100644 (file)
@@ -36,12 +36,13 @@ struct FileFlags
 };
 
 /**
- * @brief Information for file
+ * @brief Information for file.
+ * This class stores basic information from a file or folder.
+ * Information consists of file times, size and attributes.
+ * Also version info can be get for files supporting it.
  */
 struct FileInfo
 {
-       // storing __time_t if MSVC6 (__MSC_VER<1300)
-       // storing __time64_t if MSVC7 (VC.NET)
        __int64 ctime; /**< time of creation */
        __int64 mtime; /**< time of last modify */
        __int64 size; /**< file size in bytes, -1 means file does not exist*/
@@ -49,10 +50,8 @@ struct FileInfo
        FileFlags flags; /**< file attributes */
        FileInfo() { Clear(); }
 
-       void Update(CString sFilePath);
+       BOOL Update(CString sFilePath);
        void Clear();
-
-       static __int64 GetSizeFromFindData(const WIN32_FIND_DATA & findData);
 };
 
 #endif // _FILE_INFO_H_INCLUDED