diff --git a/smb/kio_smb_dir.cpp b/smb/kio_smb_dir.cpp index f5e26dfa..85c25769 100644 --- a/smb/kio_smb_dir.cpp +++ b/smb/kio_smb_dir.cpp @@ -1,784 +1,784 @@ ///////////////////////////////////////////////////////////////////////////// // // Project: SMB kioslave for KDE2 // // File: kio_smb_dir.cpp // // Abstract: member function implementations for SMBSlave that deal with // SMB directory access // // Author(s): Matthew Peterson // ////--------------------------------------------------------------------------- // // 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 #include #include #include #include //=========================================================================== void SMBSlave::copy(const QUrl& src, const QUrl& dst, int permissions, KIO::JobFlags flags) { const bool isSourceLocal = src.isLocalFile(); const bool isDestinationLocal = dst.isLocalFile(); if (!isSourceLocal && isDestinationLocal) { smbCopyGet(src, dst, permissions, flags); } else if (isSourceLocal && !isDestinationLocal) { smbCopyPut(src, dst, permissions, flags); } else { smbCopy(src, dst, permissions, flags); } } void SMBSlave::smbCopy(const QUrl& ksrc, const QUrl& kdst, int permissions, KIO::JobFlags flags) { SMBUrl src; SMBUrl dst; mode_t initialmode; ssize_t n; int dstflags; int srcfd = -1; int dstfd = -1; int errNum = 0; KIO::filesize_t processed_size = 0; unsigned char buf[MAX_XFER_BUF_SIZE]; qCDebug(KIO_SMB) << "SMBSlave::copy with src = " << ksrc << "and dest = " << kdst; // setup urls src = ksrc; dst = kdst; // Obtain information about source errNum = cache_stat(src, &st ); if( errNum != 0 ) { if ( errNum == EACCES ) { error( KIO::ERR_ACCESS_DENIED, src.toDisplayString()); } else { error( KIO::ERR_DOES_NOT_EXIST, src.toDisplayString()); } return; } if ( S_ISDIR( st.st_mode ) ) { error( KIO::ERR_IS_DIRECTORY, src.toDisplayString() ); return; } totalSize(st.st_size); // Check to se if the destination exists errNum = cache_stat(dst, &st); if( errNum == 0 ) { if(S_ISDIR(st.st_mode)) { error( KIO::ERR_DIR_ALREADY_EXIST, dst.toDisplayString()); return; } if(!(flags & KIO::Overwrite)) { error( KIO::ERR_FILE_ALREADY_EXIST, dst.toDisplayString()); return; } } // Open the source file srcfd = smbc_open(src.toSmbcUrl(), O_RDONLY, 0); if (srcfd < 0){ errNum = errno; } else { errNum = 0; } if(srcfd < 0) { if(errNum == EACCES) { error( KIO::ERR_ACCESS_DENIED, src.toDisplayString() ); } else { error( KIO::ERR_DOES_NOT_EXIST, src.toDisplayString() ); } return; } // Determine initial creation mode if(permissions != -1) { initialmode = permissions | S_IWUSR; } else { initialmode = 0 | S_IWUSR;//0666; } // Open the destination file dstflags = O_CREAT | O_TRUNC | O_WRONLY; if(!(flags & KIO::Overwrite)) { dstflags |= O_EXCL; } dstfd = smbc_open(dst.toSmbcUrl(), dstflags, initialmode); if (dstfd < 0){ errNum = errno; } else { errNum = 0; } if(dstfd < 0) { if(errNum == EACCES) { error(KIO::ERR_WRITE_ACCESS_DENIED, dst.toDisplayString()); } else { error(KIO::ERR_CANNOT_OPEN_FOR_READING, dst.toDisplayString()); } if(srcfd >= 0 ) { smbc_close(srcfd); } return; } // Perform copy while(1) { n = smbc_read(srcfd, buf, MAX_XFER_BUF_SIZE ); if(n > 0) { n = smbc_write(dstfd, buf, n); if(n == -1) { qCDebug(KIO_SMB) << "SMBSlave::copy copy now KIO::ERR_COULD_NOT_WRITE"; error( KIO::ERR_COULD_NOT_WRITE, dst.toDisplayString()); break; } processed_size += n; processedSize(processed_size); } else if(n == 0) { break; // finished } else { error( KIO::ERR_COULD_NOT_READ, src.toDisplayString()); break; } } // FINISHED: if(srcfd >= 0 ) { smbc_close(srcfd); } if(dstfd >= 0) { if(smbc_close(dstfd) == 0) { // TODO: set final permissions } else { error( KIO::ERR_COULD_NOT_WRITE, dst.toDisplayString()); return; } } finished(); } void SMBSlave::smbCopyGet(const QUrl& ksrc, const QUrl& kdst, int permissions, KIO::JobFlags flags) { qCDebug(KIO_SMB) << "src = " << ksrc << ", dest = " << kdst; // check if destination is ok ... const QString dstFile = kdst.toLocalFile(); const QFileInfo dstInfo (dstFile); if(dstInfo.exists()) { if(dstInfo.isDir()) { error (ERR_IS_DIRECTORY, kdst.toDisplayString()); return; } if(!(flags & KIO::Overwrite)) { error(ERR_FILE_ALREADY_EXIST, kdst.toDisplayString()); return; } } bool bResume = false; const QFileInfo partInfo (dstFile + QLatin1String(".part")); const bool bPartExists = partInfo.exists(); const bool bMarkPartial = config()->readEntry("MarkPartial", true); if (bMarkPartial && bPartExists && partInfo.size() > 0) { if (partInfo.isDir()) { error(ERR_IS_DIRECTORY, partInfo.absoluteFilePath()); return; } bResume = canResume(partInfo.size()); } if (bPartExists && !bResume) // get rid of an unwanted ".part" file QFile::remove(partInfo.absoluteFilePath()); // open the output file... QFile::OpenMode mode; QString filename; if (bResume) { filename = partInfo.absoluteFilePath(); mode = QFile::WriteOnly | QFile::Append; } else { filename = (bMarkPartial ? partInfo.absoluteFilePath() : dstFile); mode = QFile::WriteOnly | QFile::Truncate; } QFile file (filename); if (!bResume) { QFile::Permissions perms; if (permissions == -1) { perms = QFile::ReadOwner | QFile::WriteOwner; } else { perms = KIO::convertPermissions(permissions | QFile::WriteOwner); } file.setPermissions(perms); } if (!file.open(mode)) { qCDebug(KIO_SMB) << "could not write to" << dstFile; switch (file.error()) { case QFile::OpenError: if (bResume) { error (ERR_CANNOT_RESUME, kdst.toDisplayString()); } else { error(ERR_CANNOT_OPEN_FOR_WRITING, kdst.toDisplayString()); } break; case QFile::PermissionsError: error(ERR_WRITE_ACCESS_DENIED, kdst.toDisplayString()); break; default: error(ERR_CANNOT_OPEN_FOR_WRITING, kdst.toDisplayString()); break; } return; } // setup the source urls const SMBUrl src(ksrc); // Obtain information about source int errNum = cache_stat (src, &st); if (errNum != 0) { if (errNum == EACCES) { error (KIO::ERR_ACCESS_DENIED, src.toDisplayString()); } else { error (KIO::ERR_DOES_NOT_EXIST, src.toDisplayString()); } return; } if (S_ISDIR( st.st_mode )) { error (KIO::ERR_IS_DIRECTORY, src.toDisplayString()); return; } totalSize(st.st_size); // Open the source file KIO::filesize_t processed_size = 0; int srcfd = smbc_open(src.toSmbcUrl(), O_RDONLY, 0); if (srcfd < 0){ errNum = errno; } else { errNum = 0; if (bResume) { qCDebug(KIO_SMB) << "seeking to size" << partInfo.size(); off_t offset = smbc_lseek(srcfd, partInfo.size(), SEEK_SET); if (offset == -1) { error(KIO::ERR_COULD_NOT_SEEK, src.toDisplayString()); smbc_close(srcfd); return; } else { processed_size += offset; } } } if (srcfd < 0) { if(errNum == EACCES) { error( KIO::ERR_ACCESS_DENIED, src.toDisplayString() ); } else { error( KIO::ERR_DOES_NOT_EXIST, src.toDisplayString() ); } return; } // Perform the copy char buf[MAX_XFER_BUF_SIZE]; bool isErr = false; while (1) { const ssize_t bytesRead = smbc_read(srcfd, buf, MAX_XFER_BUF_SIZE); if (bytesRead <= 0) { if (bytesRead < 0) { error( KIO::ERR_COULD_NOT_READ, src.toDisplayString()); isErr = true; } break; } const qint64 bytesWritten = file.write(buf, bytesRead); if (bytesWritten == -1) { qCDebug(KIO_SMB) << "copy now KIO::ERR_COULD_NOT_WRITE"; error( KIO::ERR_COULD_NOT_WRITE, kdst.toDisplayString()); isErr = true; break; } processed_size += bytesWritten; processedSize(processed_size); } // FINISHED smbc_close(srcfd); // Handle error condition. if (isErr) { const QString sPart = partInfo.absoluteFilePath(); if (bMarkPartial) { const int size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE); if (partInfo.size() < size) { QFile::remove(sPart); } } return; } // Rename partial file to its original name. if (bMarkPartial) { const QString sPart = partInfo.absoluteFilePath(); // Remove old dest file if it exists.. if (dstInfo.exists()) { QFile::remove(dstFile); } if (!QFile::rename(sPart, dstFile)) { qCDebug(KIO_SMB) << "failed to rename" << sPart << "to" << dstFile; error(ERR_CANNOT_RENAME_PARTIAL, sPart); return; } } // Restore the mtime on the file. const QString mtimeStr = metaData("modified"); qCDebug(KIO_SMB) << "modified:" << mtimeStr; if (!mtimeStr.isEmpty()) { QDateTime dt = QDateTime::fromString(mtimeStr, Qt::ISODate); if (dt.isValid()) { struct utimbuf utbuf; - utbuf.actime = QFileInfo(file).lastRead().toTime_t(); // access time, unchanged + utbuf.actime = QFileInfo(dstFile).lastRead().toTime_t(); // access time, unchanged utbuf.modtime = dt.toTime_t(); // modification time utime(QFile::encodeName(dstFile).constData(), &utbuf); } } finished(); } void SMBSlave::smbCopyPut(const QUrl& ksrc, const QUrl& kdst, int permissions, KIO::JobFlags flags) { qCDebug(KIO_SMB) << "src = " << ksrc << ", dest = " << kdst; QFile srcFile (ksrc.toLocalFile()); const QFileInfo srcInfo (srcFile); if (srcInfo.exists()) { if (srcInfo.isDir()) { error(KIO::ERR_IS_DIRECTORY, ksrc.toDisplayString()); return; } } else { error(KIO::ERR_DOES_NOT_EXIST, ksrc.toDisplayString()); return; } if (!srcFile.open(QFile::ReadOnly)) { qCDebug(KIO_SMB) << "could not read from" << ksrc; switch (srcFile.error()) { case QFile::PermissionsError: error(KIO::ERR_WRITE_ACCESS_DENIED, ksrc.toDisplayString()); break; case QFile::OpenError: default: error(KIO::ERR_CANNOT_OPEN_FOR_READING, ksrc.toDisplayString()); break; } return; } totalSize(static_cast(srcInfo.size())); bool bResume = false; bool bPartExists = false; const bool bMarkPartial = config()->readEntry("MarkPartial", true); const SMBUrl dstOrigUrl (kdst); if (bMarkPartial) { const int errNum = cache_stat(dstOrigUrl.partUrl(), &st); bPartExists = (errNum == 0); if (bPartExists) { if (!(flags & KIO::Overwrite) && !(flags & KIO::Resume)) { bResume = canResume(st.st_size); } else { bResume = (flags & KIO::Resume); } } } int dstfd = -1; int errNum = cache_stat(dstOrigUrl, &st); if (errNum == 0 && !(flags & KIO::Overwrite) && !(flags & KIO::Resume)) { if (S_ISDIR(st.st_mode)) { error( KIO::ERR_IS_DIRECTORY, dstOrigUrl.toDisplayString()); } else { error( KIO::ERR_FILE_ALREADY_EXIST, dstOrigUrl.toDisplayString()); } return; } KIO::filesize_t processed_size = 0; const SMBUrl dstUrl(bMarkPartial ? dstOrigUrl.partUrl() : dstOrigUrl); if (bResume) { // append if resuming qCDebug(KIO_SMB) << "resume" << dstUrl; dstfd = smbc_open(dstUrl.toSmbcUrl(), O_RDWR, 0 ); if (dstfd < 0) { errNum = errno; } else { const off_t offset = smbc_lseek(dstfd, 0, SEEK_END); if (offset == (off_t)-1) { error(KIO::ERR_COULD_NOT_SEEK, dstUrl.toDisplayString()); smbc_close(dstfd); return; } else { processed_size = offset; } } } else { mode_t mode; if (permissions == -1) { mode = 600; } else { mode = permissions | S_IRUSR | S_IWUSR; } qCDebug(KIO_SMB) << "NO resume" << dstUrl; dstfd = smbc_open(dstUrl.toSmbcUrl(), O_CREAT | O_TRUNC | O_WRONLY, mode); if (dstfd < 0) { errNum = errno; } } if (dstfd < 0) { if (errNum == EACCES) { qCDebug(KIO_SMB) << "access denied"; error( KIO::ERR_WRITE_ACCESS_DENIED, dstUrl.toDisplayString()); } else { qCDebug(KIO_SMB) << "can not open for writing"; error( KIO::ERR_CANNOT_OPEN_FOR_WRITING, dstUrl.toDisplayString()); } return; } bool isErr = false; if (processed_size == 0 || srcFile.seek(processed_size)) { // Perform the copy char buf[MAX_XFER_BUF_SIZE]; while (1) { const ssize_t bytesRead = srcFile.read(buf, MAX_XFER_BUF_SIZE); if (bytesRead <= 0) { if (bytesRead < 0) { error(KIO::ERR_COULD_NOT_READ, ksrc.toDisplayString()); isErr = true; } break; } const qint64 bytesWritten = smbc_write(dstfd, buf, bytesRead); if (bytesWritten == -1) { error(KIO::ERR_COULD_NOT_WRITE, kdst.toDisplayString()); isErr = true; break; } processed_size += bytesWritten; processedSize(processed_size); } } else { isErr = true; error(KIO::ERR_COULD_NOT_SEEK, ksrc.toDisplayString()); } // FINISHED if (smbc_close(dstfd) < 0) { qCDebug(KIO_SMB) << dstUrl << "could not write"; error( KIO::ERR_COULD_NOT_WRITE, dstUrl.toDisplayString()); return; } // Handle error condition. if (isErr) { if (bMarkPartial) { const int size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE); const int errNum = cache_stat(dstUrl, &st); if (errNum == 0 && st.st_size < size) { smbc_unlink(dstUrl.toSmbcUrl()); } } return; } // Rename partial file to its original name. if (bMarkPartial) { smbc_unlink(dstOrigUrl.toSmbcUrl()); if (smbc_rename(dstUrl.toSmbcUrl(), dstOrigUrl.toSmbcUrl()) < 0) { qCDebug(KIO_SMB) << "failed to rename" << dstUrl << "to" << dstOrigUrl << "->" << strerror(errno); error(ERR_CANNOT_RENAME_PARTIAL, dstUrl.toDisplayString()); return; } } #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() ) { struct utimbuf utbuf; utbuf.actime = st.st_atime; // access time, unchanged utbuf.modtime = dt.toTime_t(); // modification time smbc_utime( dstUrl.toSmbcUrl(), &utbuf ); } } #endif // We have done our job => finish finished(); } //=========================================================================== void SMBSlave::del( const QUrl &kurl, bool isfile) { qCDebug(KIO_SMB) << kurl; m_current_url = kurl; int errNum = 0; int retVal = 0; if(isfile) { // Delete file qCDebug(KIO_SMB) << "Deleting file" << kurl; retVal = smbc_unlink(m_current_url.toSmbcUrl()); if ( retVal < 0 ){ errNum = errno; } else { errNum = 0; } } else { qCDebug(KIO_SMB) << "Deleting directory" << kurl; // Delete directory retVal = smbc_rmdir(m_current_url.toSmbcUrl()); if( retVal < 0 ) { errNum = errno; } else { errNum = 0; } } if( errNum != 0 ) { reportError(kurl, errNum); } else { finished(); } } //=========================================================================== void SMBSlave::mkdir( const QUrl &kurl, int permissions ) { qCDebug(KIO_SMB) << kurl; int errNum = 0; int retVal = 0; m_current_url = kurl; retVal = smbc_mkdir(m_current_url.toSmbcUrl(), 0777); if( retVal < 0 ){ errNum = errno; } else { errNum = 0; } if( retVal < 0 ) { if (errNum == EEXIST) { errNum = cache_stat(m_current_url, &st ); if (errNum == 0 && S_ISDIR(st.st_mode)) { error( KIO::ERR_DIR_ALREADY_EXIST, m_current_url.toDisplayString()); } else { error( KIO::ERR_FILE_ALREADY_EXIST, m_current_url.toDisplayString()); } } else { reportError(kurl, errNum); } qCDebug(KIO_SMB) << "exit with error " << kurl; } else // success { if(permissions != -1) { // TODO enable the following when complete //smbc_chmod( url.toSmbcUrl(), permissions ); } finished(); } } //=========================================================================== void SMBSlave::rename( const QUrl& ksrc, const QUrl& kdest, KIO::JobFlags flags ) { SMBUrl src; SMBUrl dst; int errNum = 0; int retVal = 0; qCDebug(KIO_SMB) << "old name = " << ksrc << ", new name = " << kdest; src = ksrc; dst = kdest; // Check to se if the destination exists qCDebug(KIO_SMB) << "stat dst"; errNum = cache_stat(dst, &st); if( errNum == 0 ) { if(S_ISDIR(st.st_mode)) { qCDebug(KIO_SMB) << "KIO::ERR_DIR_ALREADY_EXIST"; error( KIO::ERR_DIR_ALREADY_EXIST, dst.toDisplayString()); return; } if(!(flags & KIO::Overwrite)) { qCDebug(KIO_SMB) << "KIO::ERR_FILE_ALREADY_EXIST"; error( KIO::ERR_FILE_ALREADY_EXIST, dst.toDisplayString()); return; } } qCDebug(KIO_SMB ) << "smbc_rename " << src.toSmbcUrl() << " " << dst.toSmbcUrl(); retVal = smbc_rename(src.toSmbcUrl(), dst.toSmbcUrl()); if( retVal < 0 ){ errNum = errno; } else { errNum = 0; } if( retVal < 0 ) { qCDebug(KIO_SMB ) << "failed "; switch(errNum) { case ENOENT: errNum = cache_stat(src, &st); if( errNum != 0 ) { if(errNum == EACCES) { qCDebug(KIO_SMB) << "KIO::ERR_ACCESS_DENIED"; error(KIO::ERR_ACCESS_DENIED, src.toDisplayString()); } else { qCDebug(KIO_SMB) << "KIO::ERR_DOES_NOT_EXIST"; error(KIO::ERR_DOES_NOT_EXIST, src.toDisplayString()); } } break; case EACCES: case EPERM: qCDebug(KIO_SMB) << "KIO::ERR_ACCESS_DENIED"; error( KIO::ERR_ACCESS_DENIED, dst.toDisplayString() ); break; default: qCDebug(KIO_SMB) << "KIO::ERR_CANNOT_RENAME"; error( KIO::ERR_CANNOT_RENAME, src.toDisplayString() ); } qCDebug(KIO_SMB) << "exit with error"; return; } qCDebug(KIO_SMB ) << "everything fine\n"; finished(); }