文件操作可是一个大的问题,因此这里采用各个击破,一个一个模块来分析。而其实文件操作也只是IO操作的一部分。
文件操作,必须得知道操作的文件是哪个撒,因此就有了文件路径,本文就先来看看apr中对文件的路径是怎么处理的。
在srclib\apr\include\arch\win32\apr_arch_file_io.h文件中定义了对路径的一些处理函数。
其中有两个比较不错的宏:
/* Win32 Exceptions:
*
* Note that trailing spaces and trailing periods are never recorded
* in the file system, except by a very obscure bug where any file
* that is created with a trailing space or period, followed by the
* ':' stream designator on an NTFS volume can never be accessed again.
* In other words, don't ever accept them when designating a stream!
*
* An interesting side effect is that two or three periods are both
* treated as the parent directory, although the fourth and on are
* not [strongly suggest all trailing periods are trimmed off, or
* down to two if there are no other characters.]
*
* Leading spaces and periods are accepted, however.
* The * ? < > codes all have wildcard side effects
* The " / \ : are exclusively component separator tokens
* The system doesn't accept | for any (known) purpose
* Oddly, \x7f _is_ acceptable ;)
*/
/* apr_c_is_fnchar[] maps Win32's file name and shell escape symbols
*
* element & 1 == valid file name character [excluding delimiters]
* element & 2 == character should be shell (caret) escaped from cmd.exe
*
* this must be in-sync with Apache httpd's gen_test_char.c for cgi escaping.
*/
const char apr_c_is_fnchar[256] =
{/* Reject all ctrl codes... Escape \n and \r (ascii 10 and 13) */
0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
1,1,2,1,3,3,3,3,3,3,2,1,1,1,1,0, 1,1,1,1,1,1,1,1,1,1,0,3,2,1,2,2,
/* @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1,
/* ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ */
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,3,2,3,3,1,
/* High bit codes are accepted (subject to utf-8->Unicode xlation) */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
};
#define IS_FNCHAR(c) (apr_c_is_fnchar[(unsigned char)(c)] & 1)
#define IS_SHCHAR(c) ((apr_c_is_fnchar[(unsigned char)(c)] & 2) == 2)
大家都知道 在windows中 命令行 不接受路径中有空格等一些特殊的字符,这里就是判断下某个字符是不是可以被命令行接受的字符,而且有些字符本身就是不能出现在文件路径中的,都是需要判断滴。
下面看下此文件中的第一个函数:
apr_status_t filepath_root_test(char *path, apr_pool_t *p)
{
apr_status_t rv;
rv = GetDriveType(path);
if (rv == DRIVE_UNKNOWN || rv == DRIVE_NO_ROOT_DIR)
return APR_EBADPATH;
return APR_SUCCESS;
}
此函数来获取路径中的驱动器类型,从而来判断路径的合法性,别传了一个根本就不存在滴路径,那就不好玩了。
在看接下来的两个函数
apr_status_t filepath_drive_get(char **rootpath, char drive,
apr_int32_t flags, apr_pool_t *p);
apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p);
这两个函数是对路径进行了一个转换,确保访问中路径正确性。
而后的
apr_status_t file_cleanup(void *);
是对文件操作的收尾工作,做了一些清理,不过这个清理,感觉挺好,把标准io句柄都设置了不可用的文件句柄,可谓彻底撒。
这个代码让我看到Apache中的严谨,和自己写代码的拙劣,自己都没有这么严格来判断和转换过程序中的路径,反正认为打开失败了系统会返回错误的,其实想想很多时候我都是想期待操作是成功的,Apache中的这样处理,可以接收好几种路径的写法,真可谓用心良苦!
apr_status_t file_cleanup(void *);