summaryrefslogtreecommitdiffstats
path: root/kioslave/nfs/kio_nfs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kioslave/nfs/kio_nfs.cpp')
-rw-r--r--kioslave/nfs/kio_nfs.cpp1615
1 files changed, 1615 insertions, 0 deletions
diff --git a/kioslave/nfs/kio_nfs.cpp b/kioslave/nfs/kio_nfs.cpp
new file mode 100644
index 000000000..18a7f1393
--- /dev/null
+++ b/kioslave/nfs/kio_nfs.cpp
@@ -0,0 +1,1615 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2000 Alexander Neundorf <[email protected]>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+#include <arpa/inet.h>
+
+// This is needed on Solaris so that rpc.h defines clnttcp_create etc.
+#ifndef PORTMAP
+#define PORTMAP
+#endif
+#include <rpc/rpc.h> // for rpc calls
+
+#include <errno.h>
+#include <grp.h>
+#include <memory.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qdir.h>
+
+#include <kdebug.h>
+#include <kinstance.h>
+#include <klocale.h>
+
+#include <kio/global.h>
+#include <iostream>
+
+#include "nfs_prot.h"
+#define fhandle _fhandle
+#include "mount.h"
+#include "kio_nfs.h"
+
+#define MAXHOSTLEN 256
+
+//#define MAXFHAGE 60*15 //15 minutes maximum age for file handles
+
+//this ioslave is for NFS version 2
+#define NFSPROG ((u_long)100003)
+#define NFSVERS ((u_long)2)
+
+using namespace KIO;
+using namespace std;
+
+//this is taken from kdelibs/kdecore/fakes.cpp
+//#if !defined(HAVE_GETDOMAINNAME)
+
+int x_getdomainname(char *name, size_t len)
+{
+ struct utsname uts;
+ struct hostent *hent;
+ int rv = -1;
+
+ if (name == 0L)
+ errno = EINVAL;
+ else
+ {
+ name[0] = '\0';
+ if (uname(&uts) >= 0)
+ {
+ if ((hent = gethostbyname(uts.nodename)) != 0L)
+ {
+ char *p = strchr(hent->h_name, '.');
+ if (p != 0L)
+ {
+ ++p;
+ if (strlen(p) > len-1)
+ errno = EINVAL;
+ else
+ {
+ strcpy(name, p);
+ rv = 0;
+ }
+ }
+ }
+ }
+ }
+ return rv;
+}
+//#endif
+
+
+extern "C" { int KDE_EXPORT 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(7121) << "NFS: kdemain: starting" << endl;
+
+ NFSProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+ return 0;
+}
+
+static bool isRoot(const QString& path)
+{
+ return (path.isEmpty() || (path=="/"));
+}
+
+static bool isAbsoluteLink(const QString& path)
+{
+ //hmm, don't know
+ if (path.isEmpty()) return TRUE;
+ if (path[0]=='/') return TRUE;
+ return FALSE;
+}
+
+static void createVirtualDirEntry(UDSEntry & entry)
+{
+ 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;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_USER;
+ atom.m_str = "root";
+ entry.append( atom );
+ atom.m_uds = KIO::UDS_GROUP;
+ atom.m_str = "root";
+ entry.append( atom );
+
+ //a dummy size
+ atom.m_uds = KIO::UDS_SIZE;
+ atom.m_long = 1024;
+ entry.append( atom );
+}
+
+
+static void stripTrailingSlash(QString& path)
+{
+ //if (path=="/") return;
+ if (path=="/") path="";
+ else if (path[path.length()-1]=='/') path.truncate(path.length()-1);
+}
+
+static void getLastPart(const QString& path, QString& lastPart, QString& rest)
+{
+ int slashPos=path.findRev("/");
+ lastPart=path.mid(slashPos+1);
+ rest=path.left(slashPos+1);
+}
+
+static QString removeFirstPart(const QString& path)
+{
+ QString result("");
+ if (path.isEmpty()) return result;
+ result=path.mid(1);
+ int slashPos=result.find("/");
+ return result.mid(slashPos+1);
+}
+
+NFSFileHandle::NFSFileHandle()
+:m_isInvalid(FALSE)
+{
+ memset(m_handle,'\0',NFS_FHSIZE+1);
+// m_detectTime=time(0);
+}
+
+NFSFileHandle::NFSFileHandle(const NFSFileHandle & handle)
+:m_isInvalid(FALSE)
+{
+ m_handle[NFS_FHSIZE]='\0';
+ memcpy(m_handle,handle.m_handle,NFS_FHSIZE);
+ m_isInvalid=handle.m_isInvalid;
+// m_detectTime=handle.m_detectTime;
+}
+
+NFSFileHandle::~NFSFileHandle()
+{}
+
+NFSFileHandle& NFSFileHandle::operator= (const NFSFileHandle& src)
+{
+ memcpy(m_handle,src.m_handle,NFS_FHSIZE);
+ m_isInvalid=src.m_isInvalid;
+// m_detectTime=src.m_detectTime;
+ return *this;
+}
+
+NFSFileHandle& NFSFileHandle::operator= (const char* src)
+{
+ if (src==0)
+ {
+ m_isInvalid=TRUE;
+ return *this;
+ };
+ memcpy(m_handle,src,NFS_FHSIZE);
+ m_isInvalid=FALSE;
+// m_detectTime=time(0);
+ return *this;
+}
+
+/*time_t NFSFileHandle::age() const
+{
+ return (time(0)-m_detectTime);
+}*/
+
+
+NFSProtocol::NFSProtocol (const QCString &pool, const QCString &app )
+:SlaveBase( "nfs", pool, app )
+,m_client(0)
+,m_sock(-1)
+,m_lastCheck(time(0))
+{
+ kdDebug(7121)<<"NFS::NFS: -"<<pool<<"-"<<endl;
+}
+
+NFSProtocol::~NFSProtocol()
+{
+ closeConnection();
+}
+
+/*This one is currently unused, so it could be removed.
+ The intention was to keep handles around, and from time to time
+ remove handles which are too old. Alex
+ */
+/*void NFSProtocol::checkForOldFHs()
+{
+ kdDebug(7121)<<"checking for fhs older than "<<MAXFHAGE<<endl;
+ kdDebug(7121)<<"current items: "<<m_handleCache.count()<<endl;
+ NFSFileHandleMap::Iterator it=m_handleCache.begin();
+ NFSFileHandleMap::Iterator lastIt=it;
+ while (it!=m_handleCache.end())
+ {
+ kdDebug(7121)<<it.data().age()<<flush;
+ if (it.data().age()>MAXFHAGE)
+ {
+ kdDebug(7121)<<"removing"<<endl;
+ m_handleCache.remove(it);
+ if (it==lastIt)
+ {
+ it=m_handleCache.begin();
+ lastIt=it;
+ }
+ else
+ it=lastIt;
+ }
+ lastIt=it;
+ it++;
+ };
+ kdDebug(7121)<<"left items: "<<m_handleCache.count()<<endl;
+ m_lastCheck=time(0);
+}*/
+
+void NFSProtocol::closeConnection()
+{
+ close(m_sock);
+ m_sock=-1;
+ if (m_client==0) return;
+ CLNT_DESTROY(m_client);
+
+ m_client=0;
+}
+
+bool NFSProtocol::isExportedDir(const QString& path)
+{
+ return (m_exportedDirs.find(path.mid(1))!=m_exportedDirs.end());
+}
+
+/* This one works recursive.
+ It tries to get the file handle out of the file handle cache.
+ If this doesn't succeed, it needs to do a nfs rpc call
+ in order to obtain one.
+ */
+NFSFileHandle NFSProtocol::getFileHandle(QString path)
+{
+ if (m_client==0) openConnection();
+
+ //I'm not sure if this is useful
+ //if ((time(0)-m_lastCheck)>MAXFHAGE) checkForOldFHs();
+
+ stripTrailingSlash(path);
+ kdDebug(7121)<<"getting FH for -"<<path<<"-"<<endl;
+ //now the path looks like "/root/some/dir" or "" if it was "/"
+ NFSFileHandle parentFH;
+ //we didn't find it
+ if (path.isEmpty())
+ {
+ kdDebug(7121)<<"path is empty, invalidating the FH"<<endl;
+ parentFH.setInvalid();
+ return parentFH;
+ }
+ //check wether we have this filehandle cached
+ //the filehandles of the exported root dirs are always in the cache
+ if (m_handleCache.find(path)!=m_handleCache.end())
+ {
+ kdDebug(7121)<<"path is in the cache, returning the FH -"<<m_handleCache[path]<<"-"<<endl;
+ return m_handleCache[path];
+ }
+ QString rest, lastPart;
+ getLastPart(path,lastPart,rest);
+ kdDebug(7121)<<"splitting path into rest -"<<rest<<"- and lastPart -"<<lastPart<<"-"<<endl;
+
+ parentFH=getFileHandle(rest);
+ //f*ck, it's invalid
+ if (parentFH.isInvalid())
+ {
+ kdDebug(7121)<<"the parent FH is invalid"<<endl;
+ return parentFH;
+ }
+ // do the rpc call
+ diropargs dirargs;
+ diropres dirres;
+ memcpy(dirargs.dir.data,(const char*)parentFH,NFS_FHSIZE);
+ QCString tmpStr=QFile::encodeName(lastPart);
+ dirargs.name=tmpStr.data();
+
+ //cerr<<"calling rpc: FH: -"<<parentFH<<"- with name -"<<dirargs.name<<"-"<<endl;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_LOOKUP,
+ (xdrproc_t) xdr_diropargs, (char*)&dirargs,
+ (xdrproc_t) xdr_diropres, (char*)&dirres,total_timeout);
+
+ if ((clnt_stat!=RPC_SUCCESS) || (dirres.status!=NFS_OK))
+ {
+ //we failed
+ kdDebug(7121)<<"lookup of filehandle failed"<<endl;
+ parentFH.setInvalid();
+ return parentFH;
+ }
+ //everything went fine up to now :-)
+ parentFH=dirres.diropres_u.diropres.file.data;
+ //kdDebug(7121)<<"filesize: "<<dirres.diropres_u.diropres.attributes.size<<endl;
+ m_handleCache.insert(path,parentFH);
+ kdDebug(7121)<<"return FH -"<<parentFH<<"-"<<endl;
+ return parentFH;
+}
+
+/* Open connection connects to the mount daemon on the server side.
+ In order to do this it needs authentication and calls auth_unix_create().
+ Then it asks the mount daemon for the exported shares. Then it tries
+ to mount all these shares. If this succeeded for at least one of them,
+ a client for the nfs daemon is created.
+ */
+void NFSProtocol::openConnection()
+{
+ kdDebug(7121)<<"NFS::openConnection for -" << m_currentHost.latin1() << "-" << endl;
+ if (m_currentHost.isEmpty())
+ {
+ error(ERR_UNKNOWN_HOST,"");
+ return;
+ }
+ struct sockaddr_in server_addr;
+ if (m_currentHost[0] >= '0' && m_currentHost[0] <= '9')
+ {
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr.s_addr = inet_addr(m_currentHost.latin1());
+ }
+ else
+ {
+ struct hostent *hp=gethostbyname(m_currentHost.latin1());
+ if (hp==0)
+ {
+ error( ERR_UNKNOWN_HOST, m_currentHost.latin1() );
+ return;
+ }
+ server_addr.sin_family = AF_INET;
+ memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ // create mount deamon client
+ closeConnection();
+ server_addr.sin_port = 0;
+ m_sock = RPC_ANYSOCK;
+ m_client=clnttcp_create(&server_addr,MOUNTPROG, MOUNTVERS, &m_sock, 0, 0);
+ if (m_client==0)
+ {
+ server_addr.sin_port = 0;
+ m_sock = RPC_ANYSOCK;
+ pertry_timeout.tv_sec = 3;
+ pertry_timeout.tv_usec = 0;
+ m_client = clntudp_create(&server_addr,MOUNTPROG, MOUNTVERS, pertry_timeout, &m_sock);
+ if (m_client==0)
+ {
+ clnt_pcreateerror(const_cast<char *>("mount clntudp_create"));
+ error(ERR_COULD_NOT_CONNECT, m_currentHost.latin1());
+ return;
+ }
+ }
+ QCString hostName("localhost");
+ char nameBuffer[1024];
+ nameBuffer[0] = '\0';
+ if (gethostname(nameBuffer, 1024)==0)
+ {
+ nameBuffer[sizeof(nameBuffer)-1] = '\0';
+ hostName=nameBuffer;
+ // I have the same problem here as Stefan Westerfeld, that's why I use
+ // the getdomainname() from fakes.cpp (renamed to x_getdomainname()), this one works
+ // taken from kdelibs/arts/mcopy/mcoputils.cc
+ nameBuffer[0] = '\0';
+ if (x_getdomainname(nameBuffer, 1024)==0)
+ {
+ nameBuffer[sizeof(nameBuffer)-1] = '\0';
+ /*
+ * I don't know why, but on my linux machine, the domainname
+ * always ends up being (none), which is certainly no valid
+ * domainname
+ */
+ if(strcmp(nameBuffer,"(none)") != 0) {
+ hostName += ".";
+ hostName += nameBuffer;
+ }
+ }
+ }
+ kdDebug(7121) << "hostname is -" << hostName << "-" << endl;
+ m_client->cl_auth = authunix_create(hostName.data(), geteuid(), getegid(), 0, 0);
+ total_timeout.tv_sec = 20;
+ total_timeout.tv_usec = 0;
+
+ exports exportlist;
+ //now do the stuff
+ memset(&exportlist, '\0', sizeof(exportlist));
+
+ int clnt_stat = clnt_call(m_client, MOUNTPROC_EXPORT,(xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_exports, (char*)&exportlist,total_timeout);
+ if (!checkForError(clnt_stat, 0, m_currentHost.latin1())) return;
+
+ fhstatus fhStatus;
+ bool atLeastOnceSucceeded(FALSE);
+ for(; exportlist!=0;exportlist = exportlist->ex_next) {
+ kdDebug(7121) << "found export: " << exportlist->ex_dir << endl;
+
+ memset(&fhStatus, 0, sizeof(fhStatus));
+ clnt_stat = clnt_call(m_client, MOUNTPROC_MNT,(xdrproc_t) xdr_dirpath, (char*)(&(exportlist->ex_dir)),
+ (xdrproc_t) xdr_fhstatus,(char*) &fhStatus,total_timeout);
+ if (fhStatus.fhs_status==0) {
+ atLeastOnceSucceeded=TRUE;
+ NFSFileHandle fh;
+ fh=fhStatus.fhstatus_u.fhs_fhandle;
+ QString fname;
+ if ( exportlist->ex_dir[0] == '/' )
+ fname = KIO::encodeFileName(exportlist->ex_dir + 1);
+ else
+ fname = KIO::encodeFileName(exportlist->ex_dir);
+ m_handleCache.insert(QString("/")+fname,fh);
+ m_exportedDirs.append(fname);
+ // kdDebug() <<"appending file -"<<fname<<"- with FH: -"<<fhStatus.fhstatus_u.fhs_fhandle<<"-"<<endl;
+ }
+ }
+ if (!atLeastOnceSucceeded)
+ {
+ closeConnection();
+ error( ERR_COULD_NOT_AUTHENTICATE, m_currentHost.latin1());
+ return;
+ }
+ server_addr.sin_port = 0;
+
+ //now create the client for the nfs daemon
+ //first get rid of the old one
+ closeConnection();
+ m_sock = RPC_ANYSOCK;
+ m_client = clnttcp_create(&server_addr,NFSPROG,NFSVERS,&m_sock,0,0);
+ if (m_client == 0)
+ {
+ server_addr.sin_port = 0;
+ m_sock = RPC_ANYSOCK;
+ pertry_timeout.tv_sec = 3;
+ pertry_timeout.tv_usec = 0;
+ m_client = clntudp_create(&server_addr,NFSPROG, NFSVERS, pertry_timeout, &m_sock);
+ if (m_client==0)
+ {
+ clnt_pcreateerror(const_cast<char *>("NFS clntudp_create"));
+ error(ERR_COULD_NOT_CONNECT, m_currentHost.latin1());
+ return;
+ }
+ }
+ m_client->cl_auth = authunix_create(hostName.data(),geteuid(),getegid(),0,0);
+ connected();
+ kdDebug(7121)<<"openConnection succeeded"<<endl;
+}
+
+void NFSProtocol::listDir( const KURL& _url)
+{
+ KURL url(_url);
+ QString path( QFile::encodeName(url.path()));
+
+ if (path.isEmpty())
+ {
+ url.setPath("/");
+ redirection(url);
+ finished();
+ return;
+ }
+ //open the connection
+ if (m_client==0) openConnection();
+ //it failed
+ if (m_client==0) return;
+ if (isRoot(path))
+ {
+ kdDebug(7121)<<"listing root"<<endl;
+ totalSize( m_exportedDirs.count());
+ //in this case we don't need to do a real listdir
+ UDSEntry entry;
+ for (QStringList::Iterator it=m_exportedDirs.begin(); it!=m_exportedDirs.end(); it++)
+ {
+ UDSAtom atom;
+ entry.clear();
+ atom.m_uds = KIO::UDS_NAME;
+ atom.m_str = (*it);
+ kdDebug(7121)<<"listing "<<(*it)<<endl;
+ entry.append( atom );
+ createVirtualDirEntry(entry);
+ listEntry( entry, false);
+ }
+ listEntry( entry, true ); // ready
+ finished();
+ return;
+ }
+
+ QStringList filesToList;
+ kdDebug(7121)<<"getting subdir -"<<path<<"-"<<endl;
+ stripTrailingSlash(path);
+ NFSFileHandle fh=getFileHandle(path);
+ //cerr<<"this is the fh: -"<<fh<<"-"<<endl;
+ if (fh.isInvalid())
+ {
+ error( ERR_DOES_NOT_EXIST, path);
+ return;
+ }
+ readdirargs listargs;
+ memset(&listargs,0,sizeof(listargs));
+ listargs.count=1024*16;
+ memcpy(listargs.dir.data,fh,NFS_FHSIZE);
+ readdirres listres;
+ do
+ {
+ memset(&listres,'\0',sizeof(listres));
+ int clnt_stat = clnt_call(m_client, NFSPROC_READDIR, (xdrproc_t) xdr_readdirargs, (char*)&listargs,
+ (xdrproc_t) xdr_readdirres, (char*)&listres,total_timeout);
+ if (!checkForError(clnt_stat,listres.status,path)) return;
+ for (entry *dirEntry=listres.readdirres_u.reply.entries;dirEntry!=0;dirEntry=dirEntry->nextentry)
+ {
+ if ((QString(".")!=dirEntry->name) && (QString("..")!=dirEntry->name))
+ filesToList.append(dirEntry->name);
+ }
+ } while (!listres.readdirres_u.reply.eof);
+ totalSize( filesToList.count());
+
+ UDSEntry entry;
+ //stat all files in filesToList
+ for (QStringList::Iterator it=filesToList.begin(); it!=filesToList.end(); it++)
+ {
+ UDSAtom atom;
+ diropargs dirargs;
+ diropres dirres;
+ memcpy(dirargs.dir.data,fh,NFS_FHSIZE);
+ QCString tmpStr=QFile::encodeName(*it);
+ dirargs.name=tmpStr.data();
+
+ kdDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-"<<endl;
+
+ int clnt_stat= clnt_call(m_client, NFSPROC_LOOKUP,
+ (xdrproc_t) xdr_diropargs, (char*)&dirargs,
+ (xdrproc_t) xdr_diropres, (char*)&dirres,total_timeout);
+ if (!checkForError(clnt_stat,dirres.status,(*it))) return;
+
+ NFSFileHandle tmpFH;
+ tmpFH=dirres.diropres_u.diropres.file.data;
+ m_handleCache.insert(path+"/"+(*it),tmpFH);
+
+ entry.clear();
+
+ atom.m_uds = KIO::UDS_NAME;
+ atom.m_str = (*it);
+ entry.append( atom );
+
+ //is it a symlink ?
+ if (S_ISLNK(dirres.diropres_u.diropres.attributes.mode))
+ {
+ kdDebug(7121)<<"it's a symlink !"<<endl;
+ //cerr<<"fh: "<<tmpFH<<endl;
+ nfs_fh nfsFH;
+ memcpy(nfsFH.data,dirres.diropres_u.diropres.file.data,NFS_FHSIZE);
+ //get the link dest
+ readlinkres readLinkRes;
+ char nameBuf[NFS_MAXPATHLEN];
+ readLinkRes.readlinkres_u.data=nameBuf;
+ int clnt_stat=clnt_call(m_client, NFSPROC_READLINK,
+ (xdrproc_t) xdr_nfs_fh, (char*)&nfsFH,
+ (xdrproc_t) xdr_readlinkres, (char*)&readLinkRes,total_timeout);
+ if (!checkForError(clnt_stat,readLinkRes.status,(*it))) return;
+ kdDebug(7121)<<"link dest is -"<<readLinkRes.readlinkres_u.data<<"-"<<endl;
+ QCString linkDest(readLinkRes.readlinkres_u.data);
+ atom.m_uds = KIO::UDS_LINK_DEST;
+ atom.m_str = linkDest;
+ entry.append( atom );
+
+ bool isValid=isValidLink(path,linkDest);
+ if (!isValid)
+ {
+ completeBadLinkUDSEntry(entry,dirres.diropres_u.diropres.attributes);
+ }
+ else
+ {
+ if (isAbsoluteLink(linkDest))
+ {
+ completeAbsoluteLinkUDSEntry(entry,linkDest);
+ }
+ else
+ {
+ tmpStr=QDir::cleanDirPath(path+QString("/")+QString(linkDest)).latin1();
+ dirargs.name=tmpStr.data();
+ tmpFH=getFileHandle(tmpStr);
+ memcpy(dirargs.dir.data,tmpFH,NFS_FHSIZE);
+
+ attrstat attrAndStat;
+
+ kdDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-"<<endl;
+
+ clnt_stat = clnt_call(m_client, NFSPROC_GETATTR,
+ (xdrproc_t) xdr_diropargs, (char*)&dirargs,
+ (xdrproc_t) xdr_attrstat, (char*)&attrAndStat,total_timeout);
+ if (!checkForError(clnt_stat,attrAndStat.status,tmpStr)) return;
+ completeUDSEntry(entry,attrAndStat.attrstat_u.attributes);
+ }
+ }
+ }
+ else
+ completeUDSEntry(entry,dirres.diropres_u.diropres.attributes);
+ listEntry( entry, false);
+ }
+ listEntry( entry, true ); // ready
+ finished();
+}
+
+void NFSProtocol::stat( const KURL & url)
+{
+ QString path( QFile::encodeName(url.path()));
+ stripTrailingSlash(path);
+ kdDebug(7121)<<"NFS::stat for -"<<path<<"-"<<endl;
+ QString tmpPath=path;
+ if ((tmpPath.length()>1) && (tmpPath[0]=='/')) tmpPath=tmpPath.mid(1);
+ // We can't stat root, but we know it's a dir
+ if (isRoot(path) || isExportedDir(path))
+ {
+ UDSEntry entry;
+ UDSAtom atom;
+
+ atom.m_uds = KIO::UDS_NAME;
+ atom.m_str = path;
+ entry.append( atom );
+ createVirtualDirEntry(entry);
+ // no size
+ statEntry( entry );
+ finished();
+ kdDebug(7121)<<"succeeded"<<endl;
+ return;
+ }
+
+ NFSFileHandle fh=getFileHandle(path);
+ if (fh.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,path);
+ return;
+ }
+
+ diropargs dirargs;
+ attrstat attrAndStat;
+ memcpy(dirargs.dir.data,fh,NFS_FHSIZE);
+ QCString tmpStr=QFile::encodeName(path);
+ dirargs.name=tmpStr.data();
+
+ kdDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-"<<endl;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_GETATTR,
+ (xdrproc_t) xdr_diropargs, (char*)&dirargs,
+ (xdrproc_t) xdr_attrstat, (char*)&attrAndStat,total_timeout);
+ if (!checkForError(clnt_stat,attrAndStat.status,path)) return;
+ UDSEntry entry;
+ entry.clear();
+
+ UDSAtom atom;
+
+ QString fileName, parentDir;
+ getLastPart(path, fileName, parentDir);
+ stripTrailingSlash(parentDir);
+
+ atom.m_uds = KIO::UDS_NAME;
+ atom.m_str = fileName;
+ entry.append( atom );
+
+ //is it a symlink ?
+ if (S_ISLNK(attrAndStat.attrstat_u.attributes.mode))
+ {
+ kdDebug(7121)<<"it's a symlink !"<<endl;
+ nfs_fh nfsFH;
+ memcpy(nfsFH.data,fh,NFS_FHSIZE);
+ //get the link dest
+ readlinkres readLinkRes;
+ char nameBuf[NFS_MAXPATHLEN];
+ readLinkRes.readlinkres_u.data=nameBuf;
+
+ int clnt_stat=clnt_call(m_client, NFSPROC_READLINK,
+ (xdrproc_t) xdr_nfs_fh, (char*)&nfsFH,
+ (xdrproc_t) xdr_readlinkres, (char*)&readLinkRes,total_timeout);
+ if (!checkForError(clnt_stat,readLinkRes.status,path)) return;
+ kdDebug(7121)<<"link dest is -"<<readLinkRes.readlinkres_u.data<<"-"<<endl;
+ QCString linkDest(readLinkRes.readlinkres_u.data);
+ atom.m_uds = KIO::UDS_LINK_DEST;
+ atom.m_str = linkDest;
+ entry.append( atom );
+
+ bool isValid=isValidLink(parentDir,linkDest);
+ if (!isValid)
+ {
+ completeBadLinkUDSEntry(entry,attrAndStat.attrstat_u.attributes);
+ }
+ else
+ {
+ if (isAbsoluteLink(linkDest))
+ {
+ completeAbsoluteLinkUDSEntry(entry,linkDest);
+ }
+ else
+ {
+
+ tmpStr=QDir::cleanDirPath(parentDir+QString("/")+QString(linkDest)).latin1();
+ diropargs dirargs;
+ dirargs.name=tmpStr.data();
+ NFSFileHandle tmpFH;
+ tmpFH=getFileHandle(tmpStr);
+ memcpy(dirargs.dir.data,tmpFH,NFS_FHSIZE);
+
+ kdDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-"<<endl;
+ clnt_stat = clnt_call(m_client, NFSPROC_GETATTR,
+ (xdrproc_t) xdr_diropargs, (char*)&dirargs,
+ (xdrproc_t) xdr_attrstat, (char*)&attrAndStat,total_timeout);
+ if (!checkForError(clnt_stat,attrAndStat.status,tmpStr)) return;
+ completeUDSEntry(entry,attrAndStat.attrstat_u.attributes);
+ }
+ }
+ }
+ else
+ completeUDSEntry(entry,attrAndStat.attrstat_u.attributes);
+ statEntry( entry );
+ finished();
+}
+
+void NFSProtocol::completeAbsoluteLinkUDSEntry(UDSEntry& entry, const QCString& path)
+{
+ //taken from file.cc
+ struct stat buff;
+ if ( ::stat( path.data(), &buff ) == -1 ) return;
+
+ UDSAtom atom;
+ atom.m_uds = KIO::UDS_FILE_TYPE;
+ atom.m_long = buff.st_mode & S_IFMT; // extract file type
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_ACCESS;
+ atom.m_long = buff.st_mode & 07777; // extract permissions
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_SIZE;
+ atom.m_long = buff.st_size;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_MODIFICATION_TIME;
+ atom.m_long = buff.st_mtime;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_USER;
+ uid_t uid = buff.st_uid;
+ QString *temp = m_usercache.find( uid );
+
+ if ( !temp )
+ {
+ struct passwd *user = getpwuid( uid );
+ if ( user )
+ {
+ m_usercache.insert( uid, new QString(QString::fromLatin1(user->pw_name)) );
+ atom.m_str = user->pw_name;
+ }
+ else
+ atom.m_str = "???";
+ }
+ else
+ atom.m_str = *temp;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_GROUP;
+ gid_t gid = buff.st_gid;
+ temp = m_groupcache.find( gid );
+ if ( !temp )
+ {
+ struct group *grp = getgrgid( gid );
+ if ( grp )
+ {
+ m_groupcache.insert( gid, new QString(QString::fromLatin1(grp->gr_name)) );
+ atom.m_str = grp->gr_name;
+ }
+ else
+ atom.m_str = "???";
+ }
+ else
+ atom.m_str = *temp;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_ACCESS_TIME;
+ atom.m_long = buff.st_atime;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_CREATION_TIME;
+ atom.m_long = buff.st_ctime;
+ entry.append( atom );
+}
+
+void NFSProtocol::completeBadLinkUDSEntry(UDSEntry& entry, fattr& attributes)
+{
+ // It is a link pointing to nowhere
+ completeUDSEntry(entry,attributes);
+
+ UDSAtom atom;
+ atom.m_uds = KIO::UDS_FILE_TYPE;
+ atom.m_long = S_IFMT - 1;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_ACCESS;
+ atom.m_long = S_IRWXU | S_IRWXG | S_IRWXO;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_SIZE;
+ atom.m_long = 0L;
+ entry.append( atom );
+}
+
+void NFSProtocol::completeUDSEntry(UDSEntry& entry, fattr& attributes)
+{
+ UDSAtom atom;
+
+ atom.m_uds = KIO::UDS_SIZE;
+ atom.m_long = attributes.size;
+ entry.append(atom);
+
+ atom.m_uds = KIO::UDS_MODIFICATION_TIME;
+ atom.m_long = attributes.mtime.seconds;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_ACCESS_TIME;
+ atom.m_long = attributes.atime.seconds;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_CREATION_TIME;
+ atom.m_long = attributes.ctime.seconds;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_ACCESS;
+ atom.m_long = (attributes.mode & 07777);
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_FILE_TYPE;
+ atom.m_long =attributes.mode & S_IFMT; // extract file type
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_USER;
+ uid_t uid = attributes.uid;
+ QString *temp = m_usercache.find( uid );
+ if ( !temp )
+ {
+ struct passwd *user = getpwuid( uid );
+ if ( user )
+ {
+ m_usercache.insert( uid, new QString(user->pw_name) );
+ atom.m_str = user->pw_name;
+ }
+ else
+ atom.m_str = "???";
+ }
+ else
+ atom.m_str = *temp;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_GROUP;
+ gid_t gid = attributes.gid;
+ temp = m_groupcache.find( gid );
+ if ( !temp )
+ {
+ struct group *grp = getgrgid( gid );
+ if ( grp )
+ {
+ m_groupcache.insert( gid, new QString(grp->gr_name) );
+ atom.m_str = grp->gr_name;
+ }
+ else
+ atom.m_str = "???";
+ }
+ else
+ atom.m_str = *temp;
+ entry.append( atom );
+
+/* KIO::UDSEntry::ConstIterator it = entry.begin();
+ for( ; it != entry.end(); it++ ) {
+ switch ((*it).m_uds) {
+ case KIO::UDS_FILE_TYPE:
+ kdDebug(7121) << "File Type : " << (mode_t)((*it).m_long) << endl;
+ break;
+ case KIO::UDS_ACCESS:
+ kdDebug(7121) << "Access permissions : " << (mode_t)((*it).m_long) << endl;
+ break;
+ case KIO::UDS_USER:
+ kdDebug(7121) << "User : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case KIO::UDS_GROUP:
+ kdDebug(7121) << "Group : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case KIO::UDS_NAME:
+ kdDebug(7121) << "Name : " << ((*it).m_str.ascii() ) << endl;
+ //m_strText = decodeFileName( (*it).m_str );
+ break;
+ case KIO::UDS_URL:
+ kdDebug(7121) << "URL : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case KIO::UDS_MIME_TYPE:
+ kdDebug(7121) << "MimeType : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ case KIO::UDS_LINK_DEST:
+ kdDebug(7121) << "LinkDest : " << ((*it).m_str.ascii() ) << endl;
+ break;
+ }
+ }*/
+}
+
+void NFSProtocol::setHost(const QString& host, int /*port*/, const QString& /*user*/, const QString& /*pass*/)
+{
+ kdDebug(7121)<<"setHost: -"<<host<<"-"<<endl;
+ if (host.isEmpty())
+ {
+ error(ERR_UNKNOWN_HOST,"");
+ return;
+ }
+ if (host==m_currentHost) return;
+ m_currentHost=host;
+ m_handleCache.clear();
+ m_exportedDirs.clear();
+ closeConnection();
+}
+
+void NFSProtocol::mkdir( const KURL& url, int permissions )
+{
+ kdDebug(7121)<<"mkdir"<<endl;
+ QString thePath( QFile::encodeName(url.path()));
+ stripTrailingSlash(thePath);
+ QString dirName, parentDir;
+ getLastPart(thePath, dirName, parentDir);
+ stripTrailingSlash(parentDir);
+ kdDebug(7121)<<"path: -"<<thePath<<"- dir: -"<<dirName<<"- parentDir: -"<<parentDir<<"-"<<endl;
+ if (isRoot(parentDir))
+ {
+ error(ERR_WRITE_ACCESS_DENIED,thePath);
+ return;
+ }
+ NFSFileHandle fh=getFileHandle(parentDir);
+ if (fh.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,thePath);
+ return;
+ }
+
+ createargs createArgs;
+ memcpy(createArgs.where.dir.data,fh,NFS_FHSIZE);
+ QCString tmpName=QFile::encodeName(dirName);
+ createArgs.where.name=tmpName.data();
+ if (permissions==-1) createArgs.attributes.mode=0755;
+ else createArgs.attributes.mode=permissions;
+
+ diropres dirres;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_MKDIR,
+ (xdrproc_t) xdr_createargs, (char*)&createArgs,
+ (xdrproc_t) xdr_diropres, (char*)&dirres,total_timeout);
+ if (!checkForError(clnt_stat,dirres.status,thePath)) return;
+ finished();
+}
+
+bool NFSProtocol::checkForError(int clientStat, int nfsStat, const QString& text)
+{
+ if (clientStat!=RPC_SUCCESS)
+ {
+ kdDebug(7121)<<"rpc error: "<<clientStat<<endl;
+ //does this mapping make sense ?
+ error(ERR_CONNECTION_BROKEN,i18n("An RPC error occurred."));
+ return FALSE;
+ }
+ if (nfsStat!=NFS_OK)
+ {
+ kdDebug(7121)<<"nfs error: "<<nfsStat<<endl;
+ switch (nfsStat)
+ {
+ case NFSERR_PERM:
+ error(ERR_ACCESS_DENIED,text);
+ break;
+ case NFSERR_NOENT:
+ error(ERR_DOES_NOT_EXIST,text);
+ break;
+ //does this mapping make sense ?
+ case NFSERR_IO:
+ error(ERR_INTERNAL_SERVER,text);
+ break;
+ //does this mapping make sense ?
+ case NFSERR_NXIO:
+ error(ERR_DOES_NOT_EXIST,text);
+ break;
+ case NFSERR_ACCES:
+ error(ERR_ACCESS_DENIED,text);
+ break;
+ case NFSERR_EXIST:
+ error(ERR_FILE_ALREADY_EXIST,text);
+ break;
+ //does this mapping make sense ?
+ case NFSERR_NODEV:
+ error(ERR_DOES_NOT_EXIST,text);
+ break;
+ case NFSERR_NOTDIR:
+ error(ERR_IS_FILE,text);
+ break;
+ case NFSERR_ISDIR:
+ error(ERR_IS_DIRECTORY,text);
+ break;
+ //does this mapping make sense ?
+ case NFSERR_FBIG:
+ error(ERR_INTERNAL_SERVER,text);
+ break;
+ //does this mapping make sense ?
+ case NFSERR_NOSPC:
+ error(ERR_INTERNAL_SERVER,i18n("No space left on device"));
+ break;
+ case NFSERR_ROFS:
+ error(ERR_COULD_NOT_WRITE,i18n("Read only file system"));
+ break;
+ case NFSERR_NAMETOOLONG:
+ error(ERR_INTERNAL_SERVER,i18n("Filename too long"));
+ break;
+ case NFSERR_NOTEMPTY:
+ error(ERR_COULD_NOT_RMDIR,text);
+ break;
+ //does this mapping make sense ?
+ case NFSERR_DQUOT:
+ error(ERR_INTERNAL_SERVER,i18n("Disk quota exceeded"));
+ break;
+ case NFSERR_STALE:
+ error(ERR_DOES_NOT_EXIST,text);
+ break;
+ default:
+ error(ERR_UNKNOWN,text);
+ break;
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void NFSProtocol::del( const KURL& url, bool isfile)
+{
+ QString thePath( QFile::encodeName(url.path()));
+ stripTrailingSlash(thePath);
+
+ QString fileName, parentDir;
+ getLastPart(thePath, fileName, parentDir);
+ stripTrailingSlash(parentDir);
+ kdDebug(7121)<<"del(): path: -"<<thePath<<"- file -"<<fileName<<"- parentDir: -"<<parentDir<<"-"<<endl;
+ if (isRoot(parentDir))
+ {
+ error(ERR_ACCESS_DENIED,thePath);
+ return;
+ }
+
+ NFSFileHandle fh=getFileHandle(parentDir);
+ if (fh.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,thePath);
+ return;
+ }
+
+ if (isfile)
+ {
+ kdDebug(7121)<<"Deleting file "<<thePath<<endl;
+ diropargs dirOpArgs;
+ memcpy(dirOpArgs.dir.data,fh,NFS_FHSIZE);
+ QCString tmpName=QFile::encodeName(fileName);
+ dirOpArgs.name=tmpName.data();
+
+ nfsstat nfsStat;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_REMOVE,
+ (xdrproc_t) xdr_diropargs, (char*)&dirOpArgs,
+ (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
+ if (!checkForError(clnt_stat,nfsStat,thePath)) return;
+ kdDebug(7121)<<"removing "<<thePath<<" from cache"<<endl;
+ m_handleCache.remove(m_handleCache.find(thePath));
+ finished();
+ }
+ else
+ {
+ kdDebug(7121)<<"Deleting directory "<<thePath<<endl;
+ diropargs dirOpArgs;
+ memcpy(dirOpArgs.dir.data,fh,NFS_FHSIZE);
+ QCString tmpName=QFile::encodeName(fileName);
+ dirOpArgs.name=tmpName.data();
+
+ nfsstat nfsStat;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_RMDIR,
+ (xdrproc_t) xdr_diropargs, (char*)&dirOpArgs,
+ (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
+ if (!checkForError(clnt_stat,nfsStat,thePath)) return;
+ kdDebug(7121)<<"removing "<<thePath<<" from cache"<<endl;
+ m_handleCache.remove(m_handleCache.find(thePath));
+ finished();
+ }
+}
+
+void NFSProtocol::chmod( const KURL& url, int permissions )
+{
+ QString thePath( QFile::encodeName(url.path()));
+ stripTrailingSlash(thePath);
+ kdDebug( 7121 ) << "chmod -"<< thePath << "-"<<endl;
+ if (isRoot(thePath) || isExportedDir(thePath))
+ {
+ error(ERR_ACCESS_DENIED,thePath);
+ return;
+ }
+
+ NFSFileHandle fh=getFileHandle(thePath);
+ if (fh.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,thePath);
+ return;
+ }
+
+ sattrargs sAttrArgs;
+ memcpy(sAttrArgs.file.data,fh,NFS_FHSIZE);
+ sAttrArgs.attributes.uid=(unsigned int)-1;
+ sAttrArgs.attributes.gid=(unsigned int)-1;
+ sAttrArgs.attributes.size=(unsigned int)-1;
+ sAttrArgs.attributes.atime.seconds=(unsigned int)-1;
+ sAttrArgs.attributes.atime.useconds=(unsigned int)-1;
+ sAttrArgs.attributes.mtime.seconds=(unsigned int)-1;
+ sAttrArgs.attributes.mtime.useconds=(unsigned int)-1;
+
+ sAttrArgs.attributes.mode=permissions;
+
+ nfsstat nfsStat;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_SETATTR,
+ (xdrproc_t) xdr_sattrargs, (char*)&sAttrArgs,
+ (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
+ if (!checkForError(clnt_stat,nfsStat,thePath)) return;
+
+ finished();
+}
+
+void NFSProtocol::get( const KURL& url )
+{
+ QString thePath( QFile::encodeName(url.path()));
+ kdDebug(7121)<<"get() -"<<thePath<<"-"<<endl;
+ NFSFileHandle fh=getFileHandle(thePath);
+ if (fh.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,thePath);
+ return;
+ }
+ readargs readArgs;
+ memcpy(readArgs.file.data,fh,NFS_FHSIZE);
+ readArgs.offset=0;
+ readArgs.count=NFS_MAXDATA;
+ readArgs.totalcount=NFS_MAXDATA;
+ readres readRes;
+ int offset(0);
+ char buf[NFS_MAXDATA];
+ readRes.readres_u.reply.data.data_val=buf;
+
+ QByteArray array;
+ do
+ {
+ int clnt_stat = clnt_call(m_client, NFSPROC_READ,
+ (xdrproc_t) xdr_readargs, (char*)&readArgs,
+ (xdrproc_t) xdr_readres, (char*)&readRes,total_timeout);
+ if (!checkForError(clnt_stat,readRes.status,thePath)) return;
+ if (readArgs.offset==0)
+ totalSize(readRes.readres_u.reply.attributes.size);
+
+ offset=readRes.readres_u.reply.data.data_len;
+ //kdDebug(7121)<<"read "<<offset<<" bytes"<<endl;
+ readArgs.offset+=offset;
+ if (offset>0)
+ {
+ array.setRawData(readRes.readres_u.reply.data.data_val, offset);
+ data( array );
+ array.resetRawData(readRes.readres_u.reply.data.data_val, offset);
+
+ processedSize(readArgs.offset);
+ }
+
+ } while (offset>0);
+ data( QByteArray() );
+ finished();
+}
+
+//TODO the partial putting thing is not yet implemented
+void NFSProtocol::put( const KURL& url, int _mode, bool _overwrite, bool /*_resume*/ )
+{
+ QString destPath( QFile::encodeName(url.path()));
+ kdDebug( 7121 ) << "Put -" << destPath <<"-"<<endl;
+ /*QString dest_part( dest_orig );
+ dest_part += ".part";*/
+
+ stripTrailingSlash(destPath);
+ QString parentDir, fileName;
+ getLastPart(destPath,fileName, parentDir);
+ if (isRoot(parentDir))
+ {
+ error(ERR_WRITE_ACCESS_DENIED,destPath);
+ return;
+ }
+
+ NFSFileHandle destFH;
+ destFH=getFileHandle(destPath);
+ kdDebug(7121)<<"file handle for -"<<destPath<<"- is "<<destFH<<endl;
+
+ //the file exists and we don't want to overwrite
+ if ((!_overwrite) && (!destFH.isInvalid()))
+ {
+ error(ERR_FILE_ALREADY_EXIST,destPath);
+ return;
+ }
+ //TODO: is this correct ?
+ //we have to "create" the file anyway, no matter if it already
+ //exists or not
+ //if we don't create it new, written text will be, hmm, "inserted"
+ //in the existing file, i.e. a file could not become smaller, since
+ //write only overwrites or extends, but doesn't remove stuff from a file (aleXXX)
+
+ kdDebug(7121)<<"creating the file -"<<fileName<<"-"<<endl;
+ NFSFileHandle parentFH;
+ parentFH=getFileHandle(parentDir);
+ //cerr<<"fh for parent dir: "<<parentFH<<endl;
+ //the directory doesn't exist
+ if (parentFH.isInvalid())
+ {
+ kdDebug(7121)<<"parent directory -"<<parentDir<<"- does not exist"<<endl;
+ error(ERR_DOES_NOT_EXIST,parentDir);
+ return;
+ }
+ createargs createArgs;
+ memcpy(createArgs.where.dir.data,(const char*)parentFH,NFS_FHSIZE);
+ QCString tmpName=QFile::encodeName(fileName);
+ createArgs.where.name=tmpName.data();
+
+ //the mode is apparently ignored if the file already exists
+ if (_mode==-1) createArgs.attributes.mode=0644;
+ else createArgs.attributes.mode=_mode;
+ createArgs.attributes.uid=geteuid();
+ createArgs.attributes.gid=getegid();
+ //this is required, otherwise we are not able to write shorter files
+ createArgs.attributes.size=0;
+ //hmm, do we need something here ? I don't think so
+ createArgs.attributes.atime.seconds=(unsigned int)-1;
+ createArgs.attributes.atime.useconds=(unsigned int)-1;
+ createArgs.attributes.mtime.seconds=(unsigned int)-1;
+ createArgs.attributes.mtime.useconds=(unsigned int)-1;
+
+ diropres dirOpRes;
+ int clnt_stat = clnt_call(m_client, NFSPROC_CREATE,
+ (xdrproc_t) xdr_createargs, (char*)&createArgs,
+ (xdrproc_t) xdr_diropres, (char*)&dirOpRes,total_timeout);
+ if (!checkForError(clnt_stat,dirOpRes.status,fileName)) return;
+ //we created the file successfully
+ //destFH=getFileHandle(destPath);
+ destFH=dirOpRes.diropres_u.diropres.file.data;
+ kdDebug(7121)<<"file -"<<fileName<<"- in dir -"<<parentDir<<"- created successfully"<<endl;
+ //cerr<<"with fh "<<destFH<<endl;
+
+ //now we can put
+ int result;
+ // Loop until we got 0 (end of data)
+ writeargs writeArgs;
+ memcpy(writeArgs.file.data,(const char*)destFH,NFS_FHSIZE);
+ writeArgs.beginoffset=0;
+ writeArgs.totalcount=0;
+ writeArgs.offset=0;
+ attrstat attrStat;
+ int bytesWritten(0);
+ kdDebug(7121)<<"starting to put"<<endl;
+ do
+ {
+ QByteArray buffer;
+ dataReq(); // Request for data
+ result = readData( buffer );
+ //kdDebug(7121)<<"received "<<result<<" bytes for putting"<<endl;
+ char * data=buffer.data();
+ int bytesToWrite=buffer.size();
+ int writeNow(0);
+ if (result > 0)
+ {
+ do
+ {
+ if (bytesToWrite>NFS_MAXDATA)
+ {
+ writeNow=NFS_MAXDATA;
+ }
+ else
+ {
+ writeNow=bytesToWrite;
+ };
+ writeArgs.data.data_val=data;
+ writeArgs.data.data_len=writeNow;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_WRITE,
+ (xdrproc_t) xdr_writeargs, (char*)&writeArgs,
+ (xdrproc_t) xdr_attrstat, (char*)&attrStat,total_timeout);
+ //kdDebug(7121)<<"written"<<endl;
+ if (!checkForError(clnt_stat,attrStat.status,fileName)) return;
+ bytesWritten+=writeNow;
+ writeArgs.offset=bytesWritten;
+
+ //adjust the pointer
+ data=data+writeNow;
+ //decrease the rest
+ bytesToWrite-=writeNow;
+ } while (bytesToWrite>0);
+ }
+ } while ( result > 0 );
+ finished();
+}
+
+void NFSProtocol::rename( const KURL &src, const KURL &dest, bool _overwrite )
+{
+ QString srcPath( QFile::encodeName(src.path()));
+ QString destPath( QFile::encodeName(dest.path()));
+ stripTrailingSlash(srcPath);
+ stripTrailingSlash(destPath);
+ kdDebug(7121)<<"renaming -"<<srcPath<<"- to -"<<destPath<<"-"<<endl;
+
+ if (isRoot(srcPath) || isExportedDir(srcPath))
+ {
+ error(ERR_CANNOT_RENAME,srcPath);
+ return;
+ }
+
+ if (!_overwrite)
+ {
+ NFSFileHandle testFH;
+ testFH=getFileHandle(destPath);
+ if (!testFH.isInvalid())
+ {
+ error(ERR_FILE_ALREADY_EXIST,destPath);
+ return;
+ }
+ }
+
+ QString srcFileName, srcParentDir, destFileName, destParentDir;
+
+ getLastPart(srcPath, srcFileName, srcParentDir);
+ NFSFileHandle srcFH=getFileHandle(srcParentDir);
+ if (srcFH.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,srcParentDir);
+ return;
+ }
+ renameargs renameArgs;
+ memcpy(renameArgs.from.dir.data,srcFH,NFS_FHSIZE);
+ QCString tmpName=QFile::encodeName(srcFileName);
+ renameArgs.from.name=tmpName.data();
+
+ getLastPart(destPath, destFileName, destParentDir);
+ NFSFileHandle destFH=getFileHandle(destParentDir);
+ if (destFH.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,destParentDir);
+ return;
+ }
+ memcpy(renameArgs.to.dir.data,destFH,NFS_FHSIZE);
+ QCString tmpName2=QFile::encodeName(destFileName);
+ renameArgs.to.name=tmpName2.data();
+ nfsstat nfsStat;
+
+ int clnt_stat = clnt_call(m_client, NFSPROC_RENAME,
+ (xdrproc_t) xdr_renameargs, (char*)&renameArgs,
+ (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
+ if (!checkForError(clnt_stat,nfsStat,destPath)) return;
+ finished();
+}
+
+void NFSProtocol::copy( const KURL &src, const KURL &dest, int _mode, bool _overwrite )
+{
+ //prepare the source
+ QString thePath( QFile::encodeName(src.path()));
+ stripTrailingSlash(thePath);
+ kdDebug( 7121 ) << "Copy to -" << thePath <<"-"<<endl;
+ NFSFileHandle fh=getFileHandle(thePath);
+ if (fh.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,thePath);
+ return;
+ };
+
+ //create the destination
+ QString destPath( QFile::encodeName(dest.path()));
+ stripTrailingSlash(destPath);
+ QString parentDir, fileName;
+ getLastPart(destPath,fileName, parentDir);
+ if (isRoot(parentDir))
+ {
+ error(ERR_ACCESS_DENIED,destPath);
+ return;
+ }
+ NFSFileHandle destFH;
+ destFH=getFileHandle(destPath);
+ kdDebug(7121)<<"file handle for -"<<destPath<<"- is "<<destFH<<endl;
+
+ //the file exists and we don't want to overwrite
+ if ((!_overwrite) && (!destFH.isInvalid()))
+ {
+ error(ERR_FILE_ALREADY_EXIST,destPath);
+ return;
+ }
+ //TODO: is this correct ?
+ //we have to "create" the file anyway, no matter if it already
+ //exists or not
+ //if we don't create it new, written text will be, hmm, "inserted"
+ //in the existing file, i.e. a file could not become smaller, since
+ //write only overwrites or extends, but doesn't remove stuff from a file
+
+ kdDebug(7121)<<"creating the file -"<<fileName<<"-"<<endl;
+ NFSFileHandle parentFH;
+ parentFH=getFileHandle(parentDir);
+ //the directory doesn't exist
+ if (parentFH.isInvalid())
+ {
+ kdDebug(7121)<<"parent directory -"<<parentDir<<"- does not exist"<<endl;
+ error(ERR_DOES_NOT_EXIST,parentDir);
+ return;
+ };
+ createargs createArgs;
+ memcpy(createArgs.where.dir.data,(const char*)parentFH,NFS_FHSIZE);
+ QCString tmpName=QFile::encodeName(fileName);
+ createArgs.where.name=tmpName.data();
+ if (_mode==-1) createArgs.attributes.mode=0644;
+ else createArgs.attributes.mode=_mode;
+ createArgs.attributes.uid=geteuid();
+ createArgs.attributes.gid=getegid();
+ createArgs.attributes.size=0;
+ createArgs.attributes.atime.seconds=(unsigned int)-1;
+ createArgs.attributes.atime.useconds=(unsigned int)-1;
+ createArgs.attributes.mtime.seconds=(unsigned int)-1;
+ createArgs.attributes.mtime.useconds=(unsigned int)-1;
+
+ diropres dirOpRes;
+ int clnt_stat = clnt_call(m_client, NFSPROC_CREATE,
+ (xdrproc_t) xdr_createargs, (char*)&createArgs,
+ (xdrproc_t) xdr_diropres, (char*)&dirOpRes,total_timeout);
+ if (!checkForError(clnt_stat,dirOpRes.status,destPath)) return;
+ //we created the file successfully
+ destFH=dirOpRes.diropres_u.diropres.file.data;
+ kdDebug(7121)<<"file -"<<fileName<<"- in dir -"<<parentDir<<"- created successfully"<<endl;
+
+ char buf[NFS_MAXDATA];
+ writeargs writeArgs;
+ memcpy(writeArgs.file.data,(const char*)destFH,NFS_FHSIZE);
+ writeArgs.beginoffset=0;
+ writeArgs.totalcount=0;
+ writeArgs.offset=0;
+ writeArgs.data.data_val=buf;
+ attrstat attrStat;
+
+ readargs readArgs;
+ memcpy(readArgs.file.data,fh,NFS_FHSIZE);
+ readArgs.offset=0;
+ readArgs.count=NFS_MAXDATA;
+ readArgs.totalcount=NFS_MAXDATA;
+ readres readRes;
+ readRes.readres_u.reply.data.data_val=buf;
+
+ int bytesRead(0);
+ do
+ {
+ //first read
+ int clnt_stat = clnt_call(m_client, NFSPROC_READ,
+ (xdrproc_t) xdr_readargs, (char*)&readArgs,
+ (xdrproc_t) xdr_readres, (char*)&readRes,total_timeout);
+ if (!checkForError(clnt_stat,readRes.status,thePath)) return;
+ if (readArgs.offset==0)
+ totalSize(readRes.readres_u.reply.attributes.size);
+
+ bytesRead=readRes.readres_u.reply.data.data_len;
+ //kdDebug(7121)<<"read "<<bytesRead<<" bytes"<<endl;
+ //then write
+ if (bytesRead>0)
+ {
+ readArgs.offset+=bytesRead;
+
+ writeArgs.data.data_len=bytesRead;
+
+ clnt_stat = clnt_call(m_client, NFSPROC_WRITE,
+ (xdrproc_t) xdr_writeargs, (char*)&writeArgs,
+ (xdrproc_t) xdr_attrstat, (char*)&attrStat,total_timeout);
+ //kdDebug(7121)<<"written"<<endl;
+ if (!checkForError(clnt_stat,attrStat.status,destPath)) return;
+ writeArgs.offset+=bytesRead;
+ }
+ } while (bytesRead>0);
+
+ finished();
+}
+
+//TODO why isn't this even called ?
+void NFSProtocol::symlink( const QString &target, const KURL &dest, bool )
+{
+ kdDebug(7121)<<"symlinking "<<endl;
+ QString destPath=dest.path();
+ stripTrailingSlash(destPath);
+
+ QString parentDir, fileName;
+ getLastPart(destPath,fileName, parentDir);
+ kdDebug(7121)<<"symlinking "<<parentDir<<" "<<fileName<<" to "<<target<<endl;
+ NFSFileHandle fh=getFileHandle(parentDir);
+ if (fh.isInvalid())
+ {
+ error(ERR_DOES_NOT_EXIST,parentDir);
+ return;
+ }
+ if (isRoot(parentDir))
+ {
+ error(ERR_ACCESS_DENIED,destPath);
+ return;
+ }
+
+ kdDebug(7121)<<"tach"<<endl;
+ QCString tmpStr=target.latin1();
+ symlinkargs symLinkArgs;
+ symLinkArgs.to=tmpStr.data();
+ memcpy(symLinkArgs.from.dir.data,(const char*)fh,NFS_FHSIZE);
+ QCString tmpStr2=QFile::encodeName(destPath);
+ symLinkArgs.from.name=tmpStr2.data();
+
+ nfsstat nfsStat;
+ int clnt_stat = clnt_call(m_client, NFSPROC_SYMLINK,
+ (xdrproc_t) xdr_symlinkargs, (char*)&symLinkArgs,
+ (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
+ if (!checkForError(clnt_stat,nfsStat,destPath)) return;
+
+ finished();
+
+}
+
+bool NFSProtocol::isValidLink(const QString& parentDir, const QString& linkDest)
+{
+ kdDebug(7121)<<"isValidLink: parent: "<<parentDir<<" link: "<<linkDest<<endl;
+ if (linkDest.isEmpty()) return FALSE;
+ if (isAbsoluteLink(linkDest))
+ {
+ kdDebug(7121)<<"is an absolute link"<<endl;
+ return QFile::exists(linkDest);
+ }
+ else
+ {
+ kdDebug(7121)<<"is a relative link"<<endl;
+ QString absDest=parentDir+"/"+linkDest;
+ kdDebug(7121)<<"pointing abs to "<<absDest<<endl;
+ absDest=removeFirstPart(absDest);
+ kdDebug(7121)<<"removed first part "<<absDest<<endl;
+ absDest=QDir::cleanDirPath(absDest);
+ kdDebug(7121)<<"simplified to "<<absDest<<endl;
+ if (absDest.find("../")==0)
+ return FALSE;
+
+ kdDebug(7121)<<"is inside the nfs tree"<<endl;
+ absDest=parentDir+"/"+linkDest;
+ absDest=QDir::cleanDirPath(absDest);
+ kdDebug(7121)<<"getting file handle of "<<absDest<<endl;
+ NFSFileHandle fh=getFileHandle(absDest);
+ return (!fh.isInvalid());
+ }
+ return FALSE;
+}
+