strcat_s参数、文件属性

本文探讨了strcat_s函数的正确使用方法及其第二个参数的实际含义,并深入剖析了FILE_ATTRIBUTE_ARCHIEVE与FILE_ATTRIBUTE_DIRECTORY属性在文件系统中的作用及可能引起的误判。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、strcat_s第二个参数的真实意义:

        用习惯了其它类似的安全字符串函数,总想当然的以为第二个参数也表示目的buffer的可用空间大小。其实它指的是目的缓存整个空间的大小!如果把这个意思理解反了,很容易导致程序“莫名其妙”的崩溃。因为该函数首先是检查你当前缓存中的字符串长度,如果该长度都已经大于第二个参数所“标识”的长度,则立马抛出异常并结束程序;

 

二、文件属性FILE_ATTRIBUTE_ARCHIEVE与FILE_ATTRIBUTE_DIRECTORY:

       这两个属性并非是不相容的。在平常看来,文档与文件夹应该是文件中两个相互独立的属性。即一个文件系统中的object如果不是文件夹则就是普通文件,只能是这二者当中的一个。其实不然,有时候文件夹也具有FILE_ATTRIBUTE_ARCHIEVE属性。这一点在遍历文件夹的时候需要特别留意。如果仅以FILE_ATTRIBUTE_ARCHIEVE属性来判断一个对象是否是普通文档,很可能就会把一个文件夹当作一个普通文档来处理从而会产生意想不到的异常。

帮我阅读httpd代码 void accept_request(void *arg) { //pthread_create传过来的参数(void *)(intptr_t)client_sock int client = (intptr_t)arg; char buf[1024]; /*size_t是标准C库中定义的,应为unsigned int,在64位系统中为 long unsigned int。数据类型"socklen_t"和int应该具有相同的长度, 否则就会破坏 BSD套接字层的填充。*/ size_t numchars; char method[255]; char url[255]; char path[512]; size_t i, j; /*在使用这个结构体和方法时,需要引入:<sys/types.h>、<sys/stat.h> struct stat这个结构体是用来描述一个linux系统文件系统中的文件属性 的结构。有两种方法获得一个文件的属性 第一种是通过路径有两个函数可以得到 int stat(const char *path, struct stat *struct_stat); int lstat(const char *path,struct stat *struct_stat); 两个函数的第一个参数都是文件的路径,第二个参数是struct stat的指针。 返回值为0,表示成功执行。执行失败是,error被自动设置对应值。 这两个方法区别在于stat没有处理字符链接(软链接)的能力, 如果一个文件是符号链接,stat会直接返回它所指向的文件的属性; 而lstat返回的就是这个符号链接的内容。 (符号连接就是软连接,软链接的内容就是一个字符串。这个字符串就是它所链接的文件的绝对路径或者相对路径) 第二种通过文件描述符 int fstat(int fdp, struct stat *struct_stat);   *通过文件描述符获取文件对应的属性。fdp为文件描述符 */ struct stat st; /*公共网关接口(Common Gateway Interface,CGI)是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能。CGI 应用程序能与浏览器进行交互,还可通过数据API与数据库服务器等外部数据源进行通信,从数据库服务器中获取数据。格式化为HTML文档后,发送给浏览器,也可以将从浏览器获得的数据放到数据库中。*/ int cgi = 0; /* becomes true if server decides this is a CGI * program */ char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; while (!ISspace(buf[i]) && (i < sizeof(method) - 1)) { method[i] = buf[i]; i++; } j=i; method[i] = '\0'; //#include <strings.h> int strcasecmp(cost char*s1,const char* s2); //若参数s1和s2字符串相等则返回0。s1大于s2则返回大于0 的值,s1 小于s2 则返回小于0的值。 if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return; } //get提交,提交的信息都显示在地址栏中。get提交,对于大数据不行,因为地址栏存储体积有限。 //post提交,提交的信息不显示地址栏中,显示在消息体中。post提交,可以提交大体积数据。 if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; while (ISspace(buf[j]) && (j < numchars)) j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < numchars)) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; //strcasecmp忽略大小写比较字符串 if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 0; *query_string = '\0'; query_string++; headers(client, path); while (*query_string != '=') query_string++; printf("%s\n", query_string); query_string++; search_mysql(client, query_string); return; } } sprintf(path, "htdocs%s", url); if (path[strlen(path) - 1] == '/') //extern char *strcat(char *dest, const char *src); //把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。 strcat(path, "indexall.html"); //stat返回值: 成功返回0,返回-1表示失败 if (stat(path, &st) == -1) { //strcmp不忽略大小写比较字符串 //一直用get_line读取文件,读到http头结束 while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); not_found(client); } //执行这一步代表读取到了这个文件 else { /* S_IFMT   0170000   文件类型的位遮罩   S_IFSOCK 0140000   套接字   S_IFLNK 0120000     符号连接   S_IFREG 0100000     一般文件   S_IFBLK 0060000     区块装置   S_IFDIR 0040000     目录   S_IFCHR 0020000     字符装置   S_IFIFO 0010000     先进先出 ​   S_ISUID 04000     文件的(set user-id on execution)位   S_ISGID 02000     文件的(set group-id on execution)位   S_ISVTX 01000     文件的sticky位 ​   S_IRUSR(S_IREAD) 00400     文件所有者具可读取权限   S_IWUSR(S_IWRITE)00200     文件所有者具可写入权限   S_IXUSR(S_IEXEC) 00100     文件所有者具可执行权限 ​   S_IRGRP 00040             用户组具可读取权限   S_IWGRP 00020             用户组具可写入权限   S_IXGRP 00010             用户组具可执行权限 ​   S_IROTH 00004             其他用户具可读取权限   S_IWOTH 00002             其他用户具可写入权限   S_IXOTH 00001             其他用户具可执行权限 */ //是否是文件夹 if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/myblog.html"); //文件所有者或文件所属组或其他人 具有可执行权限 if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; if (!cgi) //执行这一步代表这个文件存在,但是不能执行 //于是就换成读取文件内容再发送 serve_file(client, path); else execute_cgi(client, path, method, query_string); } close(client); }
最新发布
08-01
解释代码:void *accept_request(void* from_client) { int client = *(int *)from_client; char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { //提取其中的请求方式 method[i] = buf[j]; i++; j++; } method[i] = '\0'; if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return NULL; } if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; //GET请求url可能会带有?,有查询参数 if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; /* 如果有?表明是动态请求, 开启cgi */ if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } sprintf(path, "httpdocs%s", url); if (path[strlen(path) - 1] == '/') { strcat(path, "test.html"); } if (stat(path, &st) == -1) { while ((numchars > 0) && strcmp("\n", buf)) numchars = get_line(client, buf, sizeof(buf)); not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR)//S_IFDIR代表目录 //如果请求参数为目录, 自动打开test.html { strcat(path, "/test.html"); } //文件可执行 if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)) //S_IXUSR:文件所有者具可执行权限 //S_IXGRP:用户组具可执行权限 //S_IXOTH:其他用户具可读取权限 cgi = 1; if (!cgi) serve_file(client, path); else execute_cgi(client, path, method, query_string); } close(client); //printf("connection close....client: %d \n",client); return NULL; }
06-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值