TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

file.cc 55KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889
  1. /*
  2. Copyright (C) 2000-2002 Stephan Kulow <coolo@kde.org>
  3. Copyright (C) 2000-2002 David Faure <faure@kde.org>
  4. Copyright (C) 2000-2002 Waldo Bastian <bastian@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 (LGPL) as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later
  9. 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.
  14. You should have received a copy of the GNU Library General Public License
  15. along with this library; see the file COPYING.LIB. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. Boston, MA 02110-1301, USA.
  18. */
  19. // $Id$
  20. #include <config.h>
  21. #include <tqglobal.h> //for Q_OS_XXX
  22. #include <sys/types.h>
  23. #include <sys/wait.h>
  24. #include <sys/stat.h>
  25. #ifdef HAVE_SYS_TIME_H
  26. #include <sys/time.h>
  27. #endif
  28. //sendfile has different semantics in different platforms
  29. #if defined HAVE_SENDFILE && defined Q_OS_LINUX
  30. #define USE_SENDFILE 1
  31. #endif
  32. #ifdef USE_SENDFILE
  33. #include <sys/sendfile.h>
  34. #endif
  35. #ifdef USE_POSIX_ACL
  36. #include <sys/acl.h>
  37. #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
  38. #include <acl/libacl.h>
  39. #else
  40. #include <posixacladdons.h>
  41. #endif
  42. #endif
  43. #include <assert.h>
  44. #include <dirent.h>
  45. #include <errno.h>
  46. #include <fcntl.h>
  47. #include <grp.h>
  48. #include <pwd.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <signal.h>
  52. #include <time.h>
  53. #include <utime.h>
  54. #include <unistd.h>
  55. #ifdef HAVE_STRING_H
  56. #include <string.h>
  57. #endif
  58. #include <tqvaluelist.h>
  59. #include <tqregexp.h>
  60. #include <dcopref.h>
  61. #include <kshred.h>
  62. #include <kdebug.h>
  63. #include <kurl.h>
  64. #include <kinstance.h>
  65. #include <ksimpleconfig.h>
  66. #include <tdetempfile.h>
  67. #include <tdelocale.h>
  68. #include <tqfile.h>
  69. #include <tqstrlist.h>
  70. #include "file.h"
  71. #include <limits.h>
  72. #include <kprocess.h>
  73. #include <kmountpoint.h>
  74. #include <kstandarddirs.h>
  75. #ifdef HAVE_VOLMGT
  76. #include <volmgt.h>
  77. #include <sys/mnttab.h>
  78. #endif
  79. #include <kstandarddirs.h>
  80. #include <tdeio/ioslave_defaults.h>
  81. #include <klargefile.h>
  82. #include <tdeglobal.h>
  83. #include <kmimetype.h>
  84. using namespace TDEIO;
  85. #define MAX_IPC_SIZE (1024*32)
  86. static TQString testLogFile( const char *_filename );
  87. #ifdef USE_POSIX_ACL
  88. static TQString aclAsString( acl_t p_acl );
  89. static bool isExtendedACL( acl_t p_acl );
  90. static void appendACLAtoms( const TQCString & path, UDSEntry& entry,
  91. mode_t type, bool withACL );
  92. #endif
  93. extern "C" { KDE_EXPORT int kdemain(int argc, char **argv); }
  94. int kdemain( int argc, char **argv )
  95. {
  96. TDELocale::setMainCatalogue("tdelibs");
  97. TDEInstance instance( "tdeio_file" );
  98. ( void ) TDEGlobal::locale();
  99. kdDebug(7101) << "Starting " << getpid() << endl;
  100. if (argc != 4)
  101. {
  102. fprintf(stderr, "Usage: tdeio_file protocol domain-socket1 domain-socket2\n");
  103. exit(-1);
  104. }
  105. FileProtocol slave(argv[2], argv[3]);
  106. slave.dispatchLoop();
  107. kdDebug(7101) << "Done" << endl;
  108. return 0;
  109. }
  110. FileProtocol::FileProtocol( const TQCString &pool, const TQCString &app ) : SlaveBase( "file", pool, app )
  111. {
  112. usercache.setAutoDelete( true );
  113. groupcache.setAutoDelete( true );
  114. }
  115. int FileProtocol::setACL( const char *path, mode_t perm, bool directoryDefault )
  116. {
  117. int ret = 0;
  118. #ifdef USE_POSIX_ACL
  119. const TQString ACLString = metaData( "ACL_STRING" );
  120. const TQString defaultACLString = metaData( "DEFAULT_ACL_STRING" );
  121. // Empty strings mean leave as is
  122. if ( !ACLString.isEmpty() ) {
  123. acl_t acl = 0;
  124. if ( ACLString == "ACL_DELETE" ) {
  125. // user told us to delete the extended ACL, so let's write only
  126. // the minimal (UNIX permission bits) part
  127. acl = acl_from_mode( perm );
  128. }
  129. acl = acl_from_text( ACLString.latin1() );
  130. if ( acl_valid( acl ) == 0 ) { // let's be safe
  131. ret = acl_set_file( path, ACL_TYPE_ACCESS, acl );
  132. kdDebug(7101) << "Set ACL on: " << path << " to: " << aclAsString( acl ) << endl;
  133. }
  134. acl_free( acl );
  135. if ( ret != 0 ) return ret; // better stop trying right away
  136. }
  137. if ( directoryDefault && !defaultACLString.isEmpty() ) {
  138. if ( defaultACLString == "ACL_DELETE" ) {
  139. // user told us to delete the default ACL, do so
  140. ret += acl_delete_def_file( path );
  141. } else {
  142. acl_t acl = acl_from_text( defaultACLString.latin1() );
  143. if ( acl_valid( acl ) == 0 ) { // let's be safe
  144. ret += acl_set_file( path, ACL_TYPE_DEFAULT, acl );
  145. kdDebug(7101) << "Set Default ACL on: " << path << " to: " << aclAsString( acl ) << endl;
  146. }
  147. acl_free( acl );
  148. }
  149. }
  150. #endif
  151. return ret;
  152. }
  153. void FileProtocol::chmod( const KURL& url, int permissions )
  154. {
  155. TQCString _path( TQFile::encodeName(url.path()) );
  156. /* FIXME: Should be atomic */
  157. if ( ::chmod( _path.data(), permissions ) == -1 ||
  158. ( setACL( _path.data(), permissions, false ) == -1 ) ||
  159. /* if not a directory, cannot set default ACLs */
  160. ( setACL( _path.data(), permissions, true ) == -1 && errno != ENOTDIR ) ) {
  161. switch (errno) {
  162. case EPERM:
  163. case EACCES:
  164. error( TDEIO::ERR_ACCESS_DENIED, url.path() );
  165. break;
  166. case ENOTSUP:
  167. error( TDEIO::ERR_UNSUPPORTED_ACTION, url.path() );
  168. break;
  169. case ENOSPC:
  170. error( TDEIO::ERR_DISK_FULL, url.path() );
  171. break;
  172. default:
  173. error( TDEIO::ERR_CANNOT_CHMOD, url.path() );
  174. }
  175. } else
  176. finished();
  177. }
  178. void FileProtocol::mkdir( const KURL& url, int permissions )
  179. {
  180. TQCString _path( TQFile::encodeName(url.path()));
  181. kdDebug(7101) << "mkdir(): " << _path << ", permission = " << permissions << endl;
  182. KDE_struct_stat buff;
  183. if ( KDE_stat( _path.data(), &buff ) == -1 ) {
  184. if ( ::mkdir( _path.data(), 0777 /*umask will be applied*/ ) != 0 ) {
  185. if ( errno == EACCES ) {
  186. error( TDEIO::ERR_ACCESS_DENIED, url.path() );
  187. return;
  188. } else if ( errno == ENOSPC ) {
  189. error( TDEIO::ERR_DISK_FULL, url.path() );
  190. return;
  191. } else {
  192. error( TDEIO::ERR_COULD_NOT_MKDIR, url.path() );
  193. return;
  194. }
  195. } else {
  196. if ( permissions != -1 )
  197. chmod( url, permissions );
  198. else
  199. finished();
  200. return;
  201. }
  202. }
  203. if ( S_ISDIR( buff.st_mode ) ) {
  204. kdDebug(7101) << "ERR_DIR_ALREADY_EXIST" << endl;
  205. error( TDEIO::ERR_DIR_ALREADY_EXIST, url.path() );
  206. return;
  207. }
  208. error( TDEIO::ERR_FILE_ALREADY_EXIST, url.path() );
  209. return;
  210. }
  211. void FileProtocol::get( const KURL& url )
  212. {
  213. if (!url.isLocalFile()) {
  214. KURL redir(url);
  215. redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
  216. redirection(redir);
  217. finished();
  218. return;
  219. }
  220. TQCString _path( TQFile::encodeName(url.path()));
  221. KDE_struct_stat buff;
  222. if ( KDE_stat( _path.data(), &buff ) == -1 ) {
  223. if ( errno == EACCES )
  224. error( TDEIO::ERR_ACCESS_DENIED, url.path() );
  225. else
  226. error( TDEIO::ERR_DOES_NOT_EXIST, url.path() );
  227. return;
  228. }
  229. if ( S_ISDIR( buff.st_mode ) ) {
  230. error( TDEIO::ERR_IS_DIRECTORY, url.path() );
  231. return;
  232. }
  233. if ( !S_ISREG( buff.st_mode ) ) {
  234. error( TDEIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
  235. return;
  236. }
  237. int fd = KDE_open( _path.data(), O_RDONLY);
  238. if ( fd < 0 ) {
  239. error( TDEIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
  240. return;
  241. }
  242. #ifdef HAVE_FADVISE
  243. posix_fadvise( fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  244. #endif
  245. // Determine the mimetype of the file to be retrieved, and emit it.
  246. // This is mandatory in all slaves (for KRun/BrowserRun to work).
  247. KMimeType::Ptr mt = KMimeType::findByURL( url, buff.st_mode, true /* local URL */ );
  248. emit mimeType( mt->name() );
  249. TDEIO::filesize_t processed_size = 0;
  250. TQString resumeOffset = metaData("resume");
  251. if ( !resumeOffset.isEmpty() )
  252. {
  253. bool ok;
  254. TDEIO::fileoffset_t offset = resumeOffset.toLongLong(&ok);
  255. if (ok && (offset > 0) && (offset < buff.st_size))
  256. {
  257. if (KDE_lseek(fd, offset, SEEK_SET) == offset)
  258. {
  259. canResume ();
  260. processed_size = offset;
  261. kdDebug( 7101 ) << "Resume offset: " << TDEIO::number(offset) << endl;
  262. }
  263. }
  264. }
  265. totalSize( buff.st_size );
  266. char buffer[ MAX_IPC_SIZE ];
  267. TQByteArray array;
  268. while( 1 )
  269. {
  270. int n = ::read( fd, buffer, MAX_IPC_SIZE );
  271. if (n == -1)
  272. {
  273. if (errno == EINTR)
  274. continue;
  275. error( TDEIO::ERR_COULD_NOT_READ, url.path());
  276. close(fd);
  277. return;
  278. }
  279. if (n == 0)
  280. break; // Finished
  281. array.setRawData(buffer, n);
  282. data( array );
  283. array.resetRawData(buffer, n);
  284. processed_size += n;
  285. processedSize( processed_size );
  286. //kdDebug( 7101 ) << "Processed: " << TDEIO::number (processed_size) << endl;
  287. }
  288. data( TQByteArray() );
  289. close( fd );
  290. processedSize( buff.st_size );
  291. finished();
  292. }
  293. static int
  294. write_all(int fd, const char *buf, size_t len)
  295. {
  296. while (len > 0)
  297. {
  298. ssize_t written = write(fd, buf, len);
  299. if (written < 0)
  300. {
  301. if (errno == EINTR)
  302. continue;
  303. return -1;
  304. }
  305. buf += written;
  306. len -= written;
  307. }
  308. return 0;
  309. }
  310. static bool
  311. same_inode(const KDE_struct_stat &src, const KDE_struct_stat &dest)
  312. {
  313. if (src.st_ino == dest.st_ino &&
  314. src.st_dev == dest.st_dev)
  315. return true;
  316. return false;
  317. }
  318. void FileProtocol::put( const KURL& url, int _mode, bool _overwrite, bool _resume )
  319. {
  320. TQString dest_orig = url.path();
  321. TQCString _dest_orig( TQFile::encodeName(dest_orig));
  322. kdDebug(7101) << "put(): " << dest_orig << ", mode=" << _mode << endl;
  323. TQString dest_part( dest_orig );
  324. dest_part += TQString::fromLatin1(".part");
  325. TQCString _dest_part( TQFile::encodeName(dest_part));
  326. KDE_struct_stat buff_orig;
  327. bool bOrigExists = (KDE_lstat( _dest_orig.data(), &buff_orig ) != -1);
  328. bool bPartExists = false;
  329. bool bMarkPartial = config()->readBoolEntry("MarkPartial", true);
  330. if (bMarkPartial)
  331. {
  332. KDE_struct_stat buff_part;
  333. bPartExists = (KDE_stat( _dest_part.data(), &buff_part ) != -1);
  334. if (bPartExists && !_resume && !_overwrite && buff_part.st_size > 0 && S_ISREG(buff_part.st_mode))
  335. {
  336. kdDebug(7101) << "FileProtocol::put : calling canResume with "
  337. << TDEIO::number(buff_part.st_size) << endl;
  338. // Maybe we can use this partial file for resuming
  339. // Tell about the size we have, and the app will tell us
  340. // if it's ok to resume or not.
  341. _resume = canResume( buff_part.st_size );
  342. kdDebug(7101) << "FileProtocol::put got answer " << _resume << endl;
  343. }
  344. }
  345. if ( bOrigExists && !_overwrite && !_resume)
  346. {
  347. if (S_ISDIR(buff_orig.st_mode))
  348. error( TDEIO::ERR_DIR_ALREADY_EXIST, dest_orig );
  349. else
  350. error( TDEIO::ERR_FILE_ALREADY_EXIST, dest_orig );
  351. return;
  352. }
  353. int result;
  354. TQString dest;
  355. TQCString _dest;
  356. int fd = -1;
  357. // Loop until we got 0 (end of data)
  358. do
  359. {
  360. TQByteArray buffer;
  361. dataReq(); // Request for data
  362. result = readData( buffer );
  363. if (result >= 0)
  364. {
  365. if (dest.isEmpty())
  366. {
  367. if (bMarkPartial)
  368. {
  369. kdDebug(7101) << "Appending .part extension to " << dest_orig << endl;
  370. dest = dest_part;
  371. if ( bPartExists && !_resume )
  372. {
  373. kdDebug(7101) << "Deleting partial file " << dest_part << endl;
  374. remove( _dest_part.data() );
  375. // Catch errors when we try to open the file.
  376. }
  377. }
  378. else
  379. {
  380. dest = dest_orig;
  381. if ( bOrigExists && !_resume )
  382. {
  383. kdDebug(7101) << "Deleting destination file " << dest_orig << endl;
  384. remove( _dest_orig.data() );
  385. // Catch errors when we try to open the file.
  386. }
  387. }
  388. _dest = TQFile::encodeName(dest);
  389. if ( _resume )
  390. {
  391. fd = KDE_open( _dest.data(), O_RDWR ); // append if resuming
  392. KDE_lseek(fd, 0, SEEK_END); // Seek to end
  393. }
  394. else
  395. {
  396. // WABA: Make sure that we keep writing permissions ourselves,
  397. // otherwise we can be in for a surprise on NFS.
  398. mode_t initialMode;
  399. if (_mode != -1)
  400. initialMode = _mode | S_IWUSR | S_IRUSR;
  401. else
  402. initialMode = 0666;
  403. fd = KDE_open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
  404. }
  405. if ( fd < 0 )
  406. {
  407. kdDebug(7101) << "####################### COULD NOT WRITE " << dest << " _mode=" << _mode << endl;
  408. kdDebug(7101) << "errno==" << errno << "(" << strerror(errno) << ")" << endl;
  409. if ( errno == EACCES )
  410. error( TDEIO::ERR_WRITE_ACCESS_DENIED, dest );
  411. else
  412. error( TDEIO::ERR_CANNOT_OPEN_FOR_WRITING, dest );
  413. return;
  414. }
  415. }
  416. if (write_all( fd, buffer.data(), buffer.size()))
  417. {
  418. if ( errno == ENOSPC ) // disk full
  419. {
  420. error( TDEIO::ERR_DISK_FULL, dest_orig);
  421. result = -2; // means: remove dest file
  422. }
  423. else
  424. {
  425. kdWarning(7101) << "Couldn't write. Error:" << strerror(errno) << endl;
  426. error( TDEIO::ERR_COULD_NOT_WRITE, dest_orig);
  427. result = -1;
  428. }
  429. }
  430. }
  431. }
  432. while ( result > 0 );
  433. // An error occurred deal with it.
  434. if (result < 0)
  435. {
  436. kdDebug(7101) << "Error during 'put'. Aborting." << endl;
  437. if (fd != -1)
  438. {
  439. close(fd);
  440. KDE_struct_stat buff;
  441. if (bMarkPartial && KDE_stat( _dest.data(), &buff ) == 0)
  442. {
  443. int size = config()->readNumEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
  444. if (buff.st_size < size)
  445. remove(_dest.data());
  446. }
  447. }
  448. ::exit(255);
  449. }
  450. if ( fd == -1 ) // we got nothing to write out, so we never opened the file
  451. {
  452. finished();
  453. return;
  454. }
  455. if ( close(fd) )
  456. {
  457. kdWarning(7101) << "Error when closing file descriptor:" << strerror(errno) << endl;
  458. error( TDEIO::ERR_COULD_NOT_WRITE, dest_orig);
  459. return;
  460. }
  461. // after full download rename the file back to original name
  462. if ( bMarkPartial )
  463. {
  464. // If the original URL is a symlink and we were asked to overwrite it,
  465. // remove the symlink first. This ensures that we do not overwrite the
  466. // current source if the symlink points to it.
  467. if( _overwrite && S_ISLNK( buff_orig.st_mode ) )
  468. remove( _dest_orig.data() );
  469. if ( ::rename( _dest.data(), _dest_orig.data() ) )
  470. {
  471. kdWarning(7101) << " Couldn't rename " << _dest << " to " << _dest_orig << endl;
  472. error( TDEIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig );
  473. return;
  474. }
  475. }
  476. // set final permissions
  477. if ( _mode != -1 && !_resume )
  478. {
  479. if (::chmod(_dest_orig.data(), _mode) != 0)
  480. {
  481. // couldn't chmod. Eat the error if the filesystem apparently doesn't support it.
  482. if ( TDEIO::testFileSystemFlag( _dest_orig, TDEIO::SupportsChmod ) )
  483. warning( i18n( "Could not change permissions for\n%1" ).arg( dest_orig ) );
  484. }
  485. }
  486. // set modification time
  487. const TQString mtimeStr = metaData( "modified" );
  488. if ( !mtimeStr.isEmpty() ) {
  489. TQDateTime dt = TQT_TQDATETIME_OBJECT(TQDateTime::fromString( mtimeStr, Qt::ISODate ));
  490. if ( dt.isValid() ) {
  491. KDE_struct_stat dest_statbuf;
  492. if (KDE_stat( _dest_orig.data(), &dest_statbuf ) == 0) {
  493. struct utimbuf utbuf;
  494. utbuf.actime = dest_statbuf.st_atime; // access time, unchanged
  495. utbuf.modtime = dt.toTime_t(); // modification time
  496. kdDebug() << k_funcinfo << "setting modtime to " << utbuf.modtime << endl;
  497. utime( _dest_orig.data(), &utbuf );
  498. }
  499. }
  500. }
  501. // We have done our job => finish
  502. finished();
  503. }
  504. void FileProtocol::copy( const KURL &src, const KURL &dest,
  505. int _mode, bool _overwrite )
  506. {
  507. kdDebug(7101) << "copy(): " << src << " -> " << dest << ", mode=" << _mode << endl;
  508. TQCString _src( TQFile::encodeName(src.path()));
  509. TQCString _dest( TQFile::encodeName(dest.path()));
  510. KDE_struct_stat buff_src;
  511. #ifdef USE_POSIX_ACL
  512. acl_t acl;
  513. #endif
  514. if ( KDE_stat( _src.data(), &buff_src ) == -1 ) {
  515. if ( errno == EACCES )
  516. error( TDEIO::ERR_ACCESS_DENIED, src.path() );
  517. else
  518. error( TDEIO::ERR_DOES_NOT_EXIST, src.path() );
  519. return;
  520. }
  521. if ( S_ISDIR( buff_src.st_mode ) ) {
  522. error( TDEIO::ERR_IS_DIRECTORY, src.path() );
  523. return;
  524. }
  525. if ( S_ISFIFO( buff_src.st_mode ) || S_ISSOCK ( buff_src.st_mode ) ) {
  526. error( TDEIO::ERR_CANNOT_OPEN_FOR_READING, src.path() );
  527. return;
  528. }
  529. KDE_struct_stat buff_dest;
  530. bool dest_exists = ( KDE_lstat( _dest.data(), &buff_dest ) != -1 );
  531. if ( dest_exists )
  532. {
  533. if (S_ISDIR(buff_dest.st_mode))
  534. {
  535. error( TDEIO::ERR_DIR_ALREADY_EXIST, dest.path() );
  536. return;
  537. }
  538. if ( same_inode( buff_dest, buff_src) )
  539. {
  540. error( TDEIO::ERR_IDENTICAL_FILES, dest.path() );
  541. return;
  542. }
  543. if (!_overwrite)
  544. {
  545. error( TDEIO::ERR_FILE_ALREADY_EXIST, dest.path() );
  546. return;
  547. }
  548. // If the destination is a symlink and overwrite is TRUE,
  549. // remove the symlink first to prevent the scenario where
  550. // the symlink actually points to current source!
  551. if (_overwrite && S_ISLNK(buff_dest.st_mode))
  552. {
  553. kdDebug(7101) << "copy(): LINK DESTINATION" << endl;
  554. remove( _dest.data() );
  555. }
  556. }
  557. int src_fd = KDE_open( _src.data(), O_RDONLY);
  558. if ( src_fd < 0 ) {
  559. error( TDEIO::ERR_CANNOT_OPEN_FOR_READING, src.path() );
  560. return;
  561. }
  562. #ifdef HAVE_FADVISE
  563. posix_fadvise(src_fd,0,0,POSIX_FADV_SEQUENTIAL);
  564. #endif
  565. // WABA: Make sure that we keep writing permissions ourselves,
  566. // otherwise we can be in for a surprise on NFS.
  567. mode_t initialMode;
  568. if (_mode != -1)
  569. initialMode = _mode | S_IWUSR;
  570. else
  571. initialMode = 0666;
  572. int dest_fd = KDE_open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
  573. if ( dest_fd < 0 ) {
  574. kdDebug(7101) << "###### COULD NOT WRITE " << dest.url() << endl;
  575. if ( errno == EACCES ) {
  576. error( TDEIO::ERR_WRITE_ACCESS_DENIED, dest.path() );
  577. } else {
  578. error( TDEIO::ERR_CANNOT_OPEN_FOR_WRITING, dest.path() );
  579. }
  580. close(src_fd);
  581. return;
  582. }
  583. #ifdef HAVE_FADVISE
  584. posix_fadvise(dest_fd,0,0,POSIX_FADV_SEQUENTIAL);
  585. #endif
  586. #ifdef USE_POSIX_ACL
  587. acl = acl_get_fd(src_fd);
  588. if ( acl && !isExtendedACL( acl ) ) {
  589. kdDebug(7101) << _dest.data() << " doesn't have extended ACL" << endl;
  590. acl_free( acl );
  591. acl = NULL;
  592. }
  593. #endif
  594. totalSize( buff_src.st_size );
  595. TDEIO::filesize_t processed_size = 0;
  596. char buffer[ MAX_IPC_SIZE ];
  597. int n;
  598. #ifdef USE_SENDFILE
  599. bool use_sendfile=buff_src.st_size < 0x7FFFFFFF;
  600. #endif
  601. while( 1 )
  602. {
  603. #ifdef USE_SENDFILE
  604. if (use_sendfile) {
  605. off_t sf = processed_size;
  606. n = ::sendfile( dest_fd, src_fd, &sf, MAX_IPC_SIZE );
  607. processed_size = sf;
  608. if ( n == -1 && errno == EINVAL ) { //not all filesystems support sendfile()
  609. kdDebug(7101) << "sendfile() not supported, falling back " << endl;
  610. use_sendfile = false;
  611. }
  612. }
  613. if (!use_sendfile)
  614. #endif
  615. n = ::read( src_fd, buffer, MAX_IPC_SIZE );
  616. if (n == -1)
  617. {
  618. if (errno == EINTR)
  619. continue;
  620. #ifdef USE_SENDFILE
  621. if ( use_sendfile ) {
  622. kdDebug(7101) << "sendfile() error:" << strerror(errno) << endl;
  623. if ( errno == ENOSPC ) // disk full
  624. {
  625. error( TDEIO::ERR_DISK_FULL, dest.path());
  626. remove( _dest.data() );
  627. }
  628. else {
  629. error( TDEIO::ERR_SLAVE_DEFINED,
  630. i18n("Cannot copy file from %1 to %2. (Errno: %3)")
  631. .arg( src.path() ).arg( dest.path() ).arg( errno ) );
  632. }
  633. } else
  634. #endif
  635. error( TDEIO::ERR_COULD_NOT_READ, src.path());
  636. close(src_fd);
  637. close(dest_fd);
  638. #ifdef USE_POSIX_ACL
  639. if (acl) acl_free(acl);
  640. #endif
  641. return;
  642. }
  643. if (n == 0)
  644. break; // Finished
  645. #ifdef USE_SENDFILE
  646. if ( !use_sendfile ) {
  647. #endif
  648. if (write_all( dest_fd, buffer, n))
  649. {
  650. close(src_fd);
  651. close(dest_fd);
  652. if ( errno == ENOSPC ) // disk full
  653. {
  654. error( TDEIO::ERR_DISK_FULL, dest.path());
  655. remove( _dest.data() );
  656. }
  657. else
  658. {
  659. kdWarning(7101) << "Couldn't write[2]. Error:" << strerror(errno) << endl;
  660. error( TDEIO::ERR_COULD_NOT_WRITE, dest.path());
  661. }
  662. #ifdef USE_POSIX_ACL
  663. if (acl) acl_free(acl);
  664. #endif
  665. return;
  666. }
  667. processed_size += n;
  668. #ifdef USE_SENDFILE
  669. }
  670. #endif
  671. processedSize( processed_size );
  672. }
  673. close( src_fd );
  674. if (close( dest_fd))
  675. {
  676. kdWarning(7101) << "Error when closing file descriptor[2]:" << strerror(errno) << endl;
  677. error( TDEIO::ERR_COULD_NOT_WRITE, dest.path());
  678. #ifdef USE_POSIX_ACL
  679. if (acl) acl_free(acl);
  680. #endif
  681. return;
  682. }
  683. // set final permissions
  684. if ( _mode != -1 )
  685. {
  686. if ( (::chmod(_dest.data(), _mode) != 0)
  687. #ifdef USE_POSIX_ACL
  688. || (acl && acl_set_file(_dest.data(), ACL_TYPE_ACCESS, acl) != 0)
  689. #endif
  690. )
  691. {
  692. // Eat the error if the filesystem apparently doesn't support chmod.
  693. if ( TDEIO::testFileSystemFlag( _dest, TDEIO::SupportsChmod ) )
  694. warning( i18n( "Could not change permissions for\n%1" ).arg( dest.path() ) );
  695. }
  696. }
  697. #ifdef USE_POSIX_ACL
  698. if (acl) acl_free(acl);
  699. #endif
  700. // copy access and modification time
  701. struct utimbuf ut;
  702. ut.actime = buff_src.st_atime;
  703. ut.modtime = buff_src.st_mtime;
  704. if ( ::utime( _dest.data(), &ut ) != 0 )
  705. {
  706. kdWarning() << TQString(TQString::fromLatin1("Couldn't preserve access and modification time for\n%1").arg( dest.path() )) << endl;
  707. }
  708. processedSize( buff_src.st_size );
  709. finished();
  710. }
  711. void FileProtocol::rename( const KURL &src, const KURL &dest,
  712. bool _overwrite )
  713. {
  714. TQCString _src( TQFile::encodeName(src.path()));
  715. TQCString _dest( TQFile::encodeName(dest.path()));
  716. KDE_struct_stat buff_src;
  717. if ( KDE_lstat( _src.data(), &buff_src ) == -1 ) {
  718. if ( errno == EACCES )
  719. error( TDEIO::ERR_ACCESS_DENIED, src.path() );
  720. else
  721. error( TDEIO::ERR_DOES_NOT_EXIST, src.path() );
  722. return;
  723. }
  724. KDE_struct_stat buff_dest;
  725. bool dest_exists = ( KDE_stat( _dest.data(), &buff_dest ) != -1 );
  726. if ( dest_exists )
  727. {
  728. if (S_ISDIR(buff_dest.st_mode))
  729. {
  730. error( TDEIO::ERR_DIR_ALREADY_EXIST, dest.path() );
  731. return;
  732. }
  733. if ( same_inode( buff_dest, buff_src) )
  734. {
  735. error( TDEIO::ERR_IDENTICAL_FILES, dest.path() );
  736. return;
  737. }
  738. if (!_overwrite)
  739. {
  740. error( TDEIO::ERR_FILE_ALREADY_EXIST, dest.path() );
  741. return;
  742. }
  743. }
  744. if ( ::rename( _src.data(), _dest.data()))
  745. {
  746. if (( errno == EACCES ) || (errno == EPERM)) {
  747. error( TDEIO::ERR_ACCESS_DENIED, dest.path() );
  748. }
  749. else if (errno == EXDEV) {
  750. error( TDEIO::ERR_UNSUPPORTED_ACTION, TQString::fromLatin1("rename"));
  751. }
  752. else if (errno == EROFS) { // The file is on a read-only filesystem
  753. error( TDEIO::ERR_CANNOT_DELETE, src.path() );
  754. }
  755. else {
  756. error( TDEIO::ERR_CANNOT_RENAME, src.path() );
  757. }
  758. return;
  759. }
  760. finished();
  761. }
  762. void FileProtocol::symlink( const TQString &target, const KURL &dest, bool overwrite )
  763. {
  764. // Assume dest is local too (wouldn't be here otherwise)
  765. if ( ::symlink( TQFile::encodeName( target ), TQFile::encodeName( dest.path() ) ) == -1 )
  766. {
  767. // Does the destination already exist ?
  768. if ( errno == EEXIST )
  769. {
  770. if ( overwrite )
  771. {
  772. // Try to delete the destination
  773. if ( unlink( TQFile::encodeName( dest.path() ) ) != 0 )
  774. {
  775. error( TDEIO::ERR_CANNOT_DELETE, dest.path() );
  776. return;
  777. }
  778. // Try again - this won't loop forever since unlink succeeded
  779. symlink( target, dest, overwrite );
  780. }
  781. else
  782. {
  783. KDE_struct_stat buff_dest;
  784. KDE_lstat( TQFile::encodeName( dest.path() ), &buff_dest );
  785. if (S_ISDIR(buff_dest.st_mode))
  786. error( TDEIO::ERR_DIR_ALREADY_EXIST, dest.path() );
  787. else
  788. error( TDEIO::ERR_FILE_ALREADY_EXIST, dest.path() );
  789. return;
  790. }
  791. }
  792. else
  793. {
  794. // Some error occurred while we tried to symlink
  795. error( TDEIO::ERR_CANNOT_SYMLINK, dest.path() );
  796. return;
  797. }
  798. }
  799. finished();
  800. }
  801. void FileProtocol::del( const KURL& url, bool isfile)
  802. {
  803. TQCString _path( TQFile::encodeName(url.path()));
  804. /*****
  805. * Delete files
  806. *****/
  807. if (isfile) {
  808. kdDebug( 7101 ) << "Deleting file "<< url.url() << endl;
  809. // TODO deletingFile( source );
  810. if ( unlink( _path.data() ) == -1 ) {
  811. if ((errno == EACCES) || (errno == EPERM))
  812. error( TDEIO::ERR_ACCESS_DENIED, url.path());
  813. else if (errno == EISDIR)
  814. error( TDEIO::ERR_IS_DIRECTORY, url.path());
  815. else
  816. error( TDEIO::ERR_CANNOT_DELETE, url.path() );
  817. return;
  818. }
  819. } else {
  820. /*****
  821. * Delete empty directory
  822. *****/
  823. kdDebug( 7101 ) << "Deleting directory " << url.url() << endl;
  824. if ( ::rmdir( _path.data() ) == -1 ) {
  825. if ((errno == EACCES) || (errno == EPERM))
  826. error( TDEIO::ERR_ACCESS_DENIED, url.path());
  827. else {
  828. kdDebug( 7101 ) << "could not rmdir " << perror << endl;
  829. error( TDEIO::ERR_COULD_NOT_RMDIR, url.path() );
  830. return;
  831. }
  832. }
  833. }
  834. finished();
  835. }
  836. TQString FileProtocol::getUserName( uid_t uid )
  837. {
  838. TQString *temp;
  839. temp = usercache.find( uid );
  840. if ( !temp ) {
  841. struct passwd *user = getpwuid( uid );
  842. if ( user ) {
  843. usercache.insert( uid, new TQString(TQString::fromLatin1(user->pw_name)) );
  844. return TQString::fromLatin1( user->pw_name );
  845. }
  846. else
  847. return TQString::number( uid );
  848. }
  849. else
  850. return *temp;
  851. }
  852. TQString FileProtocol::getGroupName( gid_t gid )
  853. {
  854. TQString *temp;
  855. temp = groupcache.find( gid );
  856. if ( !temp ) {
  857. struct group *grp = getgrgid( gid );
  858. if ( grp ) {
  859. groupcache.insert( gid, new TQString(TQString::fromLatin1(grp->gr_name)) );
  860. return TQString::fromLatin1( grp->gr_name );
  861. }
  862. else
  863. return TQString::number( gid );
  864. }
  865. else
  866. return *temp;
  867. }
  868. bool FileProtocol::createUDSEntry( const TQString & filename, const TQCString & path, UDSEntry & entry,
  869. short int details, bool withACL )
  870. {
  871. assert(entry.count() == 0); // by contract :-)
  872. // Note: details = 0 (only "file or directory or symlink or doesn't exist") isn't implemented
  873. // because there's no real performance penalty in tdeio_file for returning the complete
  874. // details. Please consider doing it in your tdeioslave if you're using this one as a model :)
  875. UDSAtom atom;
  876. atom.m_uds = TDEIO::UDS_NAME;
  877. atom.m_str = filename;
  878. entry.append( atom );
  879. mode_t type;
  880. mode_t access;
  881. KDE_struct_stat buff;
  882. if ( KDE_lstat( path.data(), &buff ) == 0 ) {
  883. if (S_ISLNK(buff.st_mode)) {
  884. char buffer2[ 1000 ];
  885. int n = readlink( path.data(), buffer2, 1000 );
  886. if ( n != -1 ) {
  887. buffer2[ n ] = 0;
  888. }
  889. atom.m_uds = TDEIO::UDS_LINK_DEST;
  890. atom.m_str = TQFile::decodeName( buffer2 );
  891. entry.append( atom );
  892. // A symlink -> follow it only if details>1
  893. if ( details > 1 && KDE_stat( path.data(), &buff ) == -1 ) {
  894. // It is a link pointing to nowhere
  895. type = S_IFMT - 1;
  896. access = S_IRWXU | S_IRWXG | S_IRWXO;
  897. atom.m_uds = TDEIO::UDS_FILE_TYPE;
  898. atom.m_long = type;
  899. entry.append( atom );
  900. atom.m_uds = TDEIO::UDS_ACCESS;
  901. atom.m_long = access;
  902. entry.append( atom );
  903. atom.m_uds = TDEIO::UDS_SIZE;
  904. atom.m_long = 0L;
  905. entry.append( atom );
  906. goto notype;
  907. }
  908. }
  909. } else {
  910. // kdWarning() << "lstat didn't work on " << path.data() << endl;
  911. return false;
  912. }
  913. type = buff.st_mode & S_IFMT; // extract file type
  914. access = buff.st_mode & 07777; // extract permissions
  915. atom.m_uds = TDEIO::UDS_FILE_TYPE;
  916. atom.m_long = type;
  917. entry.append( atom );
  918. atom.m_uds = TDEIO::UDS_ACCESS;
  919. atom.m_long = access;
  920. entry.append( atom );
  921. atom.m_uds = TDEIO::UDS_SIZE;
  922. atom.m_long = buff.st_size;
  923. entry.append( atom );
  924. #ifdef USE_POSIX_ACL
  925. /* Append an atom indicating whether the file has extended acl information
  926. * and if withACL is specified also one with the acl itself. If it's a directory
  927. * and it has a default ACL, also append that. */
  928. appendACLAtoms( path, entry, type, withACL );
  929. #endif
  930. notype:
  931. atom.m_uds = TDEIO::UDS_MODIFICATION_TIME;
  932. atom.m_long = buff.st_mtime;
  933. entry.append( atom );
  934. atom.m_uds = TDEIO::UDS_USER;
  935. atom.m_str = getUserName( buff.st_uid );
  936. entry.append( atom );
  937. atom.m_uds = TDEIO::UDS_GROUP;
  938. atom.m_str = getGroupName( buff.st_gid );
  939. entry.append( atom );
  940. atom.m_uds = TDEIO::UDS_ACCESS_TIME;
  941. atom.m_long = buff.st_atime;
  942. entry.append( atom );
  943. // Note: buff.st_ctime isn't the creation time !
  944. // We made that mistake for KDE 2.0, but it's in fact the
  945. // "file status" change time, which we don't care about.
  946. return true;
  947. }
  948. void FileProtocol::stat( const KURL & url )
  949. {
  950. if (!url.isLocalFile()) {
  951. KURL redir(url);
  952. redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
  953. redirection(redir);
  954. kdDebug(7101) << "redirecting to " << redir.url() << endl;
  955. finished();
  956. return;
  957. }
  958. /* directories may not have a slash at the end if
  959. * we want to stat() them; it requires that we
  960. * change into it .. which may not be allowed
  961. * stat("/is/unaccessible") -> rwx------
  962. * stat("/is/unaccessible/") -> EPERM H.Z.
  963. * This is the reason for the -1
  964. */
  965. TQCString _path( TQFile::encodeName(url.path(-1)));
  966. TQString sDetails = metaData(TQString::fromLatin1("details"));
  967. int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
  968. kdDebug(7101) << "FileProtocol::stat details=" << details << endl;
  969. UDSEntry entry;
  970. if ( !createUDSEntry( url.fileName(), _path, entry, details, true /*with acls*/ ) )
  971. {
  972. error( TDEIO::ERR_DOES_NOT_EXIST, url.path(-1) );
  973. return;
  974. }
  975. #if 0
  976. ///////// debug code
  977. TDEIO::UDSEntry::ConstIterator it = entry.begin();
  978. for( ; it != entry.end(); it++ ) {
  979. switch ((*it).m_uds) {
  980. case TDEIO::UDS_FILE_TYPE:
  981. kdDebug(7101) << "File Type : " << (mode_t)((*it).m_long) << endl;
  982. break;
  983. case TDEIO::UDS_ACCESS:
  984. kdDebug(7101) << "Access permissions : " << (mode_t)((*it).m_long) << endl;
  985. break;
  986. case TDEIO::UDS_USER:
  987. kdDebug(7101) << "User : " << ((*it).m_str.ascii() ) << endl;
  988. break;
  989. case TDEIO::UDS_GROUP:
  990. kdDebug(7101) << "Group : " << ((*it).m_str.ascii() ) << endl;
  991. break;
  992. case TDEIO::UDS_NAME:
  993. kdDebug(7101) << "Name : " << ((*it).m_str.ascii() ) << endl;
  994. //m_strText = decodeFileName( (*it).m_str );
  995. break;
  996. case TDEIO::UDS_URL:
  997. kdDebug(7101) << "URL : " << ((*it).m_str.ascii() ) << endl;
  998. break;
  999. case TDEIO::UDS_MIME_TYPE:
  1000. kdDebug(7101) << "MimeType : " << ((*it).m_str.ascii() ) << endl;
  1001. break;
  1002. case TDEIO::UDS_LINK_DEST:
  1003. kdDebug(7101) << "LinkDest : " << ((*it).m_str.ascii() ) << endl;
  1004. break;
  1005. case TDEIO::UDS_EXTENDED_ACL:
  1006. kdDebug(7101) << "Contains extended ACL " << endl;
  1007. break;
  1008. }
  1009. }
  1010. MetaData::iterator it1 = mOutgoingMetaData.begin();
  1011. for ( ; it1 != mOutgoingMetaData.end(); it1++ ) {
  1012. kdDebug(7101) << it1.key() << " = " << it1.data() << endl;
  1013. }
  1014. /////////
  1015. #endif
  1016. statEntry( entry );
  1017. finished();
  1018. }
  1019. void FileProtocol::listDir( const KURL& url)
  1020. {
  1021. kdDebug(7101) << "========= LIST " << url.url() << " =========" << endl;
  1022. if (!url.isLocalFile()) {
  1023. KURL redir(url);
  1024. redir.setProtocol(config()->readEntry("DefaultRemoteProtocol", "smb"));
  1025. redirection(redir);
  1026. kdDebug(7101) << "redirecting to " << redir.url() << endl;
  1027. finished();
  1028. return;
  1029. }
  1030. TQCString _path( TQFile::encodeName(url.path()));
  1031. KDE_struct_stat buff;
  1032. if ( KDE_stat( _path.data(), &buff ) == -1 ) {
  1033. error( TDEIO::ERR_DOES_NOT_EXIST, url.path() );
  1034. return;
  1035. }
  1036. if ( !S_ISDIR( buff.st_mode ) ) {
  1037. error( TDEIO::ERR_IS_FILE, url.path() );
  1038. return;
  1039. }
  1040. DIR *dp = 0L;
  1041. KDE_struct_dirent *ep;
  1042. dp = opendir( _path.data() );
  1043. if ( dp == 0 ) {
  1044. switch (errno)
  1045. {
  1046. #ifdef ENOMEDIUM
  1047. case ENOMEDIUM:
  1048. error( ERR_SLAVE_DEFINED,
  1049. i18n( "No media in device for %1" ).arg( url.path() ) );
  1050. break;
  1051. #endif
  1052. default:
  1053. error( TDEIO::ERR_CANNOT_ENTER_DIRECTORY, url.path() );
  1054. break;
  1055. }
  1056. return;
  1057. }
  1058. // Don't make this a TQStringList. The locale file name we get here
  1059. // should be passed intact to createUDSEntry to avoid problems with
  1060. // files where TQFile::encodeName(TQFile::decodeName(a)) != a.
  1061. TQStrList entryNames;
  1062. while ( ( ep = KDE_readdir( dp ) ) != 0L ) {
  1063. entryNames.append( ep->d_name );
  1064. }
  1065. closedir( dp );
  1066. totalSize( entryNames.count() );
  1067. /* set the current dir to the path to speed up
  1068. in not having to pass an absolute path.
  1069. We restore the path later to get out of the
  1070. path - the kernel wouldn't unmount or delete
  1071. directories we keep as active directory. And
  1072. as the slave runs in the background, it's hard
  1073. to see for the user what the problem would be */
  1074. #if !defined(PATH_MAX) && defined(__GLIBC__)
  1075. char *path_buffer;
  1076. path_buffer = getcwd(NULL, 0);
  1077. #else
  1078. char path_buffer[PATH_MAX];
  1079. (void) getcwd(path_buffer, PATH_MAX - 1);
  1080. #endif
  1081. if ( chdir( _path.data() ) ) {
  1082. if (errno == EACCES)
  1083. error(ERR_ACCESS_DENIED, _path);
  1084. else
  1085. error(ERR_CANNOT_ENTER_DIRECTORY, _path);
  1086. finished();
  1087. }
  1088. UDSEntry entry;
  1089. TQStrListIterator it(entryNames);
  1090. for (; it.current(); ++it) {
  1091. entry.clear();
  1092. if ( createUDSEntry( TQFile::decodeName(*it),
  1093. *it /* we can use the filename as relative path*/,
  1094. entry, 2, true ) )
  1095. listEntry( entry, false);
  1096. //else
  1097. // ;//Well, this should never happen... but with wrong encoding names
  1098. }
  1099. listEntry( entry, true ); // ready
  1100. kdDebug(7101) << "============= COMPLETED LIST ============" << endl;
  1101. chdir(path_buffer);
  1102. #if !defined(PATH_MAX) && defined(__GLIBC__)
  1103. free(path_buffer);
  1104. #endif
  1105. finished();
  1106. }
  1107. /*
  1108. void FileProtocol::testDir( const TQString& path )
  1109. {
  1110. TQCString _path( TQFile::encodeName(path));
  1111. KDE_struct_stat buff;
  1112. if ( KDE_stat( _path.data(), &buff ) == -1 ) {
  1113. error( TDEIO::ERR_DOES_NOT_EXIST, path );
  1114. return;
  1115. }
  1116. if ( S_ISDIR( buff.st_mode ) )
  1117. isDirectory();
  1118. else
  1119. isFile();
  1120. finished();
  1121. }
  1122. */
  1123. void FileProtocol::special( const TQByteArray &data)
  1124. {
  1125. int tmp;
  1126. TQDataStream stream(data, IO_ReadOnly);
  1127. stream >> tmp;
  1128. switch (tmp) {
  1129. case 1:
  1130. {
  1131. TQString fstype, dev, point;
  1132. TQ_INT8 iRo;
  1133. stream >> iRo >> fstype >> dev >> point;
  1134. bool ro = ( iRo != 0 );
  1135. kdDebug(7101) << "MOUNTING fstype=" << fstype << " dev=" << dev << " point=" << point << " ro=" << ro << endl;
  1136. bool ok = pmount( dev );
  1137. if (ok)
  1138. finished();
  1139. else
  1140. mount( ro, fstype.ascii(), dev, point );
  1141. }
  1142. break;
  1143. case 2:
  1144. {
  1145. TQString point;
  1146. stream >> point;
  1147. bool ok = pumount( point );
  1148. if (ok)
  1149. finished();
  1150. else
  1151. unmount( point );
  1152. }
  1153. break;
  1154. case 3:
  1155. {
  1156. TQString filename;
  1157. stream >> filename;
  1158. KShred shred( filename );
  1159. connect( &shred, TQT_SIGNAL( processedSize( TDEIO::filesize_t ) ),
  1160. this, TQT_SLOT( slotProcessedSize( TDEIO::filesize_t ) ) );
  1161. connect( &shred, TQT_SIGNAL( infoMessage( const TQString & ) ),
  1162. this, TQT_SLOT( slotInfoMessage( const TQString & ) ) );
  1163. if (!shred.shred())
  1164. error( TDEIO::ERR_CANNOT_DELETE, filename );
  1165. else
  1166. finished();
  1167. break;
  1168. }
  1169. default:
  1170. break;
  1171. }
  1172. }
  1173. // Connected to KShred
  1174. void FileProtocol::slotProcessedSize( TDEIO::filesize_t bytes )
  1175. {
  1176. kdDebug(7101) << "FileProtocol::slotProcessedSize (" << (unsigned int) bytes << ")" << endl;
  1177. processedSize( bytes );
  1178. }
  1179. // Connected to KShred
  1180. void FileProtocol::slotInfoMessage( const TQString & msg )
  1181. {
  1182. kdDebug(7101) << "FileProtocol::slotInfoMessage (" << msg << ")" << endl;
  1183. infoMessage( msg );
  1184. }
  1185. void FileProtocol::mount( bool _ro, const char *_fstype, const TQString& _dev, const TQString& _point )
  1186. {
  1187. kdDebug(7101) << "FileProtocol::mount _fstype=" << _fstype << endl;
  1188. TQCString buffer;
  1189. #ifdef HAVE_VOLMGT
  1190. /*
  1191. * support for Solaris volume management
  1192. */
  1193. TQString err;
  1194. TQCString devname = TQFile::encodeName( _dev );
  1195. if( volmgt_running() ) {
  1196. // kdDebug(7101) << "VOLMGT: vold ok." << endl;
  1197. if( volmgt_check( devname.data() ) == 0 ) {
  1198. kdDebug(7101) << "VOLMGT: no media in "
  1199. << devname.data() << endl;
  1200. err = i18n("No Media inserted or Media not recognized.");
  1201. error( TDEIO::ERR_COULD_NOT_MOUNT, err );
  1202. return;
  1203. } else {
  1204. kdDebug(7101) << "VOLMGT: " << devname.data()
  1205. << ": media ok" << endl;
  1206. finished();
  1207. return;
  1208. }
  1209. } else {
  1210. err = i18n("\"vold\" is not running.");
  1211. kdDebug(7101) << "VOLMGT: " << err << endl;
  1212. error( TDEIO::ERR_COULD_NOT_MOUNT, err );
  1213. return;
  1214. }
  1215. #else
  1216. KTempFile tmpFile;
  1217. TQCString tmpFileC = TQFile::encodeName(tmpFile.name());
  1218. const char *tmp = tmpFileC.data();
  1219. TQCString dev;
  1220. if ( _dev.startsWith( "LABEL=" ) ) { // turn LABEL=foo into -L foo (#71430)
  1221. TQString labelName = _dev.mid( 6 );
  1222. dev = "-L ";
  1223. dev += TQFile::encodeName( TDEProcess::quote( labelName ) ); // is it correct to assume same encoding as filesystem?
  1224. } else if ( _dev.startsWith( "UUID=" ) ) { // and UUID=bar into -U bar
  1225. TQString uuidName = _dev.mid( 5 );
  1226. dev = "-U ";
  1227. dev += TQFile::encodeName( TDEProcess::quote( uuidName ) );
  1228. }
  1229. else
  1230. dev = TQFile::encodeName( TDEProcess::quote(_dev) ); // get those ready to be given to a shell
  1231. TQCString point = TQFile::encodeName( TDEProcess::quote(_point) );
  1232. bool fstype_empty = !_fstype || !*_fstype;
  1233. TQCString fstype = TDEProcess::quote(_fstype).latin1(); // good guess
  1234. TQCString readonly = _ro ? "-r" : "";
  1235. TQString epath = TQString::fromLatin1(getenv("PATH"));
  1236. TQString path = TQString::fromLatin1("/sbin:/bin");
  1237. if(!epath.isEmpty())
  1238. path += TQString::fromLatin1(":") + epath;
  1239. TQString mountProg = TDEGlobal::dirs()->findExe("mount", path);
  1240. if (mountProg.isEmpty()){
  1241. error( TDEIO::ERR_COULD_NOT_MOUNT, i18n("Could not find program \"mount\""));
  1242. return;
  1243. }
  1244. // Two steps, in case mount doesn't like it when we pass all options
  1245. for ( int step = 0 ; step <= 1 ; step++ )
  1246. {
  1247. // Mount using device only if no fstype nor mountpoint (KDE-1.x like)
  1248. if ( !_dev.isEmpty() && _point.isEmpty() && fstype_empty )
  1249. buffer.sprintf( "%s %s 2>%s", mountProg.latin1(), dev.data(), tmp );
  1250. else
  1251. // Mount using the mountpoint, if no fstype nor device (impossible in first step)
  1252. if ( !_point.isEmpty() && _dev.isEmpty() && fstype_empty )
  1253. buffer.sprintf( "%s %s 2>%s", mountProg.latin1(), point.data(), tmp );
  1254. else
  1255. // mount giving device + mountpoint but no fstype
  1256. if ( !_point.isEmpty() && !_dev.isEmpty() && fstype_empty )
  1257. buffer.sprintf( "%s %s %s %s 2>%s", mountProg.latin1(), readonly.data(), dev.data(), point.data(), tmp );
  1258. else
  1259. // mount giving device + mountpoint + fstype
  1260. #if defined(__svr4__) && defined(__sun__) // MARCO for Solaris 8 and I
  1261. // believe this is true for SVR4 in general
  1262. buffer.sprintf( "%s -F %s %s %s %s 2>%s"
  1263. mountProg.latin1()
  1264. fstype.data()
  1265. _ro ? "-oro" : ""
  1266. dev.data()
  1267. point.data()
  1268. tmp );
  1269. #elif defined(__OpenBSD__)
  1270. buffer.sprintf( "%s %s %s -t %s %s %s 2>%s", "tdesu", mountProg.latin1(), readonly.data(),
  1271. fstype.data(), dev.data(), point.data(), tmp );
  1272. #else
  1273. buffer.sprintf( "%s %s -t %s %s %s 2>%s", mountProg.latin1(), readonly.data(),
  1274. fstype.data(), dev.data(), point.data(), tmp );
  1275. #endif
  1276. kdDebug(7101) << buffer << endl;
  1277. int mount_ret = system( buffer.data() );
  1278. TQString err = testLogFile( tmp );
  1279. if ( err.isEmpty() && mount_ret == 0)
  1280. {
  1281. finished();
  1282. return;
  1283. }
  1284. else
  1285. {
  1286. // Didn't work - or maybe we just got a warning
  1287. TQString mp = TDEIO::findDeviceMountPoint( _dev );
  1288. // Is the device mounted ?
  1289. if ( !mp.isEmpty() && mount_ret == 0)
  1290. {
  1291. kdDebug(7101) << "mount got a warning: " << err << endl;
  1292. warning( err );
  1293. finished();
  1294. return;
  1295. }
  1296. else
  1297. {
  1298. if ( (step == 0) && !_point.isEmpty())
  1299. {
  1300. kdDebug(7101) << err << endl;
  1301. kdDebug(7101) << "Mounting with those options didn't work, trying with only mountpoint" << endl;
  1302. fstype = "";
  1303. fstype_empty = true;
  1304. dev = "";
  1305. // The reason for trying with only mountpoint (instead of
  1306. // only device) is that some people (hi Malte!) have the
  1307. // same device associated with two mountpoints
  1308. // for different fstypes, like /dev/fd0 /mnt/e2floppy and
  1309. // /dev/fd0 /mnt/dosfloppy.
  1310. // If the user has the same mountpoint associated with two
  1311. // different devices, well they shouldn't specify the
  1312. // mountpoint but just the device.
  1313. }
  1314. else
  1315. {
  1316. error( TDEIO::ERR_COULD_NOT_MOUNT, err );
  1317. return;
  1318. }
  1319. }
  1320. }
  1321. }
  1322. #endif /* ! HAVE_VOLMGT */
  1323. }
  1324. void FileProtocol::unmount( const TQString& _point )
  1325. {
  1326. TQCString buffer;
  1327. KTempFile tmpFile;
  1328. TQCString tmpFileC = TQFile::encodeName(tmpFile.name());
  1329. TQString err;
  1330. const char *tmp = tmpFileC.data();
  1331. #ifdef HAVE_VOLMGT
  1332. /*
  1333. * support for Solaris volume management
  1334. */
  1335. char *devname;
  1336. char *ptr;
  1337. FILE *mnttab;
  1338. struct mnttab mnt;
  1339. if( volmgt_running() ) {
  1340. kdDebug(7101) << "VOLMGT: looking for "
  1341. << _point.local8Bit() << endl;
  1342. if( (mnttab = KDE_fopen( MNTTAB, "r" )) == NULL ) {
  1343. err = "couldn't open mnttab";
  1344. kdDebug(7101) << "VOLMGT: " << err << endl;
  1345. error( TDEIO::ERR_COULD_NOT_UNMOUNT, err );
  1346. return;
  1347. }
  1348. /*
  1349. * since there's no way to derive the device name from
  1350. * the mount point through the volmgt library (and
  1351. * media_findname() won't work in this case), we have to
  1352. * look ourselves...
  1353. */
  1354. devname = NULL;
  1355. rewind( mnttab );
  1356. while( getmntent( mnttab, &mnt ) == 0 ) {
  1357. if( strcmp( _point.local8Bit(), mnt.mnt_mountp ) == 0 ){
  1358. devname = mnt.mnt_special;
  1359. break;
  1360. }
  1361. }
  1362. fclose( mnttab );
  1363. if( devname == NULL ) {
  1364. err = "not in mnttab";
  1365. kdDebug(7101) << "VOLMGT: "
  1366. << TQFile::encodeName(_point).data()
  1367. << ": " << err << endl;
  1368. error( TDEIO::ERR_COULD_NOT_UNMOUNT, err );
  1369. return;
  1370. }
  1371. /*
  1372. * strip off the directory name (volume name)
  1373. * the eject(1) command will handle unmounting and
  1374. * physically eject the media (if possible)
  1375. */
  1376. ptr = strrchr( devname, '/' );
  1377. *ptr = '\0';
  1378. TQCString qdevname(TQFile::encodeName(TDEProcess::quote(TQFile::decodeName(TQCString(devname)))).data());
  1379. buffer.sprintf( "/usr/bin/eject %s 2>%s", qdevname.data(), tmp );
  1380. kdDebug(7101) << "VOLMGT: eject " << qdevname << endl;
  1381. /*
  1382. * from eject(1): exit status == 0 => need to manually eject
  1383. * exit status == 4 => media was ejected
  1384. */
  1385. // if( WEXITSTATUS( system( buffer.local8Bit() )) == 4 ) {
  1386. if( WEXITSTATUS( system( buffer.data() )) == 4 ) { // Fix for TQString -> QCString?
  1387. /*
  1388. * this is not an error, so skip "testLogFile()"
  1389. * to avoid wrong/confusing error popup
  1390. */
  1391. unlink( tmp );
  1392. finished();
  1393. return;
  1394. }
  1395. } else {
  1396. /*
  1397. * eject(1) should do its job without vold(1M) running,
  1398. * so we probably could call eject anyway, but since the
  1399. * media is mounted now, vold must've died for some reason
  1400. * during the user's session, so it should be restarted...
  1401. */
  1402. err = i18n("\"vold\" is not running.");
  1403. kdDebug(7101) << "VOLMGT: " << err << endl;
  1404. error( TDEIO::ERR_COULD_NOT_UNMOUNT, err );
  1405. return;
  1406. }
  1407. #else
  1408. TQString epath = getenv("PATH");
  1409. TQString path = TQString::fromLatin1("/sbin:/bin");
  1410. if (!epath.isEmpty())
  1411. path += ":" + epath;
  1412. TQString umountProg = TDEGlobal::dirs()->findExe("umount", path);
  1413. if (umountProg.isEmpty()) {
  1414. error( TDEIO::ERR_COULD_NOT_UNMOUNT, i18n("Could not find program \"umount\""));
  1415. return;
  1416. }
  1417. #ifdef __OpenBSD__
  1418. buffer.sprintf( "%s %s %s 2>%s", "tdesu", umountProg.latin1(), TQFile::encodeName(TDEProcess::quote(_point)).data(), tmp );
  1419. #else
  1420. buffer.sprintf( "%s %s 2>%s", umountProg.latin1(), TQFile::encodeName(TDEProcess::quote(_point)).data(), tmp );
  1421. #endif
  1422. system( buffer.data() );
  1423. #endif /* HAVE_VOLMGT */
  1424. err = testLogFile( tmp );
  1425. if (err.contains("fstab") || err.contains("root")) {
  1426. TQString olderr;
  1427. err = TQString::null;
  1428. DCOPRef d("kded", "mediamanager");
  1429. d.setDCOPClient ( dcopClient() );
  1430. DCOPReply reply = d.call("properties", _point);
  1431. TQString udi;
  1432. if ( reply.isValid() ) {
  1433. TQStringList list = reply;
  1434. if (list.size())
  1435. udi = list[0];
  1436. }
  1437. if (!udi.isEmpty())
  1438. reply = d.call("unmount", udi);
  1439. if (udi.isEmpty() || !reply.isValid())
  1440. err = olderr;
  1441. else if (reply.isValid())
  1442. reply.get(err);
  1443. }
  1444. if ( err.isEmpty() )
  1445. finished();
  1446. else
  1447. error( TDEIO::ERR_COULD_NOT_UNMOUNT, err );
  1448. }
  1449. /*************************************
  1450. *
  1451. * pmount handling
  1452. *
  1453. *************************************/
  1454. bool FileProtocol::pmount(const TQString &dev)
  1455. {
  1456. TQString mountProg;
  1457. TQCString buffer;
  1458. #ifdef WITH_UDISKS2
  1459. // Use 'udisksctl' (UDISKS2) if available
  1460. if (mountProg.isEmpty()) {
  1461. mountProg = TDEGlobal::dirs()->findExe("udisksctl");
  1462. if (!mountProg.isEmpty()) {
  1463. buffer.sprintf( "%s mount -b %s", TQFile::encodeName(mountProg).data(),
  1464. TQFile::encodeName(TDEProcess::quote(dev)).data() );
  1465. }
  1466. }
  1467. #endif // WITH_UDISKS2
  1468. #ifdef WITH_UDISKS
  1469. // Use 'udisks' (UDISKS1) if available
  1470. if (mountProg.isEmpty()) {
  1471. mountProg = TDEGlobal::dirs()->findExe("udisks");
  1472. if (!mountProg.isEmpty()) {
  1473. buffer.sprintf( "%s --mount %s", TQFile::encodeName(mountProg).data(),
  1474. TQFile::encodeName(TDEProcess::quote(dev)).data() );
  1475. }
  1476. }
  1477. #endif // WITH_UDISKS
  1478. // Use 'pmount', if available
  1479. if (mountProg.isEmpty()) {
  1480. mountProg = TDEGlobal::dirs()->findExe("pmount");
  1481. if (!mountProg.isEmpty()) {
  1482. buffer.sprintf( "%s %s", TQFile::encodeName(mountProg).data(),
  1483. TQFile::encodeName(TDEProcess::quote(dev)).data() );
  1484. }
  1485. }
  1486. if (mountProg.isEmpty()) {
  1487. return false;
  1488. }
  1489. int res = system( buffer.data() );
  1490. return res==0;
  1491. }
  1492. bool FileProtocol::pumount(const TQString &point)
  1493. {
  1494. TQString real_point = TDEStandardDirs::realPath(point);
  1495. KMountPoint::List mtab = KMountPoint::currentMountPoints();
  1496. KMountPoint::List::const_iterator it = mtab.begin();
  1497. KMountPoint::List::const_iterator end = mtab.end();
  1498. TQString dev;
  1499. for (; it!=end; ++it)
  1500. {
  1501. TQString tmp = (*it)->mountedFrom();
  1502. TQString mp = (*it)->mountPoint();
  1503. mp = TDEStandardDirs::realPath(mp);
  1504. if (mp==real_point)
  1505. dev = TDEStandardDirs::realPath(tmp);
  1506. }
  1507. if (dev.isEmpty()) return false;
  1508. if (dev.endsWith("/")) dev.truncate(dev.length()-1);
  1509. TQString umountProg;
  1510. TQCString buffer;
  1511. #ifdef WITH_UDISKS2
  1512. // Use 'udisksctl' (UDISKS2), if available
  1513. if (umountProg.isEmpty()) {
  1514. umountProg = TDEGlobal::dirs()->findExe("udisksctl");
  1515. if (!umountProg.isEmpty()) {
  1516. buffer.sprintf( "%s unmount -b %s", TQFile::encodeName(umountProg).data(),
  1517. TQFile::encodeName(TDEProcess::quote(dev)).data() );
  1518. }
  1519. }
  1520. #endif // WITH_UDISKS2
  1521. #ifdef WITH_UDISKS
  1522. // Use 'udisks' (UDISKS1), if available
  1523. if (umountProg.isEmpty()) {
  1524. umountProg = TDEGlobal::dirs()->findExe("udisks");
  1525. if (!umountProg.isEmpty()) {
  1526. buffer.sprintf( "%s --unmount %s", TQFile::encodeName(umountProg).data(),
  1527. TQFile::encodeName(TDEProcess::quote(dev)).data() );
  1528. }
  1529. }
  1530. #endif // WITH_UDISKS
  1531. // Use 'pumount', if available
  1532. if (umountProg.isEmpty()) {
  1533. umountProg = TDEGlobal::dirs()->findExe("pumount");
  1534. if (!umountProg.isEmpty()) {
  1535. buffer.sprintf( "%s %s", TQFile::encodeName(umountProg).data(),
  1536. TQFile::encodeName(TDEProcess::quote(dev)).data() );
  1537. }
  1538. }
  1539. if (umountProg.isEmpty()) {
  1540. return false;
  1541. }
  1542. int res = system( buffer.data() );
  1543. return res==0;
  1544. }
  1545. /*************************************
  1546. *
  1547. * Utilities
  1548. *
  1549. *************************************/
  1550. static TQString testLogFile( const char *_filename )
  1551. {
  1552. char buffer[ 1024 ];
  1553. KDE_struct_stat buff;
  1554. TQString result;
  1555. KDE_stat( _filename, &buff );
  1556. int size = buff.st_size;
  1557. if ( size == 0 ) {
  1558. unlink( _filename );
  1559. return result;
  1560. }
  1561. FILE * f = KDE_fopen( _filename, "rb" );
  1562. if ( f == 0L ) {
  1563. unlink( _filename );
  1564. result = i18n("Could not read %1").arg(TQFile::decodeName(_filename));
  1565. return result;
  1566. }
  1567. result = "";
  1568. const char *p = "";
  1569. while ( p != 0L ) {
  1570. p = fgets( buffer, sizeof(buffer)-1, f );
  1571. if ( p != 0L )
  1572. result += TQString::fromLocal8Bit(buffer);
  1573. }
  1574. fclose( f );
  1575. unlink( _filename );
  1576. return result;
  1577. }
  1578. /*************************************
  1579. *
  1580. * ACL handling helpers
  1581. *
  1582. *************************************/
  1583. #ifdef USE_POSIX_ACL
  1584. static bool isExtendedACL( acl_t acl )
  1585. {
  1586. return ( acl_equiv_mode( acl, 0 ) != 0 );
  1587. }
  1588. static TQString aclAsString( acl_t acl )
  1589. {
  1590. char *aclString = acl_to_text( acl, 0 );
  1591. TQString ret = TQString::fromLatin1( aclString );
  1592. acl_free( (void*)aclString );
  1593. return ret;
  1594. }
  1595. static void appendACLAtoms( const TQCString & path, UDSEntry& entry, mode_t type, bool withACL )
  1596. {
  1597. // first check for a noop
  1598. #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS
  1599. if ( acl_extended_file( path.data() ) == 0 ) return;
  1600. #endif
  1601. acl_t acl = 0;
  1602. acl_t defaultAcl = 0;
  1603. UDSAtom atom;
  1604. bool isDir = S_ISDIR( type );
  1605. // do we have an acl for the file, and/or a default acl for the dir, if it is one?
  1606. if ( ( acl = acl_get_file( path.data(), ACL_TYPE_ACCESS ) ) ) {
  1607. if ( !isExtendedACL( acl ) ) {
  1608. acl_free( acl );
  1609. acl = 0;
  1610. }
  1611. }
  1612. /* Sadly libacl does not provided a means of checking for extended ACL and default
  1613. * ACL separately. Since a directory can have both, we need to check again. */
  1614. if ( isDir )
  1615. defaultAcl = acl_get_file( path.data(), ACL_TYPE_DEFAULT );
  1616. if ( acl || defaultAcl ) {
  1617. kdDebug(7101) << path.data() << " has extended ACL entries " << endl;
  1618. atom.m_uds = TDEIO::UDS_EXTENDED_ACL;
  1619. atom.m_long = 1;
  1620. entry.append( atom );
  1621. }
  1622. if ( withACL ) {
  1623. if ( acl ) {
  1624. atom.m_uds = TDEIO::UDS_ACL_STRING;
  1625. atom.m_str = aclAsString( acl );
  1626. entry.append( atom );
  1627. kdDebug(7101) << path.data() << "ACL: " << atom.m_str << endl;
  1628. }
  1629. if ( defaultAcl ) {
  1630. atom.m_uds = TDEIO::UDS_DEFAULT_ACL_STRING;
  1631. atom.m_str = aclAsString( defaultAcl );
  1632. entry.append( atom );
  1633. kdDebug(7101) << path.data() << "DEFAULT ACL: " << atom.m_str << endl;
  1634. }
  1635. }
  1636. if ( acl ) acl_free( acl );
  1637. if ( defaultAcl ) acl_free( defaultAcl );
  1638. }
  1639. #endif
  1640. #include "file.moc"