| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 | 
							- ///////////////////////////////////////////////////////////////////////////////
 
- // Name:        tests/streams/largefile.cpp
 
- // Purpose:     Tests for large file support
 
- // Author:      Mike Wetherell
 
- // Copyright:   (c) 2004 Mike Wetherell
 
- // Licence:     wxWindows licence
 
- ///////////////////////////////////////////////////////////////////////////////
 
- //
 
- // We're interested in what happens around offsets 0x7fffffff and 0xffffffff
 
- // so the test writes a small chunk of test data just before and just after
 
- // these offsets, then reads them back.
 
- //
 
- // The tests can be run with:
 
- //
 
- //  test --verbose largeFile
 
- //
 
- // On systems supporting sparse files they will also be registered in the
 
- // Streams subsuite so that they run by default.
 
- //
 
- // For compilers that support precompilation, includes "wx/wx.h".
 
- #include "testprec.h"
 
- #ifdef __BORLANDC__
 
-     #pragma hdrstop
 
- #endif
 
- // for all others, include the necessary headers
 
- #ifndef WX_PRECOMP
 
-     #include "wx/wx.h"
 
- #endif
 
- #include "wx/filename.h"
 
- #include "wx/wfstream.h"
 
- #ifdef __WINDOWS__
 
-     #include "wx/msw/wrapwin.h"
 
-     #ifdef __VISUALC__
 
-         // 'nonstandard extension used : nameless struct/union' occurs inside
 
-         // winioctl.h
 
-         #pragma warning(disable:4201)
 
-     #endif
 
-     #include <winioctl.h>
 
-     #ifdef __VISUALC__
 
-         #pragma warning(default:4201)
 
-     #endif
 
- #endif
 
- #ifdef __VISUALC__
 
-     #define fileno _fileno
 
- #endif
 
- using std::auto_ptr;
 
- ///////////////////////////////////////////////////////////////////////////////
 
- // Helpers
 
- bool IsFAT(const wxString& path);
 
- void MakeSparse(const wxString& path, int fd);
 
- ///////////////////////////////////////////////////////////////////////////////
 
- // Base class for the test cases - common code
 
- class LargeFileTest : public CppUnit::TestCase
 
- {
 
- public:
 
-     LargeFileTest(std::string name) : CppUnit::TestCase(name) { }
 
-     virtual ~LargeFileTest() { }
 
- protected:
 
-     void runTest();
 
-     virtual wxInputStream *MakeInStream(const wxString& name) const = 0;
 
-     virtual wxOutputStream *MakeOutStream(const wxString& name) const = 0;
 
-     virtual bool HasLFS() const = 0;
 
- };
 
- void LargeFileTest::runTest()
 
- {
 
-     // self deleting temp file
 
-     struct TmpFile {
 
-         TmpFile() : m_name(wxFileName::CreateTempFileName(wxT("wxlfs-"))) { }
 
-         ~TmpFile() { if (!m_name.empty()) wxRemoveFile(m_name); }
 
-         wxString m_name;
 
-     } tmpfile;
 
-     CPPUNIT_ASSERT(!tmpfile.m_name.empty());
 
-     bool haveLFS = true;
 
-     bool fourGigLimit = false;
 
-     if (!HasLFS()) {
 
-         haveLFS = false;
 
-         wxString n(getName().c_str(), *wxConvCurrent);
 
-         wxLogInfo(n + wxT(": No large file support, testing up to 2GB only"));
 
-     }
 
-     else if (IsFAT(tmpfile.m_name)) {
 
-         fourGigLimit = true;
 
-         wxString n(getName().c_str(), *wxConvCurrent);
 
-         wxLogInfo(n + wxT(": FAT volumes are limited to 4GB files"));
 
-     }
 
-     // size of the test blocks
 
-     const size_t size = 0x40;
 
-     // the test blocks
 
-     char upto2Gig[size];
 
-     char past2Gig[size];
 
-     char upto4Gig[size];
 
-     char past4Gig[size];
 
-     memset(upto2Gig, 'A', size);
 
-     memset(past2Gig, 'B', size);
 
-     memset(upto4Gig, 'X', size);
 
-     memset(past4Gig, 'Y', size);
 
-     wxFileOffset pos;
 
-     // write a large file
 
-     {
 
-         auto_ptr<wxOutputStream> out(MakeOutStream(tmpfile.m_name));
 
-         // write 'A's at [ 0x7fffffbf, 0x7fffffff [
 
-         pos = 0x7fffffff - size;
 
-         CPPUNIT_ASSERT(out->SeekO(pos) == pos);
 
-         CPPUNIT_ASSERT(out->Write(upto2Gig, size).LastWrite() == size);
 
-         pos += size;
 
-         if (haveLFS) {
 
-             // write 'B's at [ 0x7fffffff, 0x8000003f [
 
-             CPPUNIT_ASSERT(out->Write(past2Gig, size).LastWrite() == size);
 
-             pos += size;
 
-             CPPUNIT_ASSERT(out->TellO() == pos);
 
-             // write 'X's at [ 0xffffffbf, 0xffffffff [
 
-             pos = 0xffffffff - size;
 
-             CPPUNIT_ASSERT(out->SeekO(pos) == pos);
 
-             CPPUNIT_ASSERT(out->Write(upto4Gig, size).LastWrite() == size);
 
-             pos += size;
 
-             if (!fourGigLimit) {
 
-                 // write 'Y's at [ 0xffffffff, 0x10000003f [
 
-                 CPPUNIT_ASSERT(out->Write(past4Gig, size).LastWrite() == size);
 
-                 pos += size;
 
-             }
 
-         }
 
-         // check the file seems to be the right length
 
-         CPPUNIT_ASSERT(out->TellO() == pos);
 
-         CPPUNIT_ASSERT(out->GetLength() == pos);
 
-     }
 
-     // read the large file back
 
-     {
 
-         auto_ptr<wxInputStream> in(MakeInStream(tmpfile.m_name));
 
-         char buf[size];
 
-         if (haveLFS) {
 
-             CPPUNIT_ASSERT(in->GetLength() == pos);
 
-             pos = 0xffffffff;
 
-             if (!fourGigLimit) {
 
-                 CPPUNIT_ASSERT(in->GetLength() > pos);
 
-                 // read back the 'Y's at [ 0xffffffff, 0x10000003f [
 
-                 CPPUNIT_ASSERT(in->SeekI(pos) == pos);
 
-                 CPPUNIT_ASSERT(in->Read(buf, size).LastRead() == size);
 
-                 CPPUNIT_ASSERT(memcmp(buf, past4Gig, size) == 0);
 
-                 CPPUNIT_ASSERT(in->TellI() == in->GetLength());
 
-             }
 
-             // read back the 'X's at [ 0xffffffbf, 0xffffffff [
 
-             pos -= size;
 
-             CPPUNIT_ASSERT(in->SeekI(pos) == pos);
 
-             CPPUNIT_ASSERT(in->Read(buf, size).LastRead() == size);
 
-             CPPUNIT_ASSERT(memcmp(buf, upto4Gig, size) == 0);
 
-             pos += size;
 
-             CPPUNIT_ASSERT(in->TellI() == pos);
 
-             // read back the 'B's at [ 0x7fffffff, 0x8000003f [
 
-             pos = 0x7fffffff;
 
-             CPPUNIT_ASSERT(in->SeekI(pos) == pos);
 
-             CPPUNIT_ASSERT(in->Read(buf, size).LastRead() == size);
 
-             CPPUNIT_ASSERT(memcmp(buf, past2Gig, size) == 0);
 
-         }
 
-         else {
 
-             CPPUNIT_ASSERT(in->GetLength() == 0x7fffffff);
 
-             pos = 0x7fffffff;
 
-         }
 
-         // read back the 'A's at [ 0x7fffffbf, 0x7fffffff [
 
-         pos -= size;
 
-         CPPUNIT_ASSERT(in->SeekI(pos) == pos);
 
-         CPPUNIT_ASSERT(in->Read(buf, size).LastRead() == size);
 
-         CPPUNIT_ASSERT(memcmp(buf, upto2Gig, size) == 0);
 
-         pos += size;
 
-         CPPUNIT_ASSERT(in->TellI() == pos);
 
-     }
 
- }
 
- ///////////////////////////////////////////////////////////////////////////////
 
- // wxFile test case
 
- class LargeFileTest_wxFile : public LargeFileTest
 
- {
 
- public:
 
-     LargeFileTest_wxFile() : LargeFileTest("wxFile streams") { }
 
- protected:
 
-     wxInputStream *MakeInStream(const wxString& name) const;
 
-     wxOutputStream *MakeOutStream(const wxString& name) const;
 
-     bool HasLFS() const { return (wxFileOffset)0xffffffff > 0; }
 
- };
 
- wxInputStream *LargeFileTest_wxFile::MakeInStream(const wxString& name) const
 
- {
 
-     auto_ptr<wxFileInputStream> in(new wxFileInputStream(name));
 
-     CPPUNIT_ASSERT(in->IsOk());
 
-     return in.release();
 
- }
 
- wxOutputStream *LargeFileTest_wxFile::MakeOutStream(const wxString& name) const
 
- {
 
-     wxFile file(name, wxFile::write);
 
-     CPPUNIT_ASSERT(file.IsOpened());
 
-     int fd = file.fd();
 
-     file.Detach();
 
-     MakeSparse(name, fd);
 
-     return new wxFileOutputStream(fd);
 
- }
 
- ///////////////////////////////////////////////////////////////////////////////
 
- // wxFFile test case
 
- class LargeFileTest_wxFFile : public LargeFileTest
 
- {
 
- public:
 
-     LargeFileTest_wxFFile() : LargeFileTest("wxFFile streams") { }
 
- protected:
 
-     wxInputStream *MakeInStream(const wxString& name) const;
 
-     wxOutputStream *MakeOutStream(const wxString& name) const;
 
-     bool HasLFS() const;
 
- };
 
- wxInputStream *LargeFileTest_wxFFile::MakeInStream(const wxString& name) const
 
- {
 
-     auto_ptr<wxFFileInputStream> in(new wxFFileInputStream(name));
 
-     CPPUNIT_ASSERT(in->IsOk());
 
-     return in.release();
 
- }
 
- wxOutputStream *LargeFileTest_wxFFile::MakeOutStream(const wxString& name) const
 
- {
 
-     wxFFile file(name, wxT("w"));
 
-     CPPUNIT_ASSERT(file.IsOpened());
 
-     FILE *fp = file.fp();
 
-     file.Detach();
 
-     MakeSparse(name, fileno(fp));
 
-     return new wxFFileOutputStream(fp);
 
- }
 
- bool LargeFileTest_wxFFile::HasLFS() const
 
- {
 
- #ifdef wxHAS_LARGE_FFILES
 
-     return true;
 
- #else
 
-     return false;
 
- #endif
 
- }
 
- ///////////////////////////////////////////////////////////////////////////////
 
- // The suite
 
- class largeFile : public CppUnit::TestSuite
 
- {
 
- public:
 
-     largeFile() : CppUnit::TestSuite("largeFile") { }
 
-     static CppUnit::Test *suite();
 
- };
 
- CppUnit::Test *largeFile::suite()
 
- {
 
-     largeFile *suite = new largeFile;
 
-     suite->addTest(new LargeFileTest_wxFile);
 
-     suite->addTest(new LargeFileTest_wxFFile);
 
-     return suite;
 
- }
 
- ///////////////////////////////////////////////////////////////////////////////
 
- // Implement the helpers
 
- //
 
- // Ideally these tests will be part of the default suite so that regressions
 
- // are picked up. However this is only possible when sparse files are
 
- // supported otherwise the tests require too much disk space.
 
- #ifdef __WINDOWS__
 
- #ifndef FILE_SUPPORTS_SPARSE_FILES
 
- #define FILE_SUPPORTS_SPARSE_FILES 0x00000040
 
- #endif
 
- #ifndef FSCTL_SET_SPARSE
 
- #   ifndef FILE_SPECIAL_ACCESS
 
- #       define FILE_SPECIAL_ACCESS FILE_ANY_ACCESS
 
- #   endif
 
- #   define FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, \
 
-                                      METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
 
- #endif
 
- static DWORD  volumeFlags;
 
- static wxChar volumeType[64];
 
- static bool   volumeInfoInit;
 
- void GetVolumeInfo(const wxString& path)
 
- {
 
-     // extract the volume 'C:\' or '\\tooter\share\' from the path
 
-     wxString vol;
 
-     if (path.substr(1, 2) == wxT(":\\")) {
 
-         vol = path.substr(0, 3);
 
-     } else {
 
-         if (path.substr(0, 2) == wxT("\\\\")) {
 
-             size_t i = path.find(wxT('\\'), 2);
 
-             if (i != wxString::npos && i > 2) {
 
-                 size_t j = path.find(wxT('\\'), ++i);
 
-                 if (j != i)
 
-                     vol = path.substr(0, j) + wxT("\\");
 
-             }
 
-         }
 
-     }
 
-     // NULL means the current volume
 
-     const wxChar *pVol = vol.empty() ? (const wxChar *)NULL
 
-                                      : vol.c_str();
 
-     if (!::GetVolumeInformation(pVol, NULL, 0, NULL, NULL,
 
-                                 &volumeFlags,
 
-                                 volumeType,
 
-                                 WXSIZEOF(volumeType)))
 
-     {
 
-         wxLogSysError(wxT("GetVolumeInformation() failed"));
 
-     }
 
-     volumeInfoInit = true;
 
- }
 
- bool IsFAT(const wxString& path)
 
- {
 
-     if (!volumeInfoInit)
 
-         GetVolumeInfo(path);
 
-     return wxString(volumeType).Upper().find(wxT("FAT")) != wxString::npos;
 
- }
 
- void MakeSparse(const wxString& path, int fd)
 
- {
 
-     DWORD cb;
 
-     if (!volumeInfoInit)
 
-         GetVolumeInfo(path);
 
-     if ((volumeFlags & FILE_SUPPORTS_SPARSE_FILES) != 0)
 
-         if (!::DeviceIoControl((HANDLE)_get_osfhandle(fd),
 
-                                FSCTL_SET_SPARSE,
 
-                                NULL, 0, NULL, 0, &cb, NULL))
 
-             volumeFlags &= ~FILE_SUPPORTS_SPARSE_FILES;
 
- }
 
- // return the suite if sparse files are supported, otherwise return NULL
 
- //
 
- CppUnit::Test* GetlargeFileSuite()
 
- {
 
-     if (!volumeInfoInit) {
 
-         wxString path;
 
-         {
 
-             wxFile file;
 
-             path = wxFileName::CreateTempFileName(wxT("wxlfs-"), &file);
 
-             MakeSparse(path, file.fd());
 
-         }
 
-         wxRemoveFile(path);
 
-     }
 
-     if ((volumeFlags & FILE_SUPPORTS_SPARSE_FILES) != 0)
 
-         return largeFile::suite();
 
-     else
 
-         return NULL;
 
- }
 
- #else // __WINDOWS__
 
- bool IsFAT(const wxString& WXUNUSED(path)) { return false; }
 
- void MakeSparse(const wxString& WXUNUSED(path), int WXUNUSED(fd)) { }
 
- // return the suite if sparse files are supported, otherwise return NULL
 
- //
 
- CppUnit::Test* GetlargeFileSuite()
 
- {
 
-     wxString path;
 
-     struct stat st1, st2;
 
-     memset(&st1, 0, sizeof(st1));
 
-     memset(&st2, 0, sizeof(st2));
 
-     {
 
-         wxFile file;
 
-         path = wxFileName::CreateTempFileName(wxT("wxlfs-"), &file);
 
-         fstat(file.fd(), &st1);
 
-         file.Seek(st1.st_blksize);
 
-         file.Write("x", 1);
 
-         fstat(file.fd(), &st1);
 
-         file.Seek(0);
 
-         file.Write("x", 1);
 
-         fstat(file.fd(), &st2);
 
-     }
 
-     wxRemoveFile(path);
 
-     if (st1.st_blocks != st2.st_blocks)
 
-         return largeFile::suite();
 
-     else
 
-         return NULL;
 
- }
 
- #endif // __WINDOWS__
 
- CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(largeFile, "largeFile");
 
- CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(largeFile, "Streams.largeFile");
 
 
  |