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>
25 #include <sys/utsname.h>
27 #include <arpa/inet.h>
29 // This is needed on Solaris so that rpc.h defines clnttcp_create etc.
33 #include <rpc/rpc.h> // for rpc calls
52 #include <kcomponentdata.h>
55 #include <kio/global.h>
59 #define fhandle _fhandle
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)
74 //this is taken from kdelibs/kdecore/fakes.cpp
75 //#if !defined(HAVE_GETDOMAINNAME)
77 int x_getdomainname(char *name
, size_t len
)
90 if ((hent
= gethostbyname(uts
.nodename
)) != 0L)
92 char *p
= strchr(hent
->h_name
, '.');
96 if (strlen(p
) > len
-1)
112 extern "C" { int KDE_EXPORT
kdemain(int argc
, char **argv
); }
114 int kdemain( int argc
, char **argv
)
116 KComponentData
componentData( "kio_nfs" );
120 fprintf(stderr
, "Usage: kio_nfs protocol domain-socket1 domain-socket2\n");
123 kDebug(7121) << "NFS: kdemain: starting";
125 NFSProtocol
slave(argv
[2], argv
[3]);
126 slave
.dispatchLoop();
130 static bool isRoot(const QString
& path
)
132 return (path
.isEmpty() || (path
=="/"));
135 static bool isAbsoluteLink(const QString
& path
)
138 if (path
.isEmpty()) return true;
139 if (path
[0]=='/') return true;
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") );
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
)
171 if (path
.isEmpty()) return result
;
173 int slashPos
=result
.indexOf("/");
174 return result
.mid(slashPos
+1);
177 NFSFileHandle::NFSFileHandle()
180 memset(m_handle
,'\0',NFS_FHSIZE
+1);
181 // m_detectTime=time(0);
184 NFSFileHandle::NFSFileHandle(const NFSFileHandle
& handle
)
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;
204 NFSFileHandle
& NFSFileHandle::operator= (const char* src
)
211 memcpy(m_handle
,src
,NFS_FHSIZE
);
213 // m_detectTime=time(0);
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
)
227 ,m_lastCheck(time(0))
229 kDebug(7121)<<"NFS::NFS: -"<<pool
<<"-";
232 NFSProtocol::~NFSProtocol()
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);
256 it=m_handleCache.begin();
265 kDebug(7121)<<"left items: "<<m_handleCache.count();
269 void NFSProtocol::closeConnection()
273 if (m_client
==0) return;
274 CLNT_DESTROY(m_client
);
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
;
303 kDebug(7121)<<"path is empty, invalidating the FH";
304 parentFH
.setInvalid();
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
);
320 if (parentFH
.isInvalid())
322 kDebug(7121)<<"the parent FH is invalid";
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
))
341 kDebug(7121)<<"lookup of filehandle failed";
342 parentFH
.setInvalid();
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
<<"-";
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
,"");
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());
375 struct hostent
*hp
=gethostbyname(m_currentHost
.toLatin1());
378 error( ERR_UNKNOWN_HOST
, m_currentHost
.toLatin1() );
381 server_addr
.sin_family
= AF_INET
;
382 memcpy(&server_addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
385 // create mount daemon client
387 server_addr
.sin_port
= 0;
388 m_sock
= RPC_ANYSOCK
;
389 m_client
=clnttcp_create(&server_addr
,MOUNTPROG
, MOUNTVERS
, &m_sock
, 0, 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
);
399 clnt_pcreateerror(const_cast<char *>("mount clntudp_create"));
400 error(ERR_COULD_NOT_CONNECT
, m_currentHost
.toLatin1());
404 QByteArray
hostName("localhost");
405 char nameBuffer
[1024];
406 nameBuffer
[0] = '\0';
407 if (gethostname(nameBuffer
, 1024)==0)
409 nameBuffer
[sizeof(nameBuffer
)-1] = '\0';
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
423 if(strcmp(nameBuffer
,"(none)") != 0) {
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;
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;
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;
453 fh
=fhStatus
.fhstatus_u
.fhs_fhandle
;
455 if ( exportlist
->ex_dir
[0] == '/' )
456 fname
= KIO::encodeFileName(exportlist
->ex_dir
+ 1);
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
)
467 error( ERR_COULD_NOT_AUTHENTICATE
, m_currentHost
.toLatin1());
470 server_addr
.sin_port
= 0;
472 //now create the client for the nfs daemon
473 //first get rid of the old one
475 m_sock
= RPC_ANYSOCK
;
476 m_client
= clnttcp_create(&server_addr
,NFSPROG
,NFSVERS
,&m_sock
,0,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
);
486 clnt_pcreateerror(const_cast<char *>("NFS clntudp_create"));
487 error(ERR_COULD_NOT_CONNECT
, m_currentHost
.toLatin1());
491 m_client
->cl_auth
= authunix_create(hostName
.data(),geteuid(),getegid(),0,0);
493 kDebug(7121)<<"openConnection succeeded";
496 void NFSProtocol::listDir( const KUrl
& _url
)
499 QString
path( QFile::encodeName(url
.path()));
508 //open the connection
509 if (m_client
==0) openConnection();
511 if (m_client
==0) return;
514 kDebug(7121)<<"listing root";
515 totalSize( m_exportedDirs
.count());
516 //in this case we don't need to do a real listdir
518 for (QStringList::const_iterator it
=m_exportedDirs
.constBegin(); it
!=m_exportedDirs
.constEnd(); ++it
)
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
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;
538 error( ERR_DOES_NOT_EXIST
, path
);
541 readdirargs listargs
;
542 memset(&listargs
,0,sizeof(listargs
));
543 listargs
.count
=1024*16;
544 memcpy(listargs
.dir
.data
,fh
,NFS_FHSIZE
);
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());
561 //stat all files in filesToList
562 for (QStringList::const_iterator it
=filesToList
.constBegin(); it
!=filesToList
.constEnd(); ++it
)
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;
578 tmpFH
=dirres
.diropres_u
.diropres
.file
.data
;
579 m_handleCache
.insert(path
+'/'+(*it
),tmpFH
);
583 entry
.insert( KIO::UDSEntry::UDS_NAME
, (*it
) );
586 if (S_ISLNK(dirres
.diropres_u
.diropres
.attributes
.mode
))
588 kDebug(7121)<<"it's a symlink !";
589 //cerr<<"fh: "<<tmpFH<<endl;
591 memcpy(nfsFH
.data
,dirres
.diropres_u
.diropres
.file
.data
,NFS_FHSIZE
);
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
);
607 completeBadLinkUDSEntry(entry
,dirres
.diropres_u
.diropres
.attributes
);
611 if (isAbsoluteLink(linkDest
))
613 completeAbsoluteLinkUDSEntry(entry
,linkDest
);
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
);
635 completeUDSEntry(entry
,dirres
.diropres_u
.diropres
.attributes
);
636 listEntry( entry
, false);
638 listEntry( entry
, true ); // ready
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
))
654 entry
.insert( KIO::UDSEntry::UDS_NAME
, path
);
655 createVirtualDirEntry(entry
);
659 kDebug(7121)<<"succeeded";
663 NFSFileHandle fh
=getFileHandle(path
);
666 error(ERR_DOES_NOT_EXIST
,path
);
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;
685 QString fileName
, parentDir
;
686 getLastPart(path
, fileName
, parentDir
);
687 stripTrailingSlash(parentDir
);
689 entry
.insert( KIO::UDSEntry::UDS_NAME
, fileName
);
692 if (S_ISLNK(attrAndStat
.attrstat_u
.attributes
.mode
))
694 kDebug(7121)<<"it's a symlink !";
696 memcpy(nfsFH
.data
,fh
,NFS_FHSIZE
);
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
);
713 completeBadLinkUDSEntry(entry
,attrAndStat
.attrstat_u
.attributes
);
717 if (isAbsoluteLink(linkDest
))
719 completeAbsoluteLinkUDSEntry(entry
,linkDest
);
724 tmpStr
=QDir::cleanPath(parentDir
+QString("/")+QString(linkDest
)).toLatin1();
726 dirargs
.name
=tmpStr
.data();
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
);
741 completeUDSEntry(entry
,attrAndStat
.attrstat_u
.attributes
);
746 void NFSProtocol::completeAbsoluteLinkUDSEntry(UDSEntry
& entry
, const QByteArray
& path
)
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
;
760 if ( !m_usercache
.contains( uid
) ) {
761 struct passwd
*user
= getpwuid( uid
);
764 m_usercache
.insert( uid
, QString::fromLatin1(user
->pw_name
) );
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
);
781 m_groupcache
.insert( gid
, QString::fromLatin1(grp
->gr_name
) );
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
;
817 if ( !m_usercache
.contains( uid
) )
819 struct passwd
*user
= getpwuid( uid
);
822 m_usercache
.insert( uid
, QString::fromLatin1(user
->pw_name
) );
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
);
840 m_groupcache
.insert( gid
, QString::fromLatin1(grp
->gr_name
) );
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++ ) {
854 case KIO::UDSEntry::UDS_FILE_TYPE:
855 kDebug(7121) << "File Type : " << (mode_t)((*it).m_long);
857 case KIO::UDSEntry::UDS_ACCESS:
858 kDebug(7121) << "Access permissions : " << (mode_t)((*it).m_long);
860 case KIO::UDSEntry::UDS_USER:
861 kDebug(7121) << "User : " << ((*it).m_str.toAscii() );
863 case KIO::UDSEntry::UDS_GROUP:
864 kDebug(7121) << "Group : " << ((*it).m_str.toAscii() );
866 case KIO::UDSEntry::UDS_NAME:
867 kDebug(7121) << "Name : " << ((*it).m_str.toAscii() );
868 //m_strText = decodeFileName( (*it).m_str );
870 case KIO::UDSEntry::UDS_URL:
871 kDebug(7121) << "URL : " << ((*it).m_str.toAscii() );
873 case KIO::UDSEntry::UDS_MIME_TYPE:
874 kDebug(7121) << "MimeType : " << ((*it).m_str.toAscii() );
876 case KIO::UDSEntry::UDS_LINK_DEST:
877 kDebug(7121) << "LinkDest : " << ((*it).m_str.toAscii() );
883 void NFSProtocol::setHost(const QString
& host
, quint16
/*port*/, const QString
& /*user*/, const QString
& /*pass*/)
885 kDebug(7121)<<"setHost: -"<<host
<<"-";
888 error(ERR_UNKNOWN_HOST
,"");
891 if (host
==m_currentHost
) return;
893 m_handleCache
.clear();
894 m_exportedDirs
.clear();
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
);
912 NFSFileHandle fh
=getFileHandle(parentDir
);
915 error(ERR_DOES_NOT_EXIST
,thePath
);
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
;
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;
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."));
946 kDebug(7121)<<"nfs error: "<<nfsStat
;
950 error(ERR_ACCESS_DENIED
,text
);
953 error(ERR_DOES_NOT_EXIST
,text
);
955 //does this mapping make sense ?
957 error(ERR_INTERNAL_SERVER
,text
);
959 //does this mapping make sense ?
961 error(ERR_DOES_NOT_EXIST
,text
);
964 error(ERR_ACCESS_DENIED
,text
);
967 error(ERR_FILE_ALREADY_EXIST
,text
);
969 //does this mapping make sense ?
971 error(ERR_DOES_NOT_EXIST
,text
);
974 error(ERR_IS_FILE
,text
);
977 error(ERR_IS_DIRECTORY
,text
);
979 //does this mapping make sense ?
981 error(ERR_INTERNAL_SERVER
,text
);
983 //does this mapping make sense ?
985 error(ERR_INTERNAL_SERVER
,i18n("No space left on device"));
988 error(ERR_COULD_NOT_WRITE
,i18n("Read only file system"));
990 case NFSERR_NAMETOOLONG
:
991 error(ERR_INTERNAL_SERVER
,i18n("Filename too long"));
993 case NFSERR_NOTEMPTY
:
994 error(ERR_COULD_NOT_RMDIR
,text
);
996 //does this mapping make sense ?
998 error(ERR_INTERNAL_SERVER
,i18n("Disk quota exceeded"));
1001 error(ERR_DOES_NOT_EXIST
,text
);
1004 error(ERR_UNKNOWN
,text
);
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
);
1027 NFSFileHandle fh
=getFileHandle(parentDir
);
1030 error(ERR_DOES_NOT_EXIST
,thePath
);
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();
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
));
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();
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
));
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
);
1083 NFSFileHandle fh
=getFileHandle(thePath
);
1086 error(ERR_DOES_NOT_EXIST
,thePath
);
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
;
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;
1112 void NFSProtocol::get( const KUrl
& url
)
1114 QString
thePath( QFile::encodeName(url
.path()));
1115 kDebug(7121)<<"get() -"<<thePath
<<"-";
1116 NFSFileHandle fh
=getFileHandle(thePath
);
1119 error(ERR_DOES_NOT_EXIST
,thePath
);
1123 memcpy(readArgs
.file
.data
,fh
,NFS_FHSIZE
);
1125 readArgs
.count
=NFS_MAXDATA
;
1126 readArgs
.totalcount
=NFS_MAXDATA
;
1129 char buf
[NFS_MAXDATA
];
1130 readRes
.readres_u
.reply
.data
.data_val
=buf
;
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
;
1147 array
= QByteArray::fromRawData(readRes
.readres_u
.reply
.data
.data_val
, offset
);
1151 processedSize(readArgs
.offset
);
1155 data( QByteArray() );
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
);
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
);
1186 //TODO: is this correct ?
1187 //we have to "create" the file anyway, no matter if it already
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
);
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;
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;
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;
1242 int bytesWritten(0);
1243 kDebug(7121)<<"starting to put";
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();
1257 if (bytesToWrite
>NFS_MAXDATA
)
1259 writeNow
=NFS_MAXDATA
;
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
1279 bytesToWrite
-=writeNow
;
1280 } while (bytesToWrite
>0);
1282 } while ( result
> 0 );
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
);
1300 if (!(_flags
& KIO::Overwrite
))
1302 NFSFileHandle testFH
;
1303 testFH
=getFileHandle(destPath
);
1304 if (!testFH
.isInvalid())
1306 error(ERR_FILE_ALREADY_EXIST
,destPath
);
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
);
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
);
1332 memcpy(renameArgs
.to
.dir
.data
,destFH
,NFS_FHSIZE
);
1333 QByteArray tmpName2
=QFile::encodeName(destFileName
);
1334 renameArgs
.to
.name
=tmpName2
.data();
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;
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
);
1353 error(ERR_DOES_NOT_EXIST
,thePath
);
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
);
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
);
1377 //TODO: is this correct ?
1378 //we have to "create" the file anyway, no matter if it already
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
);
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;
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;
1423 writeArgs
.data
.data_val
=buf
;
1427 memcpy(readArgs
.file
.data
,fh
,NFS_FHSIZE
);
1429 readArgs
.count
=NFS_MAXDATA
;
1430 readArgs
.totalcount
=NFS_MAXDATA
;
1432 readRes
.readres_u
.reply
.data
.data_val
=buf
;
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";
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);
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
);
1479 error(ERR_DOES_NOT_EXIST
,parentDir
);
1482 if (isRoot(parentDir
))
1484 error(ERR_ACCESS_DENIED
,destPath
);
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();
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;
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
);
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)
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());