kde-workspace/kioslave/smb/kio_smb_file.cpp
2014-11-15 04:16:00 +02:00

463 lines
13 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Project: SMB kioslave for KDE2
//
// File: kio_smb_file.cpp
//
// Abstract: member function implementations for SMBSlave that deal with
// SMB file access
//
// Author(s): Matthew Peterson <mpeterson@caldera.com>
//
//---------------------------------------------------------------------------
//
// Copyright (c) 2000 Caldera Systems, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This program 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING. If not, please obtain
// a copy from http://www.gnu.org/copyleft/gpl.html
//
/////////////////////////////////////////////////////////////////////////////
#include "kio_smb.h"
#include "kio_smb_internal.h"
#include <QVarLengthArray>
#include <QDateTime>
#include <kmimetype.h>
//===========================================================================
void SMBSlave::get( const KUrl& kurl )
{
char buf[MAX_XFER_BUF_SIZE];
int filefd = 0;
int errNum = 0;
ssize_t bytesread = 0;
// time_t curtime = 0;
time_t lasttime = 0;
time_t starttime = 0;
KIO::filesize_t totalbytesread = 0;
QByteArray filedata;
SMBUrl url;
kDebug(KIO_SMB) << kurl;
// check (correct) URL
KUrl kvurl = checkURL(kurl);
// if URL is not valid we have to redirect to correct URL
if (kvurl != kurl) {
redirection(kvurl);
finished();
return;
}
if(!auth_initialize_smbc())
return;
// Stat
url = kurl;
errNum = cache_stat(url,&st);
if( errNum != 0 )
{
if ( errNum == EACCES )
error( KIO::ERR_ACCESS_DENIED, url.prettyUrl());
else
error( KIO::ERR_DOES_NOT_EXIST, url.prettyUrl());
return;
}
if ( S_ISDIR( st.st_mode ) ) {
error( KIO::ERR_IS_DIRECTORY, url.prettyUrl());
return;
}
// Set the total size
totalSize( st.st_size );
// Open and read the file
filefd = smbc_open(url.toSmbcUrl(),O_RDONLY,0);
if(filefd >= 0)
{
bool isFirstPacket = true;
lasttime = starttime = time(NULL);
while(1)
{
bytesread = smbc_read(filefd, buf, MAX_XFER_BUF_SIZE);
if(bytesread == 0)
{
// All done reading
break;
}
else if(bytesread < 0)
{
error( KIO::ERR_COULD_NOT_READ, url.prettyUrl());
return;
}
filedata = QByteArray::fromRawData(buf,bytesread);
if (isFirstPacket)
{
KMimeType::Ptr p_mimeType = KMimeType::findByNameAndContent(url.fileName(), filedata);
mimeType(p_mimeType->name());
isFirstPacket = false;
}
data( filedata );
filedata.clear();
// increment total bytes read
totalbytesread += bytesread;
processedSize(totalbytesread);
}
smbc_close(filefd);
data( QByteArray() );
processedSize(static_cast<KIO::filesize_t>(st.st_size));
}
else
{
error( KIO::ERR_CANNOT_OPEN_FOR_READING, url.prettyUrl());
return;
}
finished();
}
//===========================================================================
void SMBSlave::open( const KUrl& kurl, QIODevice::OpenMode mode)
{
int errNum = 0;
kDebug(KIO_SMB) << kurl;
// check (correct) URL
KUrl kvurl = checkURL(kurl);
// if URL is not valid we have to redirect to correct URL
if (kvurl != kurl) {
redirection(kvurl);
finished();
return;
}
if(!auth_initialize_smbc()) {
error( KIO::ERR_ACCESS_DENIED, kurl.prettyUrl());
return;
}
// Save the URL as a private member
// FIXME For some reason m_openUrl has be be declared in bottom private
// section of the class SMBSlave declaratiom instead of the top section
// or else this assignment fails
m_openUrl = kurl;
// Stat
errNum = cache_stat(m_openUrl,&st);
if( errNum != 0 )
{
if ( errNum == EACCES )
error( KIO::ERR_ACCESS_DENIED, m_openUrl.prettyUrl());
else
error( KIO::ERR_DOES_NOT_EXIST, m_openUrl.prettyUrl());
return;
}
if ( S_ISDIR( st.st_mode ) ) {
error( KIO::ERR_IS_DIRECTORY, m_openUrl.prettyUrl());
return;
}
// Set the total size
totalSize( st.st_size );
// Convert permissions
int flags = 0;
if (mode & QIODevice::ReadOnly) {
if (mode & QIODevice::WriteOnly) {
flags = O_RDWR | O_CREAT;
} else {
flags = O_RDONLY;
}
} else if (mode & QIODevice::WriteOnly) {
flags = O_WRONLY | O_CREAT;
}
if (mode & QIODevice::Append) {
flags |= O_APPEND;
} else if (mode & QIODevice::Truncate) {
flags |= O_TRUNC;
}
// Open the file
m_openFd = smbc_open(m_openUrl.toSmbcUrl(), flags, 0);
if(m_openFd < 0)
{
error( KIO::ERR_CANNOT_OPEN_FOR_READING, m_openUrl.prettyUrl());
return;
}
// Determine the mimetype of the file to be retrieved, and emit it.
// This is mandatory in all slaves (for KRun/BrowserRun to work).
// If we're not opening the file ReadOnly or ReadWrite, don't attempt to
// read the file and send the mimetype.
if (mode & QIODevice::ReadOnly){
ssize_t bytesRequested = 1024;
ssize_t bytesRead = 0;
QVarLengthArray<char> buffer(bytesRequested);
bytesRead = smbc_read(m_openFd, buffer.data(), bytesRequested);
if(bytesRead < 0)
{
error( KIO::ERR_COULD_NOT_READ, m_openUrl.prettyUrl());
close();
return;
}
else
{
QByteArray fileData = QByteArray::fromRawData(buffer.data(),bytesRead);
KMimeType::Ptr p_mimeType = KMimeType::findByNameAndContent(m_openUrl.fileName(), fileData);
mimeType(p_mimeType->name());
off_t res = smbc_lseek(m_openFd, 0, SEEK_SET);
if (res == (off_t)-1) {
error(KIO::ERR_COULD_NOT_SEEK, m_openUrl.path());
close();
return;
}
}
}
position( 0 );
emit opened();
}
void SMBSlave::read( KIO::filesize_t bytesRequested )
{
Q_ASSERT(m_openFd != -1);
QVarLengthArray<char> buffer(bytesRequested);
ssize_t bytesRead = 0;
bytesRead = smbc_read(m_openFd, buffer.data(), bytesRequested);
Q_ASSERT(bytesRead <= static_cast<ssize_t>(bytesRequested));
if(bytesRead < 0)
{
kDebug(KIO_SMB) << "Could not read " << m_openUrl;
error( KIO::ERR_COULD_NOT_READ, m_openUrl.prettyUrl());
close();
return;
}
QByteArray fileData = QByteArray::fromRawData(buffer.data(), bytesRead);
data( fileData );
}
void SMBSlave::write(const QByteArray &fileData)
{
Q_ASSERT(m_openFd != -1);
QByteArray buf(fileData);
ssize_t size = smbc_write(m_openFd, buf.data(), buf.size());
if (size < 0)
{
kDebug(KIO_SMB) << "Could not write to " << m_openUrl;
error( KIO::ERR_COULD_NOT_WRITE, m_openUrl.prettyUrl());
close();
return;
}
written(size);
}
void SMBSlave::seek(KIO::filesize_t offset)
{
off_t res = smbc_lseek(m_openFd, static_cast<off_t>(offset), SEEK_SET);
if (res == (off_t)-1) {
error(KIO::ERR_COULD_NOT_SEEK, m_openUrl.path());
close();
} else {
kDebug( KIO_SMB ) << "res" << res;
position( res );
}
}
void SMBSlave::close()
{
smbc_close(m_openFd);
finished();
}
//===========================================================================
void SMBSlave::put( const KUrl& kurl,
int permissions,
KIO::JobFlags flags )
{
void *buf;
size_t bufsize;
m_current_url = kurl;
int filefd;
bool exists;
int errNum = 0;
off_t retValLSeek = 0;
mode_t mode;
QByteArray filedata;
kDebug(KIO_SMB) << kurl;
errNum = cache_stat(m_current_url, &st);
exists = (errNum == 0);
if ( exists && !(flags & KIO::Overwrite) && !(flags & KIO::Resume))
{
if (S_ISDIR(st.st_mode))
{
kDebug(KIO_SMB) << kurl <<" already isdir !!";
error( KIO::ERR_DIR_ALREADY_EXIST, m_current_url.prettyUrl());
}
else
{
kDebug(KIO_SMB) << kurl <<" already exist !!";
error( KIO::ERR_FILE_ALREADY_EXIST, m_current_url.prettyUrl());
}
return;
}
if (exists && !(flags & KIO::Resume) && (flags & KIO::Overwrite))
{
kDebug(KIO_SMB) << "exists try to remove " << m_current_url.toSmbcUrl();
// remove(m_current_url.url().toLocal8Bit());
}
if (flags & KIO::Resume)
{
// append if resuming
kDebug(KIO_SMB) << "resume " << m_current_url.toSmbcUrl();
filefd = smbc_open(m_current_url.toSmbcUrl(), O_RDWR, 0 );
if (filefd < 0) {
errNum = errno;
} else {
errNum = 0;
}
retValLSeek = smbc_lseek(filefd, 0, SEEK_END);
if (retValLSeek == (off_t)-1) {
errNum = errno;
} else {
errNum = 0;
}
}
else
{
if (permissions != -1)
{
mode = permissions | S_IWUSR | S_IRUSR;
}
else
{
mode = 600;//0666;
}
kDebug(KIO_SMB) << "NO resume " << m_current_url.toSmbcUrl();
filefd = smbc_open(m_current_url.toSmbcUrl(), O_CREAT | O_TRUNC | O_WRONLY, mode);
if (filefd < 0) {
errNum = errno;
} else {
errNum = 0;
}
}
if ( filefd < 0 )
{
if ( errNum == EACCES )
{
kDebug(KIO_SMB) << "error " << kurl <<" access denied !!";
error( KIO::ERR_WRITE_ACCESS_DENIED, m_current_url.prettyUrl());
}
else
{
kDebug(KIO_SMB) << "error " << kurl <<" can not open for writing !!";
error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, m_current_url.prettyUrl());
}
return;
}
// Loop until we got 0 (end of data)
while(1)
{
kDebug(KIO_SMB) << "request data ";
dataReq(); // Request for data
kDebug(KIO_SMB) << "write " << m_current_url.toSmbcUrl();
if (readData(filedata) <= 0)
{
kDebug(KIO_SMB) << "readData <= 0";
break;
}
kDebug(KIO_SMB) << "write " << m_current_url.toSmbcUrl();
buf = filedata.data();
bufsize = filedata.size();
ssize_t size = smbc_write(filefd, buf, bufsize);
if ( size < 0)
{
kDebug(KIO_SMB) << "error " << kurl << "could not write !!";
error( KIO::ERR_COULD_NOT_WRITE, m_current_url.prettyUrl());
return;
}
kDebug(KIO_SMB ) << "wrote " << size;
}
kDebug(KIO_SMB) << "close " << m_current_url.toSmbcUrl();
if(smbc_close(filefd) < 0)
{
kDebug(KIO_SMB) << kurl << "could not write !!";
error( KIO::ERR_COULD_NOT_WRITE, m_current_url.prettyUrl());
return;
}
// set final permissions, if the file was just created
if ( permissions != -1 && !exists )
{
// TODO: did the smbc_chmod fail?
// TODO: put in call to chmod when it is working!
// smbc_chmod(url.toSmbcUrl(),permissions);
}
#ifdef HAVE_UTIME_H
// set modification time
const QString mtimeStr = metaData( "modified" );
if ( !mtimeStr.isEmpty() ) {
QDateTime dt = QDateTime::fromString( mtimeStr, Qt::ISODate );
if ( dt.isValid() ) {
if (cache_stat( m_current_url, &st ) == 0) {
struct utimbuf utbuf;
utbuf.actime = st.st_atime; // access time, unchanged
utbuf.modtime = dt.toTime_t(); // modification time
smbc_utime( m_current_url.toSmbcUrl(), &utbuf );
}
}
}
#endif
// We have done our job => finish
finished();
}