免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: duanjigang
打印 上一主题 下一主题

源码阅读第一期:axel和wget [复制链接]

论坛徽章:
0
51 [报告]
发表于 2011-09-29 11:32 |只看该作者
最基本的类型有:
(1):

  1. typedef struct
  2. {
  3.         void *next;
  4.         char text[MAX_STRING];
  5. } message_t;
复制代码
这个类型能表示很多数据结构,因为它本身是一个通用的链型存储数据结构定义。
我们可以看到

  1. typedef message_t url_t;
  2. typedef message_t if_t;
复制代码
URL列表可以用message_t来表示
网卡列表也可以用message_t来表示

(2):

  1. typedef struct
  2. {
  3.         char host[MAX_STRING];
  4.         char auth[MAX_STRING];
  5.         char request[MAX_QUERY];
  6.         char headers[MAX_QUERY];
  7.         int proto;                        /* FTP through HTTP proxies        */
  8.         int proxy;
  9.         long long int firstbyte;
  10.         long long int lastbyte;
  11.         int status;
  12.         int fd;
  13.         char *local_if;
  14. } http_t;
复制代码
表示http下载的一个对象

host:
        表示http下载服务器的主机名称
比如

  1. axel  http://en.newhua.com/down/mysql-5.5.15-win32.zip
复制代码
这个命令,在conn_set中,我们能看到代码段:

  1. strncpy( conn->host, url, MAX_STRING );
复制代码
在运行时,得到的host值为 (主机名 或者 主机名:端口值)
en.newhua.com
或者
en.newhua.com:82

auth:
为http验证信息,用来生成http头中的验证信息,其中user和pass都是根据你输入的URL地址来解析的
这个参考函数conn_set中的代码
比如输入以下命令:

  1. axel  http://test_user:test_pass@test_host:80/down/mysql-5.5.15-win32.zip
复制代码
这时,axel就会从URL的'/'以前去解析主机地址,端口,用户名和密码
这样,在函数http_connect中拼接成的auth信息就是

  1. snprintf( auth, MAX_STRING, "%s:%s", user, pass );
复制代码
得到为

  1. test_user:test_pass
复制代码
然后经过base64编码后存入http的头信息中.
request:
http请求的请求缓冲区
关于http协议的请求和响应的知识,可以参考文章:
http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html
在http.c中的函数http_addheader
中,添加打印语句

  1. printf ("===request=%s\n", conn->request);
复制代码
则每次调用http_addheader后都会打印http请求的内容,我们可以看到:

  1. ===request=GET /down/mysql-5.5.15-win32.zip HTTP/1.0
  2. Host: en.newhua.com
  3. Range: bytes=21019046-28025394
  4. User-Agent: Axel 2.4 (Linux)
复制代码
另外,axel支持以 -H x方式添加http头来运行。我们如下测试:

  1. ./axel  -H test_header1:header1 -H test_header2:header2  http://en.newhua.com/down/mysql-5.5.15-win32.zip
复制代码
讲能够看到添加到http的Request中的内容:

  1. ===request=GET /down/mysql-5.5.15-win32.zip HTTP/1.0
  2. Host: en.newhua.com
  3. Range: bytes=15061273-21019045
  4. User-Agent: Axel 2.4 (Linux)
  5. test_header1:header1
  6. test_header2:header2
复制代码
后两行是我们添加的自定义http消息中的header内容

header:
        axel中用来存储http响应消息的缓冲区,.
        第一,存储正常的http响应消息,第二:存储http请求出错时的错误信息。
        还有,就是存储从输入的URL中解析后的参数。
        在http.c和conn.c中使用较多。

proto:
        存储协议 HTTP 或者FTP
proxy:
        是否使用代理的开关

firstbyte和lastbyte:
下载的起始偏移和结束偏移,指定一个下载范围.(因为是多连接下载,因此每个连接都要分配一个下载范围的)
status:
http每次请求的返回码

fd:
该http对应的连接的写文件的文件描述符.

local_if:
        绑定的本地IP。

论坛徽章:
0
52 [报告]
发表于 2011-09-29 11:37 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-09-29 13:15 编辑

看来版主读代码很熟练,我弱弱的写出点。wget的一些代码理解
首先是用工具分析。当然我没有一下子就看出代码整体能力的本事,虽然内核代码看了不少,但是这还是有区别的。though wget 我只用过下载.......
不废话了。
  1. calltree -gb -np -m *.c |more
复制代码

  1. main [test.c:71]:
  2. |   DEBUGP
  3. |   HYPHENP
  4. |   S_ISREG
  5. |   _
  6. |   _fileno
  7. |   _setmode
  8. |   all_tests [test.c:53]
  9. |   |   mu_run_test
  10. |   .......
复制代码
这个all_tests实在是可怕,不停的检查。。。。。。应用程序是从main开始的,所以这就是全部程序的开始,由它不停的生长,直至吃掉所有文件的定义和函数。

  1. 52 all_tests()
  2. 53 {
  3. 54   mu_run_test (test_parse_content_disposition); /*解析路径内容*/
  4. 55   mu_run_test (test_subdir_p);
  5. 56   mu_run_test (test_dir_matches_p);
  6. 57   mu_run_test (test_commands_sorted);
  7. 58   mu_run_test (test_cmd_spec_restrict_file_names);
  8. 59   mu_run_test (test_path_simplify);
  9. 60   mu_run_test (test_append_uri_pathel);
  10. 61   mu_run_test (test_are_urls_equal);
  11. 62   mu_run_test (test_is_robots_txt_url);
  12. 63
  13. 64   return NULL;
  14. 65 }
复制代码
test_parse_content_disposition( )_____------>______extract_param( ) /*解析网站路径。包括处理=前面的部分,和后面的。 */
分析路径时,用到数据结构

  1. typedef struct {
  2.     /*A token consists of characters in the[b, e) range.: 此标记包含两部分的字符串*/
  3.    const char *b, *e;  /*此指针指向的内容只读*/
  4. }param_token;  
复制代码
处理字符串时,使用了很有意思的一种用法,不得不说一下:
[code]   
/src/http.c
extract_param( )
{
.......
value->b = p;
while( *p && *p != separator) ++p;
value->e = p;
while (value->e != value->b && c_isspace (value->e[-1]))
        --value->e;
    if (*p == separator) ++p;
.........}
这个e[-1]一开始认为可能是错误的用法,但是此处e是指针类型,e[-1]并不会出现越界,因为这是___________________________
_|____|___|___|____|____|___|____| 、e指向不是个数组,所以根据指针运算,此会取道e前面元素。
         e___|
后面的value只是消除separator(分隔符)。这就是前面主要名称,和提取的区别,以=号作为分隔*/
>----------------------------------<

评分

参与人数 1可用积分 +5 收起 理由
duanjigang + 5 加油,鼓励!

查看全部评分

论坛徽章:
0
53 [报告]
发表于 2011-09-29 12:01 |只看该作者
本帖最后由 duanjigang 于 2011-09-29 12:05 编辑

(3):

  1. typedef struct
  2. {
  3.         char cwd[MAX_STRING];
  4.         char *message;
  5.         int status;
  6.         int fd;
  7.         int data_fd;
  8.         int ftp_mode;
  9.         char *local_if;
  10. } ftp_t;
复制代码
表示ftp下载的对象

cwd:
改变当前工作目录时,用来存储目录的缓冲区
message:

用来存储FTP操作的相关信息,比如错误信息,FTP服务器的返回信息等。
status:
存储ftp操作的返回码

fd:
类似于http中的,写文件的文件描述符

data_fd:
        FTP传输数据时,打开数据通道的socket描述符
local_if:
        绑定本地的IP地址
ftp_mode:
        FTP传输模式,在axel中采用被动模式,正如作者在代码中说明的那样,只支持被动模式,这样简单。
        为何简单,因为采用被动模式传输的话,ftp客户端(也就是我们的Axel)不是数据传输端口的监听者,而把这些工作交给ftp服务器去做,axel需要做的仅仅是向ftp服务器发送PASSIV命令,然后从返回中解析数据端口,最后,直接connect服务器的数据端口进行read就行了。
关于ftp的被动和主动模式,下面是从文章
http://www.cnblogs.com/zhouqianh ... /02/15/1955353.html
中复制的一段描述:   (更详细的支持请参考FTP协议的RFC)
在主动模式下,FTP客户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,然后开放N+1号端口进行监听,并向服务器发出PORT N+1命令。服务器接收到命令后,会用其本地的FTP数据端口(通常是20)来连接客户端指定的端口N+1,进行数据传输。
    在被动模式下,FTP库户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,同时会开启N+1号端口。然后向服务器发送PASV命令,通 知服务器自己处于被动模式。服务器收到命令后,会开放一个大于1024的端口P进行监听,然后用PORT P命令通知客户端,自己的数据端口是P。客户端收到命令后,会通过N+1号端口连接服务器的端口P,然后在两个端口之间进行数据传输

论坛徽章:
1
双子座
日期:2013-11-06 17:18:01
54 [报告]
发表于 2011-09-29 13:30 |只看该作者
回复 47# duanjigang


    请问你这样的图是用什么画的

论坛徽章:
0
55 [报告]
发表于 2011-09-29 13:36 |只看该作者
回复  duanjigang


    请问你这样的图是用什么画的
seufy88 发表于 2011-09-29 13:30



    visio,呵呵,graphvip没搞懂

论坛徽章:
0
56 [报告]
发表于 2011-09-29 13:55 |只看该作者
modify_param_name(param_token *name)_______________-------------->


  1. /* extract_param extracts the parameter name into NAME.
  2. 977    However, if the parameter name is in RFC2231 format then
  3. 978    this function adjusts NAME by stripping of the trailing
  4. 979    characters that are not part of the name but are present to
  5. 980    indicate the presence of encoding information in the value
  6. 981    or a fragment of a long parameter value
  7. 982 */
  8. 如果exract_param()提取变量的名称放入NAME,但是如果变量是RFC2331格式,那么这个函数就以删除到不是名字的那些尾随部分,这些部分用来表明是编码信息的,此信息在一个很长的变量直中。
  9. modify_param_name()
  10. {
  11.    const char *delim1 = memchr (name->b, '*', name->e - name->b);
  12.    const char *delim2 = memrchr (name->b, '*', name->e - name->b); /*这两个得做个判定:
  13. -------> /lib/string.in.h*/
  14. 是c++或者c库
  15. .........

  16. 最后调用 _GL_EXTERN_C int _gl_cxxalias_dummy,看字面的意思就是extern c.
  17. 这里函数这么做的意思就是查看编码方式。有RFC_2331.
  18. }
  19. 返回后,如果根据不同的编码方式来判断是否再次调整*/
  20. <-----________
  21. exract_param()中
  22. if (NOT_RFC2331 != param_type)
  23. {
  24.    modify_param_value(value, param_type);  /*说明不是NOT_RFC2331编码方式,再次矫正*/
  25. }
  26. ____________------------>
  27. [code]
  28. modify_param_value( )  /*这里就说明就是RFC_2331格式了*/
  29. {
  30.   .....
  31.   *delim - memrch(value->b, '\', value->e - value->b);
  32.    ......
  33. }格式真特殊,这可能就是将其他字符转义
复制代码

论坛徽章:
0
57 [报告]
发表于 2011-09-29 14:33 |只看该作者
axel-2.4
ansic:         2377 (90.79%)
sh:             203 (7.75%)
python:          38 (1.45%)


curl-7.22.0
ansic:        86789 (80.99%)
sh:           11919 (11.12%)
perl:          8081 (7.54%)
cpp:            179 (0.17%)
pascal:         112 (0.10%)
awk:             48 (0.04%)
lisp:            33 (0.03%)


wget-1.13
ansic:        35615 (76.41%)
sh:            5686 (12.20%)
perl:          5140 (11.03%)
lex:            139 (0.30%)
sed:             31 (0.07%)



挑战一下代码量最大的curl

论坛徽章:
0
58 [报告]
发表于 2011-09-29 14:58 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-09-29 15:43 编辑

<---------------__________________
返回到
parse_content_disposion()
{
   int isFilename = BOUNDED_EQUAL_NO_CASE ( name.b, name.e, "filename" );/*判断是否是个文件名*/

_____________------------------> D (define) /*wget-1.13/src/wget.h*/

  这里才恍然过来,远来的test的作用就是这样.......,前面安排了很多路径,
#define BOUNDED_EQUAL_NO_CASE (beg , end, string_literal)
   ((end) - (beg) == sizeof(string_literal) -1 && ! strncasecmp (beg, string_literal, sizeof(string_literal) -1 ))
__________________________--------------------------->
/*src/cmpt.c*/
int strncasecmp(const char *s1, const char *s2, size_t)
{
      ......
     do{
     c1 = c_tolower(*p1++);
     c2 = c_tolower(*p2++);
     if (c1 == '\0' | | c1 != c2) /*如果c1中出现'\0',或者c1 != c2,这句话有意思。
          return c1 - c2;  就返回c1 - c2;/*一般只有test中第一个字符串会成功,返回为0*/
       }while(--n > 0);
   return c1 - c2;
}
前面的memrchr( )

#include <string.h>
void *memchr(const void *s, int c, size_t n);

void *memrchr(const void *s, int c, size_t n);
Description
The memchr() function scans the first n bytes of the memory area pointed to by s for the character c. The first byte to match c (interpreted as an unsigned character) stops the operation.

The memrchr() function is like the memchr() function, except that it searches backwards from the end of the n bytes pointed to by s instead of forwards from the front.
Return Value
The memchr() and memrchr() functions return a pointer to the matching byte or NULL if the character does not occur in the given memory area.




<-------------__________

  1. 回到
  2.       parse_content_disposion()  
  3. {
  4.     .......
  5.     else
  6.      *filename = strdupdelim(value.b, value.e)/*__________------------->src/utils.c */

  7. char *strdupdelim(const char * beg, const char *end)
  8. {  
  9.     char *res = xmalloc(end - beg + 1);  _____________----------------->/*lib/xmalloc.c*/
  10.     memcpy(res, beg, end - beg);
  11.     res[end - beg] = '\0'
  12.     return res;
  13. }
  14. void * xmalloc(size_t n)
  15. {
  16.    void *p = malloc(n);
  17.    if (! p && n! = 0)
  18.      xalloc_die( );   ___________-------------->/* /lib/xalloc-die.c*/
  19.      return p;
  20. }
  21. void xalloc_die(void)
  22. {
  23.    error(exit_failure, 0, "%s", _(memory exhausted));
  24.   abort();  /*This is so familiar to me : )_________------------>*/
  25. }
复制代码

论坛徽章:
0
59 [报告]
发表于 2011-09-29 16:00 |只看该作者
[code]
<---------------____________
返回到
test_parse_constent_dipostion()  /*读到这里可以看出只是一个测试,某某编码格式的一种*/
{
mu_assert()      /*返回某个信息*/
}
__________------------>
/*src/test.h*/
#define  mu_assert(message, test) do{ if (!test)) return message; } while (0)
/*根据提供的实参,我们可以知道一次也不会返回错误的:理由是:如果返回res 为 false 那么 filename 和 test_array[i].name 是肯定不会相等的,如果是ture,更不用说*/

_____________________________________________________________________
返回到main
#define  mu_run_test (test) 定义在 /src/test.h
#define  mu_run_test(test) \
do{   \
   const  char *message ; \
   puts("RUNNING TEST " #test ". . .");  \
   message = test( );  \
   tests_run++;   \
   if (message ) return message ; \  /*这里message返回的是NULL,所以不会输出什么*/
   puts ("PASSED \n") ;   \
  } while ( 0 )
________________________________________________
mu_run_test (test_parse_content_disposition); 分析完毕  */

论坛徽章:
0
60 [报告]
发表于 2011-09-29 16:52 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-09-29 20:48 编辑

_____________________________________________________________________________________
第二个是 mu_test_test(test_subdir_p) _____--------------->
/* src/utils.c*/
[code]
test_subdir_p()
{
  
  .......
  subdir_p(const char *d1, const char * p2);/* In the same file */





______________________________________________
subdir_p()
{
   .....
   if ( ! opt.ignore_case) /*这个数据结构剖析下_________--------> /src/options*/
  ......
}
/*这个函数比较简单*/
__________________________________________________
struct  options opt;  /*选项*/

struct options{
int verbose ;  /*Are we verbose? 显示详细?初次设置为 -1*/
bool quiet;    /*Are we quite? */
int ntry ;  /*Number of tries per URL*/
bool retry_connrefused ; /*对待连接拒绝为非致命*/
bool background;  /*是否后台工作*/
bool ignore_length /*是否内容长度是1时注意*/
bool recursive;   /*是否递归*/
bool spanhost  ; /*在递归时是否跨主机*/
int  max_redirect ;/*重定向最大次数*/
bool relative_only ;/* 只跟相对连接*/
bool no_parent;   /*重定向到父目录*/
int reclevel;   /*最大递归嵌套*/
bool  dirstruct; /*是否建立文件目录,当向前追溯目录时*/
int cut_dirs;   /*减去目录部分的数目*/
bool add_hostdir; /*是否加本地主机名目录*/
bool protocol_directories; /*是否在目录前加http/ftp*/
bool noclobber; /*不能破坏已存在数据*/
bool unlink;  /*在破坏文件前删除文件*/
char *dir_prefix; /*目录树最高层*/
char *lfilename; /*日志文件名*/
char *input_filename; /*输入文件名*/
char *choose_config; /*指定配置文件*/
char *force_html; /*输入的文件是HTML格式吗*/
char *default_page; /*默认文件*/
bool spider; /*Wget 是抓取模式吗*/
char **accepts ; /*可以接收的格式清单*/
char **reject; /*要拒绝的格式清单*/
char **excludes; /*FTP目录*/
char **include; /*需要继续进入的FTP目录清单*/
bool  ignore_case; /*是否需要当匹配目录和文件的情况*/
char **domains  /*______________---------->host.c*/
char **exclude_domains;  
bool  dns_cache;    /*是否cashe DNS 的查找*/
char **follow_tags ;/*递归进入的HTML标记*/
char **ignore_tags; /*如果递归忽略的HTML的标记*/
bool  follow_ftp ; /*FTP 的URL 是否递归检索*/
bool  retr_symlinks; /*是否检索在FTP中的符号连接*/
char *output_document; /*输出到可以打印的文件*/

char *user  ;  /*通用的用户名*/
char *passwd ; /*通用的密码*/
bool ask_passwd;/*是否要密码*/

bool  always_rest; /*经常用REST*/
char *ftp_user;  /*FTP 用户名*/
char *ftp_passwd; /*FTP 密码*/
bool netrc;   /*是否要读取.netrc文件  (FTP初始化文件.netrc)*/
bool  ftp_glob;  /*FTP 通配符*/
bool  ftp_pasv;  /*无源FTP?*/

char *http_user ; /*HTTP 用户名*/
char *http_passwd;  /*HTTP 密码*/
char **user_headers;  /*用户定义的头部*/
bool http_keep_alive; /*是否保持活跃*/

bool user_prox  ; /*是否使用代理*/
bool allow_cache ; /*是否允许服务器端cache*/
char *http_proxy, *ftp_proxy, *https_proxy;

char **no_proxy;
char *base_href;
char *progress_type ; /*程序指示类型*/
char *proxy_user;
char *proxy_passwd;

double read_timeout;  /*读写时间延迟*/
double dns_timeout;  /*DNS 延迟*/
doubel connct_timeout /*链接延迟*/

bool random_wait; /*随机延迟*/
double  wait; /*在两次检索之间的时间*/
double waitretry;/*两次重试之间时间*/
bool  use_robots /*是否注意robots.txt维基百科,自由的百科全书
robots.txt(统一小写)是一种存放于网站根目录下的ASCII编码的文本文件,它通常告诉网络搜索引擎的漫游器(又称网络蜘蛛),此网站中的哪些内容是不能被搜索引擎的漫游器获取的,哪些是可以被(漫游器)获取的。 因为一些系统中的URL是大小写敏感的,所以robots.txt的文件名应统一为小写。robots.txt应放置于网站的根目录下。如果想单独定义搜索引擎的漫游器访问子目录时的行为,那么可以将自定的设置合并到根目录下的robots.txt,或者使用robots元数据。
*/
wgint limit_rate; /*限制下载速率*/
SUM_SIZE_INT quota; /*最大下载和存储大小*/
bool  server_response; /*是否打印服务器回应*/
bool save_headers;  /*是否将头部和文件一起保存*/
#ifdef ENABLE_DEBUG  
bool debug; /*是否开启debug*/
#endif
#ifdef  USE_WAIT#@
bool wdebug; /*Watt-32 为WindowsNT 和 DOS准备 tcp/ip debug是否开启*/
#endif
bool  timestamping; /*时间戳*/
bool backup_converted; /*是否将预转换文件以.orig保存*/
bool backups; /*是否数字备份*/
                实在太多了,我不翻译了。。。。。。。。。。。。自己看吧
char *useragent;

char *referer;                /* Naughty Referer, which can be  set to something other     NULL. */
   bool convert_links;           /* Will the links be converted
                                    locally? */
  bool remove_listing;          /* Do we remove .listing files
                               generated by FTP? */
bool htmlify;                 /* Do we HTML-ify the OS-dependent
                                   listings? */
char *dot_style;
wgint dot_bytes;              /* How many bytes in a printing
                                    dot. */
int dots_in_line;             /* How many dots in one line. *    /
int dot_spacing;              /* How many dots between spacings. */
bool delete_after;            /* Whether the files will be deleted
after download. */

bool adjust_extension;                /* Use ".html" extension on all text/html? */

bool page_requisites;         /* Whether we need to download all files
171                                    necessary to display a page properly. */
172   char *bind_address;           /* What local IP address to bind to. */
173
174 #ifdef HAVE_SSL
175   enum {
176     secure_protocol_auto,
177     secure_protocol_sslv2,
178     secure_protocol_sslv3,
179     secure_protocol_tlsv1
180   } secure_protocol;            /* type of secure protocol to use. */
181   bool check_cert;              /* whether to validate the server's cert */
182   char *cert_file;              /* external client certificate to use. */
183   char *private_key;            /* private key file (if not internal). */
184   enum keyfile_type {
185     keyfile_pem,
186     keyfile_asn1
187   } cert_type;                  /* type of client certificate file */
188   enum keyfile_type
189     private_key_type;           /* type of private key file */
190
191   char *ca_directory;           /* CA directory (hash files) */
192   char *ca_cert;                /* CA certificate file to use */
193
194
195   char *random_file;            /* file with random data to seed the PRNG */
196   char *egd_file;               /* file name of the egd daemon socket */
197 #endif /* HAVE_SSL */
198
199   bool cookies;                 /* whether cookies are used. */
200   char *cookies_input;          /* file we're loading the cookies from. */
201   char *cookies_output;         /* file we're saving the cookies to. */
202   bool keep_session_cookies;    /* whether session cookies should be
203                                    saved and loaded. */
204
205   char *post_data;              /* POST query string */
206   char *post_file_name;         /* File to post */
207
208   enum {
209     restrict_unix,
210     restrict_windows
211   } restrict_files_os;          /* file name restriction ruleset. */
212   bool restrict_files_ctrl;     /* non-zero if control chars in URLs
213                                    are restricted from appearing in
214                                    generated file names. */
215   bool restrict_files_nonascii; /* non-zero if bytes with values greater
216                                    than 127 are restricted. */
217   enum {
218     restrict_no_case_restriction,
219     restrict_lowercase,
220     restrict_uppercase
221   } restrict_files_case;        /* file name case restriction. */
222
223   bool strict_comments;         /* whether strict SGML comments are
224                                    enforced.  */
225
226   bool preserve_perm;           /* whether remote permissions are used
227                                   or that what is set by umask. */
228
229 #ifdef ENABLE_IPV6
230   bool ipv4_only;               /* IPv4 connections have been requested. */
231   bool ipv6_only;               /* IPv4 connections have been requested. */
232 #endif
233   enum {
234     prefer_ipv4,
235     prefer_ipv6,
236     prefer_none
237   } prefer_family;              /* preferred address family when more
238                                    than one type is available */
239
240   bool content_disposition;     /* Honor HTTP Content-Disposition header. */
241   bool auth_without_challenge;  /* Issue Basic authentication creds without
242                                    waiting for a challenge. */
243
244   bool enable_iri;
245   char *encoding_remote;
246   char *locale;
247
248   bool trustservernames;
249 #ifdef __VMS
250   int ftp_stmlf;                /* Force Stream_LF format for binary FTP. 强行转化为二进制的FTP*/
251 #endif /* def __VMS */
252
253   bool useservertimestamps;     /* Update downloaded files' timestamps to
254                                    match those on server? */
255
256   bool show_all_dns_entries; /* Show all the DNS entries when resolving a
257                                 name. */
258 };
259
260 extern struct options opt;
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP