diff options
author | Fritz Elfert <felfert@to.com> | 2001-01-31 02:02:56 +0000 |
---|---|---|
committer | Fritz Elfert <felfert@to.com> | 2001-01-31 02:02:56 +0000 |
commit | dd2fe02677f9c15e1e13fdf7d45f91896e174ec1 (patch) | |
tree | 016ada4310f396297d066a7378f868eca1c474b3 | |
parent | 764b9679bb9188a973047982c82f06813d161325 (diff) | |
download | plptools-dd2fe02677f9c15e1e13fdf7d45f91896e174ec1.tar.gz plptools-dd2fe02677f9c15e1e13fdf7d45f91896e174ec1.tar.bz2 plptools-dd2fe02677f9c15e1e13fdf7d45f91896e174ec1.zip |
Added a KDE2 kioslave and a simple commandline backup-tool
(no restore yet ;-)
-rw-r--r-- | kde2/.cvsignore | 2 | ||||
-rw-r--r-- | kde2/Makefile.am | 12 | ||||
-rw-r--r-- | kde2/kioslave/.cvsignore | 6 | ||||
-rw-r--r-- | kde2/kioslave/Makefile.am | 26 | ||||
-rw-r--r-- | kde2/kioslave/README | 3 | ||||
-rw-r--r-- | kde2/kioslave/kio_plp.cpp | 781 | ||||
-rw-r--r-- | kde2/kioslave/kio_plp.h | 77 | ||||
-rw-r--r-- | kde2/kioslave/psion.protocol | 11 | ||||
-rw-r--r-- | plpbackup/.cvsignore | 5 | ||||
-rw-r--r-- | plpbackup/Makefile.am | 10 | ||||
-rw-r--r-- | plpbackup/plpbackup.cc | 530 |
11 files changed, 1463 insertions, 0 deletions
diff --git a/kde2/.cvsignore b/kde2/.cvsignore new file mode 100644 index 0000000..3dda729 --- /dev/null +++ b/kde2/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/kde2/Makefile.am b/kde2/Makefile.am new file mode 100644 index 0000000..4c8fb84 --- /dev/null +++ b/kde2/Makefile.am @@ -0,0 +1,12 @@ +# $Id$ +# + +SUBDIRS = kioslave + +TMPDEST= +# +# remove all intermediate files that can be recreated using +# Makefile.cvs +# +maintainer-clean-local: + rm -f Makefile.in diff --git a/kde2/kioslave/.cvsignore b/kde2/kioslave/.cvsignore new file mode 100644 index 0000000..b9f26ab --- /dev/null +++ b/kde2/kioslave/.cvsignore @@ -0,0 +1,6 @@ +Makefile.in +Makefile +*.la +*.lo +.libs +.deps diff --git a/kde2/kioslave/Makefile.am b/kde2/kioslave/Makefile.am new file mode 100644 index 0000000..1b573d9 --- /dev/null +++ b/kde2/kioslave/Makefile.am @@ -0,0 +1,26 @@ +## Makefile.am of kdebase/kioslave/plp + +INCLUDES = $(all_includes) -I$(top_srcdir)/lib +LDFLAGS = $(all_libraries) $(KDE_RPATH) + +####### Files + +kio_plp_la_LDFLAGS = -module -avoid-version -no-undefined + +if BUILD_KDE + +myprotodir = $(kde_servicesdir) + +lib_LTLIBRARIES = kio_plp.la + +kio_plp_la_SOURCES = kio_plp.cpp +kio_plp_la_LIBADD = -L$(top_srcdir)/lib -lplp -lkio +noinst_HEADERS = kio_plp.h + +myproto_DATA = psion.protocol + +METASOURCES = AUTO + +bin_SCRIPTS = + +endif diff --git a/kde2/kioslave/README b/kde2/kioslave/README new file mode 100644 index 0000000..7402231 --- /dev/null +++ b/kde2/kioslave/README @@ -0,0 +1,3 @@ +this is an ioslave for KDE 2 for PLP. + +Fritz diff --git a/kde2/kioslave/kio_plp.cpp b/kde2/kioslave/kio_plp.cpp new file mode 100644 index 0000000..8cf76c7 --- /dev/null +++ b/kde2/kioslave/kio_plp.cpp @@ -0,0 +1,781 @@ +/* + A KIOslave for KDE2 + + Copyright (C) 2001 Fritz Elfert <felfert@to.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "kio_plp.h" + +#include <stdio.h> +#include <sys/stat.h> + +#include <qfile.h> + +#include <kinstance.h> +#include <kdebug.h> +#include <klocale.h> + +#include <rfsvfactory.h> +#include <bufferarray.h> + +#include <string> + +using namespace KIO; + +static int PLP_DEBUGAREA = 7999; +// until we get an offical assignment +#define kdDebug(PLP_DEBUGAREA) cout + +extern "C" { + int kdemain(int argc, char **argv); +} + +int +kdemain( int argc, char **argv ) { + KInstance instance( "kio_nfs" ); + + if (argc != 4) { + fprintf(stderr, "Usage: kio_nfs protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + kdDebug(PLP_DEBUGAREA) << "PLP: kdemain: starting" << endl; + + PLPProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + return 0; +} + +static void +stripTrailingSlash(QString& path) { + if (path=="/") + path=""; + else + if (path[path.length()-1]=='/') + path.truncate(path.length()-1); +} + +static QString +baseName(const QString& path) { + return path.mid(path.findRev("/") + 1); +} + +static QString +removeFirstPart(const QString& path, QString &removed) { + QString result(""); + if (path.isEmpty()) { + removed = ""; + return result; + } + result = path.mid(1); + int slashPos = result.find("/"); + if (slashPos == -1) { + removed = result; + result = ""; + } else { + removed = result.left(slashPos); + result = result.mid(slashPos); + } + return result; +} + +PLPProtocol::PLPProtocol (const QCString &pool, const QCString &app) + :SlaveBase("psion", pool, app), plpRfsv(0), plpRfsvSocket(0) { + currentHost = ""; + struct servent *se = getservbyname("psion", "tcp"); + endservent(); + if (se != 0L) + currentPort = ntohs(se->s_port); + else + currentPort = DPORT; + kdDebug(PLP_DEBUGAREA) << "PLP::PLP: -" << pool << "-" << endl; +} + +PLPProtocol::~PLPProtocol() { + closeConnection(); +} + +void PLPProtocol:: +closeConnection() { + if (plpRfsv) + delete(plpRfsv); + if (plpRfsvSocket) + delete(plpRfsvSocket); + plpRfsv = 0; + plpRfsvSocket = 0; +} + +bool PLPProtocol:: +isRoot(const QString& path) { + return (path.isEmpty() || (path=="/")); +} + +bool PLPProtocol:: +isDrive(const QString& path) { + QString tmp = path; + stripTrailingSlash(tmp); + for (QStringList::Iterator it = drives.begin(); it != drives.end(); it++) { + QString cmp = "/" + *it; + if (cmp == tmp) + return TRUE; + } + return FALSE; +} + +bool PLPProtocol:: +isRomDrive(const QString& path) { + return (driveChar(path) == 'Z'); +} + +char PLPProtocol:: +driveChar(const QString& path) { + QString vname; + QString dummy = removeFirstPart(path, vname); + if (drivechars.find(vname) != drivechars.end()) + return drivechars[vname]; + return '\0'; +} + +void PLPProtocol:: +convertName(QString &path) { + kdDebug(PLP_DEBUGAREA) << "convert: in='" << path << "' out='"; + QString dummy; + QString drive; + + drive.sprintf("%c:", driveChar(path)); + path = drive + removeFirstPart(path, dummy); + path.replace(QRegExp("/"), "\\"); + kdDebug(PLP_DEBUGAREA) << path << "'" << endl; +} + +void PLPProtocol:: +openConnection() { + kdDebug(PLP_DEBUGAREA) << "PLP::openConnection" << endl; + closeConnection(); + + plpRfsvSocket = new ppsocket(); + if (!plpRfsvSocket->connect((char *)(currentHost.data()), currentPort)) { + error(ERR_COULD_NOT_CONNECT, i18n("Could not connect to ncpd")); + return; + } + rfsvfactory factory(plpRfsvSocket); + plpRfsv = factory.create(false); + if (plpRfsv == 0) { + error(ERR_COULD_NOT_CONNECT, i18n("Could not read version info")); + return; + } + long devbits; + Enum<rfsv::errs> res; + + if ((res = plpRfsv->devlist(devbits)) == rfsv::E_PSI_GEN_NONE) { + for (int i = 0; i < 26; i++) { + char vname[256]; + long vtotal, vfree, vattr, vuniqueid; + + if ((devbits & 1) != 0) { + if (plpRfsv->devinfo(i, vfree, vtotal, vattr, vuniqueid, + vname) == rfsv::E_PSI_GEN_NONE) { + QString name; + + if (strlen(vname)) + name = QString(vname); + else + name.sprintf("%c", 'A' + i); + drives.append(name); + drivechars.insert(name, 'A' + i); + } + } + devbits >>= 1; + } + } else { + error(ERR_COULD_NOT_CONNECT, i18n("Could not get drive list")); + return; + } + connected(); + kdDebug(PLP_DEBUGAREA) << "openConnection succeeded" << endl; +} + +bool PLPProtocol:: +checkConnection() { + if (plpRfsv == 0) + openConnection(); + return (plpRfsv == 0); +} + +void PLPProtocol:: +listDir(const KURL& _url) { + KURL url(_url); + QString path(QFile::encodeName(url.path())); + + if (path.isEmpty()) { + url.setPath("/"); + redirection(url); + finished(); + return; + } + + if (checkConnection()) + return; + + if (isRoot(path)) { + kdDebug(PLP_DEBUGAREA) << "listing root" << endl; + totalSize(drives.count()); + //in this case we don't need to do a real listdir + UDSEntry entry; + for (QStringList::Iterator it = drives.begin(); it != drives.end(); it++) { + UDSAtom atom; + entry.clear(); + atom.m_uds = KIO::UDS_NAME; + atom.m_str = (*it); + kdDebug(PLP_DEBUGAREA) << "listing " << (*it) << endl; + entry.append(atom); + createVirtualDirEntry(entry, drivechars[*it] == 'Z'); + listEntry(entry, false); + } + listEntry(entry, true); + finished(); + return; + } + + kdDebug(PLP_DEBUGAREA) << "getting subdir -" << path << "-" << endl; + bool rom = isRomDrive(path); + convertName(path); + path += "\\"; + + bufferArray files; + Enum<rfsv::errs> res = plpRfsv->dir(path, files); + if (checkForError(res)) + return; + totalSize(files.length()); + UDSEntry entry; + while (!files.empty()) { + UDSAtom atom; + bufferStore s = files.pop(); + PsiTime *date = (PsiTime *)s.getDWord(0); + long size = s.getDWord(4); + long attr = s.getDWord(8); + entry.clear(); + + atom.m_uds = KIO::UDS_NAME; + atom.m_str = s.getString(12); + entry.append(atom); + + if (rom) + attr |= rfsv::PSI_A_RDONLY; + completeUDSEntry(entry, attr, size, date); + listEntry(entry, false); + } + listEntry(entry, true); // ready + finished(); +} + +void PLPProtocol:: +createVirtualDirEntry(UDSEntry & entry, bool rdonly) { + UDSAtom atom; + + atom.m_uds = KIO::UDS_FILE_TYPE; + atom.m_long = S_IFDIR; + entry.append( atom ); + + atom.m_uds = KIO::UDS_ACCESS; + atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + if (!rdonly) + atom.m_long |= (S_IWUSR | S_IWGRP | S_IWOTH); + entry.append( atom ); + + atom.m_uds = KIO::UDS_SIZE; + atom.m_long = 0; + entry.append( atom ); +} + +bool PLPProtocol:: +emitTotalSize(QString &name) { + long attr; + long size; + bool err; + PsiTime time; + + Enum<rfsv::errs> res = plpRfsv->fgeteattr(name, attr, size, time); + if (checkForError(res)) + return true; + totalSize(size); + return false; +} + +void PLPProtocol:: +stat( const KURL & url) { + QString path(QFile::encodeName(url.path())); + UDSEntry entry; + UDSAtom atom; + + if (checkConnection()) + return; + + kdDebug(PLP_DEBUGAREA) << "stat(" << path << ")" << endl; + stripTrailingSlash(path); + + if (isRoot(path) || isDrive(path)) { + + atom.m_uds = KIO::UDS_NAME; + atom.m_str = path; + entry.append(atom); + createVirtualDirEntry(entry, isRoot(path) || isRomDrive(path)); + statEntry(entry); + finished(); + kdDebug(PLP_DEBUGAREA) << "succeeded" << endl; + return; + } + + bool rom = isRomDrive(path); + QString fileName = baseName(path); + convertName(path); + + if (path.isEmpty()) { + error(ERR_DOES_NOT_EXIST, fileName); + return; + } + + long attr, size; + PsiTime time; + Enum<rfsv::errs> res = plpRfsv->fgeteattr(path, attr, size, time); + if (checkForError(res)) + return; + if (rom) + attr |= rfsv::PSI_A_RDONLY; + + atom.m_uds = KIO::UDS_NAME; + atom.m_str = fileName; + entry.append(atom); + completeUDSEntry(entry, attr, size, &time); + statEntry(entry); + + finished(); +} + +void PLPProtocol:: +completeUDSEntry(UDSEntry& entry, const long attr, const long size, PsiTime *date) { + UDSAtom atom; + + atom.m_uds = KIO::UDS_SIZE; + atom.m_long = size; + entry.append(atom); + + atom.m_uds = KIO::UDS_MODIFICATION_TIME; + atom.m_long = date->getTime(); + entry.append(atom); + + atom.m_uds = KIO::UDS_ACCESS; + atom.m_long = S_IRUSR | S_IRGRP | S_IROTH; + if (attr & rfsv::PSI_A_DIR) + atom.m_long |= S_IXUSR | S_IXGRP | S_IXOTH; + if (!(attr & rfsv::PSI_A_RDONLY)) + atom.m_long |= S_IWUSR | S_IWGRP | S_IWOTH; + entry.append(atom); + + atom.m_uds = KIO::UDS_FILE_TYPE; + atom.m_long = (attr & rfsv::PSI_A_DIR) ? S_IFDIR : S_IFREG; + entry.append(atom); + +#if 0 + KIO::UDSEntry::ConstIterator it = entry.begin(); + for( ; it != entry.end(); it++ ) { + switch ((*it).m_uds) { + case KIO::UDS_FILE_TYPE: + kdDebug(PLP_DEBUGAREA) << "File Type : " << + (mode_t)((*it).m_long) << endl; + break; + case KIO::UDS_SIZE: + kdDebug(PLP_DEBUGAREA) << "File Size : " << + (long)((*it).m_long) << endl; + break; + case KIO::UDS_ACCESS: + kdDebug(PLP_DEBUGAREA) << "Access permissions : " << + (mode_t)((*it).m_long) << endl; + break; + case KIO::UDS_USER: + kdDebug(PLP_DEBUGAREA) << "User : " << + ((*it).m_str.ascii() ) << endl; + break; + case KIO::UDS_GROUP: + kdDebug(PLP_DEBUGAREA) << "Group : " << + ((*it).m_str.ascii() ) << endl; + break; + case KIO::UDS_NAME: + kdDebug(PLP_DEBUGAREA) << "Name : " << + ((*it).m_str.ascii() ) << endl; + //m_strText = decodeFileName( (*it).m_str ); + break; + case KIO::UDS_URL: + kdDebug(PLP_DEBUGAREA) << "URL : " << + ((*it).m_str.ascii() ) << endl; + break; + case KIO::UDS_MIME_TYPE: + kdDebug(PLP_DEBUGAREA) << "MimeType : " << + ((*it).m_str.ascii() ) << endl; + break; + case KIO::UDS_LINK_DEST: + kdDebug(PLP_DEBUGAREA) << "LinkDest : " << + ((*it).m_str.ascii() ) << endl; + break; + } + } +#endif +} + +void PLPProtocol:: +setHost(const QString& host, int port, const QString&, const QString&) { + kdDebug(PLP_DEBUGAREA) << "setHost(" << host << "," << port << ")" << endl; + QString tmphost = host; + if (host.isEmpty()) + tmphost = "localhost"; + if (port == 0) { + struct servent *se = getservbyname("psion", "tcp"); + endservent(); + if (se != 0L) + port = ntohs(se->s_port); + else + port = DPORT; + } + if ((tmphost == currentHost) && (port == currentPort)) + return; + currentHost = tmphost; + currentPort = port; + closeConnection(); +} + +void PLPProtocol:: +mkdir(const KURL& url, int) { + kdDebug(PLP_DEBUGAREA) << "mkdir" << endl; + QString name(QFile::encodeName(url.path())); + + if (checkConnection()) + return; + kdDebug(PLP_DEBUGAREA) << "mkdir(" << name << ")" << endl; + if (isRomDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("read only filesystem")); + return; + } + if (isRoot(name) || isDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + return; + } + convertName(name); + Enum<rfsv::errs> res = plpRfsv->mkdir(name); + if (checkForError(res)) + return; + finished(); +} + +bool PLPProtocol:: +checkForError(Enum<rfsv::errs> res) { + if (res != rfsv::E_PSI_GEN_NONE) { + kdDebug(PLP_DEBUGAREA) << "plp error: " << res << endl; + QString text(res.toString().data()); + switch (res) { + case rfsv::E_PSI_FILE_ACCESS: + error(ERR_ACCESS_DENIED, text); + break; + case rfsv::E_PSI_FILE_EXIST: + error(ERR_FILE_ALREADY_EXIST, text); + break; + case rfsv::E_PSI_FILE_NXIST: + error(ERR_DOES_NOT_EXIST, text); + break; + case rfsv::E_PSI_FILE_DIR: + error(ERR_IS_DIRECTORY, text); + break; + default: + error(ERR_UNKNOWN, text); + break; + } + return TRUE; + } + return FALSE; +} + +void PLPProtocol:: +del( const KURL& url, bool isfile) { + kdDebug(PLP_DEBUGAREA) << "del" << endl; + QString name(QFile::encodeName(url.path())); + + if (checkConnection()) + return; + kdDebug(PLP_DEBUGAREA) << "del(" << name << ")" << endl; + if (isRomDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("read only filesystem")); + return; + } + if (isRoot(name) || isDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + return; + } + convertName(name); + + Enum<rfsv::errs> res = + (isfile) ? plpRfsv->remove(name) : plpRfsv->rmdir(name); + if (checkForError(res)) + return; + finished(); +} + +void PLPProtocol:: +chmod( const KURL& url, int permissions ) { + kdDebug(PLP_DEBUGAREA) << "del" << endl; + QString name(QFile::encodeName(url.path())); + + if (checkConnection()) + return; + kdDebug(PLP_DEBUGAREA) << "chmod(" << name << ")" << endl; + if (isRomDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("read only filesystem")); + return; + } + if (isRoot(name) || isDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + return; + } + convertName(name); + long attr[2]; + attr[0] = attr[1] = 0; + Enum <rfsv::errs> res = plpRfsv->fsetattr(name, attr[0], attr[1]); + if (checkForError(res)) + return; + finished(); +} + +void PLPProtocol:: +get( const KURL& url ) { + kdDebug(PLP_DEBUGAREA) << "get" << endl; + QString name(QFile::encodeName(url.path())); + + if (checkConnection()) + return; + kdDebug(PLP_DEBUGAREA) << "get(" << name << ")" << endl; + if (isRoot(name) || isDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + return; + } + convertName(name); + + Enum<rfsv::errs> res; + long handle; + long len; + long size; + long total = 0; + + if (emitTotalSize(name)) + return; + res = plpRfsv->fopen(plpRfsv->opMode(rfsv::PSI_O_RDONLY), name, handle); + if (checkForError(res)) + return; + + QByteArray a(RFSV_SENDLEN); + do { + if ((res = plpRfsv->fread(handle, (unsigned char *)(a.data()), + RFSV_SENDLEN, len)) == rfsv::E_PSI_GEN_NONE) { + if (len < RFSV_SENDLEN) + a.resize(len); + data(a); + total += len; + calcprogress(total); + } + } while ((len > 0) && (res == rfsv::E_PSI_GEN_NONE)); + plpRfsv->fclose(handle); + if (checkForError(res)) + return; + data(QByteArray()); + + finished(); +} + +//TODO the partial putting thing is not yet implemented +void PLPProtocol:: +put( const KURL& url, int _mode, bool _overwrite, bool /*_resume*/ ) { + kdDebug(PLP_DEBUGAREA) << "get" << endl; + QString name(QFile::encodeName(url.path())); + + if (checkConnection()) + return; + kdDebug(PLP_DEBUGAREA) << "put(" << name << ")" << endl; + if (isRomDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("read only filesystem")); + return; + } + if (isRoot(name) || isDrive(name)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + return; + } + convertName(name); + + Enum<rfsv::errs> res; + long handle; + int result; + + res = plpRfsv->fcreatefile(plpRfsv->opMode(rfsv::PSI_O_RDWR), name, handle); + if ((res == rfsv::E_PSI_FILE_EXIST) && _overwrite) + res = plpRfsv->freplacefile(plpRfsv->opMode(rfsv::PSI_O_RDWR), name, handle); + if (checkForError(res)) + return; + + do { + QByteArray a; + dataReq(); + result = readData(a); + const unsigned char *data = (const unsigned char *)(a.data()); + long len = a.size(); + + if (result > 0) + do { + long written; + int count = (len > RFSV_SENDLEN) ? RFSV_SENDLEN : len; + res = plpRfsv->fwrite(handle, data, count, written); + if (checkForError(res)) { + plpRfsv->fclose(handle); + return; + } + len -= written; + data += written; + } while (len > 0); + } while (result > 0); + plpRfsv->fclose(handle); + finished(); +} + +void PLPProtocol:: +rename(const KURL &src, const KURL &dest, bool _overwrite) { + QString from( QFile::encodeName(src.path())); + QString to( QFile::encodeName(dest.path())); + + if (checkConnection()) + return; + kdDebug(PLP_DEBUGAREA) << "rename(" << from << "," << to << ")" << endl; + if ((driveChar(from) != driveChar(to)) && (driveChar(to) != '\0')) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + kdDebug(PLP_DEBUGAREA) << "from FS != to FS" << endl; + return; + } + if (isRomDrive(from)) { + error(ERR_ACCESS_DENIED, i18n("read only filesystem")); + kdDebug(PLP_DEBUGAREA) << "from ROFS" << endl; + return; + } + if (isRoot(from)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + kdDebug(PLP_DEBUGAREA) << "from VFS" << endl; + return; + } + bool volRename = isDrive(from); + if (isRomDrive(to)) { + error(ERR_ACCESS_DENIED, i18n("read only filesystem")); + kdDebug(PLP_DEBUGAREA) << "to ROFS" << endl; + return; + } + if (isRoot(to)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + kdDebug(PLP_DEBUGAREA) << "to VFS" << endl; + return; + } + + Enum <rfsv::errs> res; + kdDebug(PLP_DEBUGAREA) << "ren: from=" << from << " to=" << to << endl; + if (volRename) { + to = to.mid(1); + res = plpRfsv->setVolumeName(driveChar(from), to); + if (res == rfsv::E_PSI_GEN_NONE) { + char drvc = driveChar(from); + drivechars.remove(from); + drivechars.insert(to, drvc); + } + } else { + convertName(from); + convertName(to); + if (!_overwrite) { + long attr; + if ((res = plpRfsv->fgetattr(to, attr)) == rfsv::E_PSI_GEN_NONE) { + + error(ERR_FILE_ALREADY_EXIST, to); + return; + } + } + res = plpRfsv->rename(from, to); + } + if (checkForError(res)) + return; + finished(); +} + +extern "C" { +static int +progresswrapper(void *ptr, long total) { + + ((PLPProtocol *)ptr)->calcprogress(total); + return 1; +} +} + +void PLPProtocol:: +calcprogress(long total) { + time_t t = time(0); + if (t - t_last) { + processedSize(total); + speed(total / (t - t_start)); + t_last = t; + } +} + +void PLPProtocol:: +copy( const KURL &src, const KURL &dest, int _mode, bool _overwrite ) { + QString from( QFile::encodeName(src.path())); + QString to( QFile::encodeName(dest.path())); + + if (checkConnection()) + return; + kdDebug(PLP_DEBUGAREA) << "copy(" << from << "," << to << ")" << endl; + if (isRoot(from) || isDrive(from)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + return; + } + convertName(from); + if (isRomDrive(to)) { + error(ERR_ACCESS_DENIED, i18n("read only filesystem")); + return; + } + if (isRoot(to) || isDrive(to)) { + error(ERR_ACCESS_DENIED, i18n("Virtual directory")); + return; + } + convertName(to); + Enum <rfsv::errs> res; + if (!_overwrite) { + long attr; + if ((res = plpRfsv->fgetattr(to, attr)) == rfsv::E_PSI_GEN_NONE) { + error(ERR_FILE_ALREADY_EXIST, to); + return; + } + } + if (emitTotalSize(from)) + return; + t_last = t_start = time(0); + res = plpRfsv->copyOnPsion(from, to, (void *)this, progresswrapper); + if (checkForError(res)) + return; + finished(); +} diff --git a/kde2/kioslave/kio_plp.h b/kde2/kioslave/kio_plp.h new file mode 100644 index 0000000..4f1bc23 --- /dev/null +++ b/kde2/kioslave/kio_plp.h @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Alexander Neundorf <neundorf@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef KIO_PLP_H +#define KIO_PLP_H + +#include <kio/slavebase.h> +#include <kio/global.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qmap.h> +#include <rfsv.h> +#include <ppsocket.h> + +class PLPProtocol : public KIO::SlaveBase +{ + public: + PLPProtocol (const QCString &pool, const QCString &app ); + virtual ~PLPProtocol(); + + virtual void openConnection(); + virtual void closeConnection(); + + virtual void setHost( const QString& host, int port, const QString& user, const QString& pass ); + + virtual void put( const KURL& url, int _mode,bool _overwrite, bool _resume ); + virtual void get( const KURL& url ); + virtual void listDir( const KURL& url); + virtual void stat( const KURL & url); + virtual void mkdir( const KURL& url, int permissions ); + virtual void del( const KURL& url, bool isfile); + virtual void chmod(const KURL& url, int permissions ); + virtual void rename(const KURL &src, const KURL &dest, bool overwrite); + virtual void copy( const KURL& src, const KURL &dest, int mode, bool overwrite ); + + void calcprogress(long total); + private: + bool checkConnection(); + + char driveChar(const QString& path); + + void createVirtualDirEntry(KIO::UDSEntry & entry, bool rdonly); + void completeUDSEntry(KIO::UDSEntry& entry, const long attr, const long size, PsiTime *date); + bool checkForError(Enum<rfsv::errs> res); + bool isRomDrive(const QString& path); + bool isDrive(const QString& path); + bool isRoot(const QString& path); + void convertName(QString &path); + bool emitTotalSize(QString &name); + + rfsv *plpRfsv; + ppsocket *plpRfsvSocket; + QStringList drives; + QMap<QString,char> drivechars; + QString currentHost; + int currentPort; + time_t t_last; + time_t t_start; +}; + +#endif diff --git a/kde2/kioslave/psion.protocol b/kde2/kioslave/psion.protocol new file mode 100644 index 0000000..6e14b80 --- /dev/null +++ b/kde2/kioslave/psion.protocol @@ -0,0 +1,11 @@ +[Protocol] +exec=kio_plp +protocol=psion +input=none +output=filesystem +listing=Name,Type,Size,Date,Access +reading=true +writing=true +makedir=true +deleting=true +moving=true diff --git a/plpbackup/.cvsignore b/plpbackup/.cvsignore new file mode 100644 index 0000000..9e9544d --- /dev/null +++ b/plpbackup/.cvsignore @@ -0,0 +1,5 @@ +Makefile.in +Makefile +plpbackup +.libs +.deps diff --git a/plpbackup/Makefile.am b/plpbackup/Makefile.am new file mode 100644 index 0000000..a1a859b --- /dev/null +++ b/plpbackup/Makefile.am @@ -0,0 +1,10 @@ +# $Id$ +# +INCLUDES=-I$(top_srcdir)/lib + +bin_PROGRAMS = plpbackup +plpbackup_LDADD = $(top_srcdir)/lib/libplp.la +plpbackup_SOURCES = plpbackup.cc + +maintainer-clean-local: + rm -f Makefile.in diff --git a/plpbackup/plpbackup.cc b/plpbackup/plpbackup.cc new file mode 100644 index 0000000..ebc77e5 --- /dev/null +++ b/plpbackup/plpbackup.cc @@ -0,0 +1,530 @@ +// $Id$ +// +// plpbackup - A backup program for Psion. +// +// Copyright (C) 2000 Fritz Elfert <felfert@to.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <dirent.h> +#include <fstream.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <iomanip.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <errno.h> +#include <pwd.h> + +#include "bool.h" +#include "ppsocket.h" +#include "rfsv.h" +#include "rfsvfactory.h" +#include "rpcs.h" +#include "rpcsfactory.h" +#include "bufferstore.h" +#include "bufferarray.h" +#include "Enum.h" + +void +usage(ostream *hlp) +{ + *hlp << "Usage : plpbackup [-p <port>] [-v] [-f] [drive1:] [drive2:] ..." << endl; + *hlp << endl; + *hlp << " Options:" << endl; + *hlp << " -h Print this message and exit." << endl; + *hlp << " -V Print version and exit." << endl; + *hlp << " -p <port> Connect to ncpd using given port." << endl; + *hlp << " -v Increase verbosity." << endl; + *hlp << " -f Do a full backup. (Incremental otherwise)" << endl; + *hlp << " <drive> A drive character. If none given, scan all drives" << endl; +} + +bool full; +int verbose = 0; +bufferArray toBackup; +unsigned long backupSize = 0; +unsigned long totalBytes = 0; +unsigned long fileSize = 0; +char home[1024]; + +static int +killsave(rpcs *r, bool S5mx) { + Enum<rfsv::errs> res; + bufferArray tmp; + char psfile[1024]; + + sprintf(psfile, "%s/.plpbackup.%d", home, getpid()); + if ((res = r->queryDrive('C', tmp)) != rfsv::E_PSI_GEN_NONE) { + cerr << "Could not get process list, Error: " << res << endl; + return 1; + } else { + ofstream op(psfile); + if (!op) { + cerr << "Could not write processlist " << psfile << endl; + return 1; + } + op << "#plpbackup processlist" << endl; + while (!tmp.empty()) { + char pbuf[128]; + bufferStore cmdargs; + bufferStore bs = tmp.pop(); + int pid = bs.getWord(0); + const char *proc = bs.getString(2); + if (S5mx) + sprintf(pbuf, "%s.$%02d", proc, pid); + else + sprintf(pbuf, "%s.$%d", proc, pid); + bs = tmp.pop(); + if (r->getCmdLine(pbuf, cmdargs) == 0) + op << cmdargs.getString(0) << " " << bs.getString(0) << endl; + if (verbose > 1) + cout << cmdargs.getString(0) << " " << bs.getString(0) << endl; + r->stopProgram(pbuf); + } + op.close(); + } + return 0; +} + +static int +runrestore(rfsv *a, rpcs *r) { + Enum<rfsv::errs> res; + bufferArray tmp; + char psfile[1024]; + + sprintf(psfile, "%s/.plpbackup.%d", home, getpid()); + ifstream ip(psfile); + char cmd[512]; + char arg[512]; + + if (!ip) { + cerr << "Could not read processlist " << psfile << endl; + return 1; + } + ip >> cmd >> arg; + + if (strcmp(cmd, "#plpbackup") || strcmp(arg, "processlist")) { + ip.close(); + cerr << "Error: " << psfile << + " is not a process list saved with plpbackup" << endl; + return 1; + } + while (!ip.eof()) { + ip >> cmd >> arg; + ip.get(&arg[strlen(arg)], sizeof(arg) - strlen(arg), '\n'); + if (strlen(cmd) > 0) { + // Workaround for broken programs like Backlite. These do not store + // the full program path. In that case we try running the arg1 which + // results in starting the program via recog. facility. + if (verbose > 1) + cout << cmd << " " << arg << endl; + if ((strlen(arg) > 2) && (arg[1] == ':') && (arg[0] >= 'A') && + (arg[0] <= 'Z')) + res = r->execProgram(arg, ""); + else + res = r->execProgram(cmd, arg); + if (res != rfsv::E_PSI_GEN_NONE) { + // If we got an error here, that happened probably because + // we have no path at all (e.g. Macro5) and the program is + // not registered in the Psion's path properly. Now try + // the ususal \System\Apps\<AppName>\<AppName>.app + // on all drives. + if (strchr(cmd, '\\') == NULL) { + long devbits; + char tmp[512]; + if ((res = a->devlist(devbits)) == rfsv::E_PSI_GEN_NONE) { + int i; + for (i = 0; i < 26; i++) { + if (devbits & 1) { + sprintf(tmp, + "%c:\\System\\Apps\\%s\\%s.app", + 'A' + i, cmd, cmd); + res = r->execProgram(tmp, ""); + } + if (res == rfsv::E_PSI_GEN_NONE) + break; + } + } + } + } + if (res != rfsv::E_PSI_GEN_NONE) { + cerr << "Could not start " << cmd << " " << arg << endl; + cerr << "Error: " << res << endl; + } + } + } + ip.close(); + unlink(psfile); + return 0; +} + +static void +collectFiles(rfsv *a, char *dir) { + Enum<rfsv::errs> res; + bufferArray files; + char tmp[1024]; + + strcpy(tmp, dir); + strcat(tmp, "\\"); + if ((res = a->dir(tmp, files)) != rfsv::E_PSI_GEN_NONE) + cerr << "Error: " << res << endl; + else + while (!files.empty()) { + bufferStore s; + + s = files.pop(); + long size = s.getDWord(4); + long attr = s.getDWord(8); + strcpy(tmp, dir); + strcat(tmp, "\\"); + strcat(tmp, s.getString(12)); + if (attr & rfsv::PSI_A_DIR) { + collectFiles(a, tmp); + } else { + if ((attr & rfsv::PSI_A_ARCHIVE) || full) { + s.truncate(12); + s.addStringT(tmp); + toBackup += s; + } + } + } +} + +static int +reportProgress(void *, long size) +{ + unsigned long percent; + char pstr[10]; + char bstr[10]; + + switch (verbose) { + case 0: + return 1; + case 1: + percent = (totalBytes + size) * 100 / backupSize; + break; + case 2: + percent = size * 100 / fileSize; + break; + } + sprintf(pstr, " %3d%%", percent); + memset(bstr, 8, sizeof(bstr)); + bstr[strlen(pstr)] = '\0'; + printf("%s%s", pstr, bstr); + fflush(stdout); + return 1; +} + +int +mkdirp(char *path) { + char *p = strchr(path, '/'); + while (p) { + char csave = *(++p); + *p = '\0'; + switch (mkdir(path, S_IRWXU|S_IRWXG)) { + struct stat stbuf; + + case 0: + break; + default: + if (errno != EEXIST) { + perror(path); + return 1; + } + stat(path, &stbuf); + if (!S_ISDIR(stbuf.st_mode)) { + perror(path); + return 1; + } + break; + } + *p++ = csave; + p = strchr(p, '/'); + } + return 0; +} + +int +main(int argc, char **argv) +{ + ppsocket *skt; + ppsocket *skt2; + rfsv *a; + rpcs *r; + cpCallback_t cab = reportProgress; + int status = 0; + int sockNum = DPORT; + char dstPath[1024]; + struct passwd *pw; + sigset_t sigset; + + sigemptyset(&sigset); + sigaddset(&sigset, SIGPIPE); + sigprocmask(SIG_BLOCK, &sigset, 0L); + + struct servent *se = getservbyname("psion", "tcp"); + endservent(); + if (se != 0L) + sockNum = ntohs(se->s_port); + + // Command line parameter processing + bool parmFound; + do { + parmFound = false; + if ((argc > 1) && !strcmp(argv[1], "-V")) { + cout << "plpbackup version " << VERSION << endl; + exit(0); + } + if ((argc > 1) && !strcmp(argv[1], "-h")) { + usage(&cout); + exit(0); + } + if ((argc > 2) && !strcmp(argv[1], "-p")) { + sockNum = atoi(argv[2]); + argc -= 2; + parmFound = true; + for (int i = 1; i < argc; i++) + argv[i] = argv[i + 2]; + } + if ((argc > 1) && !strcmp(argv[1], "-v")) { + verbose++; + argc -= 1; + parmFound = true; + for (int i = 1; i < argc; i++) + argv[i] = argv[i + 1]; + } + if ((argc > 1) && !strcmp(argv[1], "-f")) { + full = true; + argc -= 1; + parmFound = true; + for (int i = 1; i < argc; i++) + argv[i] = argv[i + 1]; + } + } while (parmFound); + + pw = getpwuid(getuid()); + if (pw && pw->pw_dir && strlen(pw->pw_dir)) { + time_t now = time(0); + char tstr[80]; + strcpy(home, pw->pw_dir); + strftime(tstr, sizeof(tstr), "%Y-%m-%d-%H-%M-%S", + localtime(&now)); + sprintf(dstPath, "%s/plpbackup-%s/", home, tstr); + } else { + cerr << "Could not get user's home directory from /etc/passwd" << endl; + exit(-1); + } + + skt = new ppsocket(); + if (!skt->connect(NULL, sockNum)) { + cerr << "plpbackup: could not connect to ncpd" << endl; + return 1; + } + skt2 = new ppsocket(); + if (!skt2->connect(NULL, sockNum)) { + cerr << "plpbackup: could not connect to ncpd" << endl; + return 1; + } + rfsvfactory *rf = new rfsvfactory(skt); + rpcsfactory *rp = new rpcsfactory(skt2); + a = rf->create(false); + r = rp->create(false); + if ((a != NULL) && (r != NULL)) { + Enum<rfsv::errs> res; + Enum<rpcs::machs> machType; + bool S5mx = false; + bool bErr = false; + int i; + unsigned long backupCount = 0; + char dest[1024]; + + r->getMachineType(machType); + if (machType == rpcs::PSI_MACH_S5) { + rpcs::machineInfo mi; + if ((res = r->getMachineInfo(mi)) == rfsv::E_PSI_GEN_NONE) { + if (!strcmp(mi.machineName, "SERIES5mx")) + S5mx = true; + } + } + if (verbose) { + cout << "Performing " << (full ? "Full" : "Incremental") << + " backup to " << dstPath << endl; + cout << "Stopping programs ..." << endl; + } + killsave(r, S5mx); + if (argc > 1) { + for (i = 1; i < argc; i++) { + if ((strlen(argv[i]) != 2) || (argv[i][1] != ':')) { + usage(&cerr); + exit(1); + runrestore(a, r); + } + if (verbose) + cout << "Scanning Drive " << argv[i] << " ..." << endl; + collectFiles(a, argv[i]); + } + } else { + char drive[3]; + long devbits; + long vtotal, vfree, vattr, vuniqueid; + + if (a->devlist(devbits) == rfsv::E_PSI_GEN_NONE) { + for (i = 0; i < 26; i++) { + if ((devbits & 1) && a->devinfo(i, vfree, vtotal, vattr, vuniqueid, NULL) == rfsv::E_PSI_GEN_NONE) { + if (vattr != 7) { + sprintf(drive, "%c:\0", 'A' + i); + if (verbose) + cout << "Scanning Drive " << drive << " ..." << endl; + collectFiles(a, drive); + } + } + devbits >>= 1; + } + } else + cerr << "Couldn't get Drive list" << endl; + } + for (i = 0; i < toBackup.length(); i++) { + bufferStore s = toBackup[i]; + backupSize += s.getDWord(4); + backupCount++; + } + if (verbose) + cout << "Size of backup: " << backupSize << " bytes in " << + backupCount << " files." << endl; + if (backupCount == 0) + cerr << "Nothing to backup" << endl; + else { + for (i = 0; i < toBackup.length(); i++) { + bufferStore s = toBackup[i]; + const char *fn = s.getString(12); + const char *p; + char *q; + char tmp[1024]; + + for (p = fn, q = tmp; *p; p++, q++) + switch (*p) { + case '%': + *q++ = '%'; + *q++ = '2'; + *q = '5'; + break; + case '/': + *q++ = '%'; + *q++ = '2'; + *q= 'f'; + break; + case '\\': + *q = '/'; + break; + default: + *q = *p; + } + *q = '\0'; + strcpy(dest, dstPath); + strcat(dest, tmp); + fileSize = s.getDWord(4); + if (verbose > 1) + cout << "Backing up " << fn << flush; + if (mkdirp(dest) != 0) { + bErr = true; + break; + } + res = a->copyFromPsion(fn, dest, NULL, cab); + if (verbose > 1) + cout << endl; + totalBytes += fileSize; + if (res != rfsv::E_PSI_GEN_NONE) { + cerr << "Error during backup of " << + fn << ": " << res << endl; + bErr = true; + break; + } + } + if (!bErr) { + if (verbose) + cout << "Writing index ..." << endl; + strcpy(dest, dstPath); + strcat(dest, ".index"); + ofstream op(dest); + if (op) { + op << "#plpbackup index" << endl; + for (i = 0; i < toBackup.length(); i++) { + bufferStore s = toBackup[i]; + PsiTime *t = (PsiTime *)s.getDWord(0); + long size = s.getDWord(4); + long attr = s.getDWord(8); + const char *fn = s.getString(12); + attr &= ~rfsv::PSI_A_ARCHIVE; + op << hex + << setw(8) << setfill('0') << + t->getPsiTimeHi() << " " + << setw(8) << setfill('0') << + t->getPsiTimeLo() << " " + << setw(8) << setfill('0') << + size << " " + << setw(8) << setfill('0') << + attr << " " + << setw(0) << fn << endl; + } + op.close(); + } else { + cerr << "Could not write index " << dest << endl; + bErr = true; + } + } + if (!bErr) { + if (verbose) + cout << "Resetting archive attributes ..." << endl; + for (i = 0; i < toBackup.length(); i++) { + bufferStore s = toBackup[i]; + long attr = s.getDWord(8); + const char *fn = s.getString(12); + if (attr & rfsv::PSI_A_ARCHIVE) { + res = a->fsetattr(fn, 0, + rfsv::PSI_A_ARCHIVE); + if (res != rfsv::E_PSI_GEN_NONE) { + bErr = true; + break; + } + } + } + } + } + if (bErr) + cerr << "Backup aborted due to error" << endl; + if (verbose) + cout << "Restarting programs ..." << endl; + runrestore(a, r); + delete r; + delete a; + } else { + if (!a) + cerr << "plpbackup: could not create rfsv object" << endl; + if (!r) + cerr << "plpbackup: could not create rpcs object" << endl; + exit(1); + } + return 0; +} |