[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Fwd: Re: 64 bit file support
From:       Waldo Bastian <bastian () kde ! org>
Date:       2001-08-10 18:53:56
[Download RAW message or body]

Hiya,

One of the things todo for KDE 3.0 is to get 64-bit file support working. You 
might want to read the following URL in order to understand the problem.

http://ftp.sas.com/standards/large.file/x_open.20Mar96.html

It seems that since we can't control the way in which either Qt, other libs 
or applications are being compiled we will need to use the "Transitional 
Extensions".

I haven't tried it yet but I hope that we can circumvent this define mess 
that Jeff talks about. I'm sure that after all the problems with X-headers 
the glibc-developers wouldn't be that stupid.

As far as KDE's internal interfaces goes, I think that we should start to use 
"long long" in the interfaces that need it. Maybe we can add a 
KIO::filesize_t typedef so that we have a central place to change it to 
something else.

Cheers,
Waldo

----------  Forwarded Message  ----------

Subject: Re: 64 bit file support
Date: Mon, 6 Aug 2001 14:53:46 -0400
From: Jeff Woods <Jeff.Woods@ChoicePointPRG.net>
To: Waldo Bastian <bastian@kde.org>

On Wednesday 25 July 2001 02:56 pm, you wrote:
> There are various problems with 64 bit file-sizes, one of them being that
> our APIs don't support 64 bits. We hope to fix that in KDE 3.0. Your
> experiences will be usefull in that regard so that we know what needs
> fixing.

We finally got 64 files partially supported.  Basically, we replaced the
stat's and lstat's in kio/kfileitem.cpp and kio/file/file.cc with stat64 and
lstat64.  This allows files with sizes greater than 4 GB to be displayed in
the file browser (which was our greatest concern).  The application we've
been working with already used 64 bit access routines where necessary.

This solution won't work under Linux, though.  Linux headers define "struct
stat" based on the value of _FILE_OFFSET_BITS.  If you place the line
"#define _FILE_OFFSET_BITS 64" prior to any #include's in your source, you
get the 64 bit version, otherwise you get the 32 bit version.  An unfortunate
side effect of this is that all system calls, such as open and truncate,  get
a #define like this:

#define open open64
#define truncate truncate64

This caused problems with some QT member functions which had the same name as
a system call.  For example, QString::truncate() was renamed
QString::truncate64(), which did not resolve against the QT dynamic library.

We were able to get away with this since Solaris defines a seperate "struct
stat64" for use with stat64 and lstat64.  We just surrounded our changes with
#ifdef sun ... #endif statements to keep the builds clean.

As you're aware, there are many more changes which are necessary.  Even
though we are able to list the file, we do not get the correct file size.
This would require a number of internal changes.

I've attached the changed files (my reason for not posting to the developer
list).

Jeff Woods

-------------------------------------------------------



-- 
KDE 2.2: We deliver.

["kfileitem.cpp" (text/x-c++)]

/* This file is part of the KDE project
   Copyright (C) 1999 David Faure <faure@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/
// $Id: kfileitem.cpp,v 1.89 2001/02/10 12:58:21 hausmann Exp $

#include <sys/time.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>

#include <assert.h>
#include <unistd.h>

#include "kfileitem.h"

#include <qdir.h>
#include <qfile.h>

#include <kglobal.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmimetype.h>
#include <krun.h>

#include <errno.h>
extern int errno;

class KFileItem::KFileItemPrivate
{
public:
  KFileItemPrivate() { bMimeTypeKnown = false; }
   // For special case like link to dirs over FTP
  QString m_guessedMimeType;
  bool bMimeTypeKnown;
};

KFileItem::KFileItem( const KIO::UDSEntry& _entry, const KURL& _url,
                      bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) :
  m_entry( _entry ),
  m_url( _url ),
  m_bIsLocalURL( _url.isLocalFile() ),
  m_fileMode( (mode_t)-1 ),
  m_permissions( (mode_t)-1 ),
  m_bLink( false ),
  m_pMimeType( 0 ),
  m_bMarked( false ),
  d(new KFileItemPrivate)
{
  bool UDS_URL_seen = false;
  // extract the mode and the filename from the KIO::UDS Entry
  KIO::UDSEntry::ConstIterator it = m_entry.begin();
  for( ; it != m_entry.end(); it++ ) {
    switch ((*it).m_uds) {

        case KIO::UDS_FILE_TYPE:
          m_fileMode = (mode_t)((*it).m_long);
          break;

        case KIO::UDS_ACCESS:
          m_permissions = (mode_t)((*it).m_long);
          break;

        case KIO::UDS_USER:
          m_user = ((*it).m_str);
          break;

        case KIO::UDS_GROUP:
          m_group = ((*it).m_str);
          break;

        case KIO::UDS_NAME:
          m_strName = (*it).m_str;
          m_strText = KIO::decodeFileName( m_strName );
          break;

        case KIO::UDS_URL:
          UDS_URL_seen = true;
          m_url = KURL((*it).m_str);
          break;

        case KIO::UDS_MIME_TYPE:
          m_pMimeType = KMimeType::mimeType((*it).m_str);
          break;

        case KIO::UDS_GUESSED_MIME_TYPE:
          d->m_guessedMimeType = (*it).m_str;
          break;

        case KIO::UDS_LINK_DEST:
          m_bLink = !(*it).m_str.isEmpty(); // we don't store the link dest
          break;
    }
  }
  // avoid creating these QStrings again and again
  static const QString& dot = KGlobal::staticQString(".");
  if ( _urlIsDirectory && !UDS_URL_seen && !m_strName.isEmpty() && m_strName != dot )
    m_url.addPath( m_strName );
  init( _determineMimeTypeOnDemand );
}

KFileItem::KFileItem( mode_t _mode, mode_t _permissions, const KURL& _url, bool \
_determineMimeTypeOnDemand ) :  m_entry(), // warning !
  m_url( _url ),
  m_bIsLocalURL( _url.isLocalFile() ),
  m_strName( _url.fileName() ),
  m_strText( KIO::decodeFileName( m_strName ) ),
  m_fileMode ( _mode ),
  m_permissions( _permissions ),
  m_bLink( false ),
  m_bMarked( false ),
  d(new KFileItemPrivate)
{
  init( _determineMimeTypeOnDemand );
}

KFileItem::KFileItem( const KURL &url, const QString &mimeType, mode_t mode )
> m_url( url ),
  m_bIsLocalURL( url.isLocalFile() ),
  m_strName( url.fileName() ),
  m_strText( KIO::decodeFileName( m_strName ) ),
  m_fileMode( mode ),
  m_permissions( 0 ),
  m_bLink( false ),
  m_bMarked( false ),
  d(new KFileItemPrivate)
{
  m_pMimeType = KMimeType::mimeType( mimeType );
  init( false );
}

KFileItem::KFileItem( const KFileItem & item ) :
  d(new KFileItemPrivate)
{
    assign( item );
}

KFileItem::~KFileItem()
{
  delete d;
}

void KFileItem::init( bool _determineMimeTypeOnDemand )
{
  // determine mode and/or permissions if unknown
  if ( m_fileMode == (mode_t) -1 || m_permissions == (mode_t) -1 )
  {
    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
       */
      QCString path = QFile::encodeName(m_url.path( -1 ));
#ifdef sun
      struct stat64 buf;
      if ( lstat64( path.data(), &buf ) == 0 )
#else
      struct stat buf;
      if ( lstat( path.data(), &buf ) == 0 )
#endif
      {
        mode = buf.st_mode;
        if ( S_ISLNK( mode ) )
        {
          m_bLink = true;
#ifdef sun
          if ( stat64(path.data(), &buf) == 0 )
#else
          if ( stat( path.data(), &buf) == 0 )
#endif
              mode = buf.st_mode;
          else // link pointing to nowhere (see kio/file/file.cc)
              mode = (S_IFMT-1) | S_IRWXU | S_IRWXG | S_IRWXO;
        }
      }
    }
    if ( m_fileMode == (mode_t) -1 )
      m_fileMode = mode & S_IFMT; // extract file type
    if ( m_permissions == (mode_t) -1 )
      m_permissions = mode & 07777; // extract permissions
  }

  // determine the mimetype
  if (!m_pMimeType )
  {
      m_pMimeType = KMimeType::findByURL( m_url, m_fileMode, m_bIsLocalURL,
                                          // use fast mode if not mimetype on demand
                                          _determineMimeTypeOnDemand );
      // 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.
      d->bMimeTypeKnown = (!_determineMimeTypeOnDemand) || (m_pMimeType->name() != \
KMimeType::defaultMimeType());  }

}

void KFileItem::refresh()
{
  m_fileMode = (mode_t)-1;
  m_permissions = (mode_t)-1;
  m_user = QString::null;
  m_group = QString::null;
  // Basically, we can't trust any information we got while listing.
  // Everything could have changed...
  // Clearing m_entry makes it possible to detect changes in the size of the file,
  // the time information, etc.
  m_entry = KIO::UDSEntry();
  init( false );
}

void KFileItem::refreshMimeType()
{
  m_pMimeType = 0L;
  init( false ); // Will determine the mimetype
}

void KFileItem::setURL( const KURL &url )
{
  m_url = url;
  m_strName = url.fileName();
  m_strText = KIO::decodeFileName( m_strName );
}

QString KFileItem::linkDest() const
{
  // Extract it from the KIO::UDSEntry
  KIO::UDSEntry::ConstIterator it = m_entry.begin();
  for( ; it != m_entry.end(); it++ )
    if ( (*it).m_uds == KIO::UDS_LINK_DEST )
      return (*it).m_str;
  // If not in the KIO::UDSEntry, or if UDSEntry empty, use readlink() [if local URL]
  if ( m_bIsLocalURL )
  {
    char buf[1000];
    int n = readlink( QFile::encodeName(m_url.path( -1 )), buf, 1000 );
    if ( n != -1 )
    {
      buf[ n ] = 0;
      return QString::fromLocal8Bit( buf );
    }
  }
  return QString::null;
}

long KFileItem::size() const
{
  // Extract it from the KIO::UDSEntry
  KIO::UDSEntry::ConstIterator it = m_entry.begin();
  for( ; it != m_entry.end(); it++ )
    if ( (*it).m_uds == KIO::UDS_SIZE )
      return (*it).m_long;
  // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL]
  if ( m_bIsLocalURL )
  {
#ifdef sun
    struct stat64 buf;
    stat64( QFile::encodeName(m_url.path( -1 )), &buf );
#else
    struct stat buf;
    stat( QFile::encodeName(m_url.path( -1 )), &buf );
#endif

    return buf.st_size;
  }
  return 0L;
}

time_t KFileItem::time( unsigned int which ) const
{
  // Extract it from the KIO::UDSEntry
  KIO::UDSEntry::ConstIterator it = m_entry.begin();
  for( ; it != m_entry.end(); it++ )
    if ( (*it).m_uds == which )
      return static_cast<time_t>((*it).m_long);

  // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL]
  if ( m_bIsLocalURL )
  {
#ifdef sun
    struct stat64 buf;
    stat64( QFile::encodeName(m_url.path( -1 )), &buf );
#else
    struct stat buf;
    stat( QFile::encodeName(m_url.path( -1 )), &buf );
#endif

    return (which == KIO::UDS_MODIFICATION_TIME) ? buf.st_mtime :
           (which == KIO::UDS_ACCESS_TIME) ? buf.st_atime :
        static_cast<time_t>(0); // We can't determine creation time for local files
  }
  return static_cast<time_t>(0);
}


QString KFileItem::user() const
{
  if ( m_user.isEmpty() && m_bIsLocalURL )
  {
#ifdef sun
    struct stat64 buff;
    if ( lstat64( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid \
of the link, if it's a link #else
    struct stat buff;
    if ( lstat( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of \
the link, if it's a link #endif
    {
      struct passwd *user = getpwuid( buff.st_uid );
      if ( user != 0L )
        m_user = QString::fromLocal8Bit(user->pw_name);
    }
  }

  return m_user;
}

QString KFileItem::group() const
{
  if (m_group.isEmpty() && m_bIsLocalURL )
  {
#ifdef sun
    struct stat64 buff;
    if ( lstat64( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid \
of the link, if it's a link #else
    struct stat buff;
    if ( lstat( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of \
the link, if it's a link #endif
    {
      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);
    }
    else if (errno == EOVERFLOW)
    {
      m_group = (char *) NULL;
    }
  }
  return m_group;
}

QString KFileItem::mimetype() const
{
  KFileItem * that = const_cast<KFileItem *>(this);
  return that->determineMimeType()->name();
}

KMimeType::Ptr KFileItem::determineMimeType()
{
  if ( !m_pMimeType || !d->bMimeTypeKnown )
  {
    //kdDebug(1203) << "finding mimetype for " << m_url.url() << endl;
    m_pMimeType = KMimeType::findByURL( m_url, m_fileMode, m_bIsLocalURL );
    d->bMimeTypeKnown = true;
  }

  return m_pMimeType;
}

bool KFileItem::isMimeTypeKnown() const
{
  return d->bMimeTypeKnown;
}

QString KFileItem::mimeComment()
{
 KMimeType::Ptr mType = determineMimeType();
 QString comment = mType->comment( m_url, false );
  if (!comment.isEmpty())
    return comment;
  else
    return mType->name();
}

QString KFileItem::iconName()
{
  return determineMimeType()->icon(m_url, false);
}

QPixmap KFileItem::pixmap( int _size, int _state ) const
{
  if ( !m_pMimeType )
  {
    static const QString & defaultFolderIcon =
       KGlobal::staticQString(KMimeType::mimeType( "inode/directory" \
)->KServiceType::icon());  if ( S_ISDIR( m_fileMode ) )
     return DesktopIcon( defaultFolderIcon, _size, _state );

    return DesktopIcon( "unknown", _size, _state );
  }

  if ( m_bLink )
      _state |= KIcon::LinkOverlay;

  if ( !S_ISDIR( m_fileMode ) // Locked dirs have a special icon
       && !isReadable())
     _state |= KIcon::LockOverlay;

  KMimeType::Ptr mime;
  // Use guessed mimetype if the main one is clueless
  if ( m_pMimeType->name() == KMimeType::defaultMimeType()
      && !d->m_guessedMimeType.isEmpty() )
      mime = KMimeType::mimeType( d->m_guessedMimeType );
  else
      mime = m_pMimeType;

  // Support for gzipped files
  if ( mime->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" )
  {
      QString subFileName = m_url.path().left( m_url.path().length() - 3 );
      //kdDebug() << "KFileItem::pixmap subFileName=" << subFileName << endl;
      mime = KMimeType::findByURL( subFileName, 0, m_bIsLocalURL );
      _state |= KIcon::ZipOverlay;
  }

  QPixmap p = mime->pixmap( m_url, KIcon::Desktop, _size, _state );
  if (p.isNull())
      kdWarning() << "Pixmap not found for mimetype " << m_pMimeType->name() << endl;

  return p;
}

bool KFileItem::isReadable() const
{
  /*
  struct passwd * user = getpwuid( geteuid() );
  bool isMyFile = (QString::fromLocal8Bit(user->pw_name) == m_user);
  // This gets ugly for the group....
  // Maybe we want a static QString for the user and a static QStringList
  // for the groups... then we need to handle the deletion properly...
  */

  // No read permission at all
  if ( !(S_IRUSR & m_permissions) && !(S_IRGRP & m_permissions) && !(S_IROTH & \
m_permissions) )  return false;

  // Or if we can't read it [using access()] - not network transparent
  else if ( m_bIsLocalURL && access( QFile::encodeName(m_url.path()), R_OK ) == -1 )
      return false;

  return true;
}


bool KFileItem::acceptsDrops()
{
  // A directory ?
  if ( S_ISDIR( mode() ) )
  {
    if ( m_bIsLocalURL ) // local -> check if we can enter it
       return (access( QFile::encodeName(m_url.path()), X_OK ) == 0);
    else
       return true; // assume ok for remote urls
  }

  // But only local .desktop files and executables
  if ( !m_bIsLocalURL )
    return false;

  if ( mimetype() == "application/x-desktop")
    return true;

  // Executable, shell script ... ?
  if ( access( QFile::encodeName(m_url.path()), X_OK ) == 0 )
    return true;

  return false;
}

QString KFileItem::getStatusBarInfo()
{
  QString comment = determineMimeType()->comment( m_url, false );
  QString text = m_strText;
  // Extract from the KIO::UDSEntry the additional info we didn't get previously
  QString myLinkDest = linkDest();
  long mySize = size();

  QString text2 = text.copy();

  if ( m_bLink )
  {
      QString tmp;
      if ( comment.isEmpty() )
        tmp = i18n ( "Symbolic Link" );
      else
        tmp = i18n("%1 (Link)").arg(comment);
      text += "->";
      text += myLinkDest;
      text += "  ";
      text += tmp;
  }
  else if ( S_ISREG( m_fileMode ) )
  {
      text = QString("%1 (%2)").arg(text2).arg( KIO::convertSize( mySize ) );
      text += "  ";
      text += comment;
  }
  else if ( S_ISDIR ( m_fileMode ) )
  {
      text += "/  ";
      text += comment;
    }
    else
    {
      text += "  ";
      text += comment;
    }
    return text;
}

void KFileItem::run()
{
  KURL url( m_url );
  if ( m_bLink )
    url = KURL( m_url, linkDest() );
  (void) new KRun( url, m_fileMode, m_bIsLocalURL );
}

bool KFileItem::cmp( const KFileItem & item )
{
    return ( m_strName == item.m_strName
             && m_bIsLocalURL == item.m_bIsLocalURL
             && m_fileMode == item.m_fileMode
             && m_permissions == item.m_permissions
             && m_user == item.m_user
             && m_group == item.m_group
             && m_bLink == item.m_bLink
             && size() == item.size()
             && time(KIO::UDS_MODIFICATION_TIME) == \
item.time(KIO::UDS_MODIFICATION_TIME) ); }

void KFileItem::assign( const KFileItem & item )
{
    m_entry = item.m_entry;
    m_url = item.m_url;
    m_bIsLocalURL = item.m_bIsLocalURL;
    m_strName = item.m_strName;
    m_strText = item.m_strText;
    m_fileMode = item.m_fileMode;
    m_permissions = item.m_permissions;
    m_user = item.m_user;
    m_group = item.m_group;
    m_bLink = item.m_bLink;
    m_pMimeType = item.m_pMimeType;
    m_strLowerCaseName = item.m_strLowerCaseName;
    *d = *item.d;
    // We had a mimetype previously (probably), so we need to re-determine it
    determineMimeType();
}


["file.cc" (text/x-c++)]

// $Id: file.cc,v 1.103.2.1 2001/03/12 12:10:54 faure Exp $

#include <config.h>

#ifdef __linux__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#include <features.h>
#endif

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif

#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include <qvaluelist.h>

#include <kshred.h>
#include <kdebug.h>
#include <kurl.h>
#include <kprotocolmanager.h>
#include <kinstance.h>
#include <ksimpleconfig.h>
#include <ktempfile.h>
#include <klocale.h>
#include <qfile.h>
#include <qstrlist.h>
#include "file.h"
#include <limits.h>

using namespace KIO;

#define MAX_IPC_SIZE (1024*32)

QString testLogFile( const char *_filename );

extern "C" { int kdemain(int argc, char **argv); }

int kdemain( int argc, char **argv )
{
  KInstance instance( "kio_file" );

  kdDebug(7101) << "Starting " << getpid() << endl;

  if (argc != 4)
  {
     fprintf(stderr, "Usage: kio_file protocol domain-socket1 domain-socket2\n");
     exit(-1);
  }

  FileProtocol slave(argv[2], argv[3]);
  slave.dispatchLoop();

  kdDebug(7101) << "Done" << endl;
  return 0;
}


FileProtocol::FileProtocol( const QCString &pool, const QCString &app ) : SlaveBase( \
"file", pool, app ) {
    usercache.setAutoDelete( TRUE );
    groupcache.setAutoDelete( TRUE );
}

void FileProtocol::chmod( const KURL& url, int permissions )
{
    QCString _path( QFile::encodeName(url.path()));
    if ( ::chmod( _path.data(), permissions ) == -1 )
        error( KIO::ERR_CANNOT_CHMOD, url.path() );
    else
        finished();
}

void FileProtocol::mkdir( const KURL& url, int permissions )
{
    QCString _path( QFile::encodeName(url.path()));
#ifdef sun
    struct stat64 buff;
    if ( stat64( _path.data(), &buff ) == -1 ) {
#else
    struct stat buff;
    if ( ::stat( _path.data(), &buff ) == -1 ) {
#endif
	if ( ::mkdir( _path.data(), 0777 /*umask will be applied*/ ) != 0 ) {
	    if ( errno == EACCES ) {
		error( KIO::ERR_ACCESS_DENIED, url.path() );
		return;
	    } else {
		error( KIO::ERR_COULD_NOT_MKDIR, url.path() );
		return;
	    }
	} else {
	    if ( permissions != -1 )
	        chmod( url, permissions );
	    else
	        finished();
	    return;
	}
    }

    if ( S_ISDIR( buff.st_mode ) ) {
	kdDebug() << "ERR_DIR_ALREADY_EXIST" << endl;
	error( KIO::ERR_DIR_ALREADY_EXIST, url.path() );
	return;
    }
    error( KIO::ERR_FILE_ALREADY_EXIST, url.path() );
    return;
}

void FileProtocol::get( const KURL& url )
{
    QCString _path( QFile::encodeName(url.path()));
#ifdef sun
    struct stat64 buff;
    if ( stat64( _path.data(), &buff ) == -1 ) {
#else
    struct stat buff;
    if ( ::stat( _path.data(), &buff ) == -1 ) {
#endif
        if ( errno == EACCES )
           error( KIO::ERR_ACCESS_DENIED, url.path() );
        else
           error( KIO::ERR_DOES_NOT_EXIST, url.path() );
	return;
    }

    if ( S_ISDIR( buff.st_mode ) ) {
	error( KIO::ERR_IS_DIRECTORY, url.path() );
	return;
    }
    if ( S_ISFIFO( buff.st_mode ) || S_ISSOCK ( buff.st_mode ) ) {
	error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
	return;
    }

    int fd = open( _path.data(), O_RDONLY);
    if ( fd < 0 ) {
	error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.path() );
	return;
    }

    totalSize( buff.st_size );
    int processed_size = 0;
    time_t t_start = time( 0L );
    time_t t_last = t_start;

    char buffer[ MAX_IPC_SIZE ];
    QByteArray array;

    while( 1 )
    {
       int n = ::read( fd, buffer, MAX_IPC_SIZE );
       if (n == -1)
       {
          if (errno == EINTR)
              continue;
          error( KIO::ERR_COULD_NOT_READ, url.path());
          close(fd);
          return;
       }
       if (n == 0)
          break; // Finished

       array.setRawData(buffer, n);
       data( array );
       array.resetRawData(buffer, n);

       processed_size += n;
       time_t t = time( 0L );
       if ( t - t_last >= 1 )
       {
          processedSize( processed_size );
          speed( processed_size / ( t - t_start ) );
          t_last = t;
       }
    }

    data( QByteArray() );

    close( fd );

    processedSize( buff.st_size );
    time_t t = time( 0L );
    if ( t - t_start >= 1 )
	speed( processed_size / ( t - t_start ) );

    finished();
}

static int
write_all(int fd, const char *buf, size_t len)
{
   while (len > 0)
   {
      int written = write(fd, buf, len);
      if (written < 0)
      {
          if (errno == EINTR)
             continue;
          return -1;
      }
      buf += written;
      len -= written;
   }
   return 0;
}

void FileProtocol::put( const KURL& url, int _mode, bool _overwrite, bool _resume )
{
    QString dest_orig = url.path();
    QCString _dest_orig( QFile::encodeName(dest_orig));
    kdDebug( 7101 ) << "Put " << dest_orig << endl;
    QString dest_part( dest_orig );
    dest_part += QString::fromLatin1(".part");
    QCString _dest_part( QFile::encodeName(dest_part));

    bool bMarkPartial = KProtocolManager::markPartial();

#ifdef sun
    struct stat64 buff_orig;
    bool orig_exists = ( stat64( _dest_orig.data(), &buff_orig ) != -1 );
#else
    struct stat buff_orig;
    bool orig_exists = ( ::stat( _dest_orig.data(), &buff_orig ) != -1 );
#endif
    if ( orig_exists &&  !_overwrite && !_resume)
    {
        if (S_ISDIR(buff_orig.st_mode))
           error( KIO::ERR_DIR_ALREADY_EXIST, dest_orig );
        else
           error( KIO::ERR_FILE_ALREADY_EXIST, dest_orig );
        return;
    }

    QString dest;
    if (bMarkPartial)
    {
        kdDebug(7101) << "Appending .part extension to " << dest_orig << endl;
        dest = dest_part;

#ifdef sun
        struct stat64 buff_part;
        bool part_exists = ( stat64( _dest_part.data(), &buff_part ) != -1 );
#else
        struct stat buff_part;
        bool part_exists = ( ::stat( _dest_part.data(), &buff_part ) != -1 );
#endif
        if ( part_exists && !_resume && buff_part.st_size > 0 )
        {
            kdDebug() << "FileProtocol::put : calling canResume with " << (unsigned \
long)buff_part.st_size << endl;  // Maybe we can use this partial file for resuming
             // Tell about the size we have, and the app will tell us
             // if it's ok to resume or not.
             _resume = canResume( buff_part.st_size );

             kdDebug() << "FileProtocol::put got answer " << _resume << endl;

             if (!_resume)
             {
                 kdDebug(7101) << "Deleting partial file " << dest_part << endl;
                 if ( ! remove( _dest_part.data() ) ) {
                     part_exists = false;
                 } else {
                     error( KIO::ERR_CANNOT_DELETE_PARTIAL, dest_part );
                     return;
                 }
             }
        }
    }
    else
    {
       dest = dest_orig;
       if ( orig_exists && !_resume )
        {
             kdDebug(7101) << "Deleting destination file " << dest_part << endl;
             remove( _dest_orig.data() );
             // Catch errors when we try to open the file.
        }
    }
    QCString _dest( QFile::encodeName(dest));

    int fd;

    if ( _resume ) {
        fd = open( _dest.data(), O_RDWR );  // append if resuming
        lseek(fd, 0, SEEK_END); // Seek to end
    } else {
        // WABA: Make sure that we keep writing permissions ourselves,
        // otherwise we can be in for a surprise on NFS.
        mode_t initialMode;
        if (_mode != -1)
           initialMode = _mode | S_IWUSR | S_IRUSR;
        else
           initialMode = 0666;

        fd = open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
    }

    if ( fd < 0 ) {
	kdDebug(7101) << "####################### COULD NOT WRITE " << dest << _mode << \
endl;  kdDebug(7101) << "errno==" << errno << "(" << strerror(errno) << ")" << endl;
        if ( errno == EACCES ) {
            error( KIO::ERR_WRITE_ACCESS_DENIED, dest );
        } else {
            error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest );
        }
        return;
    }

    int result;
    // Loop until we got 0 (end of data)
    do
    {
      QByteArray buffer;
      dataReq(); // Request for data
      result = readData( buffer );
      if (result > 0)
      {
         if (write_all( fd, buffer.data(), buffer.size()))
         {
            if ( errno == ENOSPC ) // disk full
            {
              error( KIO::ERR_DISK_FULL, dest_orig);
              result = -2; // means: remove dest file
            }
            else
            {
              error( KIO::ERR_COULD_NOT_WRITE, dest_orig);
              result = -1;
            }
         }
      }
    }
    while ( result > 0 );


    if (result != 0)
    {
        close(fd);
	kdDebug(7101) << "Error during 'put'. Aborting." << endl;
        if (result == -2)
        {
	   remove(_dest.data());
        } else if (bMarkPartial)
        {
#ifdef sun
           struct stat64 buff;
           if (( stat64( _dest.data(), &buff ) == -1 ) ||
               ( buff.st_size < KProtocolManager::minimumKeepSize() ))
#else
           struct stat buff;
           if (( ::stat( _dest.data(), &buff ) == -1 ) ||
               ( buff.st_size < KProtocolManager::minimumKeepSize() ))
#endif
           {
	       remove(_dest.data());
           }
        }
        ::exit(255);
    }

    if ( close(fd) )
    {
        error( KIO::ERR_COULD_NOT_WRITE, dest_orig);
        return;
    }

    // after full download rename the file back to original name
    if ( bMarkPartial )
    {
       if ( ::rename( _dest.data(), _dest_orig.data() ) )
       {
           kdWarning(7101) << " Couldn't rename " << _dest << " to " << _dest_orig << \
endl;  error( KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig );
           return;
       }
    }

    // set final permissions, if the file was just created
    if ( _mode != -1 && !orig_exists )
    {
       if (::chmod(_dest_orig.data(), _mode) != 0)
       {
           warning( i18n( "Could not change permissions for\n%1" ).arg( dest_orig ) \
);  }
    }

    // We have done our job => finish
    finished();
}


void FileProtocol::copy( const KURL &src, const KURL &dest,
                         int _mode, bool _overwrite )
{
    QCString _src( QFile::encodeName(src.path()));
    QCString _dest( QFile::encodeName(dest.path()));
#ifdef sun
    struct stat64 buff_src;
    if ( stat64( _src.data(), &buff_src ) == -1 ) {
#else
    struct stat buff_src;
    if ( ::stat( _src.data(), &buff_src ) == -1 ) {
#endif
        if ( errno == EACCES )
           error( KIO::ERR_ACCESS_DENIED, src.path() );
        else
           error( KIO::ERR_DOES_NOT_EXIST, src.path() );
	return;
    }

    if ( S_ISDIR( buff_src.st_mode ) ) {
	error( KIO::ERR_IS_DIRECTORY, src.path() );
	return;
    }
    if ( S_ISFIFO( buff_src.st_mode ) || S_ISSOCK ( buff_src.st_mode ) ) {
	error( KIO::ERR_CANNOT_OPEN_FOR_READING, src.path() );
	return;
    }

#ifdef sun
    struct stat64 buff_dest;
    bool dest_exists = ( stat64( _dest.data(), &buff_dest ) != -1 );
#else
    struct stat buff_dest;
    bool dest_exists = ( ::stat( _dest.data(), &buff_dest ) != -1 );
#endif
    if ( dest_exists )
    {
        if (S_ISDIR(buff_dest.st_mode))
        {
           error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
           return;
        }

        if (!_overwrite)
        {
           error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
           return;
        }
    }

    int src_fd = open( _src.data(), O_RDONLY);
    if ( src_fd < 0 ) {
	error( KIO::ERR_CANNOT_OPEN_FOR_READING, src.path() );
	return;
    }

    // WABA: Make sure that we keep writing permissions ourselves,
    // otherwise we can be in for a surprise on NFS.
    mode_t initialMode;
    if (_mode != -1)
       initialMode = _mode | S_IWUSR;
    else
       initialMode = 0666;

    int dest_fd = open(_dest.data(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
    if ( dest_fd < 0 ) {
	kdDebug(7101) << "###### COULD NOT WRITE " << dest.url() << endl;
        if ( errno == EACCES ) {
            error( KIO::ERR_WRITE_ACCESS_DENIED, dest.path() );
        } else {
            error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest.path() );
        }
        close(src_fd);
        return;
    }

    totalSize( buff_src.st_size );
    int processed_size = 0;
    time_t t_start = time( 0L );
    time_t t_last = t_start;

    char buffer[ MAX_IPC_SIZE ];
    QByteArray array;

    while( 1 )
    {
       int n = ::read( src_fd, buffer, MAX_IPC_SIZE );
       if (n == -1)
       {
          if (errno == EINTR)
              continue;
          error( KIO::ERR_COULD_NOT_READ, src.path());
          close(src_fd);
          close(dest_fd);
          return;
       }
       if (n == 0)
          break; // Finished

       if (write_all( dest_fd, buffer, n))
       {
          close(src_fd);
          close(dest_fd);
          if ( errno == ENOSPC ) // disk full
          {
              error( KIO::ERR_DISK_FULL, dest.path());
              remove( _dest.data() );
          }
          else
          {
              error( KIO::ERR_COULD_NOT_WRITE, dest.path());
          }
          return;
       }

       processed_size += n;
       time_t t = time( 0L );
       if ( t - t_last >= 1 )
       {
          processedSize( processed_size );
	  speed( processed_size / ( t - t_start ) );
	  t_last = t;
       }
    }

    close( src_fd );

    if (close( dest_fd))
    {
        error( KIO::ERR_COULD_NOT_WRITE, dest.path());
        return;
    }

    // set final permissions
    if ( _mode != -1 )
    {
       if (::chmod(_dest.data(), _mode) != 0)
       {
           warning( i18n( "Could not change permissions for\n%1" ).arg( dest.path() ) \
);  }
    }

    processedSize( buff_src.st_size );
    time_t t = time( 0L );
    if ( t - t_start >= 1 )
	speed( processed_size / ( t - t_start ) );

    finished();
}

void FileProtocol::rename( const KURL &src, const KURL &dest,
                           bool _overwrite )
{
    QCString _src( QFile::encodeName(src.path()));
    QCString _dest( QFile::encodeName(dest.path()));
#ifdef sun
    struct stat64 buff_src;
    if ( stat64( _src.data(), &buff_src ) == -1 ) {
#else
    struct stat buff_src;
    if ( ::stat( _src.data(), &buff_src ) == -1 ) {
#endif
        if ( errno == EACCES )
           error( KIO::ERR_ACCESS_DENIED, src.path() );
        else
           error( KIO::ERR_DOES_NOT_EXIST, src.path() );
	return;
    }

#ifdef sun
    struct stat64 buff_dest;
    bool dest_exists = ( stat64( _dest.data(), &buff_dest ) != -1 );
#else
    struct stat buff_dest;
    bool dest_exists = ( ::stat( _dest.data(), &buff_dest ) != -1 );
#endif
    if ( dest_exists )
    {
        if (S_ISDIR(buff_dest.st_mode))
        {
           error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
           return;
        }

        if (!_overwrite)
        {
           error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
           return;
        }
    }

    if ( ::rename( _src.data(), _dest.data()))
    {
        if (( errno == EACCES ) || (errno == EPERM)) {
            error( KIO::ERR_ACCESS_DENIED, dest.path() );
        }
        else if (errno == EXDEV) {
           error( KIO::ERR_UNSUPPORTED_ACTION, QString::fromLatin1("rename"));
        }
        else if (errno == EROFS) { // The file is on a read-only filesystem
           error( KIO::ERR_CANNOT_DELETE, src.path() );
        }
        else {
           error( KIO::ERR_CANNOT_RENAME, src.path() );
        }
        return;
    }

    finished();
}

void FileProtocol::symlink( const QString &target, const KURL &dest, bool overwrite )
{
    // Assume dest is local too (wouldn't be here otherwise)
    if ( ::symlink( QFile::encodeName( target ), QFile::encodeName( dest.path() ) ) \
== -1 )  {
        // Does the destination already exist ?
        if ( errno == EEXIST )
        {
            if ( overwrite )
            {
                // Try to delete the destination
                if ( unlink( QFile::encodeName( dest.path() ) ) != 0 )
                {
                    error( KIO::ERR_CANNOT_DELETE, dest.path() );
                    return;
                }
                // Try again - this won't loop forever since unlink succeeded
                symlink( target, dest, overwrite );
            }
            else
            {
#ifdef sun
                struct stat64 buff_dest;
                lstat64( QFile::encodeName( dest.path() ), &buff_dest );
#else
                struct stat buff_dest;
                ::lstat( QFile::encodeName( dest.path() ), &buff_dest );
#endif
                if (S_ISDIR(buff_dest.st_mode))
                    error( KIO::ERR_DIR_ALREADY_EXIST, dest.path() );
                else
                    error( KIO::ERR_FILE_ALREADY_EXIST, dest.path() );
                return;
            }
        }
        else
        {
            // Some error occured while we tried to symlink
            error( KIO::ERR_CANNOT_SYMLINK, dest.path() );
            return;
        }
    }
    finished();
}

void FileProtocol::del( const KURL& url, bool isfile)
{
    QCString _path( QFile::encodeName(url.path()));
    /*****
     * Delete files
     *****/

    if (isfile) {
	kdDebug( 7101 ) <<  "Deleting file "<< url.url() << endl;

	// TODO deletingFile( source );

	if ( unlink( _path.data() ) == -1 ) {
            if ((errno == EACCES) || (errno == EPERM))
               error( KIO::ERR_ACCESS_DENIED, url.path());
            else if (errno == EISDIR)
               error( KIO::ERR_IS_DIRECTORY, url.path());
            else
               error( KIO::ERR_CANNOT_DELETE, url.path() );
	    return;
	}
    } else {

      /*****
       * Delete empty directory
       *****/

      kdDebug( 7101 ) << "Deleting directory " << url.url() << endl;

      if ( ::rmdir( _path.data() ) == -1 ) {
	if ((errno == EACCES) || (errno == EPERM))
	  error( KIO::ERR_ACCESS_DENIED, url.path());
	else {
	  kdDebug( 7101 ) << "could not rmdir " << perror << endl;
	  error( KIO::ERR_COULD_NOT_RMDIR, url.path() );
	  return;
	}
      }
    }

    finished();
}

bool FileProtocol::createUDSEntry( const QString & filename, const QCString & path, \
UDSEntry & entry  ) {
    assert(entry.count() == 0); // by contract :-)
    UDSAtom atom;
    atom.m_uds = KIO::UDS_NAME;
    atom.m_str = filename;
    entry.append( atom );

    mode_t type;
    mode_t access;

#ifdef sun
   struct stat64 buff;
	if ( lstat64( path.data(), &buff ) == 0 )  {
#else
   struct stat buff;
	if ( lstat( path.data(), &buff ) == 0 )  {
#endif

	    if (S_ISLNK(buff.st_mode)) {

		char buffer2[ 1000 ];
		int n = readlink( path.data(), buffer2, 1000 );
		if ( n != -1 ) {
		    buffer2[ n ] = 0;
                }

		atom.m_uds = KIO::UDS_LINK_DEST;
		atom.m_str = QString::fromLocal8Bit( buffer2 );
		entry.append( atom );

		// A link poiting to nowhere ?
#ifdef sun
      kdWarning() << "using 64 bit stat" << endl;
		if ( stat64( path.data(), &buff ) == -1 ) {
#else
      kdWarning() << "using 32 bit stat" << endl;
		if ( ::stat( path.data(), &buff ) == -1 ) {
#endif
		    // It is a link pointing to nowhere
		    type = S_IFMT - 1;
		    access = S_IRWXU | S_IRWXG | S_IRWXO;

		    atom.m_uds = KIO::UDS_FILE_TYPE;
		    atom.m_long = type;
		    entry.append( atom );

		    atom.m_uds = KIO::UDS_ACCESS;
		    atom.m_long = access;
		    entry.append( atom );

		    atom.m_uds = KIO::UDS_SIZE;
		    atom.m_long = 0L;
		    entry.append( atom );

		    goto notype;

		}
	    }
	} else {
            kdWarning() << "lstat didn't work on " << path.data() << endl;
	    return false;
	}

	type = buff.st_mode & S_IFMT; // extract file type
	access = buff.st_mode & 07777; // extract permissions

	atom.m_uds = KIO::UDS_FILE_TYPE;
	atom.m_long = type;
	entry.append( atom );

	atom.m_uds = KIO::UDS_ACCESS;
	atom.m_long = access;
	entry.append( atom );

	atom.m_uds = KIO::UDS_SIZE;
	atom.m_long = buff.st_size;
	entry.append( atom );

    notype:
	atom.m_uds = KIO::UDS_MODIFICATION_TIME;
	atom.m_long = buff.st_mtime;
	entry.append( atom );

	atom.m_uds = KIO::UDS_USER;
	uid_t uid = buff.st_uid;
	QString *temp = usercache.find( uid );

	if ( !temp ) {
	    struct passwd *user = getpwuid( uid );
	    if ( user ) {
		usercache.insert( uid, new QString(QString::fromLatin1(user->pw_name)) );
		atom.m_str = user->pw_name;
	    }
	    else
		atom.m_str = QString::number( uid );
	}
	else
	    atom.m_str = *temp;
	entry.append( atom );

	atom.m_uds = KIO::UDS_GROUP;
	gid_t gid = buff.st_gid;
	temp = groupcache.find( gid );
	if ( !temp ) {
	    struct group *grp = getgrgid( gid );
	    if ( grp ) {
		groupcache.insert( gid, new QString(QString::fromLatin1(grp->gr_name)) );
		atom.m_str = grp->gr_name;
	    }
	    else
		atom.m_str = QString::number( gid );
	}
	else
	    atom.m_str = *temp;
	entry.append( atom );

	atom.m_uds = KIO::UDS_ACCESS_TIME;
	atom.m_long = buff.st_atime;
	entry.append( atom );

	// Note: buff.st_ctime isn't the creation time !
        // We made that mistake for KDE 2.0, but it's in fact the
        // "file status" change time, which we don't care about.

	return true;
}

void FileProtocol::stat( const KURL & url )
{
    /* 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
     */
    QCString _path( QFile::encodeName(url.path(-1)));
#ifdef sun
    struct stat64 buff;
    if ( lstat64( _path.data(), &buff ) == -1 ) {
#else
    struct stat buff;
    if ( ::lstat( _path.data(), &buff ) == -1 ) {
#endif
	error( KIO::ERR_DOES_NOT_EXIST, url.path(-1) );
	return;
    }

    UDSEntry entry;
    if ( !createUDSEntry( url.fileName(), _path, entry ) )
    {
	// Should never happen
	error( KIO::ERR_DOES_NOT_EXIST, url.path(-1) );
	return;
    }
#if 0
///////// debug code
    KIO::UDSEntry::ConstIterator it = entry.begin();
    for( ; it != entry.end(); it++ ) {
        switch ((*it).m_uds) {
            case KIO::UDS_FILE_TYPE:
                kdDebug(7101) << "File Type : " << (mode_t)((*it).m_long) << endl;
                break;
            case KIO::UDS_ACCESS:
                kdDebug(7101) << "Access permissions : " << (mode_t)((*it).m_long) << \
endl;  break;
            case KIO::UDS_USER:
                kdDebug(7101) << "User : " << ((*it).m_str.ascii() ) << endl;
                break;
            case KIO::UDS_GROUP:
                kdDebug(7101) << "Group : " << ((*it).m_str.ascii() ) << endl;
                break;
            case KIO::UDS_NAME:
                kdDebug(7101) << "Name : " << ((*it).m_str.ascii() ) << endl;
                //m_strText = decodeFileName( (*it).m_str );
                break;
            case KIO::UDS_URL:
                kdDebug(7101) << "URL : " << ((*it).m_str.ascii() ) << endl;
                break;
            case KIO::UDS_MIME_TYPE:
                kdDebug(7101) << "MimeType : " << ((*it).m_str.ascii() ) << endl;
                break;
            case KIO::UDS_LINK_DEST:
                kdDebug(7101) << "LinkDest : " << ((*it).m_str.ascii() ) << endl;
                break;
        }
    }
/////////
#endif
    statEntry( entry );

    finished();
}

void FileProtocol::listDir( const KURL& url)
{
    QCString _path( QFile::encodeName(url.path()));
    kdDebug(7101) << "========= LIST " << url.url() << " =========" << endl;

#ifdef sun
    struct stat64 buff;
    if ( stat64( _path.data(), &buff ) == -1 ) {
#else
    struct stat buff;
    if ( ::stat( _path.data(), &buff ) == -1 ) {
#endif
	error( KIO::ERR_DOES_NOT_EXIST, url.path() );
	return;
    }

    if ( !S_ISDIR( buff.st_mode ) ) {
	error( KIO::ERR_IS_FILE, url.path() );
	return;
    }

    DIR *dp = 0L;
#if defined( __DECCXX) && defined(__linux__)
    struct dirent64 *ep; // XXX struct dirent *ep;
#else
    struct dirent *ep;
#endif

    dp = opendir( _path.data() );
    if ( dp == 0 ) {
	error( KIO::ERR_CANNOT_ENTER_DIRECTORY, url.path() );
	return;
    }

    // Don't make this a QStringList. The locale file name we get here
    // should be passed intact to createUDSEntry to avoid problems with
    // files where QFile::encodeName(QFile::decodeName(a)) != a.
    QStrList entryNames;

    while ( ( ep = readdir( dp ) ) != 0L )
	entryNames.append( ep->d_name );

    closedir( dp );
    totalSize( entryNames.count() );

    /* set the current dir to the path to speed up
       in not having to pass an absolute path.
       We restore the path later to get out of the
       path - the kernel wouldn't unmount or delete
       directories we keep as active directory. And
       as the slave runs in the background, it's hard
       to see for the user what the problem would be */
    char path_buffer[PATH_MAX];
    getcwd(path_buffer, PATH_MAX - 1);
    chdir( _path.data() );

    UDSEntry entry;
    QStrListIterator it(entryNames);
    for (; it.current(); ++it) {
        entry.clear();
        if ( createUDSEntry( QFile::decodeName(*it), *it /* we can use the filename \
as relative path*/, entry ) )  listEntry( entry, false);
        else
          ;//Well, this should never happen... but with wrong encoding names
    }

    listEntry( entry, true ); // ready

    kdDebug(7101) << "============= COMPLETED LIST ============" << endl;

    chdir(path_buffer);

    finished();

    kdDebug(7101) << "=============== BYE ===========" << endl;
}

/*
void FileProtocol::testDir( const QString& path )
{
    QCString _path( QFile::encodeName(path));
    struct stat buff;
    if ( ::stat( _path.data(), &buff ) == -1 ) {
	error( KIO::ERR_DOES_NOT_EXIST, path );
	return;
    }

    if ( S_ISDIR( buff.st_mode ) )
	isDirectory();
    else
	isFile();

    finished();
}
*/

void FileProtocol::special( const QByteArray &data)
{
    int tmp;
    QDataStream stream(data, IO_ReadOnly);

    stream >> tmp;
    switch (tmp) {
    case 1:
      {
	QString fstype, dev, point;
	Q_INT8 iRo;

	stream >> iRo >> fstype >> dev >> point;

	bool ro = ( iRo != 0 );

	kdDebug(7101) << "MOUNTING fstype=" << fstype << " dev=" << dev << " point=" << \
point << " ro=" << ro << endl;  mount( ro, fstype.ascii(), dev, point );

      }
      break;
    case 2:
      {
	QString point;
	stream >> point;
	unmount( point );
      }
      break;

    case 3:
    {
      QString filename;
      stream >> filename;
      KShred shred( filename );
      connect( &shred, SIGNAL( processedSize( unsigned long ) ),
               this, SLOT( slotProcessedSize( unsigned long ) ) );
      connect( &shred, SIGNAL( infoMessage( const QString & ) ),
               this, SLOT( slotInfoMessage( const QString & ) ) );
      if (!shred.shred())
          error( KIO::ERR_CANNOT_DELETE, filename );
      else
          finished();
      break;
    }
    default:
      assert(0);
    }
}

// Connected to KShred
void FileProtocol::slotProcessedSize( unsigned long bytes )
{
  kdDebug(7101) << "FileProtocol::slotProcessedSize (" << (unsigned int) bytes << ")" \
<< endl;  processedSize( bytes );
}

// Connected to KShred
void FileProtocol::slotInfoMessage( const QString & msg )
{
  kdDebug(7101) << "FileProtocol::slotInfoMessage (" << msg << ")" << endl;
  infoMessage( msg );
}

static QString shellQuote( const QString &_str )
{
    // Credits to Walter, says Bernd G. :)
    QString str(_str);
    str.replace(QRegExp(QString::fromLatin1("'")), QString::fromLatin1("'\"'\"'"));
    return QString::fromLatin1("'")+str+'\'';
}

void FileProtocol::mount( bool _ro, const char *_fstype, const QString& _dev, const \
QString& _point ) {
    kdDebug(7101) << "FileProtocol::mount _fstype=" << _fstype << endl;
    QString buffer;

    KTempFile tmpFile;
    QCString tmpFileC = QFile::encodeName(tmpFile.name());
    const char *tmp = tmpFileC.data();
    QCString dev = QFile::encodeName( shellQuote(_dev) ); // get those ready to be \
given to a shell  QCString point = QFile::encodeName( shellQuote(_point) );
    QCString fstype = _fstype;
    QCString readonly = _ro ? "-r" : "";

    // Two steps, in case mount doesn't like it when we pass all options
    for ( int step = 0 ; step <= 1 ; step++ )
    {
        // Mount using device only if no fstype nor mountpoint (KDE-1.x like)
        if ( !_dev.isEmpty() && _point.isEmpty() && fstype.isEmpty() )
            buffer.sprintf( "mount %s 2>%s", dev.data(), tmp );
        else
          // Mount using the mountpoint, if no fstype nor device (impossible in first \
step)  if ( !_point.isEmpty() && _dev.isEmpty() && fstype.isEmpty() )
            buffer.sprintf( "mount %s 2>%s", point.data(), tmp );
          else
            // mount giving device + mountpoint but no fstype
            if ( !_point.isEmpty() && !_dev.isEmpty() && fstype.isEmpty() )
              buffer.sprintf( "mount %s %s %s 2>%s", readonly.data(), dev.data(), \
point.data(), tmp );  else
              // mount giving device + mountpoint + fstype
              buffer.sprintf( "mount %s -t %s %s %s 2>%s", readonly.data(),
                              fstype.data(), dev.data(), point.data(), tmp );

        kdDebug(7101) << buffer << endl;

        system( buffer.ascii() );

        QString err = testLogFile( tmp );
        if ( err.isEmpty() )
        {
            finished();
            return;
        }
        else
        {
            // Didn't work - or maybe we just got a warning
            QString mp = KIO::findDeviceMountPoint( _dev );
            // Is the device mounted ?
            if ( !mp.isNull() )
            {
                kdDebug(7101) << "mount got a warning: " << err << endl;
                warning( err );
                finished();
                return;
            }
            else
            {
                if ( step == 0 )
                {
                    kdDebug(7101) << err << endl;
                    kdDebug(7101) << "Mounting with those options didn't work, trying \
with only mountpoint" << endl;  fstype = "";
                    dev = "";
                    // The reason for trying with only mountpoint (instead of
                    // only device) is that some people (hi Malte!) have the
                    // same device associated with two mountpoints
                    // for different fstypes, like /dev/fd0 /mnt/e2floppy and
                    // /dev/fd0 /mnt/dosfloppy.
                    // If the user has the same mountpoint associated with two
                    // different devices, well they shouldn't specify the
                    // mountpoint but just the device.
                }
                else
                {
                    error( KIO::ERR_COULD_NOT_MOUNT, err );
                    return;
                }
            }
        }
    }
}


void FileProtocol::unmount( const QString& _point )
{
    QString buffer;

    KTempFile tmpFile;
    QCString tmpFileC = QFile::encodeName(tmpFile.name());
    const char *tmp = tmpFileC.data();

    buffer.sprintf( "umount %s 2>%s", QFile::encodeName(_point).data(), tmp );
    system( buffer.ascii() );

    QString err = testLogFile( tmp );
    if ( err.isEmpty() )
	finished();
    else
        error( KIO::ERR_COULD_NOT_UNMOUNT, err );
}

/*************************************
 *
 * Utilities
 *
 *************************************/

QString testLogFile( const char *_filename )
{
    char buffer[ 1024 ];
    QString result;
#ifdef sun
    struct stat64 buff;
    stat64( _filename, &buff );
#else
    struct stat buff;
    stat( _filename, &buff );
#endif

    int size = buff.st_size;
    if ( size == 0 ) {
	unlink( _filename );
	return result;
    }

    FILE * f = fopen( _filename, "rb" );
    if ( f == 0L ) {
	unlink( _filename );
	result = i18n("Could not read %1").arg(QFile::decodeName(_filename));
	return result;
    }

    result = "";
    const char *p = "";
    while ( p != 0L ) {
	p = fgets( buffer, sizeof(buffer)-1, f );
	if ( p != 0L )
	    result += QString::fromLocal8Bit(buffer);
    }

    fclose( f );

    unlink( _filename );

    return result;
}

#include "file.moc"



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic