Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/other-licenses/7zstub/src/CPP/Windows/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  FileFind.cpp   Sprache: C

 
// Windows/FileFind.cpp

#include "StdAfx.h"

#ifndef _UNICODE
#include "../Common/StringConvert.h"
#endif

#include "FileFind.h"
#include "FileIO.h"
#include "FileName.h"

#ifndef _UNICODE
extern bool g_IsNT;
#endif

using namespace NWindows;
using namespace NFile;
using namespace NName;

#if defined(_WIN32) && !defined(UNDER_CE)

EXTERN_C_BEGIN

typedef enum
{
  My_FindStreamInfoStandard,
  My_FindStreamInfoMaxInfoLevel
} MY_STREAM_INFO_LEVELS;

typedef struct
{
  LARGE_INTEGER StreamSize;
  WCHAR cStreamName[MAX_PATH + 36];
} MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA;

typedef WINBASEAPI HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel,
    LPVOID findStreamData, DWORD flags);

typedef WINBASEAPI BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData);

EXTERN_C_END

#endif

namespace NWindows {
namespace NFile {

#ifdef SUPPORT_DEVICE_FILE
namespace NSystem
{
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
}
#endif

namespace NFind {

bool CFileInfo::IsDots() const throw()
{
  if (!IsDir() || Name.IsEmpty())
    return false;
  if (Name[0] != '.')
    return false;
  return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.');
}

#define WIN_FD_TO_MY_FI(fi, fd) \
  fi.Attrib = fd.dwFileAttributes; \
  fi.CTime = fd.ftCreationTime; \
  fi.ATime = fd.ftLastAccessTime; \
  fi.MTime = fd.ftLastWriteTime; \
  fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \
  fi.IsAltStream = false; \
  fi.IsDevice = false;

  /*
  #ifdef UNDER_CE
  fi.ObjectID = fd.dwOID;
  #else
  fi.ReparseTag = fd.dwReserved0;
  #endif
  */


static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi)
{
  WIN_FD_TO_MY_FI(fi, fd);
  fi.Name = us2fs(fd.cFileName);
  #if defined(_WIN32) && !defined(UNDER_CE)
  // fi.ShortName = us2fs(fd.cAlternateFileName);
  #endif
}

#ifndef _UNICODE

static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi)
{
  WIN_FD_TO_MY_FI(fi, fd);
  fi.Name = fas2fs(fd.cFileName);
  #if defined(_WIN32) && !defined(UNDER_CE)
  // fi.ShortName = fas2fs(fd.cAlternateFileName);
  #endif
}
#endif
  
////////////////////////////////
// CFindFile

bool CFindFileBase::Close() throw()
{
  if (_handle == INVALID_HANDLE_VALUE)
    return true;
  if (!::FindClose(_handle))
    return false;
  _handle = INVALID_HANDLE_VALUE;
  return true;
}

/*
WinXP-64 FindFirstFile():
  ""      -  ERROR_PATH_NOT_FOUND
  folder\ -  ERROR_FILE_NOT_FOUND
  \       -  ERROR_FILE_NOT_FOUND
  c:\     -  ERROR_FILE_NOT_FOUND
  c:      -  ERROR_FILE_NOT_FOUND, if current dir is ROOT     ( c:\ )
  c:      -  OK,                   if current dir is NOT ROOT ( c:\folder )
  folder  -  OK

  \\               - ERROR_INVALID_NAME
  \\Server         - ERROR_INVALID_NAME
  \\Server\        - ERROR_INVALID_NAME
      
  \\Server\Share            - ERROR_BAD_NETPATH
  \\Server\Share            - ERROR_BAD_NET_NAME (Win7).
             !!! There is problem : Win7 makes some requests for "\\Server\Shar" (look in Procmon),
                 when we call it for "\\Server\Share"
                      
  \\Server\Share\           - ERROR_FILE_NOT_FOUND
  
  \\?\UNC\Server\Share      - ERROR_INVALID_NAME
  \\?\UNC\Server\Share      - ERROR_BAD_PATHNAME (Win7)
  \\?\UNC\Server\Share\     - ERROR_FILE_NOT_FOUND
  
  \\Server\Share_RootDrive  - ERROR_INVALID_NAME
  \\Server\Share_RootDrive\ - ERROR_INVALID_NAME
  
  c:\* - ERROR_FILE_NOT_FOUND, if thare are no item in that folder
*/


bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi)
{
  if (!Close())
    return false;
  #ifndef _UNICODE
  if (!g_IsNT)
  {
    WIN32_FIND_DATAA fd;
    _handle = ::FindFirstFileA(fs2fas(path), &fd);
    if (_handle == INVALID_HANDLE_VALUE)
      return false;
    Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
  }
  else
  #endif
  {
    WIN32_FIND_DATAW fd;

    IF_USE_MAIN_PATH
      _handle = ::FindFirstFileW(fs2us(path), &fd);
    #ifdef WIN_LONG_PATH
    if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
    {
      UString superPath;
      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
        _handle = ::FindFirstFileW(superPath, &fd);
    }
    #endif
    if (_handle == INVALID_HANDLE_VALUE)
      return false;
    Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
  }
  return true;
}

bool CFindFile::FindNext(CFileInfo &fi)
{
  #ifndef _UNICODE
  if (!g_IsNT)
  {
    WIN32_FIND_DATAA fd;
    if (!::FindNextFileA(_handle, &fd))
      return false;
    Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
  }
  else
  #endif
  {
    WIN32_FIND_DATAW fd;
    if (!::FindNextFileW(_handle, &fd))
      return false;
    Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
  }
  return true;
}

#if defined(_WIN32) && !defined(UNDER_CE)

////////////////////////////////
// AltStreams

static FindFirstStreamW_Ptr g_FindFirstStreamW;
static FindNextStreamW_Ptr g_FindNextStreamW;

struct CFindStreamLoader
{
  CFindStreamLoader()
  {
    g_FindFirstStreamW = (FindFirstStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindFirstStreamW");
    g_FindNextStreamW = (FindNextStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindNextStreamW");
  }
} g_FindStreamLoader;

bool CStreamInfo::IsMainStream() const throw()
{
  return StringsAreEqualNoCase_Ascii(Name, "::$DATA");
};

UString CStreamInfo::GetReducedName() const
{
  // remove ":$DATA" postfix, but keep postfix, if Name is "::$DATA"
  UString s (Name);
  if (s.Len() > 6 + 1 && StringsAreEqualNoCase_Ascii(s.RightPtr(6), ":$DATA"))
    s.DeleteFrom(s.Len() - 6);
  return s;
}

/*
UString CStreamInfo::GetReducedName2() const
{
  UString s = GetReducedName();
  if (!s.IsEmpty() && s[0] == ':')
    s.Delete(0);
  return s;
}
*/


static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si)
{
  si.Size = sd.StreamSize.QuadPart;
  si.Name = sd.cStreamName;
}

/*
  WinXP-64 FindFirstStream():
  ""      -  ERROR_PATH_NOT_FOUND
  folder\ -  OK
  folder  -  OK
  \       -  OK
  c:\     -  OK
  c:      -  OK, if current dir is ROOT     ( c:\ )
  c:      -  OK, if current dir is NOT ROOT ( c:\folder )
  \\Server\Share   - OK
  \\Server\Share\  - OK

  \\               - ERROR_INVALID_NAME
  \\Server         - ERROR_INVALID_NAME
  \\Server\        - ERROR_INVALID_NAME
*/


bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si)
{
  if (!Close())
    return false;
  if (!g_FindFirstStreamW)
  {
    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return false;
  }
  {
    MY_WIN32_FIND_STREAM_DATA sd;
    SetLastError(0);
    IF_USE_MAIN_PATH
      _handle = g_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0);
    if (_handle == INVALID_HANDLE_VALUE)
    {
      if (::GetLastError() == ERROR_HANDLE_EOF)
        return false;
      // long name can be tricky for path like ".\dirName".
      #ifdef WIN_LONG_PATH
      if (USE_SUPER_PATH)
      {
        UString superPath;
        if (GetSuperPath(path, superPath, USE_MAIN_PATH))
          _handle = g_FindFirstStreamW(superPath, My_FindStreamInfoStandard, &sd, 0);
      }
      #endif
    }
    if (_handle == INVALID_HANDLE_VALUE)
      return false;
    Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si);
  }
  return true;
}

bool CFindStream::FindNext(CStreamInfo &si)
{
  if (!g_FindNextStreamW)
  {
    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return false;
  }
  {
    MY_WIN32_FIND_STREAM_DATA sd;
    if (!g_FindNextStreamW(_handle, &sd))
      return false;
    Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si);
  }
  return true;
}

bool CStreamEnumerator::Next(CStreamInfo &si, bool &found)
{
  bool res;
  if (_find.IsHandleAllocated())
    res = _find.FindNext(si);
  else
    res = _find.FindFirst(_filePath, si);
  if (res)
  {
    found = true;
    return true;
  }
  found = false;
  return (::GetLastError() == ERROR_HANDLE_EOF);
}

#endif


#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0;

void CFileInfoBase::ClearBase() throw()
{
  Size = 0;
  MY_CLEAR_FILETIME(CTime);
  MY_CLEAR_FILETIME(ATime);
  MY_CLEAR_FILETIME(MTime);
  Attrib = 0;
  IsAltStream = false;
  IsDevice = false;
}

/*
WinXP-64 GetFileAttributes():
  If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code

  \    - OK
  C:\  - OK, if there is such drive,
  D:\  - ERROR_PATH_NOT_FOUND, if there is no such drive,

  C:\folder     - OK
  C:\folder\    - OK
  C:\folderBad  - ERROR_FILE_NOT_FOUND

  \\Server\BadShare  - ERROR_BAD_NETPATH
  \\Server\Share     - WORKS OK, but MSDN says:
                          GetFileAttributes for a network share, the function fails, and GetLastError
                          returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share.
*/


DWORD GetFileAttrib(CFSTR path)
{
  #ifndef _UNICODE
  if (!g_IsNT)
    return ::GetFileAttributes(fs2fas(path));
  else
  #endif
  {
    IF_USE_MAIN_PATH
    {
      DWORD dw = ::GetFileAttributesW(fs2us(path));
      if (dw != INVALID_FILE_ATTRIBUTES)
        return dw;
    }
    #ifdef WIN_LONG_PATH
    if (USE_SUPER_PATH)
    {
      UString superPath;
      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
        return ::GetFileAttributesW(superPath);
    }
    #endif
    return INVALID_FILE_ATTRIBUTES;
  }
}

/* if path is "c:" or "c::" then CFileInfo::Find() returns name of current folder for that disk
   so instead of absolute path we have relative path in Name. That is not good in some calls */


/* In CFileInfo::Find() we want to support same names for alt streams as in CreateFile(). */

/* CFileInfo::Find()
We alow the following paths (as FindFirstFile):
  C:\folder
  c:                      - if current dir is NOT ROOT ( c:\folder )

also we support paths that are not supported by FindFirstFile:
  \
  \\.\c:
  c:\                     - Name will be without tail slash ( c: )
  \\?\c:\                 - Name will be without tail slash ( c: )
  \\Server\Share
  \\?\UNC\Server\Share

  c:\folder:stream  - Name = folder:stream
  c:\:stream        - Name = :stream
  c::stream         - Name = c::stream
*/


bool CFileInfo::Find(CFSTR path)
{
  #ifdef SUPPORT_DEVICE_FILE
  if (IsDevicePath(path))
  {
    ClearBase();
    Name = path + 4;
    IsDevice = true;
    
    if (NName::IsDrivePath2(path + 4) && path[6] == 0)
    {
      FChar drive[4] = { path[4], ':''\\', 0 };
      UInt64 clusterSize, totalSize, freeSize;
      if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize))
      {
        Size = totalSize;
        return true;
      }
    }

    NIO::CInFile inFile;
    // ::OutputDebugStringW(path);
    if (!inFile.Open(path))
      return false;
    // ::OutputDebugStringW(L"---");
    if (inFile.SizeDefined)
      Size = inFile.Size;
    return true;
  }
  #endif

  #if defined(_WIN32) && !defined(UNDER_CE)

  int colonPos = FindAltStreamColon(path);
  if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0)
  {
    UString streamName = fs2us(path + (unsigned)colonPos);
    FString filePath (path);
    filePath.DeleteFrom(colonPos);
    /* we allow both cases:
      name:stream
      name:stream:$DATA
    */

    const unsigned kPostfixSize = 6;
    if (streamName.Len() <= kPostfixSize
        || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA"))
      streamName += ":$DATA";

    bool isOk = true;
    
    if (IsDrivePath2(filePath) &&
        (colonPos == 2 || colonPos == 3 && filePath[2] == '\\'))
    {
      // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT)
      ClearBase();
      Name.Empty();
      if (colonPos == 2)
        Name = filePath;
    }
    else
      isOk = Find(filePath);

    if (isOk)
    {
      Attrib &= ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
      Size = 0;
      CStreamEnumerator enumerator(filePath);
      for (;;)
      {
        CStreamInfo si;
        bool found;
        if (!enumerator.Next(si, found))
          return false;
        if (!found)
        {
          ::SetLastError(ERROR_FILE_NOT_FOUND);
          return false;
        }
        if (si.Name.IsEqualTo_NoCase(streamName))
        {
          // we delete postfix, if alt stream name is not "::$DATA"
          if (si.Name.Len() > kPostfixSize + 1)
            si.Name.DeleteFrom(si.Name.Len() - kPostfixSize);
          Name += us2fs(si.Name);
          Size = si.Size;
          IsAltStream = true;
          return true;
        }
      }
    }
  }
  
  #endif

  CFindFile finder;

  #if defined(_WIN32) && !defined(UNDER_CE)
  {
    /*
    DWORD lastError = GetLastError();
    if (lastError == ERROR_FILE_NOT_FOUND
        || lastError == ERROR_BAD_NETPATH  // XP64: "\\Server\Share"
        || lastError == ERROR_BAD_NET_NAME // Win7: "\\Server\Share"
        || lastError == ERROR_INVALID_NAME // XP64: "\\?\UNC\Server\Share"
        || lastError == ERROR_BAD_PATHNAME // Win7: "\\?\UNC\Server\Share"
        )
    */

    
    unsigned rootSize = 0;
    if (IsSuperPath(path))
      rootSize = kSuperPathPrefixSize;
    
    if (NName::IsDrivePath(path + rootSize) && path[rootSize + 3] == 0)
    {
      DWORD attrib = GetFileAttrib(path);
      if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
      {
        ClearBase();
        Attrib = attrib;
        Name = path + rootSize;
        Name.DeleteFrom(2); // we don't need backslash (C:)
        return true;
      }
    }
    else if (IS_PATH_SEPAR(path[0]))
      if (path[1] == 0)
      {
        DWORD attrib = GetFileAttrib(path);
        if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
        {
          ClearBase();
          Name.Empty();
          Attrib = attrib;
          return true;
        }
      }
      else
      {
        const unsigned prefixSize = GetNetworkServerPrefixSize(path);
        if (prefixSize > 0 && path[prefixSize] != 0)
        {
          if (NName::FindSepar(path + prefixSize) < 0)
          {
            FString s (path);
            s.Add_PathSepar();
            s += '*'// CHAR_ANY_MASK
            
            bool isOK = false;
            if (finder.FindFirst(s, *this))
            {
              if (Name == FTEXT("."))
              {
                Name = path + prefixSize;
                return true;
              }
              isOK = true;
              /* if "\\server\share" maps to root folder "d:\", there is no "." item.
                 But it's possible that there are another items */

            }
            {
              DWORD attrib = GetFileAttrib(path);
              if (isOK || attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
              {
                ClearBase();
                if (attrib != INVALID_FILE_ATTRIBUTES)
                  Attrib = attrib;
                else
                  SetAsDir();
                Name = path + prefixSize;
                return true;
              }
            }
            // ::SetLastError(lastError);
          }
        }
      }
  }
  #endif

  return finder.FindFirst(path, *this);
}


bool DoesFileExist(CFSTR name)
{
  CFileInfo fi;
  return fi.Find(name) && !fi.IsDir();
}

bool DoesDirExist(CFSTR name)
{
  CFileInfo fi;
  return fi.Find(name) && fi.IsDir();
}

bool DoesFileOrDirExist(CFSTR name)
{
  CFileInfo fi;
  return fi.Find(name);
}


void CEnumerator::SetDirPrefix(const FString &dirPrefix)
{
  _wildcard = dirPrefix;
  _wildcard += '*';
}

bool CEnumerator::NextAny(CFileInfo &fi)
{
  if (_findFile.IsHandleAllocated())
    return _findFile.FindNext(fi);
  else
    return _findFile.FindFirst(_wildcard, fi);
}

bool CEnumerator::Next(CFileInfo &fi)
{
  for (;;)
  {
    if (!NextAny(fi))
      return false;
    if (!fi.IsDots())
      return true;
  }
}

bool CEnumerator::Next(CFileInfo &fi, bool &found)
{
  if (Next(fi))
  {
    found = true;
    return true;
  }
  found = false;
  return (::GetLastError() == ERROR_NO_MORE_FILES);
}

////////////////////////////////
// CFindChangeNotification
// FindFirstChangeNotification can return 0. MSDN doesn't tell about it.

bool CFindChangeNotification::Close() throw()
{
  if (!IsHandleAllocated())
    return true;
  if (!::FindCloseChangeNotification(_handle))
    return false;
  _handle = INVALID_HANDLE_VALUE;
  return true;
}
           
HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter)
{
  #ifndef _UNICODE
  if (!g_IsNT)
    _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter);
  else
  #endif
  {
    IF_USE_MAIN_PATH
    _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter);
    #ifdef WIN_LONG_PATH
    if (!IsHandleAllocated())
    {
      UString superPath;
      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
        _handle = ::FindFirstChangeNotificationW(superPath, BoolToBOOL(watchSubtree), notifyFilter);
    }
    #endif
  }
  return _handle;
}

#ifndef UNDER_CE

bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings)
{
  driveStrings.Clear();
  #ifndef _UNICODE
  if (!g_IsNT)
  {
    driveStrings.Clear();
    UINT32 size = GetLogicalDriveStrings(0, NULL);
    if (size == 0)
      return false;
    CObjArray<char> buf(size);
    UINT32 newSize = GetLogicalDriveStrings(size, buf);
    if (newSize == 0 || newSize > size)
      return false;
    AString s;
    UINT32 prev = 0;
    for (UINT32 i = 0; i < newSize; i++)
    {
      if (buf[i] == 0)
      {
        s = buf + prev;
        prev = i + 1;
        driveStrings.Add(fas2fs(s));
      }
    }
    return prev == newSize;
  }
  else
  #endif
  {
    UINT32 size = GetLogicalDriveStringsW(0, NULL);
    if (size == 0)
      return false;
    CObjArray<wchar_t> buf(size);
    UINT32 newSize = GetLogicalDriveStringsW(size, buf);
    if (newSize == 0 || newSize > size)
      return false;
    UString s;
    UINT32 prev = 0;
    for (UINT32 i = 0; i < newSize; i++)
    {
      if (buf[i] == 0)
      {
        s = buf + prev;
        prev = i + 1;
        driveStrings.Add(us2fs(s));
      }
    }
    return prev == newSize;
  }
}

#endif

}}}

Messung V0.5
C=98 H=92 G=94

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.