//--------------------------------------------------------------------------- bool SMBSlave::browse_stat_path(const SMBUrl& _url, UDSEntry& udsentry, bool ignore_errors) // Returns: true on success, false on failure { SMBUrl url = _url; int cacheStatErr = cache_stat(url, &st); if(cacheStatErr == 0) { if(!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) { qCDebug(KIO_SMB) << "mode: "<< st.st_mode; warning(i18n("%1:\n" "Unknown file type, neither directory or file.", url.toDisplayString())); return false; } udsentry.insert(KIO::UDSEntry::UDS_FILE_TYPE, st.st_mode & S_IFMT); udsentry.insert(KIO::UDSEntry::UDS_SIZE, st.st_size); QString str; uid_t uid = st.st_uid; struct passwd *user = getpwuid( uid ); if ( user ) str = user->pw_name; else str = QString::number( uid ); udsentry.insert(KIO::UDSEntry::UDS_USER, str); gid_t gid = st.st_gid; struct group *grp = getgrgid( gid ); if ( grp ) str = grp->gr_name; else str = QString::number( gid ); udsentry.insert(KIO::UDSEntry::UDS_GROUP, str); udsentry.insert(KIO::UDSEntry::UDS_ACCESS, st.st_mode & 07777); udsentry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, st.st_mtime); udsentry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, st.st_atime); // No, st_ctime is not UDS_CREATION_TIME... } else { if (!ignore_errors) { if (cacheStatErr == EPERM || cacheStatErr == EACCES) if (checkPassword(url)) { redirection( url ); return false; } reportError(url, cacheStatErr); } else if (cacheStatErr == ENOENT || cacheStatErr == ENOTDIR) { warning(i18n("File does not exist: %1", url.url())); } qCDebug(KIO_SMB) << "ERROR!!"; return false; } return true; }
void SMBSlave::fileSystemFreeSpace(const QUrl& url) { qCDebug(KIO_SMB) << url; SMBUrl smbcUrl = url; int handle = smbc_opendir(smbcUrl.toSmbcUrl()); if (handle < 0) { error(KIO::ERR_COULD_NOT_STAT, url.url()); return; } struct statvfs dirStat; memset(&dirStat, 0, sizeof(struct statvfs)); int err = smbc_fstatvfs(handle, &dirStat); smbc_closedir(handle); if (err < 0) { error(KIO::ERR_COULD_NOT_STAT, url.url()); return; } KIO::filesize_t blockSize; if (dirStat.f_frsize != 0) { blockSize = dirStat.f_frsize; } else { blockSize = dirStat.f_bsize; } setMetaData("total", QString::number(blockSize * dirStat.f_blocks)); setMetaData("available", QString::number(blockSize * dirStat.f_bavail)); finished(); }
SMBUrl SMBUrl::partUrl() const { if (m_type == SMBURLTYPE_SHARE_OR_PATH && !fileName().isEmpty()) { SMBUrl url (*this); url.setFileName(fileName() + QLatin1String(".part")); return url; } return SMBUrl(); }
int SMBSlave::cache_stat(const SMBUrl &url, struct stat *st) { int result = smbc_stat(url.toSmbcUrl(), st); kdDebug(KIO_SMB) << "smbc_stat " << url << " " << errno << " " << result << endl; kdDebug(KIO_SMB) << "size " << (KIO::filesize_t)st->st_size << endl; return result; }
int SMBSlave::cache_stat(const SMBUrl &url, struct stat* st ) { int cacheStatErr; int result = smbc_stat( url.toSmbcUrl(), st); if (result == 0){ cacheStatErr = 0; } else { cacheStatErr = errno; } qCDebug(KIO_SMB) << "size " << (KIO::filesize_t)st->st_size; return cacheStatErr; }
//=========================================================================== void SMBSlave::get( const KURL& kurl ) { char buf[MAX_XFER_BUF_SIZE]; int filefd = 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; kdDebug(KIO_SMB) << "SMBSlave::get on " << kurl << endl; // 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; if(cache_stat(url,&st) == -1 ) { if ( errno == 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) { if(buf) { 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.setRawData(buf,bytesread); if (isFirstPacket) { // We need a KMimeType::findByNameAndContent(filename,data) // For now we do: find by extension, and if not found (or extension not reliable) // then find by content. bool accurate = false; KMimeType::Ptr mime = KMimeType::findByURL( kurl, st.st_mode, false, true, &accurate ); if ( !mime || mime->name() == KMimeType::defaultMimeType() || !accurate ) { KMimeType::Ptr p_mimeType = KMimeType::findByContent(filedata); if ( p_mimeType && p_mimeType->name() != KMimeType::defaultMimeType() ) mime = p_mimeType; } mimeType(mime->name()); isFirstPacket = false; } data( filedata ); filedata.resetRawData(buf,bytesread); // 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(); }
//--------------------------------------------------------------------------- bool SMBSlave::browse_stat_path(const SMBUrl &_url, UDSEntry &udsentry, bool ignore_errors) // Returns: true on success, false on failure { UDSAtom udsatom; SMBUrl url = _url; if(cache_stat(url, &st) == 0) { if(!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) { kdDebug(KIO_SMB) << "SMBSlave::browse_stat_path mode: " << st.st_mode << endl; warning(i18n("%1:\n" "Unknown file type, neither directory or file.") .arg(url.prettyURL())); return false; } udsatom.m_uds = KIO::UDS_FILE_TYPE; udsatom.m_long = st.st_mode & S_IFMT; udsentry.append(udsatom); udsatom.m_uds = KIO::UDS_SIZE; udsatom.m_long = st.st_size; udsentry.append(udsatom); udsatom.m_uds = KIO::UDS_USER; uid_t uid = st.st_uid; struct passwd *user = getpwuid(uid); if(user) udsatom.m_str = user->pw_name; else udsatom.m_str = QString::number(uid); udsentry.append(udsatom); udsatom.m_uds = KIO::UDS_GROUP; gid_t gid = st.st_gid; struct group *grp = getgrgid(gid); if(grp) udsatom.m_str = grp->gr_name; else udsatom.m_str = QString::number(gid); udsentry.append(udsatom); udsatom.m_uds = KIO::UDS_ACCESS; udsatom.m_long = st.st_mode & 07777; udsentry.append(udsatom); udsatom.m_uds = UDS_MODIFICATION_TIME; udsatom.m_long = st.st_mtime; udsentry.append(udsatom); udsatom.m_uds = UDS_ACCESS_TIME; udsatom.m_long = st.st_atime; udsentry.append(udsatom); udsatom.m_uds = UDS_CREATION_TIME; udsatom.m_long = st.st_ctime; udsentry.append(udsatom); } else { if(!ignore_errors) { if(errno == EPERM || errno == EACCES) if(checkPassword(url)) { redirection(url); return false; } reportError(url); } else if(errno == ENOENT || errno == ENOTDIR) { warning(i18n("File does not exist: %1").arg(url.url())); } kdDebug(KIO_SMB) << "SMBSlave::browse_stat_path ERROR!!" << endl; return false; } return true; }
void SMBSlave::reportError(const SMBUrl &url) { kdDebug(KIO_SMB) << "reportError " << url << " " << perror << endl; switch(errno) { case ENOENT: if(url.getType() == SMBURLTYPE_ENTIRE_NETWORK) error(ERR_SLAVE_DEFINED, i18n("Unable to find any workgroups in your local network. This might be caused by an enabled firewall.")); else error(ERR_DOES_NOT_EXIST, url.prettyURL()); break; #ifdef ENOMEDIUM case ENOMEDIUM: error(ERR_SLAVE_DEFINED, i18n("No media in device for %1").arg(url.prettyURL())); break; #endif #ifdef EHOSTDOWN case EHOSTDOWN: #endif case ECONNREFUSED: error(ERR_SLAVE_DEFINED, i18n("Could not connect to host for %1").arg(url.prettyURL())); break; case ENOTDIR: error(ERR_CANNOT_ENTER_DIRECTORY, url.prettyURL()); break; case EFAULT: case EINVAL: error(ERR_DOES_NOT_EXIST, url.prettyURL()); break; case EPERM: case EACCES: error(ERR_ACCESS_DENIED, url.prettyURL()); break; case EIO: case ENETUNREACH: if(url.getType() == SMBURLTYPE_ENTIRE_NETWORK || url.getType() == SMBURLTYPE_WORKGROUP_OR_SERVER) error(ERR_SLAVE_DEFINED, i18n("Error while connecting to server responsible for %1").arg(url.prettyURL())); else error(ERR_CONNECTION_BROKEN, url.prettyURL()); break; case ENOMEM: error(ERR_OUT_OF_MEMORY, url.prettyURL()); break; case ENODEV: error(ERR_SLAVE_DEFINED, i18n("Share could not be found on given server")); break; case EBADF: error(ERR_INTERNAL, i18n("BAD File descriptor")); break; case ETIMEDOUT: error(ERR_SERVER_TIMEOUT, url.host()); break; #ifdef ENOTUNIQ case ENOTUNIQ: error(ERR_SLAVE_DEFINED, i18n("The given name could not be resolved to a unique server. " "Make sure your network is setup without any name conflicts " "between names used by Windows and by UNIX name resolution.")); break; #endif case 0: // success error(ERR_INTERNAL, i18n("libsmbclient reported an error, but did not specify " "what the problem is. This might indicate a severe problem " "with your network - but also might indicate a problem with " "libsmbclient.\n" "If you want to help us, please provide a tcpdump of the " "network interface while you try to browse (be aware that " "it might contain private data, so do not post it if you are " "unsure about that - you can send it privately to the developers " "if they ask for it)")); break; default: error(ERR_INTERNAL, i18n("Unknown error condition in stat: %1").arg(QString::fromLocal8Bit(strerror(errno)))); } }
//=========================================================================== 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(); }
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::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<filesize_t>(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(); }