strcat_s参数、文件属性

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

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

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

 

二、文件属性FILE_ATTRIBUTE_ARCHIEVE与FILE_ATTRIBUTE_DIRECTORY:

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

#pragma once #define _CRT_SECURE_NO_WARNINGS // 禁用Visual Studio的安全警告 #include "../Public/simple_file_helper.h" #include <stdlib.h> #include <stdio.h> #include <io.h> #include <string.h> #include <stdint.h> // 添加intptr_t支持 #include <windows.h> /** * 文件复制函数 * 参数:src - 源文件路径,dest - 目标文件路径 * 返回值:true - 复制成功,false - 复制失败 */ int copy_file(const char* src, const char* dest) { char buf[512] = { 0 }; // 缓冲区,用于暂存读取的数据 size_t file_size = 0; // 记录每次读取的字节数 FILE* f_src = NULL; // 源文件指针 FILE* f_dest = NULL; // 目标文件指针 // 以二进制只读模式打开源文件 if ((f_src = fopen(src, "rb")) != NULL) { // 以二进制写入模式打开目标文件 if ((f_dest = fopen(dest, "wb")) != NULL) { // 循环读取源文件内容 while ((file_size = fread(buf, sizeof(char), sizeof(buf), f_src)) > 0) { // 将缓冲区内容写入目标文件 size_t written = fwrite(buf, sizeof(char), file_size, f_dest); // 检查是否完整写入 if (written != file_size) { fclose(f_dest); fclose(f_src); return -1; } // 清空缓冲区 memset(buf, 0, sizeof(buf)); } // 成功复制后关闭文件 fclose(f_dest); fclose(f_src); return 0; } // 打开目标文件失败,关闭源文件 fclose(f_src); } // 源文件或目标文件打开失败 return -1; } typedef struct { int index; unsigned char paths[255][255]; // 10个路径,每个最长36字符 } defsting; // 递归当前目录所有文件 void find_files(char const* in_path, defsting* str) { struct _finddata_t finddata; intptr_t hfile = 0; // 修改为intptr_t(64位兼容) unsigned char tmp_path[255] = { 0 }; // 安全复制路径 strcpy_s(tmp_path, sizeof(tmp_path), in_path); strcat_s(tmp_path, sizeof(tmp_path), "\\*"); if ((hfile = _findfirst(tmp_path, &finddata)) != -1) { do { if (finddata.attrib & _A_SUBDIR) { // 如何是隐藏文件 if (strcmp(finddata.name, ".") == 0 || strcmp(finddata.name, "..") == 0) { // 就跳过 continue; } unsigned char new_path[255] = { 0 }; // 安全拼接路径 strcpy_s(new_path, sizeof(new_path), in_path); strcat_s(new_path, sizeof(new_path), "\\"); strcat_s(new_path, sizeof(new_path), finddata.name); str->index++; // 递归,文件调文件 find_files(new_path, str); } else { // 检查索引是否越界 if (str->index >= 255) { printf("警告:达到最大文件数限制\n"); break; } // 检查总路径长度 int total_len = strlen(in_path) + 1 + strlen(finddata.name) + 1; if (total_len >= sizeof(str->paths[str->index])) { printf("路径过长已跳过: %s\\%s\n", in_path, finddata.name); continue; } // 安全拼接路径 strcpy_s(str->paths[str->index], sizeof(str->paths[str->index]), in_path); strcat_s(str->paths[str->index], sizeof(str->paths[str->index]), "\\"); strcat_s(str->paths[str->index], sizeof(str->paths[str->index]), finddata.name); str->index++; } } while (_findnext(hfile, &finddata) == 0); _findclose(hfile); } } 如已经引入的 #include <string.h> 但还是报错:strcpy_s 还有2个重载,没有与参数列表匹配的重载函数
最新发布
11-30
帮我阅读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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值