delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / kioslave / nfs / kio_nfs.cpp
blob1cae5ec80de738e1efeac6f9e5d1c2ef0f6d14cf
1 /* This file is part of the KDE project
3 Copyright (C) 2000 Alexander Neundorf <neundorf@kde.org>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include <config-runtime.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/utsname.h>
27 #include <arpa/inet.h>
29 // This is needed on Solaris so that rpc.h defines clnttcp_create etc.
30 #ifndef PORTMAP
31 #define PORTMAP
32 #endif
33 #include <rpc/rpc.h> // for rpc calls
35 #include <errno.h>
36 #include <grp.h>
37 #include <memory.h>
38 #include <netdb.h>
39 #include <pwd.h>
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <stdio.h>
43 #include <time.h>
44 #include <unistd.h>
46 #include <QFile>
47 #include <QDir>
48 //Added by qt3to4:
49 #include <QByteArray>
51 #include <kdebug.h>
52 #include <kcomponentdata.h>
53 #include <klocale.h>
55 #include <kio/global.h>
56 #include <iostream>
58 #include "nfs_prot.h"
59 #define fhandle _fhandle
60 #include "mount.h"
61 #include "kio_nfs.h"
63 #define MAXHOSTLEN 256
65 //#define MAXFHAGE 60*15 //15 minutes maximum age for file handles
67 //this ioslave is for NFS version 2
68 #define NFSPROG ((u_long)100003)
69 #define NFSVERS ((u_long)2)
71 using namespace KIO;
72 using namespace std;
74 //this is taken from kdelibs/kdecore/fakes.cpp
75 //#if !defined(HAVE_GETDOMAINNAME)
77 int x_getdomainname(char *name, size_t len)
79 struct utsname uts;
80 struct hostent *hent;
81 int rv = -1;
83 if (name == 0L)
84 errno = EINVAL;
85 else
87 name[0] = '\0';
88 if (uname(&uts) >= 0)
90 if ((hent = gethostbyname(uts.nodename)) != 0L)
92 char *p = strchr(hent->h_name, '.');
93 if (p != 0L)
95 ++p;
96 if (strlen(p) > len-1)
97 errno = EINVAL;
98 else
100 strcpy(name, p);
101 rv = 0;
107 return rv;
109 //#endif
112 extern "C" { int KDE_EXPORT kdemain(int argc, char **argv); }
114 int kdemain( int argc, char **argv )
116 KComponentData componentData( "kio_nfs" );
118 if (argc != 4)
120 fprintf(stderr, "Usage: kio_nfs protocol domain-socket1 domain-socket2\n");
121 exit(-1);
123 kDebug(7121) << "NFS: kdemain: starting";
125 NFSProtocol slave(argv[2], argv[3]);
126 slave.dispatchLoop();
127 return 0;
130 static bool isRoot(const QString& path)
132 return (path.isEmpty() || (path=="/"));
135 static bool isAbsoluteLink(const QString& path)
137 //hmm, don't know
138 if (path.isEmpty()) return true;
139 if (path[0]=='/') return true;
140 return false;
143 static void createVirtualDirEntry(UDSEntry & entry)
145 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
146 entry.insert( KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH );
147 entry.insert( KIO::UDSEntry::UDS_USER, QString::fromLatin1("root") );
148 entry.insert( KIO::UDSEntry::UDS_GROUP, QString::fromLatin1("root") );
149 //a dummy size
150 entry.insert( KIO::UDSEntry::UDS_SIZE, 1024 );
154 static void stripTrailingSlash(QString& path)
156 //if (path=="/") return;
157 if (path=="/") path="";
158 else if (path[path.length()-1]=='/') path.truncate(path.length()-1);
161 static void getLastPart(const QString& path, QString& lastPart, QString& rest)
163 int slashPos=path.lastIndexOf("/");
164 lastPart=path.mid(slashPos+1);
165 rest=path.left(slashPos+1);
168 static QString removeFirstPart(const QString& path)
170 QString result("");
171 if (path.isEmpty()) return result;
172 result=path.mid(1);
173 int slashPos=result.indexOf("/");
174 return result.mid(slashPos+1);
177 NFSFileHandle::NFSFileHandle()
178 :m_isInvalid(false)
180 memset(m_handle,'\0',NFS_FHSIZE+1);
181 // m_detectTime=time(0);
184 NFSFileHandle::NFSFileHandle(const NFSFileHandle & handle)
185 :m_isInvalid(false)
187 m_handle[NFS_FHSIZE]='\0';
188 memcpy(m_handle,handle.m_handle,NFS_FHSIZE);
189 m_isInvalid=handle.m_isInvalid;
190 // m_detectTime=handle.m_detectTime;
193 NFSFileHandle::~NFSFileHandle()
196 NFSFileHandle& NFSFileHandle::operator= (const NFSFileHandle& src)
198 memcpy(m_handle,src.m_handle,NFS_FHSIZE);
199 m_isInvalid=src.m_isInvalid;
200 // m_detectTime=src.m_detectTime;
201 return *this;
204 NFSFileHandle& NFSFileHandle::operator= (const char* src)
206 if (src==0)
208 m_isInvalid=true;
209 return *this;
211 memcpy(m_handle,src,NFS_FHSIZE);
212 m_isInvalid=false;
213 // m_detectTime=time(0);
214 return *this;
217 /*time_t NFSFileHandle::age() const
219 return (time(0)-m_detectTime);
223 NFSProtocol::NFSProtocol (const QByteArray &pool, const QByteArray &app )
224 :SlaveBase( "nfs", pool, app )
225 ,m_client(0)
226 ,m_sock(-1)
227 ,m_lastCheck(time(0))
229 kDebug(7121)<<"NFS::NFS: -"<<pool<<"-";
232 NFSProtocol::~NFSProtocol()
234 closeConnection();
237 /*This one is currently unused, so it could be removed.
238 The intention was to keep handles around, and from time to time
239 remove handles which are too old. Alex
241 /*void NFSProtocol::checkForOldFHs()
243 kDebug(7121)<<"checking for fhs older than "<<MAXFHAGE;
244 kDebug(7121)<<"current items: "<<m_handleCache.count();
245 NFSFileHandleMap::Iterator it=m_handleCache.begin();
246 NFSFileHandleMap::Iterator lastIt=it;
247 while (it!=m_handleCache.end())
249 kDebug(7121)<<it.data().age()<<flush;
250 if (it.data().age()>MAXFHAGE)
252 kDebug(7121)<<"removing";
253 m_handleCache.remove(it);
254 if (it==lastIt)
256 it=m_handleCache.begin();
257 lastIt=it;
259 else
260 it=lastIt;
262 lastIt=it;
263 it++;
265 kDebug(7121)<<"left items: "<<m_handleCache.count();
266 m_lastCheck=time(0);
269 void NFSProtocol::closeConnection()
271 ::close(m_sock);
272 m_sock=-1;
273 if (m_client==0) return;
274 CLNT_DESTROY(m_client);
276 m_client=0;
279 bool NFSProtocol::isExportedDir(const QString& path)
281 return m_exportedDirs.contains(path.mid(1));
284 /* This one works recursive.
285 It tries to get the file handle out of the file handle cache.
286 If this doesn't succeed, it needs to do a nfs rpc call
287 in order to obtain one.
289 NFSFileHandle NFSProtocol::getFileHandle(QString path)
291 if (m_client==0) openConnection();
293 //I'm not sure if this is useful
294 //if ((time(0)-m_lastCheck)>MAXFHAGE) checkForOldFHs();
296 stripTrailingSlash(path);
297 kDebug(7121)<<"getting FH for -"<<path<<"-";
298 //now the path looks like "/root/some/dir" or "" if it was "/"
299 NFSFileHandle parentFH;
300 //we didn't find it
301 if (path.isEmpty())
303 kDebug(7121)<<"path is empty, invalidating the FH";
304 parentFH.setInvalid();
305 return parentFH;
307 //check whether we have this filehandle cached
308 //the filehandles of the exported root dirs are always in the cache
309 if (m_handleCache.find(path)!=m_handleCache.end())
311 kDebug(7121)<<"path is in the cache, returning the FH -"<<m_handleCache[path]<<"-";
312 return m_handleCache[path];
314 QString rest, lastPart;
315 getLastPart(path,lastPart,rest);
316 kDebug(7121)<<"splitting path into rest -"<<rest<<"- and lastPart -"<<lastPart<<"-";
318 parentFH=getFileHandle(rest);
319 //f*ck, it's invalid
320 if (parentFH.isInvalid())
322 kDebug(7121)<<"the parent FH is invalid";
323 return parentFH;
325 // do the rpc call
326 diropargs dirargs;
327 diropres dirres;
328 memcpy(dirargs.dir.data,(const char*)parentFH,NFS_FHSIZE);
329 QByteArray tmpStr=QFile::encodeName(lastPart);
330 dirargs.name=tmpStr.data();
332 //cerr<<"calling rpc: FH: -"<<parentFH<<"- with name -"<<dirargs.name<<"-"<<endl;
334 int clnt_stat = clnt_call(m_client, NFSPROC_LOOKUP,
335 (xdrproc_t) xdr_diropargs, (char*)&dirargs,
336 (xdrproc_t) xdr_diropres, (char*)&dirres,total_timeout);
338 if ((clnt_stat!=RPC_SUCCESS) || (dirres.status!=NFS_OK))
340 //we failed
341 kDebug(7121)<<"lookup of filehandle failed";
342 parentFH.setInvalid();
343 return parentFH;
345 //everything went fine up to now :-)
346 parentFH=dirres.diropres_u.diropres.file.data;
347 //kDebug(7121)<<"filesize: "<<dirres.diropres_u.diropres.attributes.size;
348 m_handleCache.insert(path,parentFH);
349 kDebug(7121)<<"return FH -"<<parentFH<<"-";
350 return parentFH;
353 /* Open connection connects to the mount daemon on the server side.
354 In order to do this it needs authentication and calls auth_unix_create().
355 Then it asks the mount daemon for the exported shares. Then it tries
356 to mount all these shares. If this succeeded for at least one of them,
357 a client for the nfs daemon is created.
359 void NFSProtocol::openConnection()
361 kDebug(7121)<<"NFS::openConnection for -" << m_currentHost.toLatin1() << "-";
362 if (m_currentHost.isEmpty())
364 error(ERR_UNKNOWN_HOST,"");
365 return;
367 struct sockaddr_in server_addr;
368 if (m_currentHost[0] >= '0' && m_currentHost[0] <= '9')
370 server_addr.sin_family = AF_INET;
371 server_addr.sin_addr.s_addr = inet_addr(m_currentHost.toLatin1());
373 else
375 struct hostent *hp=gethostbyname(m_currentHost.toLatin1());
376 if (hp==0)
378 error( ERR_UNKNOWN_HOST, m_currentHost.toLatin1() );
379 return;
381 server_addr.sin_family = AF_INET;
382 memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
385 // create mount daemon client
386 closeConnection();
387 server_addr.sin_port = 0;
388 m_sock = RPC_ANYSOCK;
389 m_client=clnttcp_create(&server_addr,MOUNTPROG, MOUNTVERS, &m_sock, 0, 0);
390 if (m_client==0)
392 server_addr.sin_port = 0;
393 m_sock = RPC_ANYSOCK;
394 pertry_timeout.tv_sec = 3;
395 pertry_timeout.tv_usec = 0;
396 m_client = clntudp_create(&server_addr,MOUNTPROG, MOUNTVERS, pertry_timeout, &m_sock);
397 if (m_client==0)
399 clnt_pcreateerror(const_cast<char *>("mount clntudp_create"));
400 error(ERR_COULD_NOT_CONNECT, m_currentHost.toLatin1());
401 return;
404 QByteArray hostName("localhost");
405 char nameBuffer[1024];
406 nameBuffer[0] = '\0';
407 if (gethostname(nameBuffer, 1024)==0)
409 nameBuffer[sizeof(nameBuffer)-1] = '\0';
410 hostName=nameBuffer;
411 // I have the same problem here as Stefan Westerfeld, that's why I use
412 // the getdomainname() from fakes.cpp (renamed to x_getdomainname()), this one works
413 // taken from kdelibs/arts/mcopy/mcoputils.cc
414 nameBuffer[0] = '\0';
415 if (x_getdomainname(nameBuffer, 1024)==0)
417 nameBuffer[sizeof(nameBuffer)-1] = '\0';
419 * I don't know why, but on my linux machine, the domainname
420 * always ends up being (none), which is certainly no valid
421 * domainname
423 if(strcmp(nameBuffer,"(none)") != 0) {
424 hostName += '.';
425 hostName += nameBuffer;
429 kDebug(7121) << "hostname is -" << hostName << "-";
430 m_client->cl_auth = authunix_create(hostName.data(), geteuid(), getegid(), 0, 0);
431 total_timeout.tv_sec = 20;
432 total_timeout.tv_usec = 0;
434 exports exportlist;
435 //now do the stuff
436 memset(&exportlist, '\0', sizeof(exportlist));
438 int clnt_stat = clnt_call(m_client, MOUNTPROC_EXPORT,(xdrproc_t) xdr_void, NULL,
439 (xdrproc_t) xdr_exports, (char*)&exportlist,total_timeout);
440 if (!checkForError(clnt_stat, 0, m_currentHost.toLatin1())) return;
442 fhstatus fhStatus;
443 bool atLeastOnceSucceeded(false);
444 for(; exportlist!=0;exportlist = exportlist->ex_next) {
445 kDebug(7121) << "found export: " << exportlist->ex_dir;
447 memset(&fhStatus, 0, sizeof(fhStatus));
448 clnt_stat = clnt_call(m_client, MOUNTPROC_MNT,(xdrproc_t) xdr_dirpath, (char*)(&(exportlist->ex_dir)),
449 (xdrproc_t) xdr_fhstatus,(char*) &fhStatus,total_timeout);
450 if (fhStatus.fhs_status==0) {
451 atLeastOnceSucceeded=true;
452 NFSFileHandle fh;
453 fh=fhStatus.fhstatus_u.fhs_fhandle;
454 QString fname;
455 if ( exportlist->ex_dir[0] == '/' )
456 fname = KIO::encodeFileName(exportlist->ex_dir + 1);
457 else
458 fname = KIO::encodeFileName(exportlist->ex_dir);
459 m_handleCache.insert(QString("/")+fname,fh);
460 m_exportedDirs.append(fname);
461 // kDebug() <<"appending file -"<<fname<<"- with FH: -"<<fhStatus.fhstatus_u.fhs_fhandle<<"-";
464 if (!atLeastOnceSucceeded)
466 closeConnection();
467 error( ERR_COULD_NOT_AUTHENTICATE, m_currentHost.toLatin1());
468 return;
470 server_addr.sin_port = 0;
472 //now create the client for the nfs daemon
473 //first get rid of the old one
474 closeConnection();
475 m_sock = RPC_ANYSOCK;
476 m_client = clnttcp_create(&server_addr,NFSPROG,NFSVERS,&m_sock,0,0);
477 if (m_client == 0)
479 server_addr.sin_port = 0;
480 m_sock = RPC_ANYSOCK;
481 pertry_timeout.tv_sec = 3;
482 pertry_timeout.tv_usec = 0;
483 m_client = clntudp_create(&server_addr,NFSPROG, NFSVERS, pertry_timeout, &m_sock);
484 if (m_client==0)
486 clnt_pcreateerror(const_cast<char *>("NFS clntudp_create"));
487 error(ERR_COULD_NOT_CONNECT, m_currentHost.toLatin1());
488 return;
491 m_client->cl_auth = authunix_create(hostName.data(),geteuid(),getegid(),0,0);
492 connected();
493 kDebug(7121)<<"openConnection succeeded";
496 void NFSProtocol::listDir( const KUrl& _url)
498 KUrl url(_url);
499 QString path( QFile::encodeName(url.path()));
501 if (path.isEmpty())
503 url.setPath("/");
504 redirection(url);
505 finished();
506 return;
508 //open the connection
509 if (m_client==0) openConnection();
510 //it failed
511 if (m_client==0) return;
512 if (isRoot(path))
514 kDebug(7121)<<"listing root";
515 totalSize( m_exportedDirs.count());
516 //in this case we don't need to do a real listdir
517 UDSEntry entry;
518 for (QStringList::const_iterator it=m_exportedDirs.constBegin(); it!=m_exportedDirs.constEnd(); ++it)
520 entry.clear();
521 entry.insert( KIO::UDSEntry::UDS_NAME, (*it) );
522 kDebug(7121)<<"listing "<<(*it);
523 createVirtualDirEntry(entry);
524 listEntry( entry, false);
526 listEntry( entry, true ); // ready
527 finished();
528 return;
531 QStringList filesToList;
532 kDebug(7121)<<"getting subdir -"<<path<<"-";
533 stripTrailingSlash(path);
534 NFSFileHandle fh=getFileHandle(path);
535 //cerr<<"this is the fh: -"<<fh<<"-"<<endl;
536 if (fh.isInvalid())
538 error( ERR_DOES_NOT_EXIST, path);
539 return;
541 readdirargs listargs;
542 memset(&listargs,0,sizeof(listargs));
543 listargs.count=1024*16;
544 memcpy(listargs.dir.data,fh,NFS_FHSIZE);
545 readdirres listres;
548 memset(&listres,'\0',sizeof(listres));
549 int clnt_stat = clnt_call(m_client, NFSPROC_READDIR, (xdrproc_t) xdr_readdirargs, (char*)&listargs,
550 (xdrproc_t) xdr_readdirres, (char*)&listres,total_timeout);
551 if (!checkForError(clnt_stat,listres.status,path)) return;
552 for (entry *dirEntry=listres.readdirres_u.reply.entries;dirEntry!=0;dirEntry=dirEntry->nextentry)
554 if ((QString(".")!=dirEntry->name) && (QString("..")!=dirEntry->name))
555 filesToList.append(dirEntry->name);
557 } while (!listres.readdirres_u.reply.eof);
558 totalSize( filesToList.count());
560 UDSEntry entry;
561 //stat all files in filesToList
562 for (QStringList::const_iterator it=filesToList.constBegin(); it!=filesToList.constEnd(); ++it)
564 diropargs dirargs;
565 diropres dirres;
566 memcpy(dirargs.dir.data,fh,NFS_FHSIZE);
567 QByteArray tmpStr=QFile::encodeName(*it);
568 dirargs.name=tmpStr.data();
570 kDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-";
572 int clnt_stat= clnt_call(m_client, NFSPROC_LOOKUP,
573 (xdrproc_t) xdr_diropargs, (char*)&dirargs,
574 (xdrproc_t) xdr_diropres, (char*)&dirres,total_timeout);
575 if (!checkForError(clnt_stat,dirres.status,(*it))) return;
577 NFSFileHandle tmpFH;
578 tmpFH=dirres.diropres_u.diropres.file.data;
579 m_handleCache.insert(path+'/'+(*it),tmpFH);
581 entry.clear();
583 entry.insert( KIO::UDSEntry::UDS_NAME, (*it) );
585 //is it a symlink ?
586 if (S_ISLNK(dirres.diropres_u.diropres.attributes.mode))
588 kDebug(7121)<<"it's a symlink !";
589 //cerr<<"fh: "<<tmpFH<<endl;
590 nfs_fh nfsFH;
591 memcpy(nfsFH.data,dirres.diropres_u.diropres.file.data,NFS_FHSIZE);
592 //get the link dest
593 readlinkres readLinkRes;
594 char nameBuf[NFS_MAXPATHLEN];
595 readLinkRes.readlinkres_u.data=nameBuf;
596 int clnt_stat=clnt_call(m_client, NFSPROC_READLINK,
597 (xdrproc_t) xdr_nfs_fh, (char*)&nfsFH,
598 (xdrproc_t) xdr_readlinkres, (char*)&readLinkRes,total_timeout);
599 if (!checkForError(clnt_stat,readLinkRes.status,(*it))) return;
600 kDebug(7121)<<"link dest is -"<<readLinkRes.readlinkres_u.data<<"-";
601 QByteArray linkDest(readLinkRes.readlinkres_u.data);
602 entry.insert( KIO::UDSEntry::UDS_LINK_DEST, QString::fromLocal8Bit( linkDest ) );
604 bool isValid=isValidLink(path,linkDest);
605 if (!isValid)
607 completeBadLinkUDSEntry(entry,dirres.diropres_u.diropres.attributes);
609 else
611 if (isAbsoluteLink(linkDest))
613 completeAbsoluteLinkUDSEntry(entry,linkDest);
615 else
617 tmpStr=QDir::cleanPath(path+QString("/")+QString(linkDest)).toLatin1();
618 dirargs.name=tmpStr.data();
619 tmpFH=getFileHandle(tmpStr);
620 memcpy(dirargs.dir.data,tmpFH,NFS_FHSIZE);
622 attrstat attrAndStat;
624 kDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-";
626 clnt_stat = clnt_call(m_client, NFSPROC_GETATTR,
627 (xdrproc_t) xdr_diropargs, (char*)&dirargs,
628 (xdrproc_t) xdr_attrstat, (char*)&attrAndStat,total_timeout);
629 if (!checkForError(clnt_stat,attrAndStat.status,tmpStr)) return;
630 completeUDSEntry(entry,attrAndStat.attrstat_u.attributes);
634 else
635 completeUDSEntry(entry,dirres.diropres_u.diropres.attributes);
636 listEntry( entry, false);
638 listEntry( entry, true ); // ready
639 finished();
642 void NFSProtocol::stat( const KUrl & url)
644 QString path( QFile::encodeName(url.path()));
645 stripTrailingSlash(path);
646 kDebug(7121)<<"NFS::stat for -"<<path<<"-";
647 QString tmpPath=path;
648 if ((tmpPath.length()>1) && (tmpPath[0]=='/')) tmpPath=tmpPath.mid(1);
649 // We can't stat root, but we know it's a dir
650 if (isRoot(path) || isExportedDir(path))
652 UDSEntry entry;
654 entry.insert( KIO::UDSEntry::UDS_NAME, path );
655 createVirtualDirEntry(entry);
656 // no size
657 statEntry( entry );
658 finished();
659 kDebug(7121)<<"succeeded";
660 return;
663 NFSFileHandle fh=getFileHandle(path);
664 if (fh.isInvalid())
666 error(ERR_DOES_NOT_EXIST,path);
667 return;
670 diropargs dirargs;
671 attrstat attrAndStat;
672 memcpy(dirargs.dir.data,fh,NFS_FHSIZE);
673 QByteArray tmpStr=QFile::encodeName(path);
674 dirargs.name=tmpStr.data();
676 kDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-";
678 int clnt_stat = clnt_call(m_client, NFSPROC_GETATTR,
679 (xdrproc_t) xdr_diropargs, (char*)&dirargs,
680 (xdrproc_t) xdr_attrstat, (char*)&attrAndStat,total_timeout);
681 if (!checkForError(clnt_stat,attrAndStat.status,path)) return;
682 UDSEntry entry;
683 entry.clear();
685 QString fileName, parentDir;
686 getLastPart(path, fileName, parentDir);
687 stripTrailingSlash(parentDir);
689 entry.insert( KIO::UDSEntry::UDS_NAME, fileName );
691 //is it a symlink ?
692 if (S_ISLNK(attrAndStat.attrstat_u.attributes.mode))
694 kDebug(7121)<<"it's a symlink !";
695 nfs_fh nfsFH;
696 memcpy(nfsFH.data,fh,NFS_FHSIZE);
697 //get the link dest
698 readlinkres readLinkRes;
699 char nameBuf[NFS_MAXPATHLEN];
700 readLinkRes.readlinkres_u.data=nameBuf;
702 int clnt_stat=clnt_call(m_client, NFSPROC_READLINK,
703 (xdrproc_t) xdr_nfs_fh, (char*)&nfsFH,
704 (xdrproc_t) xdr_readlinkres, (char*)&readLinkRes,total_timeout);
705 if (!checkForError(clnt_stat,readLinkRes.status,path)) return;
706 kDebug(7121)<<"link dest is -"<<readLinkRes.readlinkres_u.data<<"-";
707 QByteArray linkDest(readLinkRes.readlinkres_u.data);
708 entry.insert( KIO::UDSEntry::UDS_LINK_DEST, QString::fromLocal8Bit( linkDest ) );
710 bool isValid=isValidLink(parentDir,linkDest);
711 if (!isValid)
713 completeBadLinkUDSEntry(entry,attrAndStat.attrstat_u.attributes);
715 else
717 if (isAbsoluteLink(linkDest))
719 completeAbsoluteLinkUDSEntry(entry,linkDest);
721 else
724 tmpStr=QDir::cleanPath(parentDir+QString("/")+QString(linkDest)).toLatin1();
725 diropargs dirargs;
726 dirargs.name=tmpStr.data();
727 NFSFileHandle tmpFH;
728 tmpFH=getFileHandle(tmpStr);
729 memcpy(dirargs.dir.data,tmpFH,NFS_FHSIZE);
731 kDebug(7121)<<"calling rpc: FH: -"<<fh<<"- with name -"<<dirargs.name<<"-";
732 clnt_stat = clnt_call(m_client, NFSPROC_GETATTR,
733 (xdrproc_t) xdr_diropargs, (char*)&dirargs,
734 (xdrproc_t) xdr_attrstat, (char*)&attrAndStat,total_timeout);
735 if (!checkForError(clnt_stat,attrAndStat.status,tmpStr)) return;
736 completeUDSEntry(entry,attrAndStat.attrstat_u.attributes);
740 else
741 completeUDSEntry(entry,attrAndStat.attrstat_u.attributes);
742 statEntry( entry );
743 finished();
746 void NFSProtocol::completeAbsoluteLinkUDSEntry(UDSEntry& entry, const QByteArray& path)
748 //taken from file.cc
749 struct stat buff;
750 if ( ::stat( path.data(), &buff ) == -1 ) return;
752 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, buff.st_mode & S_IFMT ); // extract file type
753 entry.insert( KIO::UDSEntry::UDS_ACCESS, buff.st_mode & 07777 ); // extract permissions
754 entry.insert( KIO::UDSEntry::UDS_SIZE, buff.st_size );
755 entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime );
757 uid_t uid = buff.st_uid;
759 QString str;
760 if ( !m_usercache.contains( uid ) ) {
761 struct passwd *user = getpwuid( uid );
762 if ( user )
764 m_usercache.insert( uid, QString::fromLatin1(user->pw_name) );
765 str = user->pw_name;
767 else
768 str = "???";
769 } else
770 str = m_usercache.value( uid );
772 entry.insert( KIO::UDSEntry::UDS_USER, str );
774 gid_t gid = buff.st_gid;
776 if ( !m_groupcache.contains( gid ) )
778 struct group *grp = getgrgid( gid );
779 if ( grp )
781 m_groupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
782 str = grp->gr_name;
784 else
785 str = "???";
787 else
788 str = m_groupcache.value( gid );
790 entry.insert( KIO::UDSEntry::UDS_GROUP, str );
792 entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime );
793 entry.insert( KIO::UDSEntry::UDS_CREATION_TIME, buff.st_ctime );
796 void NFSProtocol::completeBadLinkUDSEntry(UDSEntry& entry, fattr& attributes)
798 // It is a link pointing to nowhere
799 completeUDSEntry(entry,attributes);
801 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFMT - 1 );
802 entry.insert( KIO::UDSEntry::UDS_ACCESS, S_IRWXU | S_IRWXG | S_IRWXO );
803 entry.insert( KIO::UDSEntry::UDS_SIZE, 0L );
806 void NFSProtocol::completeUDSEntry(UDSEntry& entry, fattr& attributes)
808 entry.insert( KIO::UDSEntry::UDS_SIZE, attributes.size );
809 entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, attributes.mtime.seconds );
810 entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, attributes.atime.seconds );
811 entry.insert( KIO::UDSEntry::UDS_CREATION_TIME, attributes.ctime.seconds );
812 entry.insert( KIO::UDSEntry::UDS_ACCESS, (attributes.mode & 07777) );
813 entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, attributes.mode & S_IFMT ); // extract file type
815 uid_t uid = attributes.uid;
816 QString str;
817 if ( !m_usercache.contains( uid ) )
819 struct passwd *user = getpwuid( uid );
820 if ( user )
822 m_usercache.insert( uid, QString::fromLatin1(user->pw_name) );
823 str = user->pw_name;
825 else
826 str = "???";
828 else
829 str = m_usercache.value( uid );
831 entry.insert( KIO::UDSEntry::UDS_USER, str );
833 gid_t gid = attributes.gid;
835 if ( !m_groupcache.contains( gid ) )
837 struct group *grp = getgrgid( gid );
838 if ( grp )
840 m_groupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
841 str = grp->gr_name;
843 else
844 str = "???";
846 else
847 str = m_groupcache.value( gid );
849 entry.insert( KIO::UDSEntry::UDS_GROUP, str );
851 /* KIO::UDSEntry::ConstIterator it = entry.begin();
852 for( ; it != entry.end(); it++ ) {
853 switch (it.key()) {
854 case KIO::UDSEntry::UDS_FILE_TYPE:
855 kDebug(7121) << "File Type : " << (mode_t)((*it).m_long);
856 break;
857 case KIO::UDSEntry::UDS_ACCESS:
858 kDebug(7121) << "Access permissions : " << (mode_t)((*it).m_long);
859 break;
860 case KIO::UDSEntry::UDS_USER:
861 kDebug(7121) << "User : " << ((*it).m_str.toAscii() );
862 break;
863 case KIO::UDSEntry::UDS_GROUP:
864 kDebug(7121) << "Group : " << ((*it).m_str.toAscii() );
865 break;
866 case KIO::UDSEntry::UDS_NAME:
867 kDebug(7121) << "Name : " << ((*it).m_str.toAscii() );
868 //m_strText = decodeFileName( (*it).m_str );
869 break;
870 case KIO::UDSEntry::UDS_URL:
871 kDebug(7121) << "URL : " << ((*it).m_str.toAscii() );
872 break;
873 case KIO::UDSEntry::UDS_MIME_TYPE:
874 kDebug(7121) << "MimeType : " << ((*it).m_str.toAscii() );
875 break;
876 case KIO::UDSEntry::UDS_LINK_DEST:
877 kDebug(7121) << "LinkDest : " << ((*it).m_str.toAscii() );
878 break;
883 void NFSProtocol::setHost(const QString& host, quint16 /*port*/, const QString& /*user*/, const QString& /*pass*/)
885 kDebug(7121)<<"setHost: -"<<host<<"-";
886 if (host.isEmpty())
888 error(ERR_UNKNOWN_HOST,"");
889 return;
891 if (host==m_currentHost) return;
892 m_currentHost=host;
893 m_handleCache.clear();
894 m_exportedDirs.clear();
895 closeConnection();
898 void NFSProtocol::mkdir( const KUrl& url, int permissions )
900 kDebug(7121)<<"mkdir";
901 QString thePath( QFile::encodeName(url.path()));
902 stripTrailingSlash(thePath);
903 QString dirName, parentDir;
904 getLastPart(thePath, dirName, parentDir);
905 stripTrailingSlash(parentDir);
906 kDebug(7121)<<"path: -"<<thePath<<"- dir: -"<<dirName<<"- parentDir: -"<<parentDir<<"-";
907 if (isRoot(parentDir))
909 error(ERR_WRITE_ACCESS_DENIED,thePath);
910 return;
912 NFSFileHandle fh=getFileHandle(parentDir);
913 if (fh.isInvalid())
915 error(ERR_DOES_NOT_EXIST,thePath);
916 return;
919 createargs createArgs;
920 memcpy(createArgs.where.dir.data,fh,NFS_FHSIZE);
921 QByteArray tmpName=QFile::encodeName(dirName);
922 createArgs.where.name=tmpName.data();
923 if (permissions==-1) createArgs.attributes.mode=0755;
924 else createArgs.attributes.mode=permissions;
926 diropres dirres;
928 int clnt_stat = clnt_call(m_client, NFSPROC_MKDIR,
929 (xdrproc_t) xdr_createargs, (char*)&createArgs,
930 (xdrproc_t) xdr_diropres, (char*)&dirres,total_timeout);
931 if (!checkForError(clnt_stat,dirres.status,thePath)) return;
932 finished();
935 bool NFSProtocol::checkForError(int clientStat, int nfsStat, const QString& text)
937 if (clientStat!=RPC_SUCCESS)
939 kDebug(7121)<<"rpc error: "<<clientStat;
940 //does this mapping make sense ?
941 error(ERR_CONNECTION_BROKEN,i18n("An RPC error occurred."));
942 return false;
944 if (nfsStat!=NFS_OK)
946 kDebug(7121)<<"nfs error: "<<nfsStat;
947 switch (nfsStat)
949 case NFSERR_PERM:
950 error(ERR_ACCESS_DENIED,text);
951 break;
952 case NFSERR_NOENT:
953 error(ERR_DOES_NOT_EXIST,text);
954 break;
955 //does this mapping make sense ?
956 case NFSERR_IO:
957 error(ERR_INTERNAL_SERVER,text);
958 break;
959 //does this mapping make sense ?
960 case NFSERR_NXIO:
961 error(ERR_DOES_NOT_EXIST,text);
962 break;
963 case NFSERR_ACCES:
964 error(ERR_ACCESS_DENIED,text);
965 break;
966 case NFSERR_EXIST:
967 error(ERR_FILE_ALREADY_EXIST,text);
968 break;
969 //does this mapping make sense ?
970 case NFSERR_NODEV:
971 error(ERR_DOES_NOT_EXIST,text);
972 break;
973 case NFSERR_NOTDIR:
974 error(ERR_IS_FILE,text);
975 break;
976 case NFSERR_ISDIR:
977 error(ERR_IS_DIRECTORY,text);
978 break;
979 //does this mapping make sense ?
980 case NFSERR_FBIG:
981 error(ERR_INTERNAL_SERVER,text);
982 break;
983 //does this mapping make sense ?
984 case NFSERR_NOSPC:
985 error(ERR_INTERNAL_SERVER,i18n("No space left on device"));
986 break;
987 case NFSERR_ROFS:
988 error(ERR_COULD_NOT_WRITE,i18n("Read only file system"));
989 break;
990 case NFSERR_NAMETOOLONG:
991 error(ERR_INTERNAL_SERVER,i18n("Filename too long"));
992 break;
993 case NFSERR_NOTEMPTY:
994 error(ERR_COULD_NOT_RMDIR,text);
995 break;
996 //does this mapping make sense ?
997 case NFSERR_DQUOT:
998 error(ERR_INTERNAL_SERVER,i18n("Disk quota exceeded"));
999 break;
1000 case NFSERR_STALE:
1001 error(ERR_DOES_NOT_EXIST,text);
1002 break;
1003 default:
1004 error(ERR_UNKNOWN,text);
1005 break;
1007 return false;
1009 return true;
1012 void NFSProtocol::del( const KUrl& url, bool isfile)
1014 QString thePath( QFile::encodeName(url.path()));
1015 stripTrailingSlash(thePath);
1017 QString fileName, parentDir;
1018 getLastPart(thePath, fileName, parentDir);
1019 stripTrailingSlash(parentDir);
1020 kDebug(7121)<<"del(): path: -"<<thePath<<"- file -"<<fileName<<"- parentDir: -"<<parentDir<<"-";
1021 if (isRoot(parentDir))
1023 error(ERR_ACCESS_DENIED,thePath);
1024 return;
1027 NFSFileHandle fh=getFileHandle(parentDir);
1028 if (fh.isInvalid())
1030 error(ERR_DOES_NOT_EXIST,thePath);
1031 return;
1034 if (isfile)
1036 kDebug(7121)<<"Deleting file "<<thePath;
1037 diropargs dirOpArgs;
1038 memcpy(dirOpArgs.dir.data,fh,NFS_FHSIZE);
1039 QByteArray tmpName=QFile::encodeName(fileName);
1040 dirOpArgs.name=tmpName.data();
1042 nfsstat nfsStat;
1044 int clnt_stat = clnt_call(m_client, NFSPROC_REMOVE,
1045 (xdrproc_t) xdr_diropargs, (char*)&dirOpArgs,
1046 (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
1047 if (!checkForError(clnt_stat,nfsStat,thePath)) return;
1048 kDebug(7121)<<"removing "<<thePath<<" from cache";
1049 m_handleCache.erase(m_handleCache.find(thePath));
1050 finished();
1052 else
1054 kDebug(7121)<<"Deleting directory "<<thePath;
1055 diropargs dirOpArgs;
1056 memcpy(dirOpArgs.dir.data,fh,NFS_FHSIZE);
1057 QByteArray tmpName=QFile::encodeName(fileName);
1058 dirOpArgs.name=tmpName.data();
1060 nfsstat nfsStat;
1062 int clnt_stat = clnt_call(m_client, NFSPROC_RMDIR,
1063 (xdrproc_t) xdr_diropargs, (char*)&dirOpArgs,
1064 (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
1065 if (!checkForError(clnt_stat,nfsStat,thePath)) return;
1066 kDebug(7121)<<"removing "<<thePath<<" from cache";
1067 m_handleCache.erase(m_handleCache.find(thePath));
1068 finished();
1072 void NFSProtocol::chmod( const KUrl& url, int permissions )
1074 QString thePath( QFile::encodeName(url.path()));
1075 stripTrailingSlash(thePath);
1076 kDebug( 7121 ) << "chmod -"<< thePath << "-";
1077 if (isRoot(thePath) || isExportedDir(thePath))
1079 error(ERR_ACCESS_DENIED,thePath);
1080 return;
1083 NFSFileHandle fh=getFileHandle(thePath);
1084 if (fh.isInvalid())
1086 error(ERR_DOES_NOT_EXIST,thePath);
1087 return;
1090 sattrargs sAttrArgs;
1091 memcpy(sAttrArgs.file.data,fh,NFS_FHSIZE);
1092 sAttrArgs.attributes.uid=(unsigned int)-1;
1093 sAttrArgs.attributes.gid=(unsigned int)-1;
1094 sAttrArgs.attributes.size=(unsigned int)-1;
1095 sAttrArgs.attributes.atime.seconds=(unsigned int)-1;
1096 sAttrArgs.attributes.atime.useconds=(unsigned int)-1;
1097 sAttrArgs.attributes.mtime.seconds=(unsigned int)-1;
1098 sAttrArgs.attributes.mtime.useconds=(unsigned int)-1;
1100 sAttrArgs.attributes.mode=permissions;
1102 nfsstat nfsStat;
1104 int clnt_stat = clnt_call(m_client, NFSPROC_SETATTR,
1105 (xdrproc_t) xdr_sattrargs, (char*)&sAttrArgs,
1106 (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
1107 if (!checkForError(clnt_stat,nfsStat,thePath)) return;
1109 finished();
1112 void NFSProtocol::get( const KUrl& url )
1114 QString thePath( QFile::encodeName(url.path()));
1115 kDebug(7121)<<"get() -"<<thePath<<"-";
1116 NFSFileHandle fh=getFileHandle(thePath);
1117 if (fh.isInvalid())
1119 error(ERR_DOES_NOT_EXIST,thePath);
1120 return;
1122 readargs readArgs;
1123 memcpy(readArgs.file.data,fh,NFS_FHSIZE);
1124 readArgs.offset=0;
1125 readArgs.count=NFS_MAXDATA;
1126 readArgs.totalcount=NFS_MAXDATA;
1127 readres readRes;
1128 int offset(0);
1129 char buf[NFS_MAXDATA];
1130 readRes.readres_u.reply.data.data_val=buf;
1132 QByteArray array;
1135 int clnt_stat = clnt_call(m_client, NFSPROC_READ,
1136 (xdrproc_t) xdr_readargs, (char*)&readArgs,
1137 (xdrproc_t) xdr_readres, (char*)&readRes,total_timeout);
1138 if (!checkForError(clnt_stat,readRes.status,thePath)) return;
1139 if (readArgs.offset==0)
1140 totalSize(readRes.readres_u.reply.attributes.size);
1142 offset=readRes.readres_u.reply.data.data_len;
1143 //kDebug(7121)<<"read "<<offset<<" bytes";
1144 readArgs.offset+=offset;
1145 if (offset>0)
1147 array = QByteArray::fromRawData(readRes.readres_u.reply.data.data_val, offset);
1148 data( array );
1149 array.clear();
1151 processedSize(readArgs.offset);
1154 } while (offset>0);
1155 data( QByteArray() );
1156 finished();
1159 //TODO the partial putting thing is not yet implemented
1160 void NFSProtocol::put( const KUrl& url, int _mode, KIO::JobFlags flags )
1162 QString destPath( QFile::encodeName(url.path()));
1163 kDebug( 7121 ) << "Put -" << destPath <<"-";
1164 /*QString dest_part( dest_orig );
1165 dest_part += ".part";*/
1167 stripTrailingSlash(destPath);
1168 QString parentDir, fileName;
1169 getLastPart(destPath,fileName, parentDir);
1170 if (isRoot(parentDir))
1172 error(ERR_WRITE_ACCESS_DENIED,destPath);
1173 return;
1176 NFSFileHandle destFH;
1177 destFH=getFileHandle(destPath);
1178 kDebug(7121)<<"file handle for -"<<destPath<<"- is "<<destFH;
1180 //the file exists and we don't want to overwrite
1181 if ((!(flags & KIO::Overwrite)) && (!destFH.isInvalid()))
1183 error(ERR_FILE_ALREADY_EXIST,destPath);
1184 return;
1186 //TODO: is this correct ?
1187 //we have to "create" the file anyway, no matter if it already
1188 //exists or not
1189 //if we don't create it new, written text will be, hmm, "inserted"
1190 //in the existing file, i.e. a file could not become smaller, since
1191 //write only overwrites or extends, but doesn't remove stuff from a file (aleXXX)
1193 kDebug(7121)<<"creating the file -"<<fileName<<"-";
1194 NFSFileHandle parentFH;
1195 parentFH=getFileHandle(parentDir);
1196 //cerr<<"fh for parent dir: "<<parentFH<<endl;
1197 //the directory doesn't exist
1198 if (parentFH.isInvalid())
1200 kDebug(7121)<<"parent directory -"<<parentDir<<"- does not exist";
1201 error(ERR_DOES_NOT_EXIST,parentDir);
1202 return;
1204 createargs createArgs;
1205 memcpy(createArgs.where.dir.data,(const char*)parentFH,NFS_FHSIZE);
1206 QByteArray tmpName=QFile::encodeName(fileName);
1207 createArgs.where.name=tmpName.data();
1209 //the mode is apparently ignored if the file already exists
1210 if (_mode==-1) createArgs.attributes.mode=0644;
1211 else createArgs.attributes.mode=_mode;
1212 createArgs.attributes.uid=geteuid();
1213 createArgs.attributes.gid=getegid();
1214 //this is required, otherwise we are not able to write shorter files
1215 createArgs.attributes.size=0;
1216 //hmm, do we need something here ? I don't think so
1217 createArgs.attributes.atime.seconds=(unsigned int)-1;
1218 createArgs.attributes.atime.useconds=(unsigned int)-1;
1219 createArgs.attributes.mtime.seconds=(unsigned int)-1;
1220 createArgs.attributes.mtime.useconds=(unsigned int)-1;
1222 diropres dirOpRes;
1223 int clnt_stat = clnt_call(m_client, NFSPROC_CREATE,
1224 (xdrproc_t) xdr_createargs, (char*)&createArgs,
1225 (xdrproc_t) xdr_diropres, (char*)&dirOpRes,total_timeout);
1226 if (!checkForError(clnt_stat,dirOpRes.status,fileName)) return;
1227 //we created the file successfully
1228 //destFH=getFileHandle(destPath);
1229 destFH=dirOpRes.diropres_u.diropres.file.data;
1230 kDebug(7121)<<"file -"<<fileName<<"- in dir -"<<parentDir<<"- created successfully";
1231 //cerr<<"with fh "<<destFH<<endl;
1233 //now we can put
1234 int result;
1235 // Loop until we got 0 (end of data)
1236 writeargs writeArgs;
1237 memcpy(writeArgs.file.data,(const char*)destFH,NFS_FHSIZE);
1238 writeArgs.beginoffset=0;
1239 writeArgs.totalcount=0;
1240 writeArgs.offset=0;
1241 attrstat attrStat;
1242 int bytesWritten(0);
1243 kDebug(7121)<<"starting to put";
1246 QByteArray buffer;
1247 dataReq(); // Request for data
1248 result = readData( buffer );
1249 //kDebug(7121)<<"received "<<result<<" bytes for putting";
1250 char * data=buffer.data();
1251 int bytesToWrite=buffer.size();
1252 int writeNow(0);
1253 if (result > 0)
1257 if (bytesToWrite>NFS_MAXDATA)
1259 writeNow=NFS_MAXDATA;
1261 else
1263 writeNow=bytesToWrite;
1265 writeArgs.data.data_val=data;
1266 writeArgs.data.data_len=writeNow;
1268 int clnt_stat = clnt_call(m_client, NFSPROC_WRITE,
1269 (xdrproc_t) xdr_writeargs, (char*)&writeArgs,
1270 (xdrproc_t) xdr_attrstat, (char*)&attrStat,total_timeout);
1271 //kDebug(7121)<<"written";
1272 if (!checkForError(clnt_stat,attrStat.status,fileName)) return;
1273 bytesWritten+=writeNow;
1274 writeArgs.offset=bytesWritten;
1276 //adjust the pointer
1277 data=data+writeNow;
1278 //decrease the rest
1279 bytesToWrite-=writeNow;
1280 } while (bytesToWrite>0);
1282 } while ( result > 0 );
1283 finished();
1286 void NFSProtocol::rename( const KUrl &src, const KUrl &dest, KIO::JobFlags _flags )
1288 QString srcPath( QFile::encodeName(src.path()));
1289 QString destPath( QFile::encodeName(dest.path()));
1290 stripTrailingSlash(srcPath);
1291 stripTrailingSlash(destPath);
1292 kDebug(7121)<<"renaming -"<<srcPath<<"- to -"<<destPath<<"-";
1294 if (isRoot(srcPath) || isExportedDir(srcPath))
1296 error(ERR_CANNOT_RENAME,srcPath);
1297 return;
1300 if (!(_flags & KIO::Overwrite))
1302 NFSFileHandle testFH;
1303 testFH=getFileHandle(destPath);
1304 if (!testFH.isInvalid())
1306 error(ERR_FILE_ALREADY_EXIST,destPath);
1307 return;
1311 QString srcFileName, srcParentDir, destFileName, destParentDir;
1313 getLastPart(srcPath, srcFileName, srcParentDir);
1314 NFSFileHandle srcFH=getFileHandle(srcParentDir);
1315 if (srcFH.isInvalid())
1317 error(ERR_DOES_NOT_EXIST,srcParentDir);
1318 return;
1320 renameargs renameArgs;
1321 memcpy(renameArgs.from.dir.data,srcFH,NFS_FHSIZE);
1322 QByteArray tmpName=QFile::encodeName(srcFileName);
1323 renameArgs.from.name=tmpName.data();
1325 getLastPart(destPath, destFileName, destParentDir);
1326 NFSFileHandle destFH=getFileHandle(destParentDir);
1327 if (destFH.isInvalid())
1329 error(ERR_DOES_NOT_EXIST,destParentDir);
1330 return;
1332 memcpy(renameArgs.to.dir.data,destFH,NFS_FHSIZE);
1333 QByteArray tmpName2=QFile::encodeName(destFileName);
1334 renameArgs.to.name=tmpName2.data();
1335 nfsstat nfsStat;
1337 int clnt_stat = clnt_call(m_client, NFSPROC_RENAME,
1338 (xdrproc_t) xdr_renameargs, (char*)&renameArgs,
1339 (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
1340 if (!checkForError(clnt_stat,nfsStat,destPath)) return;
1341 finished();
1344 void NFSProtocol::copy( const KUrl &src, const KUrl &dest, int _mode, KIO::JobFlags _flags )
1346 //prepare the source
1347 QString thePath( QFile::encodeName(src.path()));
1348 stripTrailingSlash(thePath);
1349 kDebug( 7121 ) << "Copy to -" << thePath <<"-";
1350 NFSFileHandle fh=getFileHandle(thePath);
1351 if (fh.isInvalid())
1353 error(ERR_DOES_NOT_EXIST,thePath);
1354 return;
1357 //create the destination
1358 QString destPath( QFile::encodeName(dest.path()));
1359 stripTrailingSlash(destPath);
1360 QString parentDir, fileName;
1361 getLastPart(destPath,fileName, parentDir);
1362 if (isRoot(parentDir))
1364 error(ERR_ACCESS_DENIED,destPath);
1365 return;
1367 NFSFileHandle destFH;
1368 destFH=getFileHandle(destPath);
1369 kDebug(7121)<<"file handle for -"<<destPath<<"- is "<<destFH;
1371 //the file exists and we don't want to overwrite
1372 if ((!(_flags & KIO::Overwrite)) && (!destFH.isInvalid()))
1374 error(ERR_FILE_ALREADY_EXIST,destPath);
1375 return;
1377 //TODO: is this correct ?
1378 //we have to "create" the file anyway, no matter if it already
1379 //exists or not
1380 //if we don't create it new, written text will be, hmm, "inserted"
1381 //in the existing file, i.e. a file could not become smaller, since
1382 //write only overwrites or extends, but doesn't remove stuff from a file
1384 kDebug(7121)<<"creating the file -"<<fileName<<"-";
1385 NFSFileHandle parentFH;
1386 parentFH=getFileHandle(parentDir);
1387 //the directory doesn't exist
1388 if (parentFH.isInvalid())
1390 kDebug(7121)<<"parent directory -"<<parentDir<<"- does not exist";
1391 error(ERR_DOES_NOT_EXIST,parentDir);
1392 return;
1394 createargs createArgs;
1395 memcpy(createArgs.where.dir.data,(const char*)parentFH,NFS_FHSIZE);
1396 QByteArray tmpName=QFile::encodeName(fileName);
1397 createArgs.where.name=tmpName.data();
1398 if (_mode==-1) createArgs.attributes.mode=0644;
1399 else createArgs.attributes.mode=_mode;
1400 createArgs.attributes.uid=geteuid();
1401 createArgs.attributes.gid=getegid();
1402 createArgs.attributes.size=0;
1403 createArgs.attributes.atime.seconds=(unsigned int)-1;
1404 createArgs.attributes.atime.useconds=(unsigned int)-1;
1405 createArgs.attributes.mtime.seconds=(unsigned int)-1;
1406 createArgs.attributes.mtime.useconds=(unsigned int)-1;
1408 diropres dirOpRes;
1409 int clnt_stat = clnt_call(m_client, NFSPROC_CREATE,
1410 (xdrproc_t) xdr_createargs, (char*)&createArgs,
1411 (xdrproc_t) xdr_diropres, (char*)&dirOpRes,total_timeout);
1412 if (!checkForError(clnt_stat,dirOpRes.status,destPath)) return;
1413 //we created the file successfully
1414 destFH=dirOpRes.diropres_u.diropres.file.data;
1415 kDebug(7121)<<"file -"<<fileName<<"- in dir -"<<parentDir<<"- created successfully";
1417 char buf[NFS_MAXDATA];
1418 writeargs writeArgs;
1419 memcpy(writeArgs.file.data,(const char*)destFH,NFS_FHSIZE);
1420 writeArgs.beginoffset=0;
1421 writeArgs.totalcount=0;
1422 writeArgs.offset=0;
1423 writeArgs.data.data_val=buf;
1424 attrstat attrStat;
1426 readargs readArgs;
1427 memcpy(readArgs.file.data,fh,NFS_FHSIZE);
1428 readArgs.offset=0;
1429 readArgs.count=NFS_MAXDATA;
1430 readArgs.totalcount=NFS_MAXDATA;
1431 readres readRes;
1432 readRes.readres_u.reply.data.data_val=buf;
1434 int bytesRead(0);
1437 //first read
1438 int clnt_stat = clnt_call(m_client, NFSPROC_READ,
1439 (xdrproc_t) xdr_readargs, (char*)&readArgs,
1440 (xdrproc_t) xdr_readres, (char*)&readRes,total_timeout);
1441 if (!checkForError(clnt_stat,readRes.status,thePath)) return;
1442 if (readArgs.offset==0)
1443 totalSize(readRes.readres_u.reply.attributes.size);
1445 bytesRead=readRes.readres_u.reply.data.data_len;
1446 //kDebug(7121)<<"read "<<bytesRead<<" bytes";
1447 //then write
1448 if (bytesRead>0)
1450 readArgs.offset+=bytesRead;
1452 writeArgs.data.data_len=bytesRead;
1454 clnt_stat = clnt_call(m_client, NFSPROC_WRITE,
1455 (xdrproc_t) xdr_writeargs, (char*)&writeArgs,
1456 (xdrproc_t) xdr_attrstat, (char*)&attrStat,total_timeout);
1457 //kDebug(7121)<<"written";
1458 if (!checkForError(clnt_stat,attrStat.status,destPath)) return;
1459 writeArgs.offset+=bytesRead;
1461 } while (bytesRead>0);
1463 finished();
1466 //TODO why isn't this even called ?
1467 void NFSProtocol::symlink( const QString &target, const KUrl &dest, KIO::JobFlags )
1469 kDebug(7121)<<"symlinking ";
1470 QString destPath=dest.path();
1471 stripTrailingSlash(destPath);
1473 QString parentDir, fileName;
1474 getLastPart(destPath,fileName, parentDir);
1475 kDebug(7121)<<"symlinking "<<parentDir<<" "<<fileName<<" to "<<target;
1476 NFSFileHandle fh=getFileHandle(parentDir);
1477 if (fh.isInvalid())
1479 error(ERR_DOES_NOT_EXIST,parentDir);
1480 return;
1482 if (isRoot(parentDir))
1484 error(ERR_ACCESS_DENIED,destPath);
1485 return;
1488 kDebug(7121)<<"tach";
1489 QByteArray tmpStr=target.toLatin1();
1490 symlinkargs symLinkArgs;
1491 symLinkArgs.to=tmpStr.data();
1492 memcpy(symLinkArgs.from.dir.data,(const char*)fh,NFS_FHSIZE);
1493 QByteArray tmpStr2=QFile::encodeName(destPath);
1494 symLinkArgs.from.name=tmpStr2.data();
1496 nfsstat nfsStat;
1497 int clnt_stat = clnt_call(m_client, NFSPROC_SYMLINK,
1498 (xdrproc_t) xdr_symlinkargs, (char*)&symLinkArgs,
1499 (xdrproc_t) xdr_nfsstat, (char*)&nfsStat,total_timeout);
1500 if (!checkForError(clnt_stat,nfsStat,destPath)) return;
1502 finished();
1506 bool NFSProtocol::isValidLink(const QString& parentDir, const QString& linkDest)
1508 kDebug(7121)<<"isValidLink: parent: "<<parentDir<<" link: "<<linkDest;
1509 if (linkDest.isEmpty()) return false;
1510 if (isAbsoluteLink(linkDest))
1512 kDebug(7121)<<"is an absolute link";
1513 return QFile::exists(linkDest);
1515 else
1517 kDebug(7121)<<"is a relative link";
1518 QString absDest=parentDir+'/'+linkDest;
1519 kDebug(7121)<<"pointing abs to "<<absDest;
1520 absDest=removeFirstPart(absDest);
1521 kDebug(7121)<<"removed first part "<<absDest;
1522 absDest=QDir::cleanPath(absDest);
1523 kDebug(7121)<<"simplified to "<<absDest;
1524 if (absDest.indexOf("../")==0)
1525 return false;
1527 kDebug(7121)<<"is inside the nfs tree";
1528 absDest=parentDir+'/'+linkDest;
1529 absDest=QDir::cleanPath(absDest);
1530 kDebug(7121)<<"getting file handle of "<<absDest;
1531 NFSFileHandle fh=getFileHandle(absDest);
1532 return (!fh.isInvalid());
1534 return false;