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 "kio_floppy.h"
23 #include <config-runtime.h>
37 #include <sys/types.h>
40 #include <QTextStream>
44 #include <kcomponentdata.h>
46 #include <kio/global.h>
51 extern "C" { KDE_EXPORT
int kdemain(int argc
, char **argv
); }
53 int kdemain( int argc
, char **argv
)
55 KComponentData
componentData( "kio_floppy" );
59 fprintf(stderr
, "Usage: kio_floppy protocol domain-socket1 domain-socket2\n");
62 kDebug(7101) << "Floppy: kdemain: starting";
64 FloppyProtocol
slave(argv
[2], argv
[3]);
69 void getDriveAndPath(const QString
& path
, QString
& drive
, QString
& rest
)
73 const QStringList list
=path
.split("/");
74 for (QStringList::const_iterator it
=list
.constBegin(); it
!=list
.constEnd(); ++it
)
83 FloppyProtocol::FloppyProtocol (const QByteArray
&pool
, const QByteArray
&app
)
84 :SlaveBase( "floppy", pool
, app
)
91 kDebug(7101)<<"Floppy::Floppy: -"<<pool
<<"-";
94 FloppyProtocol::~FloppyProtocol()
96 delete [] m_stdoutBuffer
;
97 delete [] m_stderrBuffer
;
104 int FloppyProtocol::readStdout()
106 //kDebug(7101)<<"Floppy::readStdout";
107 if (m_mtool
==0) return 0;
109 char buffer
[16*1024];
110 int length
=::read(m_mtool
->stdoutFD(),buffer
,16*1024);
111 if (length
<=0) return 0;
113 //+1 gives us room for a terminating 0
114 char *newBuffer
=new char[length
+m_stdoutSize
+1];
115 kDebug(7101)<<"Floppy::readStdout(): length: "<<length
<<" m_tsdoutSize: "<<m_stdoutSize
<<" +1="<<length
+m_stdoutSize
+1;
116 if (m_stdoutBuffer
!=0)
118 memcpy(newBuffer
, m_stdoutBuffer
, m_stdoutSize
);
120 memcpy(newBuffer
+m_stdoutSize
, buffer
, length
);
121 m_stdoutSize
+=length
;
122 newBuffer
[m_stdoutSize
]='\0';
124 delete [] m_stdoutBuffer
;
125 m_stdoutBuffer
=newBuffer
;
126 //kDebug(7101)<<"Floppy::readStdout(): -"<<m_stdoutBuffer<<"-";
128 //kDebug(7101)<<"Floppy::readStdout ends";
132 int FloppyProtocol::readStderr()
134 //kDebug(7101)<<"Floppy::readStderr";
135 if (m_mtool
==0) return 0;
140 ::select(0,0,0,0,&tv);*/
142 char buffer
[16*1024];
143 int length
=::read(m_mtool
->stderrFD(),buffer
,16*1024);
144 kDebug(7101)<<"Floppy::readStderr(): read "<<length
<<" bytes";
145 if (length
<=0) return 0;
147 //+1 gives us room for a terminating 0
148 char *newBuffer
=new char[length
+m_stderrSize
+1];
149 memcpy(newBuffer
, m_stderrBuffer
, m_stderrSize
);
150 memcpy(newBuffer
+m_stderrSize
, buffer
, length
);
151 m_stderrSize
+=length
;
152 newBuffer
[m_stderrSize
]='\0';
153 delete [] m_stderrBuffer
;
154 m_stderrBuffer
=newBuffer
;
155 kDebug(7101)<<"Floppy::readStderr(): -"<<m_stderrBuffer
<<"-";
160 void FloppyProtocol::clearBuffers()
162 kDebug(7101)<<"Floppy::clearBuffers()";
165 delete [] m_stdoutBuffer
;
167 delete [] m_stderrBuffer
;
169 //kDebug(7101)<<"Floppy::clearBuffers() ends";
172 void FloppyProtocol::terminateBuffers()
174 //kDebug(7101)<<"Floppy::terminateBuffers()";
175 //append a terminating 0 to be sure
176 if (m_stdoutBuffer
!=0)
178 m_stdoutBuffer
[m_stdoutSize
]='\0';
180 if (m_stderrBuffer
!=0)
182 m_stderrBuffer
[m_stderrSize
]='\0';
184 //kDebug(7101)<<"Floppy::terminateBuffers() ends";
187 bool FloppyProtocol::stopAfterError(const KUrl
& url
, const QString
& drive
)
191 //m_stderrBuffer[m_stderrSize]='\0';
193 QString
outputString(m_stderrBuffer
);
194 QTextStream
output(&outputString
, QIODevice::ReadOnly
);
195 QString line
=output
.readLine();
196 kDebug(7101)<<"line: -"<<line
<<"-";
197 if (line
.indexOf("resource busy") > -1)
199 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not access drive %1.\nThe drive is still busy.\nWait until it is inactive and then try again.", drive
));
201 else if ((line
.indexOf("Disk full") > -1) || (line
.indexOf("No free cluster") > -1))
203 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not write to file %1.\nThe disk in drive %2 is probably full.", url
.prettyUrl(), drive
));
206 else if (line
.indexOf("not found") > -1)
208 error( KIO::ERR_DOES_NOT_EXIST
, url
.prettyUrl());
211 else if (line
.indexOf("not configured") > -1)
213 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not access %1.\nThere is probably no disk in the drive %2", url
.prettyUrl(), drive
));
215 else if (line
.indexOf("No such device") > -1)
217 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not access %1.\nThere is probably no disk in the drive %2 or you do not have enough permissions to access the drive.", url
.prettyUrl(), drive
));
219 else if (line
.indexOf("not supported") > -1)
221 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not access %1.\nThe drive %2 is not supported.", url
.prettyUrl(), drive
));
223 //not supported or no such drive
224 else if (line
.indexOf("Permission denied") > -1)
226 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not access %1.\nMake sure the floppy in drive %2 is a DOS-formatted floppy disk \nand that the permissions of the device file (e.g. /dev/fd0) are set correctly (e.g. rwxrwxrwx).", url
.prettyUrl(), drive
));
228 else if (line
.indexOf("non DOS media") > -1)
230 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not access %1.\nThe disk in drive %2 is probably not a DOS-formatted floppy disk.", url
.prettyUrl(), drive
));
232 else if (line
.indexOf("Read-only") > -1)
234 error( KIO::ERR_SLAVE_DEFINED
, i18n("Access denied.\nCould not write to %1.\nThe disk in drive %2 is probably write-protected.", url
.prettyUrl(), drive
));
236 else if ((outputString
.indexOf("already exists") > -1) || (outputString
.indexOf("Skipping ") > -1))
238 error( KIO::ERR_FILE_ALREADY_EXIST
,url
.prettyUrl());
241 else if (outputString
.indexOf("could not read boot sector") > -1)
243 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not read boot sector for %1.\nThere is probably not any disk in drive %2.", url
.prettyUrl(), drive
));
248 error( KIO::ERR_UNKNOWN
, outputString
);
253 void FloppyProtocol::listDir( const KUrl
& _url
)
255 kDebug(7101)<<"Floppy::listDir() "<<_url
.path();
257 QString
path(url
.path());
259 if ((path
.isEmpty()) || (path
=="/"))
268 getDriveAndPath(path
,drive
,floppyPath
);
272 args
<<"mdir"<<"-a"<<(drive
+floppyPath
);
275 m_mtool
=new Program(args
);
279 if (!m_mtool
->start())
283 errorMissingMToolsProgram("mdir");
288 bool loopFinished(false);
289 bool errorOccured(false);
294 result
=m_mtool
->select(1,0,stdoutEvent
, stderrEvent
);
303 if (stopAfterError(url
,drive
))
309 } while (!loopFinished
);
313 //now mdir has finished
314 //let's parse the output
320 QString
outputString(m_stdoutBuffer
);
321 QTextStream
output(&outputString
, QIODevice::ReadOnly
);
328 while (!output
.atEnd())
330 line
=output
.readLine();
331 kDebug(7101)<<"Floppy::listDir(): line: -"<<line
<<"- length: "<<line
.length();
337 kDebug(7101)<<"Floppy::listDir(): switching to mode 1";
345 kDebug(7101)<<"Floppy::listDir(): ende";
346 totalSize(totalNumber
);
350 StatInfo info
=createStatInfo(line
);
353 createUDSEntry(info
,entry
);
354 //kDebug(7101)<<"Floppy::listDir(): creating UDSEntry";
355 listEntry( entry
, false);
360 listEntry( entry
, true ); // ready
362 //kDebug(7101)<<"Floppy::listDir() ends";
365 void FloppyProtocol::errorMissingMToolsProgram(const QString
& name
)
367 error(KIO::ERR_SLAVE_DEFINED
,i18n("Could not start program \"%1\".\nEnsure that the mtools package is installed correctly on your system.", name
));
370 void FloppyProtocol::createUDSEntry(const StatInfo
& info
, UDSEntry
& entry
)
372 entry
.insert( KIO::UDSEntry::UDS_NAME
, info
.name
);
373 entry
.insert( KIO::UDSEntry::UDS_SIZE
, info
.size
);
374 entry
.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME
, info
.time
);
375 entry
.insert( KIO::UDSEntry::UDS_ACCESS
, info
.mode
);
376 entry
.insert( KIO::UDSEntry::UDS_FILE_TYPE
, info
.isDir
?S_IFDIR
:S_IFREG
);
379 StatInfo
FloppyProtocol::createStatInfo(const QString line
, bool makeStat
, const QString
& dirName
)
381 //kDebug(7101)<<"Floppy::createUDSEntry()";
385 QString day
,month
, year
;
386 QString hour
, minute
;
389 if (line
.length()==41)
391 int nameLength
=line
.indexOf(' ');
392 kDebug(7101)<<"Floppy::createStatInfo: line find: "<<nameLength
<<"= -"<<line
<<"-";
395 name
=line
.mid(0,nameLength
);
396 QString ext
=line
.mid(9,3);
401 kDebug(7101)<<"Floppy::createStatInfo() name 8.3= -"<<name
<<"-";
403 else if (line
.length()>41)
406 kDebug(7101)<<"Floppy::createStatInfo() name vfat: -"<<name
<<"-";
408 if ((name
==".") || (name
==".."))
419 if (line
.mid(13,5)=="<DIR>")
421 //kDebug(7101)<<"Floppy::createUDSEntry() isDir";
428 //kDebug(7101)<<"Floppy::createUDSEntry() size: -"<<size<<"-";
431 //TEEKANNE JPG 70796 01-02-2003 17:47 Teekanne.jpg
434 month
=line
.mid(23,2);
438 else //SETUP PKG 1019 1997-09-25 10:31 setup.pkg
441 month
=line
.mid(28,2);
445 minute
=line
.mid(38,2);
446 //kDebug(7101)<<"Floppy::createUDSEntry() day: -"<<day<<"-"<<month<<"-"<<year<<"- -"<<hour<<"-"<<minute<<"-";
455 info
.size
=size
.toInt();
457 QDateTime
date(QDate(year
.toInt(),month
.toInt(),day
.toInt()),QTime(hour
.toInt(),minute
.toInt()));
458 info
.time
=date
.toTime_t();
461 info
.mode
= S_IRUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
| S_IWOTH
|S_IWGRP
|S_IWUSR
;
463 info
.mode
= S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWOTH
|S_IWGRP
|S_IWUSR
;
468 //kDebug(7101)<<"Floppy::createUDSEntry() ends";
472 StatInfo
FloppyProtocol::_stat(const KUrl
& url
)
476 QString
path(url
.path());
479 getDriveAndPath(path
,drive
,floppyPath
);
481 if (floppyPath
.isEmpty())
483 kDebug(7101)<<"Floppy::_stat(): floppyPath.isEmpty()";
487 info
.mode
=S_IRUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
| S_IWOTH
|S_IWGRP
|S_IWUSR
;
494 //kDebug(7101)<<"Floppy::_stat(): delete m_mtool";
499 args
<<"mdir"<<"-a"<<(drive
+floppyPath
);
501 //kDebug(7101)<<"Floppy::_stat(): create m_mtool";
502 m_mtool
=new Program(args
);
504 if (!m_mtool
->start())
508 errorMissingMToolsProgram("mdir");
516 bool loopFinished(false);
517 bool errorOccured(false);
522 result
=m_mtool
->select(1,0,stdoutEvent
, stderrEvent
);
531 if (stopAfterError(url
,drive
))
537 } while (!loopFinished
);
539 //kDebug(7101)<<"Floppy::_stat(): delete m_mtool";
542 //now mdir has finished
543 //let's parse the output
555 error( KIO::ERR_COULD_NOT_STAT
, url
.prettyUrl());
559 kDebug(7101)<<"Floppy::_stat(): parse stuff";
560 QString
outputString(m_stdoutBuffer
);
561 QTextStream
output(&outputString
, QIODevice::ReadOnly
);
563 for (int lineNumber
=0; !output
.atEnd(); lineNumber
++)
565 line
=output
.readLine();
566 if ( (lineNumber
<3) || (line
.isEmpty()) )
568 StatInfo info
=createStatInfo(line
,true,url
.fileName());
569 if (info
.isValid
==false)
570 error( KIO::ERR_COULD_NOT_STAT
, url
.prettyUrl());
573 if (info
.isValid
==false)
574 error( KIO::ERR_COULD_NOT_STAT
, url
.prettyUrl());
578 int FloppyProtocol::freeSpace(const KUrl
& url
)
580 QString
path(url
.path());
583 getDriveAndPath(path
,drive
,floppyPath
);
585 //kDebug(7101)<<"Floppy::freeSpace(): delete m_mtool";
590 args
<<"mdir"<<"-a"<<drive
;
592 //kDebug(7101)<<"Floppy::freeSpace(): create m_mtool";
593 m_mtool
=new Program(args
);
595 if (!m_mtool
->start())
599 errorMissingMToolsProgram("mdir");
607 bool loopFinished(false);
608 bool errorOccured(false);
613 result
=m_mtool
->select(1,0,stdoutEvent
, stderrEvent
);
622 if (stopAfterError(url
,drive
))
628 } while (!loopFinished
);
630 //kDebug(7101)<<"Floppy::freeSpace(): delete m_mtool";
633 //now mdir has finished
634 //let's parse the output
644 error( KIO::ERR_COULD_NOT_STAT
, url
.prettyUrl());
648 kDebug(7101)<<"Floppy::freeSpace(): parse stuff";
649 QString
outputString(m_stdoutBuffer
);
650 QTextStream
output(&outputString
, QIODevice::ReadOnly
);
653 while (!output
.atEnd())
655 line
=output
.readLine();
656 if (line
.indexOf("bytes free")==36)
658 QString tmp
=line
.mid(24,3);
672 void FloppyProtocol::stat( const KUrl
& _url
)
674 kDebug(7101)<<"Floppy::stat() "<<_url
.path();
676 QString
path(url
.path());
678 if ((path
.isEmpty()) || (path
=="/"))
685 StatInfo info
=this->_stat(url
);
689 createUDSEntry(info
,entry
);
692 //kDebug(7101)<<"Floppy::stat(): ends";
695 //otherwise the error() was already reported in _stat()
698 void FloppyProtocol::mkdir( const KUrl
& url
, int)
700 kDebug(7101)<<"FloppyProtocol::mkdir()";
701 QString
path(url
.path());
703 if ((path
.isEmpty()) || (path
=="/"))
706 newUrl
.setPath("/a/");
713 getDriveAndPath(path
,drive
,floppyPath
);
714 if (floppyPath
.isEmpty())
721 //kDebug(7101)<<"Floppy::stat(): create args";
724 args
<<"mmd"<<(drive
+floppyPath
);
725 kDebug(7101)<<"Floppy::mkdir(): executing: mmd -"<<(drive
+floppyPath
)<<"-";
727 m_mtool
=new Program(args
);
728 if (!m_mtool
->start())
732 errorMissingMToolsProgram("mmd");
739 bool loopFinished(false);
740 bool errorOccured(false);
745 result
=m_mtool
->select(1,0,stdoutEvent
, stderrEvent
);
754 if (stopAfterError(url
,drive
))
760 } while (!loopFinished
);
770 void FloppyProtocol::del( const KUrl
& url
, bool isfile
)
772 kDebug(7101)<<"FloppyProtocol::del()";
773 QString
path(url
.path());
775 if ((path
.isEmpty()) || (path
=="/"))
778 newUrl
.setPath("/a/");
785 getDriveAndPath(path
,drive
,floppyPath
);
786 if (floppyPath
.isEmpty())
794 //kDebug(7101)<<"Floppy::stat(): create args";
801 args
<<"mdel"<<(drive
+floppyPath
);
806 args
<<"mrd"<<(drive
+floppyPath
);
810 kDebug(7101)<<"Floppy::del(): executing: " << (usingmdel
? QString("mdel") : QString("mrd") ) << "-"<<(drive
+floppyPath
)<<"-";
812 m_mtool
=new Program(args
);
813 if (!m_mtool
->start())
817 errorMissingMToolsProgram(usingmdel
? QString("mdel") : QString("mrd"));
824 bool loopFinished(false);
825 bool errorOccured(false);
830 result
=m_mtool
->select(1,0,stdoutEvent
, stderrEvent
);
839 if (stopAfterError(url
,drive
))
845 } while (!loopFinished
);
855 void FloppyProtocol::rename( const KUrl
&src
, const KUrl
&dest
, KIO::JobFlags flags
)
857 QString
srcPath(src
.path());
858 QString
destPath(dest
.path());
860 kDebug(7101)<<"Floppy::rename() -"<<srcPath
<<"- to -"<<destPath
<<"-";
862 if ((srcPath
.isEmpty()) || (srcPath
=="/"))
865 if ((destPath
.isEmpty()) || (destPath
=="/"))
869 QString srcFloppyPath
;
870 getDriveAndPath(srcPath
,srcDrive
,srcFloppyPath
);
871 if (srcFloppyPath
.isEmpty())
878 QString destFloppyPath
;
879 getDriveAndPath(destPath
,destDrive
,destFloppyPath
);
880 if (destFloppyPath
.isEmpty())
888 //kDebug(7101)<<"Floppy::stat(): create args";
891 if (flags
& KIO::Overwrite
)
892 args
<<"mren"<<"-o"<<(srcDrive
+srcFloppyPath
)<<(destDrive
+destFloppyPath
);
894 args
<<"mren"<<"-D"<<"s"<<(srcDrive
+srcFloppyPath
)<<(destDrive
+destFloppyPath
);
896 kDebug(7101)<<"Floppy::move(): executing: mren -"<<(srcDrive
+srcFloppyPath
)<<" "<<(destDrive
+destFloppyPath
);
898 m_mtool
=new Program(args
);
899 if (!m_mtool
->start())
903 errorMissingMToolsProgram("mren");
910 bool loopFinished(false);
911 bool errorOccured(false);
916 result
=m_mtool
->select(1,0,stdoutEvent
, stderrEvent
);
925 if (stopAfterError(src
,srcDrive
))
931 } while (!loopFinished
);
941 void FloppyProtocol::get( const KUrl
& url
)
943 QString
path(url
.path());
944 kDebug(7101)<<"Floppy::get() -"<<path
<<"-";
946 if ((path
.isEmpty()) || (path
=="/"))
949 newUrl
.setPath("/a/");
954 StatInfo info
=this->_stat(url
);
955 //the error was already reported in _stat()
956 if (info
.isValid
==false)
959 totalSize( info
.size
);
963 getDriveAndPath(path
,drive
,floppyPath
);
964 if (floppyPath
.isEmpty())
972 //kDebug(7101)<<"Floppy::stat(): create args";
974 args
<<"mcopy"<<(drive
+floppyPath
)<<"-";
976 kDebug(7101)<<"Floppy::get(): executing: mcopy -"<<(drive
+floppyPath
)<<"-";
978 m_mtool
=new Program(args
);
979 if (!m_mtool
->start())
983 errorMissingMToolsProgram("mcopy");
990 bool loopFinished(false);
991 bool errorOccured(false);
996 result
=m_mtool
->select(1,0,stdoutEvent
, stderrEvent
);
999 delete [] m_stdoutBuffer
;
1004 kDebug(7101)<<"Floppy::get(): m_stdoutSize:"<<m_stdoutSize
;
1005 bytesRead
+=m_stdoutSize
;
1006 data( QByteArray::fromRawData(m_stdoutBuffer
, m_stdoutSize
) );
1015 if (readStderr()==0)
1018 if (stopAfterError(url
,drive
))
1024 } while (!loopFinished
);
1026 //kDebug(7101)<<"Floppy::get(): deleting m_mtool";
1032 //kDebug(7101)<<"Floppy::get(): finishing";
1033 data( QByteArray() );
1037 void FloppyProtocol::put( const KUrl
& url
, int , JobFlags flags
)
1039 QString
path(url
.path());
1040 kDebug(7101)<<"Floppy::put() -"<<path
<<"-";
1042 if ((path
.isEmpty()) || (path
=="/"))
1045 newUrl
.setPath("/a/");
1046 redirection(newUrl
);
1052 getDriveAndPath(path
,drive
,floppyPath
);
1053 if (floppyPath
.isEmpty())
1058 int freeSpaceLeft
=freeSpace(url
);
1059 if (freeSpaceLeft
==-1)
1064 //kDebug(7101)<<"Floppy::stat(): create args";
1066 if (flags
& KIO::Overwrite
)
1067 args
<<"mcopy"<<"-o"<<"-"<<(drive
+floppyPath
);
1069 args
<<"mcopy"<<"-s"<<"-"<<(drive
+floppyPath
);
1071 kDebug(7101)<<"Floppy::put(): executing: mcopy -"<<(drive
+floppyPath
)<<"-";
1073 m_mtool
=new Program(args
);
1074 if (!m_mtool
->start())
1078 errorMissingMToolsProgram("mcopy");
1088 // Loop until we got 0 (end of data)
1093 kDebug(7101)<<"Floppy::put(): select()...";
1094 m_mtool
->select(0,100,stdoutEvent
, stderrEvent
);
1097 if (readStdout()==0)
1102 if (readStderr()==0)
1105 if (stopAfterError(url
,drive
))
1107 kDebug(7101)<<"Floppy::put(): error: result=="<<result
;
1112 dataReq(); // Request for data
1113 //kDebug(7101)<<"Floppy::put(): after dataReq()";
1114 result
= readData( buffer
);
1115 //kDebug(7101)<<"Floppy::put(): after readData(), read "<<result<<" bytes";
1119 kDebug(7101)<<"Floppy::put() bytesRead: "<<bytesRead
<<" space: "<<freeSpaceLeft
;
1120 if (bytesRead
>freeSpaceLeft
)
1123 error( KIO::ERR_SLAVE_DEFINED
, i18n("Could not write to file %1.\nThe disk in drive %2 is probably full.", url
.prettyUrl(), drive
));
1127 //kDebug(7101)<<"Floppy::put(): writing...";
1128 result
=::write(m_mtool
->stdinFD(),buffer
.data(), buffer
.size());
1129 kDebug(7101)<<"Floppy::put(): after write(), wrote "<<result
<<" bytes";
1134 while ( result
> 0 );
1138 perror("writing to stdin");
1139 error( KIO::ERR_CANNOT_OPEN_FOR_WRITING
, url
.prettyUrl());