Example #1
0
TQString TrashImpl::trashForMountPoint( const TQString& topdir, bool createIfNeeded ) const
{
    // (1) Administrator-created $topdir/.Trash directory

    const TQString rootTrashDir = topdir + "/.Trash";
    const TQCString rootTrashDir_c = TQFile::encodeName( rootTrashDir );
    // Can't use TQFileInfo here since we need to test for the sticky bit
    uid_t uid = getuid();
    KDE_struct_stat buff;
    const uint requiredBits = S_ISVTX; // Sticky bit required
    if ( KDE_lstat( rootTrashDir_c, &buff ) == 0 ) {
        if ( (S_ISDIR(buff.st_mode)) // must be a dir
             && (!S_ISLNK(buff.st_mode)) // not a symlink
             && ((buff.st_mode & requiredBits) == requiredBits)
             && (::access(rootTrashDir_c, W_OK))
            ) {
            const TQString trashDir = rootTrashDir + "/" + TQString::number( uid );
            const TQCString trashDir_c = TQFile::encodeName( trashDir );
            if ( KDE_lstat( trashDir_c, &buff ) == 0 ) {
                if ( (buff.st_uid == uid) // must be owned by user
                     && (S_ISDIR(buff.st_mode)) // must be a dir
                     && (!S_ISLNK(buff.st_mode)) // not a symlink
                     && (buff.st_mode & 0777) == 0700 ) { // rwx for user
                    return trashDir;
                }
                kdDebug() << "Directory " << trashDir << " exists but didn't pass the security checks, can't use it" << endl;
            }
            else if ( createIfNeeded && initTrashDirectory( trashDir_c ) ) {
                return trashDir;
            }
        } else {
            kdDebug() << "Root trash dir " << rootTrashDir << " exists but didn't pass the security checks, can't use it" << endl;
        }
    }

    // (2) $topdir/.Trash-$uid
    const TQString trashDir = topdir + "/.Trash-" + TQString::number( uid );
    const TQCString trashDir_c = TQFile::encodeName( trashDir );
    if ( KDE_lstat( trashDir_c, &buff ) == 0 )
    {
        if ( (buff.st_uid == uid) // must be owned by user
             && (S_ISDIR(buff.st_mode)) // must be a dir
             && (!S_ISLNK(buff.st_mode)) // not a symlink
             && ((buff.st_mode & 0777) == 0700) ) { // rwx for user, ------ for group and others

            if ( checkTrashSubdirs( trashDir_c ) )
            return trashDir;
        }
        kdDebug() << "Directory " << trashDir << " exists but didn't pass the security checks, can't use it" << endl;
        // Exists, but not useable
        return TQString::null;
    }
    if ( createIfNeeded && initTrashDirectory( trashDir_c ) ) {
        return trashDir;
    }
    return TQString::null;
}
Example #2
0
void TrashProtocol::restore( const KUrl& trashURL )
{
    int trashId;
    QString fileId, relativePath;
    bool ok = TrashImpl::parseURL( trashURL, trashId, fileId, relativePath );
    if ( !ok ) {
        error( KIO::ERR_SLAVE_DEFINED, i18n( "Malformed URL %1", trashURL.prettyUrl() ) );
        return;
    }
    TrashedFileInfo info;
    ok = impl.infoForFile( trashId, fileId, info );
    if ( !ok ) {
        error( impl.lastErrorCode(), impl.lastErrorMessage() );
        return;
    }
    KUrl dest;
    dest.setPath( info.origPath );
    if ( !relativePath.isEmpty() )
        dest.addPath( relativePath );

    // Check that the destination directory exists, to improve the error code in case it doesn't.
    const QString destDir = dest.directory();
    KDE_struct_stat buff;
    if ( KDE_lstat( QFile::encodeName( destDir ), &buff ) == -1 ) {
        error( KIO::ERR_SLAVE_DEFINED,
               i18n( "The directory %1 does not exist anymore, so it is not possible to restore this item to its original location. "
                     "You can either recreate that directory and use the restore operation again, or drag the item anywhere else to restore it.", destDir ) );
        return;
    }

    copyOrMove( trashURL, dest, false /*overwrite*/, Move );
}
Example #3
0
bool TrashImpl::initTrashDirectory( const TQCString& trashDir_c ) const
{
    if ( ::mkdir( trashDir_c, 0700 ) != 0 )
        return false;
    // This trash dir will be useable only if the directory is owned by user.
    // In theory this is the case, but not on e.g. USB keys...
    uid_t uid = getuid();
    KDE_struct_stat buff;
    if ( KDE_lstat( trashDir_c, &buff ) != 0 )
        return false; // huh?
    if ( (buff.st_uid == uid) // must be owned by user
         && ((buff.st_mode & 0777) == 0700) ) { // rwx for user, --- for group and others

        return checkTrashSubdirs( trashDir_c );

    } else {
        kdDebug() << trashDir_c << " just created, by it doesn't have the right permissions, must be a FAT partition. Removing it again." << endl;
        // Not good, e.g. USB key. Delete again.
        // I'm paranoid, it would be better to find a solution that allows
        // to trash directly onto the USB key, but I don't see how that would
        // pass the security checks. It would also make the USB key appears as
        // empty when it's in fact full...
        ::rmdir( trashDir_c );
        return false;
    }
    return true;
}
Example #4
0
int TrashImpl::findTrashDirectory( const TQString& origPath )
{
    kdDebug() << k_funcinfo << origPath << endl;
    // First check if same device as $HOME, then we use the home trash right away.
    KDE_struct_stat buff;
    if ( KDE_lstat( TQFile::encodeName( origPath ), &buff ) == 0
         && buff.st_dev == m_homeDevice )
        return 0;

    TQString mountPoint = TDEIO::findPathMountPoint( origPath );
    const TQString trashDir = trashForMountPoint( mountPoint, true );
    kdDebug() << "mountPoint=" << mountPoint << " trashDir=" << trashDir << endl;
    if ( trashDir.isEmpty() )
        return 0; // no trash available on partition
    int id = idForTrashDirectory( trashDir );
    if ( id > -1 ) {
        kdDebug() << " known with id " << id << endl;
        return id;
    }
    // new trash dir found, register it
    // but we need stability in the trash IDs, so that restoring or asking
    // for properties works even tdeio_trash gets killed because idle.
#if 0
    kdDebug() << k_funcinfo << "found " << trashDir << endl;
    m_trashDirectories.insert( ++m_lastId, trashDir );
    if ( !mountPoint.endsWith( "/" ) )
        mountPoint += '/';
    m_topDirectories.insert( m_lastId, mountPoint );
    return m_lastId;
#endif
    scanTrashDirectories();
    return idForTrashDirectory( trashDir );
}
Example #5
0
void KStandardDirs::createSpecialResource(const char *type)
{
    char hostname[256];
    hostname[0] = 0;
    gethostname(hostname, 255);
    QString dir = QString("%1%2-%3").arg(localkdedir()).arg(type).arg(hostname);
    char link[1024];
    link[1023] = 0;
    int result = readlink(QFile::encodeName(dir).data(), link, 1023);
    bool relink = (result == -1) && (errno == ENOENT);
    if(result > 0)
    {
        link[result] = 0;
        if(!QDir::isRelativePath(link))
        {
            KDE_struct_stat stat_buf;
            int res = KDE_lstat(link, &stat_buf);
            if((res == -1) && (errno == ENOENT))
            {
                relink = true;
            }
            else if((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
            {
                fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
                relink = true;
            }
            else if(stat_buf.st_uid != getuid())
            {
                fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
                relink = true;
            }
        }
    }

    if(relink)
    {
        QString srv = findExe(QString::fromLatin1("lnusertemp"), kfsstnd_defaultbindir());
        if(srv.isEmpty())
            srv = findExe(QString::fromLatin1("lnusertemp"));
        if(!srv.isEmpty())
        {
            system(QFile::encodeName(srv) + " " + type);
            result = readlink(QFile::encodeName(dir).data(), link, 1023);
        }
    }
    if(result > 0)
    {
        link[result] = 0;
        if(link[0] == '/')
            dir = QFile::decodeName(link);
        else
            dir = QDir::cleanDirPath(dir + QFile::decodeName(link));
    }

    addResourceDir(type, dir + '/');
}
Example #6
0
static void createTestSymlink(const QString &path)
{
    // Create symlink if it doesn't exist yet
    KDE_struct_stat buf;
    if(KDE_lstat(QFile::encodeName(path), &buf) != 0)
    {
        bool ok = symlink("/IDontExist", QFile::encodeName(path)) == 0; // broken symlink
        if(!ok)
            kdFatal() << "couldn't create symlink: " << strerror(errno) << endl;
    }
}
Example #7
0
static bool testLinkCountSupport(const QByteArray &fileName)
{
   KDE_struct_stat st_buf;
   int result = -1;
   // Check if hardlinks raise the link count at all?
   if(!::link( fileName, QByteArray(fileName+".test") )) {
     result = KDE_lstat( fileName, &st_buf );
     ::unlink( QByteArray(fileName+".test") );
   }
   return (result < 0 || ((result == 0) && (st_buf.st_nlink == 2)));
}
Example #8
0
bool TrashProtocol::createUDSEntry(const QString &physicalPath, const QString &fileName, const QString &url, KIO::UDSEntry &entry,
                                   const TrashedFileInfo &info)
{
    QCString physicalPath_c = QFile::encodeName(physicalPath);
    KDE_struct_stat buff;
    if(KDE_lstat(physicalPath_c, &buff) == -1)
    {
        kdWarning() << "couldn't stat " << physicalPath << endl;
        return false;
    }
    if(S_ISLNK(buff.st_mode))
    {
        char buffer2[1000];
        int n = readlink(physicalPath_c, buffer2, 1000);
        if(n != -1)
        {
            buffer2[n] = 0;
        }

        addAtom(entry, KIO::UDS_LINK_DEST, 0, QFile::decodeName(buffer2));
// Follow symlink
// That makes sense in kio_file, but not in the trash, especially for the size
// #136876
#if 0
        if ( KDE_stat( physicalPath_c, &buff ) == -1 ) {
            // It is a link pointing to nowhere
            buff.st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
            buff.st_mtime = 0;
            buff.st_atime = 0;
            buff.st_size = 0;
        }
#endif
    }
    mode_t type = buff.st_mode & S_IFMT;  // extract file type
    mode_t access = buff.st_mode & 07777; // extract permissions
    access &= 07555;                      // make it readonly, since it's in the trashcan
    addAtom(entry, KIO::UDS_NAME, 0, fileName);
    addAtom(entry, KIO::UDS_FILE_TYPE, type);
    if(!url.isEmpty())
        addAtom(entry, KIO::UDS_URL, 0, url);

    KMimeType::Ptr mt = KMimeType::findByPath(physicalPath, buff.st_mode);
    addAtom(entry, KIO::UDS_MIME_TYPE, 0, mt->name());
    addAtom(entry, KIO::UDS_ACCESS, access);
    addAtom(entry, KIO::UDS_SIZE, buff.st_size);
    addAtom(entry, KIO::UDS_USER, 0, m_userName);   // assumption
    addAtom(entry, KIO::UDS_GROUP, 0, m_groupName); // assumption
    addAtom(entry, KIO::UDS_MODIFICATION_TIME, buff.st_mtime);
    addAtom(entry, KIO::UDS_ACCESS_TIME, buff.st_atime); // ## or use it for deletion time?
    addAtom(entry, KIO::UDS_EXTRA, 0, info.origPath);
    addAtom(entry, KIO::UDS_EXTRA, 0, info.deletionDate.toString(Qt::ISODate));
    return true;
}
Example #9
0
bool TrashProtocol::createUDSEntry( const QString& physicalPath, const QString& displayFileName, const QString& internalFileName, KIO::UDSEntry& entry, const TrashedFileInfo& info )
{
    QByteArray physicalPath_c = QFile::encodeName( physicalPath );
    KDE_struct_stat buff;
    if ( KDE_lstat( physicalPath_c, &buff ) == -1 ) {
        kWarning() << "couldn't stat " << physicalPath ;
        return false;
    }
    if (S_ISLNK(buff.st_mode)) {
        char buffer2[ 1000 ];
        int n = readlink( physicalPath_c, buffer2, 999 );
        if ( n != -1 ) {
            buffer2[ n ] = 0;
        }

        entry.insert( KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName( buffer2 ) );
        // Follow symlink
        // That makes sense in kio_file, but not in the trash, especially for the size
        // #136876
#if 0
        if ( KDE_stat( physicalPath_c, &buff ) == -1 ) {
            // It is a link pointing to nowhere
            buff.st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
            buff.st_mtime = 0;
            buff.st_atime = 0;
            buff.st_size = 0;
        }
#endif
    }
    mode_t type = buff.st_mode & S_IFMT; // extract file type
    mode_t access = buff.st_mode & 07777; // extract permissions
    access &= 07555; // make it readonly, since it's in the trashcan
    Q_ASSERT(!internalFileName.isEmpty());
    entry.insert( KIO::UDSEntry::UDS_NAME, internalFileName ); // internal filename, like "0-foo"
    entry.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, displayFileName ); // user-visible filename, like "foo"
    entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type );
    //if ( !url.isEmpty() )
    //    entry.insert( KIO::UDSEntry::UDS_URL, url );

    KMimeType::Ptr mt = KMimeType::findByPath( physicalPath, buff.st_mode );
    if ( mt )
        entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, mt->name() );
    entry.insert( KIO::UDSEntry::UDS_ACCESS, access );
    entry.insert( KIO::UDSEntry::UDS_SIZE, buff.st_size );
    entry.insert( KIO::UDSEntry::UDS_USER, m_userName ); // assumption
    entry.insert( KIO::UDSEntry::UDS_GROUP, m_groupName ); // assumption
    entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime );
    entry.insert( KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime ); // ## or use it for deletion time?
    entry.insert( KIO::UDSEntry::UDS_EXTRA, info.origPath );
    entry.insert( KIO::UDSEntry::UDS_EXTRA + 1, info.deletionDate.toString( Qt::ISODate ) );
    return true;
}
Example #10
0
static void moveLocalSymlink(const QString &src, const QString &dest)
{
    KDE_struct_stat buf;
    assert(KDE_lstat(QFile::encodeName(src), &buf) == 0);
    KURL u;
    u.setPath(src);
    KURL d;
    d.setPath(dest);

    // move the symlink with move, NOT with file_move
    bool ok = KIO::NetAccess::move(u, d);
    if(!ok)
        kdWarning() << KIO::NetAccess::lastError() << endl;
    assert(ok);
    assert(KDE_lstat(QFile::encodeName(dest), &buf) == 0);
    assert(!QFile::exists(src)); // not there anymore

    // move it back with KIO::move()
    ok = KIO::NetAccess::move(d, u, 0);
    assert(ok);
    assert(KDE_lstat(QFile::encodeName(dest), &buf) != 0); // doesn't exist anymore
    assert(KDE_lstat(QFile::encodeName(src), &buf) == 0);  // it's back
}
Example #11
0
QString KFileItem::user() const
{
  if ( m_user.isEmpty() && m_bIsLocalURL )
  {
    KDE_struct_stat buff;
    if ( KDE_lstat( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link
    {
      struct passwd *user = getpwuid( buff.st_uid );
      if ( user != 0L )
        m_user = QString::fromLocal8Bit(user->pw_name);
    }
  }
  return m_user;
}
Example #12
0
TrashImpl::TrashImpl() :
    TQObject(),
    m_lastErrorCode( 0 ),
    m_initStatus( InitToBeDone ),
    m_lastId( 0 ),
    m_homeDevice( 0 ),
    m_trashDirectoriesScanned( false ),
    m_mibEnum( TDEGlobal::locale()->fileEncodingMib() ),
    // not using tdeio_trashrc since TDEIO uses that one already for tdeio_trash
    // so better have a separate one, for faster parsing by e.g. kmimetype.cpp
    m_config( "trashrc" )
{
    KDE_struct_stat buff;
    if ( KDE_lstat( TQFile::encodeName( TQDir::homeDirPath() ), &buff ) == 0 ) {
        m_homeDevice = buff.st_dev;
    } else {
        kdError() << "Should never happen: couldn't stat $HOME " << strerror( errno ) << endl;
    }
}
Example #13
0
QString KFileItem::group() const
{
#ifdef Q_OS_UNIX
  if (m_group.isEmpty() && m_bIsLocalURL )
  {
    KDE_struct_stat buff;
    if ( KDE_lstat( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link
    {
      struct group *ge = getgrgid( buff.st_gid );
      if ( ge != 0L ) {
        m_group = QString::fromLocal8Bit(ge->gr_name);
        if (m_group.isEmpty())
          m_group.sprintf("%d",ge->gr_gid);
      } else
        m_group.sprintf("%d",buff.st_gid);
    }
  }
#endif
  return m_group;
}
Example #14
0
bool KStandardDirs::makeDir(const QString &dir, int mode)
{
    // we want an absolute path
    if(QDir::isRelativePath(dir))
        return false;

    QString target = dir;
    uint len = target.length();

    // append trailing slash if missing
    if(dir.at(len - 1) != '/')
        target += '/';

    QString base("");
    uint i = 1;

    while(i < len)
    {
        KDE_struct_stat st;
        int pos = target.find('/', i);
        base += target.mid(i - 1, pos - i + 1);
        QCString baseEncoded = QFile::encodeName(base);
        // bail out if we encountered a problem
        if(KDE_stat(baseEncoded, &st) != 0)
        {
            // Directory does not exist....
            // Or maybe a dangling symlink ?
            if(KDE_lstat(baseEncoded, &st) == 0)
                (void)unlink(baseEncoded); // try removing

            if(KDE_mkdir(baseEncoded, (mode_t)mode) != 0)
            {
                baseEncoded.prepend("trying to create local folder ");
                perror(baseEncoded.data());
                return false; // Couldn't create it :-(
            }
        }
        i = pos + 1;
    }
    return true;
}
Example #15
0
bool TrashImpl::del( int trashId, const TQString& fileId )
{
    TQString info = infoPath(trashId, fileId);
    TQString file = filesPath(trashId, fileId);

    TQCString info_c = TQFile::encodeName(info);

    KDE_struct_stat buff;
    if ( KDE_lstat( info_c.data(), &buff ) == -1 ) {
        if ( errno == EACCES )
            error( TDEIO::ERR_ACCESS_DENIED, file );
        else
            error( TDEIO::ERR_DOES_NOT_EXIST, file );
        return false;
    }

    if ( !synchronousDel( file, true, TQFileInfo(file).isDir() ) )
        return false;

    TQFile::remove( info );
    fileRemoved();
    return true;
}
Example #16
0
bool KArchive::addLocalFile(const QString &fileName, const QString &destName)
{
    QFileInfo fileInfo(fileName);
    if(!fileInfo.isFile() && !fileInfo.isSymLink())
    {
        kdWarning() << "KArchive::addLocalFile " << fileName << " doesn't exist or is not a regular file." << endl;
        return false;
    }

    KDE_struct_stat fi;
    if(KDE_lstat(QFile::encodeName(fileName), &fi) == -1)
    {
        kdWarning() << "KArchive::addLocalFile stating " << fileName << " failed: " << strerror(errno) << endl;
        return false;
    }

    if(fileInfo.isSymLink())
    {
        return writeSymLink(destName, fileInfo.readLink(), fileInfo.owner(), fileInfo.group(), fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime);
    } /*end if*/

    uint size = fileInfo.size();

    // the file must be opened before prepareWriting is called, otherwise
    // if the opening fails, no content will follow the already written
    // header and the tar file is effectively f*cked up
    QFile file(fileName);
    if(!file.open(IO_ReadOnly))
    {
        kdWarning() << "KArchive::addLocalFile couldn't open file " << fileName << endl;
        return false;
    }

    if(!prepareWriting(destName, fileInfo.owner(), fileInfo.group(), size, fi.st_mode, fi.st_atime, fi.st_mtime, fi.st_ctime))
    {
        kdWarning() << "KArchive::addLocalFile prepareWriting " << destName << " failed" << endl;
        return false;
    }

    // Read and write data in chunks to minimize memory usage
    QByteArray array(8 * 1024);
    int n;
    uint total = 0;
    while((n = file.readBlock(array.data(), array.size())) > 0)
    {
        if(!writeData(array.data(), n))
        {
            kdWarning() << "KArchive::addLocalFile writeData failed" << endl;
            return false;
        }
        total += n;
    }
    Q_ASSERT(total == size);

    if(!doneWriting(size))
    {
        kdWarning() << "KArchive::addLocalFile doneWriting failed" << endl;
        return false;
    }
    return true;
}
Example #17
0
static time_t getTimeStamp(const QString &item)
{
    KDE_struct_stat info;

    return !item.isEmpty() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0;
}
Example #18
0
static KLockFile::LockResult lockFile(const QString &lockFile, KDE_struct_stat &st_buf,
        bool &linkCountSupport, const KComponentData &componentData)
{
  QByteArray lockFileName = QFile::encodeName( lockFile );
  int result = KDE_lstat( lockFileName, &st_buf );
  if (result == 0)
     return KLockFile::LockFail;

  KTemporaryFile uniqueFile(componentData);
  uniqueFile.setFileTemplate(lockFile);
  if (!uniqueFile.open())
     return KLockFile::LockError;
  uniqueFile.setPermissions(QFile::ReadUser|QFile::WriteUser|QFile::ReadGroup|QFile::ReadOther);

  char hostname[256];
  hostname[0] = 0;
  gethostname(hostname, 255);
  hostname[255] = 0;
  QString componentName = componentData.componentName();

  QTextStream stream(&uniqueFile);
  stream << QString::number(getpid()) << endl
      << componentName << endl
      << hostname << endl;
  stream.flush();

  QByteArray uniqueName = QFile::encodeName( uniqueFile.fileName() );

  // Create lock file
  result = ::link( uniqueName, lockFileName );
  if (result != 0)
     return KLockFile::LockError;

  if (!linkCountSupport)
     return KLockFile::LockOK;

  KDE_struct_stat st_buf2;
  result = KDE_lstat( uniqueName, &st_buf2 );
  if (result != 0)
     return KLockFile::LockError;

  result = KDE_lstat( lockFileName, &st_buf );
  if (result != 0)
     return KLockFile::LockError;

  if (st_buf != st_buf2 || S_ISLNK(st_buf.st_mode) || S_ISLNK(st_buf2.st_mode))
  {
     // SMBFS supports hardlinks by copying the file, as a result the above test will always fail
     // cifs increases link count artifically but the inodes are still different
     if ((st_buf2.st_nlink > 1 ||
         ((st_buf.st_nlink == 1) && (st_buf2.st_nlink == 1))) && (st_buf.st_ino != st_buf2.st_ino))
     {
        linkCountSupport = testLinkCountSupport(uniqueName);
        if (!linkCountSupport)
           return KLockFile::LockOK; // Link count support is missing... assume everything is OK.
     }
     return KLockFile::LockFail;
  }

  return KLockFile::LockOK;
}
Example #19
0
static KLockFile::LockResult deleteStaleLock(const QString &lockFile, KDE_struct_stat &st_buf, bool &linkCountSupport, const KComponentData &componentData)
{
   // This is dangerous, we could be deleting a new lock instead of
   // the old stale one, let's be very careful

   // Create temp file
   KTemporaryFile *ktmpFile = new KTemporaryFile(componentData);
   ktmpFile->setFileTemplate(lockFile);
   if (!ktmpFile->open())
      return KLockFile::LockError;

   QByteArray lckFile = QFile::encodeName(lockFile);
   QByteArray tmpFile = QFile::encodeName(ktmpFile->fileName());
   delete ktmpFile;

   // link to lock file
   if (::link(lckFile, tmpFile) != 0)
      return KLockFile::LockFail; // Try again later

   // check if link count increased with exactly one
   // and if the lock file still matches
   KDE_struct_stat st_buf1;
   KDE_struct_stat st_buf2;
   memcpy(&st_buf1, &st_buf, sizeof(KDE_struct_stat));
   st_buf1.st_nlink++;
   if ((KDE_lstat(tmpFile, &st_buf2) == 0) && st_buf1 == st_buf2)
   {
      if ((KDE_lstat(lckFile, &st_buf2) == 0) && st_buf1 == st_buf2)
      {
         // - - if yes, delete lock file, delete temp file, retry lock
         qWarning("WARNING: deleting stale lockfile %s", lckFile.data());
         ::unlink(lckFile);
         ::unlink(tmpFile);
         return KLockFile::LockOK;
      }
   }

   // SMBFS supports hardlinks by copying the file, as a result the above test will always fail
   if (linkCountSupport)
   {
      linkCountSupport = testLinkCountSupport(tmpFile);
   }

   if (!linkCountSupport)
   {
      // Without support for link counts we will have a little race condition
      qWarning("WARNING: deleting stale lockfile %s", lckFile.data());
      ::unlink(tmpFile);
      if (::unlink(lckFile) < 0) {
          qWarning("WARNING: Problem deleting stale lockfile %s: %s", lckFile.data(),
                  strerror(errno));
          return KLockFile::LockFail;
      }
      return KLockFile::LockOK;
   }

   // Failed to delete stale lock file
   qWarning("WARNING: Problem deleting stale lockfile %s", lckFile.data());
   ::unlink(tmpFile);
   return KLockFile::LockFail;
}
Example #20
0
void KFileItem::init( bool _determineMimeTypeOnDemand )
{
  m_access = QString::null;
  m_size = (KIO::filesize_t) -1;
  //  metaInfo = KFileMetaInfo();
  for ( int i = 0; i < NumFlags; i++ )
      m_time[i] = (time_t) -1;

  // determine mode and/or permissions if unknown
  if ( m_fileMode == KFileItem::Unknown || m_permissions == KFileItem::Unknown )
  {
    mode_t mode = 0;
    if ( m_url.isLocalFile() )
    {
      /* directories may not have a slash at the end if
       * we want to stat() them; it requires that we
       * change into it .. which may not be allowed
       * stat("/is/unaccessible")  -> rwx------
       * stat("/is/unaccessible/") -> EPERM            H.Z.
       * This is the reason for the -1
       */
      KDE_struct_stat buf;
      QCString path = QFile::encodeName(m_url.path( -1 ));
      if ( KDE_lstat( path.data(), &buf ) == 0 )
      {
        mode = buf.st_mode;
        if ( S_ISLNK( mode ) )
        {
          m_bLink = true;
          if ( KDE_stat( path.data(), &buf ) == 0 )
              mode = buf.st_mode;
          else // link pointing to nowhere (see kio/file/file.cc)
              mode = (S_IFMT-1) | S_IRWXU | S_IRWXG | S_IRWXO;
        }
        // While we're at it, store the times
        m_time[ Modification ] = buf.st_mtime;
        m_time[ Access ] = buf.st_atime;
        if ( m_fileMode == KFileItem::Unknown )
          m_fileMode = mode & S_IFMT; // extract file type
        if ( m_permissions == KFileItem::Unknown )
          m_permissions = mode & 07777; // extract permissions
      }
    }
  }

  // determine the mimetype
  if (!m_pMimeType && !m_url.isEmpty())
  {
      bool accurate = false;
      bool isLocalURL;
      KURL url = mostLocalURL(isLocalURL);

      m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL,
                                          // use fast mode if not mimetype on demand
                                          _determineMimeTypeOnDemand, &accurate );
      //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl;
      // if we didn't use fast mode, or if we got a result, then this is the mimetype
      // otherwise, determineMimeType will be able to do better.
      m_bMimeTypeKnown = (!_determineMimeTypeOnDemand) || accurate;
  }
}
Example #21
0
int KDEsuClient::connect()
{
    if(sockfd >= 0)
        close(sockfd);
    if(access(sock, R_OK | W_OK))
    {
        sockfd = -1;
        return -1;
    }

    sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        kdWarning(900) << k_lineinfo << "socket(): " << perror << "\n";
        return -1;
    }
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, sock);

    if(::connect(sockfd, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0)
    {
        kdWarning(900) << k_lineinfo << "connect():" << perror << endl;
        close(sockfd);
        sockfd = -1;
        return -1;
    }

#if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED)
#if defined(HAVE_GETPEEREID)
    uid_t euid;
    gid_t egid;
    // Security: if socket exists, we must own it
    if(getpeereid(sockfd, &euid, &egid) == 0)
    {
        if(euid != getuid())
        {
            kdWarning(900) << "socket not owned by me! socket uid = " << euid << endl;
            close(sockfd);
            sockfd = -1;
            return -1;
        }
    }
#else
#ifdef __GNUC__
#warning "Using sloppy security checks"
#endif
    // We check the owner of the socket after we have connected.
    // If the socket was somehow not ours an attacker will be able
    // to delete it after we connect but shouldn't be able to
    // create a socket that is owned by us.
    KDE_struct_stat s;
    if(KDE_lstat(sock, &s) != 0)
    {
        kdWarning(900) << "stat failed (" << sock << ")" << endl;
        close(sockfd);
        sockfd = -1;
        return -1;
    }
    if(s.st_uid != getuid())
    {
        kdWarning(900) << "socket not owned by me! socket uid = " << s.st_uid << endl;
        close(sockfd);
        sockfd = -1;
        return -1;
    }
    if(!S_ISSOCK(s.st_mode))
    {
        kdWarning(900) << "socket is not a socket (" << sock << ")" << endl;
        close(sockfd);
        sockfd = -1;
        return -1;
    }
#endif
#else
    struct ucred cred;
    socklen_t siz = sizeof(cred);

    // Security: if socket exists, we must own it
    if(getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0)
    {
        if(cred.uid != getuid())
        {
            kdWarning(900) << "socket not owned by me! socket uid = " << cred.uid << endl;
            close(sockfd);
            sockfd = -1;
            return -1;
        }
    }
#endif

    return 0;
}
Example #22
0
bool TrashImpl::createInfo( const TQString& origPath, int& trashId, TQString& fileId )
{
    kdDebug() << k_funcinfo << origPath << endl;
    // Check source
    const TQCString origPath_c( TQFile::encodeName( origPath ) );
    KDE_struct_stat buff_src;
    if ( KDE_lstat( origPath_c.data(), &buff_src ) == -1 ) {
        if ( errno == EACCES )
           error( TDEIO::ERR_ACCESS_DENIED, origPath );
        else
           error( TDEIO::ERR_DOES_NOT_EXIST, origPath );
        return false;
    }

    // Choose destination trash
    trashId = findTrashDirectory( origPath );
    if ( trashId < 0 ) {
        kdWarning() << "OUCH - internal error, TrashImpl::findTrashDirectory returned " << trashId << endl;
        return false; // ### error() needed?
    }
    kdDebug() << k_funcinfo << "trashing to " << trashId << endl;

    // Grab original filename
    KURL url;
    url.setPath( origPath );
    const TQString origFileName = url.fileName();

    // Make destination file in info/
    url.setPath( infoPath( trashId, origFileName ) ); // we first try with origFileName
    KURL baseDirectory;
    baseDirectory.setPath( url.directory() );
    // Here we need to use O_EXCL to avoid race conditions with other tdeioslave processes
    int fd = 0;
    do {
        kdDebug() << k_funcinfo << "trying to create " << url.path()  << endl;
        fd = ::open( TQFile::encodeName( url.path() ), O_WRONLY | O_CREAT | O_EXCL, 0600 );
        if ( fd < 0 ) {
            if ( errno == EEXIST ) {
                url.setFileName( TDEIO::RenameDlg::suggestName( baseDirectory, url.fileName() ) );
                // and try again on the next iteration
            } else {
                error( TDEIO::ERR_COULD_NOT_WRITE, url.path() );
                return false;
            }
        }
    } while ( fd < 0 );
    const TQString infoPath = url.path();
    fileId = url.fileName();
    Q_ASSERT( fileId.endsWith( ".trashinfo" ) );
    fileId.truncate( fileId.length() - 10 ); // remove .trashinfo from fileId

    FILE* file = ::fdopen( fd, "w" );
    if ( !file ) { // can't see how this would happen
        error( TDEIO::ERR_COULD_NOT_WRITE, infoPath );
        return false;
    }

    // Contents of the info file. We could use KSimpleConfig, but that would
    // mean closing and reopening fd, i.e. opening a race condition...
    TQCString info = "[Trash Info]\n";
    info += "Path=";
    // Escape filenames according to the way they are encoded on the filesystem
    // All this to basically get back to the raw 8-bit representation of the filename...
    if ( trashId == 0 ) // home trash: absolute path
        info += KURL::encode_string( origPath, m_mibEnum ).latin1();
    else
        info += KURL::encode_string( makeRelativePath( topDirectoryPath( trashId ), origPath ), m_mibEnum ).latin1();
    info += "\n";
    info += "DeletionDate=";
    info += TQDateTime::currentDateTime().toString( Qt::ISODate ).latin1();
    info += "\n";
    size_t sz = info.size() - 1; // avoid trailing 0 from QCString

    size_t written = ::fwrite(info.data(), 1, sz, file);
    if ( written != sz ) {
        ::fclose( file );
        TQFile::remove( infoPath );
        error( TDEIO::ERR_DISK_FULL, infoPath );
        return false;
    }

    ::fclose( file );

    kdDebug() << k_funcinfo << "info file created in trashId=" << trashId << " : " << fileId << endl;
    return true;
}