![]() |
![]() |
#1 |
高级会员
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 注册: 08年04月11日
来自: 盘丝洞
帖子: 311
声望力: 20
声望:
50
![]() 现金:29两梁山币
资产:1245两梁山币
致谢数: 0
获感谢文章数:0
获会员感谢数:0 |
MUD FTP 服务器的修缮(中)
作者:jjgod 发表时间:2001年4月15日 09:08 -------------------------------------------------------------------------------- 发信人: fof (格斗之迷~思考中), 信区: wiz 标 题: MUD FTP 服务器的修缮(中) 发信站: 交通大学思源BBS (Thu Nov 16 00:39:36 2000), 转信 毛病找到了,开始着手解决吧!先查找这些错误的格式是在哪里生成的。查找什么 呢?想想:我们给 FTP 服务器发送了 ls 命令,那么 FTP 服务器必定有接收这 个命令的程序。这里需要一点 FTP 方面的知识,就是当我们对着服务器敲 ls 命 令时,我们的程序向服务器发送的实际是 nlst 命令,ls -l 实际就是 nlst -l 了,而敲 dir 命令实际发送的是 list 命令,所以,我们应该在 FTP 服务器的 源程序 /adm/daemons/ftpd.c 中查找字符串 "nlst" 或字符串 "list",找到接 收 ls 和 dir 命令的入口。 在 UltraEdit 编辑器里一找,就能找到如下的程序段: …… case "size": // return size of file …… case "nlst": // give name list of files in directory ^^^^对 ls 命令的处理就在这里了 CHECK_LOGIN(); /* Send name list */ if ((i = sizeof(command)) > 1 && command[1] == "-l") { ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -l 参数就在这里了^^ if (i == 2) command[1] = "."; else command = ({ command[0] }) + command[2..s-1]; // and fall through to "list" } else { /* Used by commands like "dir", "mget", and "mput" */ if ( i > 1 ) tmp = get_path( fd, command[ 1 ] ); else tmp = socket_info[ fd ][ CWD ]; if ( check_valid_read( tmp, fd ) ) { tmp2 = ls( tmp, 1, fd ); ^^^^^^^^^^^^^^^^^^^^^^^注意这一行,调用了 ls() 函数,没错, ^^^^^^ ls() 函数就是用来从磁盘读取目录列表的,跟进去看看吧 if (tmp2 == "") socket_write( fd, "550 No files found.\n" ); else data_conn( fd, tmp2, "ls", STRING ); } else PERMISSION_DENIED550(command[ 1 ]); break; } case "list": // give list files in a directory ^^^^对 dir 命令的处理就在这里了 CHECK_LOGIN(); /* Send directory file list (like exec'ing "ls") */ if ( sizeof( command ) > 1 ) tmp = get_path( fd, command[ 1 ] ); else tmp = socket_info[ fd ][ CWD ]; if ( check_valid_read( tmp, fd ) ) { tmp2 = ls( tmp, 0, fd ); ^^^^^^^^^^^^^^^^^^^^^^这一行也调用了 ls() 函数,与前面不同之处 ^^^^^^^^^^^^ 是第二个参数,前面是 1 ,这里是 0 ,等会儿再研究它 if (tmp2 == "") socket_write( fd, "550 No files found.\n"); else data_conn( fd, tmp2, "ls", STRING ); } else PERMISSION_DENIED550(command[ 1 ]); break; case "xpwd": // print the current working directory (deprecated) …… 看看 ls() 函数的内容: string ls( string path, int column, int fd ) { string *files; int i, j, s; mixed *xfiles; mixed *stats; string tmp, tmp2, creator, domain; /* if path is a directory get contents */ if ( directory_exists( path ) ) { if ( path[ strlen( path ) - 1 ] == '/' ) path += "*"; else path += "/*"; } // 这个判断的意思是说如果 ls 的目标是一个目录,就在它的尾巴 // 加上个记号,确保它以 "/*" 结尾,在后面的程序中好跟文件区别 /* begin narrow columnar "nlst" */ if (column) { // 前面不是说了么,调用 ls() 函数的两个地方参数 // 不同,这里是处理参数为 1 的地方 files = get_dir( path ); ^^^^^^^^^^^^^^^^^^^^^^^瞧,开始读磁盘目录列表了 /* can only happen if permissions are messed up at account level */ if (!files) return ""; // 如果目录里什么都没有,那当然传回一个空串喽 files -= ({ ".", ".." }); // 去掉这两个多余的项 if (!(i = sizeof( files ))) return ""; /* no wild cards...must have been the exact pathname to a file */ if (strsrch(path, '*') == -1 && strsrch(path, '?') == -1) { return files[0] + "\n"; } // 前面加的目录尾巴记号 "/*" 在这里起作用了 /* remove globber at end of path, leave a trailing slash */ j = strsrch(path, '/', -1); path = path[0..j]; while ( i-- ) { /* scan next level down for files */ tmp = sprintf("%s%s/", path, files[i]); if ( directory_exists( tmp ) ) { files[i] += "/"; // 瞧,这里判断如果一个目录项是目录的话,就 } // 给它加上尾巴 "/" ,虽然好跟文件项区分,却 } // 是多余的 return implode( files, "\n" ) + "\n"; } 以下就是处理 ls() 的第二个参数为 0 的地方了,也就是要返回详细目录列表的地方。 /* begin long "list" */ // 详细列表的显示 xfiles = get_dir( path, -1 ); ^^^^^^^^^^^^^^^^^^^^^^^^^^^读取磁盘目录列表 if (!xfiles || !(s = sizeof( xfiles ))) return ""; files = allocate(s); // the Unix-like file permissions are mainly for effect...hopefully it // isn't too much, since anything more would likely be too cpu intensive // and cause it to max eval... creator = (string)MASTER_OB->creator_file(path); if (!creator) creator = ROOT_UID; domain = (string)MASTER_OB->domain_file(path); if (!domain) domain = ROOT_UID; 上面这一小段程序涉及 creater 和 domain ,指的是文件的所有权问题 i = strsrch(path, '/', -1); if (i >= 0) path = path[0..i]; for (i = 0; i < s; i++) { /* process timestamp */ tmp2 = ctime((xfiles[i])[2]); /* get last modified timestamp */ if ((xfiles[i])[2] + SECS_IN_YEAR < time()) { /* MMM DD YYYY */ tmp = sprintf("%s %s", tmp2[4..9], tmp2[20..23]); } else { /* MMM DD hh:mm */ tmp = tmp2[4..15]; } j = (xfiles[i])[1]; /* get filesize */ // 获取目录项的字节数 if (j == -2) { // 字节数为 -2 ,不是文件是目录 files[i] = sprintf("drwxrwsr-x %12s %12s <DIR> %12s %s/", creator, domain, tmp, (xfiles[i])[0]); !!^^^^^^^看看这一串目录格式定义,就是我们千辛万苦要找的东东了 } else { // 除了目录就是文件了 stats = stat(path + (xfiles[i])[0]); files[i] = sprintf("-rw%crw-r-- %12s %12s %8d %12s %s", stats[2] ? 'x' : '-', /* 'x' if loaded, else ' ' */ creator, domain, j, tmp, (xfiles[i])[0]); !!^^^^^^^这一串文件格式定义也不合标准 } } return sprintf( "%-#70s\n", implode( files, "\n" ) ); ^^^^最后,把“自定义格式”的目录项传回调用它的地方,最终传回客户端 } 至此可以告一段落了,MUD FTP 服务器传回的目录项格式不正确的根源已经找到 了,将这些格式稍作修改,使之“基本”符合标准就OK了(说“基本”是因为 我没有翻过关于 FTP 协议一系列标准的典籍,自己改的是否真的符合标准我也 不清楚,:-) 另外,CuteFTP 喜欢发 list -a -l 命令,多了个 -a 参数,也 得考虑进去的喔! 有兴趣的你大可一试,有什么新发现请务必告诉我,先谢过了! (未完待续) |
![]() |
![]() |
![]() ![]() |
添加到书签 |
|
|
![]() |
||||
主题 | 主题作者 | 论坛 | 回复 | 最后发表 |
MUD FTP服务器的修缮 | Odysseus | 『 巫师天下 』 | 0 | 2011-12-03 23:17 |
MUD FTP 服务器的修缮(上) | Odysseus | 『 巫师天下 』 | 0 | 2011-12-03 23:06 |
MUD FTP 服务器的修缮(下) | Odysseus | 『 巫师天下 』 | 0 | 2011-12-03 23:05 |
综合类FTP | sandman | 『 动漫影视下载专区 』 | 7 | 2004-10-22 21:59 |
勇FTP | Csheng | 『 动漫影视下载专区 』 | 6 | 2004-04-12 19:10 |