summaryrefslogtreecommitdiffstats
path: root/libktorrent/util/mmapfile.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 02:37:40 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 02:37:40 +0000
commit9ad5c7b5e23b4940e7a3ea3ca3a6fb77e6a8fab0 (patch)
treed088b5210e77d9fa91d954d8550e00e372b47378 /libktorrent/util/mmapfile.cpp
downloadktorrent-9ad5c7b5e23b4940e7a3ea3ca3a6fb77e6a8fab0.tar.gz
ktorrent-9ad5c7b5e23b4940e7a3ea3ca3a6fb77e6a8fab0.zip
Updated to final KDE3 ktorrent release (2.2.6)
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktorrent@1077377 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libktorrent/util/mmapfile.cpp')
-rw-r--r--libktorrent/util/mmapfile.cpp294
1 files changed, 294 insertions, 0 deletions
diff --git a/libktorrent/util/mmapfile.cpp b/libktorrent/util/mmapfile.cpp
new file mode 100644
index 0000000..579c67a
--- /dev/null
+++ b/libktorrent/util/mmapfile.cpp
@@ -0,0 +1,294 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Joris Guisson *
+ * joris.guisson@gmail.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <qfile.h>
+#include <kfileitem.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <util/error.h>
+#include <util/log.h>
+#include <torrent/globals.h>
+#include "mmapfile.h"
+
+namespace bt
+{
+
+ MMapFile::MMapFile() : fd(-1),data(0),size(0),file_size(0),ptr(0),mode(READ)
+ {}
+
+
+ MMapFile::~MMapFile()
+ {
+ if (fd > 0)
+ close();
+ }
+
+ bool MMapFile::open(const QString & file,Mode mode)
+ {
+#if HAVE_STAT64
+ struct stat64 sb;
+ stat64(QFile::encodeName(file),&sb);
+#else
+ struct stat sb;
+ stat(QFile::encodeName(file),&sb);
+#endif
+
+ return open(file,mode,(Uint64)sb.st_size);
+ }
+
+ bool MMapFile::open(const QString & file,Mode mode,Uint64 size)
+ {
+ // close already open file
+ if (fd > 0)
+ close();
+
+ // setup flags
+ int flag = 0,mmap_flag = 0;
+ switch (mode)
+ {
+ case READ:
+ flag = O_RDONLY;
+ mmap_flag = PROT_READ;
+ break;
+ case WRITE:
+ flag = O_WRONLY | O_CREAT;
+ mmap_flag = PROT_WRITE;
+ break;
+ case RW:
+ flag = O_RDWR | O_CREAT;
+ mmap_flag = PROT_READ|PROT_WRITE;
+ break;
+ }
+
+ // Not all systems have O_LARGEFILE as an explicit flag
+ // (for instance, FreeBSD. Solaris does, but only if
+ // _LARGEFILE_SOURCE is defined in the compile).
+ // So OR it in if it is defined.
+#ifdef O_LARGEFILE
+ flag |= O_LARGEFILE;
+#endif
+
+ // open the file
+ fd = ::open(QFile::encodeName(file) , flag);//(int)flag);
+ if (fd == -1)
+ return false;
+
+ // read the file size
+ this->size = size;
+ this->mode = mode;
+
+#if HAVE_STAT64
+ struct stat64 sb;
+ stat64(QFile::encodeName(file),&sb);
+#else
+ struct stat sb;
+ stat(QFile::encodeName(file),&sb);
+#endif
+ file_size = (Uint64)sb.st_size;
+ filename = file;
+
+ // mmap the file
+#if HAVE_MMAP64
+ data = (Uint8*)mmap64(0, size, mmap_flag, MAP_SHARED, fd, 0);
+#else
+ data = (Uint8*)mmap(0, size, mmap_flag, MAP_SHARED, fd, 0);
+#endif
+ if (data == MAP_FAILED)
+ {
+ ::close(fd);
+ data = 0;
+ fd = -1;
+ ptr = 0;
+ return false;
+ }
+ ptr = 0;
+ return true;
+ }
+
+ void MMapFile::close()
+ {
+ if (fd > 0)
+ {
+#if HAVE_MUNMAP64
+ munmap64(data,size);
+#else
+ munmap(data,size);
+#endif
+ ::close(fd);
+ ptr = size = 0;
+ data = 0;
+ fd = -1;
+ filename = QString::null;
+ }
+ }
+
+ void MMapFile::flush()
+ {
+ if (fd > 0)
+ msync(data,size,MS_SYNC);
+ }
+
+ Uint32 MMapFile::write(const void* buf,Uint32 buf_size)
+ {
+ if (fd == -1 || mode == READ)
+ return 0;
+
+ // check if data fits in memory mapping
+ if (ptr + buf_size > size)
+ throw Error(i18n("Cannot write beyond end of the mmap buffer!"));
+
+ Out() << "MMapFile::write : " << (ptr + buf_size) << " " << file_size << endl;
+ // enlarge the file if necessary
+ if (ptr + buf_size > file_size)
+ {
+ growFile(ptr + buf_size);
+ }
+
+ // memcpy data
+ memcpy(&data[ptr],buf,buf_size);
+ // update ptr
+ ptr += buf_size;
+ // update file size if necessary
+ if (ptr >= size)
+ size = ptr;
+
+ return buf_size;
+ }
+
+ void MMapFile::growFile(Uint64 new_size)
+ {
+ Out() << "Growing file to " << new_size << " bytes " << endl;
+ Uint64 to_write = new_size - file_size;
+ ssize_t written;
+ // jump to the end of the file
+ lseek(fd,0,SEEK_END);
+
+ Uint8 buf[1024];
+ memset(buf,0,1024);
+ // write data until to_write is 0
+ while (to_write > 0)
+ {
+ ssize_t w = ::write(fd,buf, to_write > 1024 ? 1024 : to_write);
+ if (w > 0)
+ to_write -= w;
+ else if (w < 0)
+ break;
+ }
+ file_size = new_size;
+ }
+
+ Uint32 MMapFile::read(void* buf,Uint32 buf_size)
+ {
+ if (fd == -1 || mode == WRITE)
+ return 0;
+
+ // check if we aren't going to read past the end of the file
+ Uint32 to_read = ptr + buf_size >= size ? size - ptr : buf_size;
+ // read data
+ memcpy(buf,data+ptr,to_read);
+ ptr += to_read;
+ return to_read;
+ }
+
+ Uint64 MMapFile::seek(SeekPos from,Int64 num)
+ {
+ switch (from)
+ {
+ case BEGIN:
+ if (num > 0)
+ ptr = num;
+ if (ptr >= size)
+ ptr = size - 1;
+ break;
+ case END:
+ {
+ Int64 np = (size - 1) + num;
+ if (np < 0)
+ {
+ ptr = 0;
+ break;
+ }
+ if (np >= (Int64) size)
+ {
+ ptr = size - 1;
+ break;
+ }
+ ptr = np;
+ }
+ break;
+ case CURRENT:
+ {
+ Int64 np = ptr + num;
+ if (np < 0)
+ {
+ ptr = 0;
+ break;
+ }
+ if (np >= (Int64) size)
+ {
+ ptr = size - 1;
+ break;
+ }
+ ptr = np;
+ }
+ break;
+ }
+ return ptr;
+ }
+
+ bool MMapFile::eof() const
+ {
+ return ptr >= size;
+ }
+
+ Uint64 MMapFile::tell() const
+ {
+ return ptr;
+ }
+
+ QString MMapFile::errorString() const
+ {
+ return strerror(errno);
+ }
+
+ Uint64 MMapFile::getSize() const
+ {
+ return size;
+ }
+
+ Uint8* MMapFile::getData(Uint64 off)
+ {
+ if (off >= size)
+ return 0;
+ return &data[off];
+ }
+}
+