25 #define QT_NO_CAST_FROM_ASCII
28 #include <QDirIterator>
31 #include <config-kioslave-file.h>
34 #include <sys/types.h>
37 #include <sys/socket.h>
38 #ifdef HAVE_SYS_TIME_H
58 #include <QtCore/QByteRef>
59 #include <QtCore/QDate>
60 #include <QtCore/QVarLengthArray>
61 #include <QtCore/QCoreApplication>
62 #include <QtCore/QRegExp>
63 #include <QtCore/QFile>
65 #include <QtCore/QDir>
66 #include <QtCore/QFileInfo>
83 #include <sys/mnttab.h>
94 #define MAX_IPC_SIZE (1024*32)
98 static void appendACLAtoms(
const QByteArray & path,
UDSEntry& entry,
99 mode_t type,
bool withACL );
104 QCoreApplication app( argc, argv );
108 kDebug(7101) <<
"Starting" << getpid();
112 fprintf(stderr,
"Usage: kio_file protocol domain-socket1 domain-socket2\n");
117 slave.dispatchLoop();
124 :
SlaveBase(
"file", pool, app ), openFd(-1)
132 #ifdef HAVE_POSIX_ACL
133 static QString aclToText(acl_t acl) {
135 char* txt = acl_to_text(acl, &size);
136 const QString ret = QString::fromLatin1(txt, size);
142 int FileProtocol::setACL(
const char *path, mode_t perm,
bool directoryDefault )
145 #ifdef HAVE_POSIX_ACL
147 const QString ACLString = metaData(QLatin1String(
"ACL_STRING"));
148 const QString defaultACLString = metaData(QLatin1String(
"DEFAULT_ACL_STRING"));
150 if ( !ACLString.isEmpty() ) {
152 if (ACLString == QLatin1String(
"ACL_DELETE")) {
155 acl = acl_from_mode( perm );
157 acl = acl_from_text( ACLString.toLatin1() );
158 if ( acl_valid( acl ) == 0 ) {
159 ret = acl_set_file( path, ACL_TYPE_ACCESS, acl );
160 kDebug(7101) <<
"Set ACL on:" << path <<
"to:" << aclToText(acl);
163 if ( ret != 0 )
return ret;
166 if ( directoryDefault && !defaultACLString.isEmpty() ) {
167 if ( defaultACLString == QLatin1String(
"ACL_DELETE") ) {
169 ret += acl_delete_def_file( path );
171 acl_t acl = acl_from_text( defaultACLString.toLatin1() );
172 if ( acl_valid( acl ) == 0 ) {
173 ret += acl_set_file( path, ACL_TYPE_DEFAULT, acl );
174 kDebug(7101) <<
"Set Default ACL on:" << path <<
"to:" << aclToText(acl);
182 Q_UNUSED(directoryDefault);
190 const QByteArray _path( QFile::encodeName(path) );
193 ( setACL( _path.data(), permissions, false ) == -1 ) ||
195 ( setACL( _path.data(), permissions, true ) == -1 && errno != ENOTDIR ) ) {
220 KDE_struct_stat statbuf;
222 struct utimbuf utbuf;
223 utbuf.actime = statbuf.st_atime;
224 utbuf.modtime = mtime.toTime_t();
240 kDebug(7101) << path <<
"permission=" << permissions;
243 if (metaData(QLatin1String(
"overwrite")) == QLatin1String(
"true"))
246 KDE_struct_stat buff;
249 if ( errno == EACCES ) {
252 }
else if ( errno == ENOSPC ) {
260 if ( permissions != -1 )
261 chmod( url, permissions );
268 if ( S_ISDIR( buff.st_mode ) ) {
269 kDebug(7101) <<
"ERR_DIR_ALREADY_EXIST";
288 KDE_struct_stat buff;
290 if ( errno == EACCES )
297 if ( S_ISDIR( buff.st_mode ) ) {
301 if ( !S_ISREG( buff.st_mode ) ) {
313 posix_fadvise( fd, 0, 0, POSIX_FADV_SEQUENTIAL);
321 KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode,
true );
322 emit mimeType( mt->name() );
324 totalSize( buff.st_size );
328 const QString resumeOffset = metaData(QLatin1String(
"resume"));
329 if ( !resumeOffset.isEmpty() )
333 if (ok && (offset > 0) && (offset < buff.st_size))
335 if (KDE_lseek(fd, offset, SEEK_SET) == offset)
338 processed_size = offset;
361 array = QByteArray::fromRawData(buffer, n);
366 processedSize( processed_size );
371 data( QByteArray() );
375 processedSize( buff.st_size );
383 ssize_t written = write(fd, buf, len);
401 KDE_struct_stat buff;
403 if ( errno == EACCES )
410 if ( S_ISDIR( buff.st_mode ) ) {
414 if ( !S_ISREG( buff.st_mode ) ) {
420 if (mode & QIODevice::ReadOnly) {
421 if (mode & QIODevice::WriteOnly) {
422 flags = O_RDWR | O_CREAT;
426 }
else if (mode & QIODevice::WriteOnly) {
427 flags = O_WRONLY | O_CREAT;
430 if (mode & QIODevice::Append) {
432 }
else if (mode & QIODevice::Truncate) {
437 if ( flags & O_CREAT)
449 if (mode & QIODevice::ReadOnly){
450 KMimeType::Ptr mt = KMimeType::findByUrl( url, buff.st_mode,
true );
451 emit mimeType( mt->name() );
454 totalSize( buff.st_size );
463 kDebug(7101) <<
"File::open -- read";
464 Q_ASSERT(openFd != -1);
466 QVarLengthArray<char> buffer(bytes);
470 res =
::read(openFd, buffer.data(), bytes);
471 }
while (res == -1 && errno == EINTR);
474 QByteArray array = QByteArray::fromRawData(buffer.data(), res);
486 if (bytes <= 0)
break;
492 kDebug(7101) <<
"File::open -- write";
493 Q_ASSERT(openFd != -1);
495 if (
write_all(openFd, data.constData(), data.size())) {
496 if (errno == ENOSPC) {
500 kWarning(7101) <<
"Couldn't write. Error:" << strerror(errno);
505 written(data.size());
511 kDebug(7101) <<
"File::open -- seek";
512 Q_ASSERT(openFd != -1);
514 int res = KDE_lseek(openFd, offset, SEEK_SET);
525 kDebug(7101) <<
"File::open -- close ";
526 Q_ASSERT(openFd != -1);
539 kDebug(7101) << dest_orig <<
"mode=" << _mode;
541 QString dest_part(dest_orig + QLatin1String(
".part"));
543 KDE_struct_stat buff_orig;
544 const bool bOrigExists = (
KDE::lstat(dest_orig, &buff_orig) != -1);
545 bool bPartExists =
false;
546 const bool bMarkPartial =
config()->readEntry(
"MarkPartial",
true);
550 KDE_struct_stat buff_part;
551 bPartExists = (
KDE::stat( dest_part, &buff_part ) != -1);
553 if (bPartExists && !(_flags &
KIO::Resume) && !(_flags &
KIO::Overwrite) && buff_part.st_size > 0 && S_ISREG(buff_part.st_mode))
568 if (S_ISDIR(buff_orig.st_mode))
586 result = readData( buffer );
594 kDebug(7101) <<
"Appending .part extension to" << dest_orig;
598 kDebug(7101) <<
"Deleting partial file" << dest_part;
599 QFile::remove( dest_part );
608 kDebug(7101) <<
"Deleting destination file" << dest_orig;
609 QFile::remove( dest_orig );
618 KDE_lseek(fd, 0, SEEK_END);
627 initialMode = _mode | S_IWUSR | S_IRUSR;
631 fd =
KDE::open(dest, O_CREAT | O_TRUNC | O_WRONLY, initialMode);
636 kDebug(7101) <<
"####################### COULD NOT WRITE" << dest <<
"_mode=" << _mode;
637 kDebug(7101) <<
"errno==" << errno <<
"(" << strerror(errno) <<
")";
638 if ( errno == EACCES )
646 if (
write_all( fd, buffer.data(), buffer.size()))
648 if ( errno == ENOSPC )
655 kWarning(7101) <<
"Couldn't write. Error:" << strerror(errno);
662 while ( result > 0 );
667 kDebug(7101) <<
"Error during 'put'. Aborting.";
673 KDE_struct_stat buff;
674 if (bMarkPartial &&
KDE::stat( dest, &buff ) == 0)
677 if (buff.st_size < size)
678 remove(_dest.data());
693 kWarning(7101) <<
"Error when closing file descriptor:" << strerror(errno);
704 if( (_flags & KIO::Overwrite) && S_ISLNK( buff_orig.st_mode ) )
705 QFile::remove( dest_orig );
708 kWarning(7101) <<
" Couldn't rename " << _dest <<
" to " << dest_orig;
712 org::kde::KDirNotify::emitFileRenamed(dest, dest_orig);
723 warning(
i18n(
"Could not change permissions for\n%1" , dest_orig ) );
728 const QString mtimeStr = metaData(QLatin1String(
"modified"));
729 if ( !mtimeStr.isEmpty() ) {
730 QDateTime dt = QDateTime::fromString( mtimeStr, Qt::ISODate );
731 if ( dt.isValid() ) {
732 KDE_struct_stat dest_statbuf;
733 if (
KDE::stat( dest_orig, &dest_statbuf ) == 0) {
734 struct timeval utbuf[2];
736 utbuf[0].tv_sec = dest_statbuf.st_atime;
737 utbuf[0].tv_usec = 0;
739 utbuf[1].tv_sec = dt.toTime_t();
740 utbuf[1].tv_usec = dt.time().msec() * 1000;
741 utimes( QFile::encodeName(dest_orig), utbuf );
751 QString FileProtocol::getUserName( uid_t uid )
const
753 if ( !mUsercache.contains( uid ) ) {
754 struct passwd *user = getpwuid( uid );
756 mUsercache.insert( uid, QString::fromLatin1(user->pw_name) );
759 return QString::number( uid );
761 return mUsercache[uid];
764 QString FileProtocol::getGroupName( gid_t gid )
const
766 if ( !mGroupcache.contains( gid ) ) {
767 struct group *grp = getgrgid( gid );
769 mGroupcache.insert( gid, QString::fromLatin1(grp->gr_name) );
772 return QString::number( gid );
774 return mGroupcache[gid];
777 bool FileProtocol::createUDSEntry(
const QString & filename,
const QByteArray & path,
UDSEntry & entry,
778 short int details,
bool withACL )
780 #ifndef HAVE_POSIX_ACL
783 assert(entry.
count() == 0);
790 KDE_struct_stat buff;
792 if ( KDE_lstat( path.data(), &buff ) == 0 ) {
799 if (S_ISLNK(buff.st_mode)) {
801 char buffer2[ 1000 ];
802 int n = readlink( path.data(), buffer2, 999 );
810 if ( details > 1 && KDE_stat( path.data(), &buff ) == -1 ) {
813 access = S_IRWXU | S_IRWXG | S_IRWXO;
827 type = buff.st_mode & S_IFMT;
828 access = buff.st_mode & 07777;
835 #ifdef HAVE_POSIX_ACL
840 appendACLAtoms( path, entry, type, withACL );
862 QDataStream stream(data);
871 stream >> iRo >> fstype >> dev >> point;
873 bool ro = ( iRo != 0 );
875 kDebug(7101) <<
"MOUNTING fstype=" << fstype <<
" dev=" << dev <<
" point=" << point <<
" ro=" << ro;
880 mount( ro, fstype.toLatin1(), dev, point );
903 kDebug(7101) <<
"fstype=" << _fstype;
911 QByteArray devname = QFile::encodeName( _dev );
913 if( volmgt_running() ) {
915 if( volmgt_check( devname.data() ) == 0 ) {
916 kDebug(7101) <<
"VOLMGT: no media in "
918 err =
i18n(
"No Media inserted or Media not recognized.");
922 kDebug(7101) <<
"VOLMGT: " << devname.data()
928 err =
i18n(
"\"vold\" is not running.");
929 kDebug(7101) <<
"VOLMGT: " << err;
937 tmpFile.setAutoRemove(
false);
939 QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
941 if (_dev.startsWith(QLatin1String(
"LABEL="))) {
942 QString labelName = _dev.mid( 6 );
945 }
else if (_dev.startsWith(QLatin1String(
"UUID="))) {
946 QString uuidName = _dev.mid( 5 );
954 bool fstype_empty = !_fstype || !*_fstype;
955 QByteArray fstype =
KShell::quoteArg(QString::fromLatin1(_fstype)).toLatin1();
956 QByteArray readonly = _ro ?
"-r" :
"";
957 QString epath = QString::fromLocal8Bit(qgetenv(
"PATH"));
958 QString path = QLatin1String(
"/sbin:/bin");
960 path += QLatin1String(
":") + epath;
962 if (mountProg.isEmpty()){
968 for (
int step = 0 ; step <= 1 ; step++ )
970 QByteArray buffer = mountProg +
' ';
972 if ( !dev.isEmpty() && _point.isEmpty() && fstype_empty )
976 if ( !_point.isEmpty() && dev.isEmpty() && fstype_empty )
980 if ( !_point.isEmpty() && !dev.isEmpty() && fstype_empty )
981 buffer += readonly +
' ' + dev +
' ' + point;
984 #if defined(__svr4__) && defined(Q_OS_SOLARIS) // MARCO for Solaris 8 and I
986 buffer +=
"-F " + fstype +
' ' + (_ro ?
"-oro" :
"") +
' ' + dev +
' ' + point;
988 buffer += readonly +
" -t " + fstype +
' ' + dev +
' ' + point;
990 buffer +=
" 2>" + tmpFileName;
993 int mount_ret = system( buffer.constData() );
996 if ( err.isEmpty() && mount_ret == 0)
1006 if ( mp && mount_ret == 0)
1008 kDebug(7101) <<
"mount got a warning:" << err;
1015 if ( (step == 0) && !_point.isEmpty())
1018 kDebug(7101) <<
"Mounting with those options didn't work, trying with only mountpoint";
1020 fstype_empty =
true;
1042 err =
i18n(
"mounting is not supported by wince.");
1055 tmpFile.setAutoRemove(
false);
1057 QByteArray tmpFileName = QFile::encodeName(tmpFile.fileName());
1069 if( volmgt_running() ) {
1070 kDebug(7101) <<
"VOLMGT: looking for "
1071 << _point.toLocal8Bit();
1073 if( (mnttab = KDE_fopen(
MNTTAB,
"r" )) == NULL ) {
1074 err = QLatin1String(
"could not open mnttab");
1075 kDebug(7101) <<
"VOLMGT: " << err;
1088 while( getmntent( mnttab, &mnt ) == 0 ) {
1089 if( strcmp( _point.toLocal8Bit(), mnt.mnt_mountp ) == 0 ){
1090 devname = mnt.mnt_special;
1096 if( devname == NULL ) {
1097 err = QLatin1String(
"not in mnttab");
1098 kDebug(7101) <<
"VOLMGT: "
1099 << QFile::encodeName(_point).data()
1110 ptr = strrchr( devname,
'/' );
1112 QByteArray qdevname(QFile::encodeName(
KShell::quoteArg(QFile::decodeName(QByteArray(devname)))).data());
1113 buffer =
"/usr/bin/eject " + qdevname +
" 2>" + tmpFileName;
1114 kDebug(7101) <<
"VOLMGT: eject " << qdevname;
1120 if( WEXITSTATUS( system( buffer.constData() )) == 4 ) {
1137 err =
i18n(
"\"vold\" is not running.");
1138 kDebug(7101) <<
"VOLMGT: " << err;
1143 QString epath = QString::fromLocal8Bit(qgetenv(
"PATH"));
1144 QString path = QLatin1String(
"/sbin:/bin");
1145 if (!epath.isEmpty())
1146 path += QLatin1Char(
':') + epath;
1149 if (umountProg.isEmpty()) {
1153 buffer = umountProg +
' ' + QFile::encodeName(
KShell::quoteArg(_point)) +
" 2>" + tmpFileName;
1154 system( buffer.constData() );
1158 if ( err.isEmpty() )
1164 err =
i18n(
"unmounting is not supported by wince.");
1178 QString epath = QString::fromLocal8Bit(qgetenv(
"PATH"));
1179 QString path = QLatin1String(
"/sbin:/bin");
1180 if (!epath.isEmpty())
1181 path += QLatin1Char(
':') + epath;
1184 if (pmountProg.isEmpty())
1187 QByteArray buffer = QFile::encodeName(pmountProg) +
' ' +
1190 int res = system( buffer.constData() );
1204 QString dev = mp->realDeviceName();
1205 if (dev.isEmpty())
return false;
1207 QString epath = QString::fromLocal8Bit(qgetenv(
"PATH"));
1208 QString path = QLatin1String(
"/sbin:/bin");
1209 if (!epath.isEmpty())
1210 path += QLatin1Char(
':') + epath;
1213 if (pumountProg.isEmpty())
1216 QByteArray buffer = QFile::encodeName(pumountProg);
1220 int res = system( buffer.data() );
1237 QFile file(QFile::decodeName(_filename));
1238 if (file.open(QIODevice::ReadOnly)) {
1239 result = QString::fromLocal8Bit(file.readAll());
1241 (void)file.remove();
1250 #ifdef HAVE_POSIX_ACL
1252 bool FileProtocol::isExtendedACL( acl_t acl )
1254 return ( acl_equiv_mode( acl, 0 ) != 0 );
1257 static void appendACLAtoms(
const QByteArray & path,
UDSEntry& entry, mode_t type,
bool withACL )
1260 if ( acl_extended_file( path.data() ) == 0 )
return;
1263 acl_t defaultAcl = 0;
1264 bool isDir = S_ISDIR( type );
1266 acl = acl_get_file( path.data(), ACL_TYPE_ACCESS );
1271 if ( !FileProtocol::isExtendedACL( acl ) ) {
1276 defaultAcl = acl_get_file( path.data(), ACL_TYPE_DEFAULT );
1278 if ( acl || defaultAcl ) {
1279 kDebug(7101) << path.constData() <<
"has extended ACL entries";
1284 const QString str = aclToText(acl);
1286 kDebug(7101) << path.constData() <<
"ACL:" << str;
1289 const QString str = aclToText(defaultAcl);
1291 kDebug(7101) << path.constData() <<
"DEFAULT ACL:" << str;
1294 if ( acl ) acl_free( acl );
1295 if ( defaultAcl ) acl_free( defaultAcl );
1301 bool FileProtocol::deleteRecursive(
const QString& path)
1304 QDirIterator it(path, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden,
1305 QDirIterator::Subdirectories);
1307 while ( it.hasNext() ) {
1308 const QString itemPath = it.next();
1310 const QFileInfo info = it.fileInfo();
1311 if (info.isDir() && !info.isSymLink())
1312 dirsToDelete.prepend(itemPath);
1315 if (!QFile::remove(itemPath)) {
1322 Q_FOREACH(
const QString& itemPath, dirsToDelete) {
1324 if (!dir.rmdir(itemPath)) {
void unmount(const QString &point)
QString i18n(const char *text)
KAutostart::StartPhase readEntry(const KConfigGroup &group, const char *key, const KAutostart::StartPhase &aDefault)
static List currentMountPoints(DetailsNeededFlags infoNeeded=BasicInfoNeeded)
int mkdir(const QString &pathname, mode_t)
void insert(uint field, const QString &value)
virtual void seek(KIO::filesize_t offset)
Ptr findByDevice(const QString &device) const
int stat(const QString &path, KDE_struct_stat *buf)
int rename(const QString &in, const QString &out)
virtual void special(const QByteArray &data)
Special commands supported by this slave: 1 - mount 2 - unmount.
int chmod(const QString &path, mode_t mode)
virtual void read(KIO::filesize_t size)
QString toLocalFile(AdjustPathOption trailing=LeaveTrailingSlash) const
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
void mount(bool _ro, const char *_fstype, const QString &dev, const QString &point)
KSharedConfigPtr config()
int kdemain(int argc, char **argv)
int open(const QString &pathname, int flags, mode_t mode)
FileProtocol(const QByteArray &pool, const QByteArray &app)
void setProtocol(const QString &proto)
virtual void setModificationTime(const KUrl &url, const QDateTime &mtime)
static QString readLogFile(const QByteArray &_filename)
QString quoteArg(const QString &arg)
#define DEFAULT_MINIMUM_KEEP_SIZE
int lstat(const QString &path, KDE_struct_stat *buf)
virtual void write(const QByteArray &data)
bool pmount(const QString &dev)
QString dir(const QString &fileClass)
int access(const QString &path, int mode)
Ptr findByPath(const QString &path) const
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
virtual void get(const KUrl &url)
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
int write_all(int fd, const char *buf, size_t len)
virtual void chmod(const KUrl &url, int permissions)
bool pumount(const QString &point)
virtual void open(const KUrl &url, QIODevice::OpenMode mode)
virtual void mkdir(const KUrl &url, int permissions)
virtual void put(const KUrl &url, int _mode, KIO::JobFlags _flags)
int utime(const QString &filename, struct utimbuf *buf)
QString number(KIO::filesize_t size)