📄 ftp.cc
字号:
cmd += dst.ascii(); return ftpSendCmd( cmd, '2' );}void Ftp::del( const KURL& url, bool isfile ){ QString path = url.path(); if (!m_bLoggedOn) { openConnection(); if (!m_bLoggedOn) { kdDebug(7102) << "Login failure, aborting" << endl; return; } } assert( m_bLoggedOn ); if ( !isfile ) { // When deleting a directory, we must exit from it first // The last command probably went into it (to stat it) QCString tmp = "cwd "; tmp += url.directory().ascii(); (void) ftpSendCmd( tmp, '2' ); // ignore errors } QCString cmd = isfile ? "DELE " : "RMD "; cmd += path.ascii(); if ( !ftpSendCmd( cmd, '2' ) ) error( ERR_CANNOT_DELETE, path ); else finished();}bool Ftp::ftpChmod( const QString & path, int permissions ){ assert( m_bLoggedOn ); QCString cmd = "SITE CHMOD "; char buf[10]; // we need to do bit AND 777 to get permissions, in case // we were sent a full mode (unlikely) sprintf(buf, "%o ", permissions & 511 ); cmd += buf; cmd += path.ascii(); return ftpSendCmd( cmd, '2' );}void Ftp::chmod( const KURL & url, int permissions ){ if (!m_bLoggedOn) { openConnection(); if (!m_bLoggedOn) { kdDebug(7102) << "Login failure, aborting" << endl; return; } } if ( !ftpChmod( url.path(), permissions ) ) error( ERR_CANNOT_CHMOD, url.path() ); else finished();}void Ftp::createUDSEntry( const QString & filename, FtpEntry * e, UDSEntry & entry, bool isDir ){ assert(entry.count() == 0); // by contract :-) UDSAtom atom; atom.m_uds = UDS_NAME; atom.m_str = filename; entry.append( atom ); atom.m_uds = UDS_SIZE; atom.m_long = e->size; entry.append( atom ); atom.m_uds = UDS_MODIFICATION_TIME; atom.m_long = e->date; entry.append( atom ); atom.m_uds = UDS_ACCESS; atom.m_long = e->access; entry.append( atom ); atom.m_uds = UDS_USER; atom.m_str = e->owner; entry.append( atom ); if ( !e->group.isEmpty() ) { atom.m_uds = UDS_GROUP; atom.m_str = e->group; entry.append( atom ); } if ( !e->link.isEmpty() ) { atom.m_uds = UDS_LINK_DEST; atom.m_str = e->link; entry.append( atom ); KMimeType::Ptr mime = KMimeType::findByURL( KURL(QString::fromLatin1("ftp://host/") + filename ) ); // Links on ftp sites are often links to dirs, and we have no way to check // that. Let's do like Netscape : assume dirs generally. // But we do this only when the mimetype can't be known from the filename. // --> we do better than Netscape :-) if ( mime->name() == KMimeType::defaultMimeType() ) { kdDebug() << "Setting guessed mime type to inode/directory for " << filename << endl; atom.m_uds = UDS_GUESSED_MIME_TYPE; atom.m_str = "inode/directory"; entry.append( atom ); isDir = true; } } atom.m_uds = UDS_FILE_TYPE; atom.m_long = isDir ? S_IFDIR : e->type; entry.append( atom ); /* atom.m_uds = UDS_ACCESS_TIME; atom.m_long = buff.st_atime; entry.append( atom ); atom.m_uds = UDS_CREATION_TIME; atom.m_long = buff.st_ctime; entry.append( atom ); */}void Ftp::stat( const KURL &url){ kdDebug(7102) << "Ftp::stat : path='" << url.path() << "'" << endl; QString path = QDir::cleanDirPath( url.path() ); if (!m_bLoggedOn) { openConnection(); if (!m_bLoggedOn) { kdDebug(7102) << "Login failure, aborting" << endl; return; } } kdDebug(7102) << "Ftp::stat : cleaned path='" << path << "'" << endl; // We can't stat root, but we know it's a dir. if ( path.isEmpty() || path == QString::fromLatin1("/") ) { UDSEntry entry; UDSAtom atom; atom.m_uds = KIO::UDS_NAME; atom.m_str = QString::null; entry.append( atom ); atom.m_uds = KIO::UDS_FILE_TYPE; atom.m_long = S_IFDIR; entry.append( atom ); atom.m_uds = KIO::UDS_ACCESS; atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; entry.append( atom ); atom.m_uds = KIO::UDS_USER; atom.m_str = "root"; entry.append( atom ); atom.m_uds = KIO::UDS_GROUP; entry.append( atom ); // no size statEntry( entry ); finished(); return; } KURL tempurl( url ); tempurl.setPath( path ); // take the clean one QString listarg; // = tempurl.directory(false /*keep trailing slash*/); QString parentDir; QString filename = tempurl.fileName(); ASSERT(!filename.isEmpty()); QString search = filename; bool isDir = false; // Try cwd into it, if it works it's a dir (and then we'll list the parent directory to get more info) // if it doesn't work, it's a file (and then we'll use dir filename) QCString tmp = "cwd "; tmp += path.latin1(); if ( !ftpSendCmd( tmp, '\0' /* no builtin response check */ ) ) { kdDebug(7102) << "stat: ftpSendCmd returned false" << endl; // error already emitted, if e.g. transmission failure return; } // TODO: if we're only interested in "file or directory", we should stop here if ( rspbuf[0] == '5' ) { // It is a file or it doesn't exist, try going to parent directory parentDir = tempurl.directory(false /*keep trailing slash*/); // With files we can do "LIST <filename>" to avoid listing the whole dir listarg = filename; } else { // --- New implementation: // Don't list the parent dir. Too slow, might not show it, etc. // Just return that it's a dir. UDSEntry entry; UDSAtom atom; atom.m_uds = KIO::UDS_NAME; atom.m_str = filename; entry.append( atom ); atom.m_uds = KIO::UDS_FILE_TYPE; atom.m_long = S_IFDIR; entry.append( atom ); atom.m_uds = KIO::UDS_ACCESS; atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; entry.append( atom ); // No clue about size, ownership, group, etc. statEntry(entry); finished(); return; // --- Old implementation:#if 0 // It's a dir, remember that // Reason: it could be a symlink to a dir, in which case ftpReadDir // in the parent dir will have no idea about that. But we know better. isDir = true; // If the dir starts with '.', we'll need '-a' to see it in the listing. if ( search[0] == '.' ) listarg = "-a"; parentDir = "..";#endif } // Now cwd the parent dir, to prepare for listing tmp = "cwd "; tmp += parentDir.latin1(); if ( !ftpSendCmd( tmp, '2' ) ) { kdDebug(7102) << "stat: Could not go to parent directory" << endl; // error already emitted return; } if( !ftpOpenCommand( "list", listarg, 'A', ERR_DOES_NOT_EXIST ) ) { kdError(7102) << "COULD NOT LIST" << endl; return; } dirfile = fdopen( sData, "r" ); if( !dirfile ) { error( ERR_DOES_NOT_EXIST, path ); return; } kdDebug(7102) << "Starting of list was ok" << endl; ASSERT( !search.isEmpty() && search != QString::fromLatin1("/") ); FtpEntry *e; bool bFound = false; KURL linkURL; while( ( e = ftpReadDir() ) ) { // We look for search or filename, since some servers (e.g. ftp.tuwien.ac.at) // return only the filename when doing "dir /full/path/to/file" if ( !bFound ) { if ( ( search == e->name || filename == e->name ) ) { if ( !filename.isEmpty() ) { bFound = true; UDSEntry entry; createUDSEntry( filename, e, entry, isDir ); statEntry( entry ); } } else if ( isDir && ( e->name == listarg || e->name+'/' == listarg ) ) { // Damn, the dir we're trying to list is in fact a symlink // Follow it and try again if ( e->link.isEmpty() ) kdWarning(7102) << "Got " << listarg << " as answer, but empty link !" << endl; else { linkURL = url; kdDebug() << "e->link=" << e->link << endl; if ( e->link[0] == '/' ) linkURL.setPath( e->link ); // Absolute link else { // Relative link (stat will take care of cleaning ../.. etc.) linkURL.setPath( listarg ); // this is what we were listing (the link) linkURL.setPath( linkURL.directory() ); // go up one dir linkURL.addPath( e->link ); // replace link by its destination kdDebug() << "linkURL now " << linkURL.prettyURL() << endl; } // Re-add the filename we're looking for linkURL.addPath( filename ); } bFound = true; } } kdDebug(7102) << e->name << endl; } (void) ftpCloseDir(); if ( !bFound ) { // Only do the 'hack' below if we want to download an existing file (i.e. when looking at the "source") // When e.g. uploading a file, we still need stat() to return "not found" // when the file doesn't exist. QString statSide = metaData(QString::fromLatin1("statSide")); kdDebug() << "Ftp::stat statSide=" << statSide << endl; if ( statSide == "source" ) { kdDebug() << "Not found, but assuming found, because some servers don't allow listing" << endl; // MS Server is incapable of handling "list <blah>" in a case insensitive way // But "retr <blah>" works. So lie in stat(), to get going... // // There's also the case of ftp://ftp2.3ddownloads.com/90380/linuxgames/loki/patches/ut/ut-patch-436.run // where listing permissions are denied, but downloading is still possible. UDSEntry entry; UDSAtom atom; atom.m_uds = KIO::UDS_NAME; atom.m_str = filename; entry.append( atom ); atom.m_uds = KIO::UDS_FILE_TYPE; atom.m_long = S_IFREG; entry.append( atom ); atom.m_uds = KIO::UDS_ACCESS; atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; entry.append( atom ); // No clue about size, ownership, group, etc. statEntry(entry); finished(); return; } error( ERR_DOES_NOT_EXIST, path ); return; } if ( !linkURL.isEmpty() ) { if ( linkURL == url || linkURL == tempurl ) { error( ERR_CYCLIC_LINK, linkURL.prettyURL() ); return; } stat( linkURL ); return; } kdDebug(7102) << "stat : finished successfully" << endl; finished();}void Ftp::listDir( const KURL &url ){ kdDebug(7102) << "Ftp::listDir " << url.prettyURL() << endl; if (!m_bLoggedOn) { openConnection(); if (!m_bLoggedOn) { kdDebug(7102) << "Login failure, aborting" << endl; return; } } QString path = url.path(); // No path specified ? if ( path.isEmpty() ) { KURL realURL; realURL.setProtocol( QString::fromLatin1("ftp") ); if ( m_user != FTP_LOGIN ) realURL.setUser( m_user ); // We set the password, so that we don't ask for it if it was given if ( m_pass != FTP_PASSWD ) realURL.setPass( m_pass ); realURL.setHost( m_host ); realURL.setPort( m_port ); if ( m_initialPath.isEmpty() ) m_initialPath = "/"; realURL.setPath( m_initialPath ); kdDebug(7102) << "REDIRECTION to " << realURL.prettyURL() << endl; redirection( realURL.url() ); path = m_initialPath; finished(); return; } kdDebug(7102) << "hunting for path '" << path << "'" << endl; if (!ftpOpenDir( path ) ) { if ( ftpSize( path, 'I' ) ) // is it a file ? { error( ERR_IS_FILE, path ); return; } // not sure which to emit //error( ERR_DOES_NOT_EXIST, path ); error( ERR_CANNOT_ENTER_DIRECTORY, path ); return; } UDSEntry entry; FtpEntry * e; while( ( e = ftpReadDir() ) ) { kdDebug(7102) << e->name << endl; ASSERT( !e->name.isEmpty() ); if ( !e->name.isEmpty() ) { //if ( S_ISDIR( (mode_t)e->type ) ) // kdDebug(7102) << "is a dir" << endl; //if ( !e->link.isEmpty() ) // kdDebug(7102) << "is a link to " << e->link << endl; entry.clear(); createUDSEntry( e->name, e, entry, false ); listEntry( entry, false ); } } listEntry( entry, true ); // ready (void) ftpCloseDir(); finished();}void Ftp::slave_status(){ kdDebug(7102) << "Got slave_status host = " << (m_host.ascii() ? m_host.ascii() : "[None]") << " [" << (m_bLoggedOn ? "Connected" : "Not connected") << "]" << endl; slaveStatus( m_host, m_bLoggedOn );}bool Ftp::ftpOpenDir( const QString & path ){ //QString path( _url.path(-1) ); // We try to change to this directory first to see whether it really is a directory. // (And also to follow symlinks) QCString tmp = "cwd "; tmp += ( !path.isEmpty() ) ? path.latin1() : "/"; if ( !ftpSendCmd( tmp, '2' ) ) { // We get '550', whether it's a file or doesn't exist... return false; } // Don't use the path in the list command: // We changed into this directory anyway ("cwd"), so it's enough just to send "list". // We use '-a' because the application MAY be interested in dot files. // The only way to really know would be to have a metadata flag for this... if( !ftpOpenCommand( "list -a", QString::null, 'A', ERR_CANNOT_ENTER_DIRECTORY ) ) { kdWarning(7102) << "Can't open for listing" << endl; return false; } dirfile = fdopen( sData, "r" ); if( !dirfile ) return false; kdDebug(7102) << "Starting of list was ok" << endl; return true;}FtpEntry *Ftp::ftpReadDir(){ char buffer[1024]; while( fgets( buffer, sizeof(buffer), dirfile ) != 0 ) { FtpEntry* e = ftpParseDir( buffer ); if ( e ) return e; } return 0L;}FtpEntry* Ftp::ftpParseDir( char* buffer ){ QString tmp; kdDebug() << "ftpParseDir " << buffer << endl; static FtpEntry de; const char *p_access, *p_junk, *p_owner, *p_group; const char *p_size, *p_date_1, *p_date_2, *p_date_3, *p_name; if ((p_access = strtok(buffer," ")) != 0) if ((p_junk = strtok(NULL," ")) != 0) if ((p_owner = strtok(NULL," ")) != 0) if ((p_group = strtok(NULL," ")) != 0) if ((p_size = strtok(NULL," ")) != 0) { // A special hack for "/dev". A listing may look like this: // crw-rw-rw- 1 root root 1, 5 Jun 29 1997 zero // So we just ignore the number in front of the ",". Ok, its a hack :-) if ( strchr( p_size, ',' ) != 0L ) { //kdDebug() << "Size contains a ',' -> reading size again (/dev hack)" << endl; if ((p_size = strtok(NULL," ")) == 0) return 0L; } // Check whether the size we just read was really the size // or a month (this happens when the server lists no group) // Test on sunsite.uio.no, for instance if ( !isdigit( *p_size ) ) { p_date_1 = p_size; p_size = p_group; p_group = 0; //kdDebug() << "Size didn't have a digit -> size=" << p_size << " date_1=" << p_date_1 << endl; } else { p_date_1 = strtok(NULL," "); //kdDebug() << "Size has a digit -> ok. p_date_1=" << p_date_1 << endl; } if ( p_date_1 != 0 ) if ((p_date_2 = strtok(NULL," ")) != 0) if ((p_date_3 = strtok(NULL," ")) != 0) if ((p_name = strtok(NULL,"\r\n")) != 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -