Uploads: Fix big seeks on Windows. #2954
authorChristian Kamm <kamm@incasoftware.de>
Thu, 12 Mar 2015 12:18:08 +0000 (13:18 +0100)
committerChristian Kamm <kamm@incasoftware.de>
Thu, 12 Mar 2015 12:18:08 +0000 (13:18 +0100)
src/libsync/filesystem.cpp
src/libsync/filesystem.h
src/libsync/propagateupload.cpp

index ba94db03c4700266353a1506f98bc339f0de1119..8411d93c65c9386e2b1b12a014b7969ba2356fb2 100644 (file)
@@ -204,12 +204,12 @@ bool FileSystem::renameReplace(const QString& originFileName, const QString& des
     return true;
 }
 
-bool FileSystem::openFileSharedRead(QFile* file, QString* error)
+bool FileSystem::openAndSeekFileSharedRead(QFile* file, QString* errorOrNull, qint64 seek)
 {
-    bool ok = false;
-    if (error) {
-        error->clear();
-    }
+    QString errorDummy;
+    // avoid many if (errorOrNull) later.
+    QString& error = errorOrNull ? *errorOrNull : errorDummy;
+    error.clear();
 
 #ifdef Q_OS_WIN
     //
@@ -236,9 +236,7 @@ bool FileSystem::openFileSharedRead(QFile* file, QString* error)
 
     // Bail out on error.
     if (fileHandle == INVALID_HANDLE_VALUE) {
-        if (error) {
-            *error = qt_error_string();
-        }
+        error = qt_error_string();
         return false;
     }
 
@@ -247,19 +245,34 @@ bool FileSystem::openFileSharedRead(QFile* file, QString* error)
     // the fd the handle will be closed too.
     int fd = _open_osfhandle((intptr_t)fileHandle, _O_RDONLY);
     if (fd == -1) {
-        if (error) {
-            *error = "could not make fd from handle";
-        }
+        error = "could not make fd from handle";
+        return false;
+    }
+    if (!file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle)) {
+        error = file->errorString();
+        return false;
+    }
+
+    // Seek to the right spot
+    LARGE_INTEGER *li = reinterpret_cast<LARGE_INTEGER*>(&seek);
+    DWORD newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN);
+    if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
+        error = qt_error_string();
         return false;
     }
-    ok = file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle);
+
+    return true;
 #else
-    ok = file->open(QFile::ReadOnly);
-#endif
-    if (! ok && error) {
-        *error = file->errorString();
+    if (!file->open(QFile::ReadOnly)) {
+        error = file->errorString();
+        return false;
     }
-    return ok;
+    if (!file->seek(seek)) {
+        error = file->errorString();
+        return false;
+    }
+    return true;
+#endif
 }
 
 #ifdef Q_OS_WIN
index 845ffc4934fabecbe5a91ddc03354c6f89166382..eee0721eba3b1eb8555d29996fae7394860e1987 100644 (file)
@@ -75,13 +75,13 @@ bool renameReplace(const QString &originFileName, const QString &destinationFile
                    QString *errorString);
 
 /**
- * Replacement for QFile::open(ReadOnly) that sets a more permissive sharing mode
- * on Windows.
+ * Replacement for QFile::open(ReadOnly) followed by a seek().
+ * This version sets a more permissive sharing mode on Windows.
  *
  * Warning: The resuting file may have an empty fileName and be unsuitable for use
- * with QFileInfo!
+ * with QFileInfo! Calling seek() on the QFile with >32bit signed values will fail!
  */
-bool openFileSharedRead(QFile* file, QString* error);
+bool openAndSeekFileSharedRead(QFile* file, QString* error, qint64 seek);
 
 #ifdef Q_OS_WIN
 /**
index 49b213da40eb4d5f60d610b80e519abe5aa0c6fe..b16507c981b851e2748e4a863d036b6432588fcd 100644 (file)
@@ -232,17 +232,13 @@ bool UploadDevice::prepareAndOpen(const QString& fileName, qint64 start, qint64
 
     QFile file(fileName);
     QString openError;
-    if (!FileSystem::openFileSharedRead(&file, &openError)) {
+    if (!FileSystem::openAndSeekFileSharedRead(&file, &openError, start)) {
         setErrorString(openError);
         return false;
     }
 
-    size = qMin(FileSystem::getSize(fileName), size);
+    size = qBound(0ll, size, FileSystem::getSize(fileName) - start);
     _data.resize(size);
-    if (!file.seek(start)) {
-        setErrorString(file.errorString());
-        return false;
-    }
     auto read = file.read(_data.data(), size);
     if (read != size) {
         setErrorString(file.errorString());