配套代码笔记仓库。目录目录文件系统目录和文件系统数据文件和信息进程环境main函数进程的终止命令行参数的分析环境变量C程序的存储空间布局库函数之间正常的跳转资源的获取及控制文件系统类ls的实现,如myls -l -a -i -ncmd --长格式 -短格式 非选项的传参目录和文件获取文件属性/** * 将文件的属性存储到buf中 * stat : 通过文件路径获取属性,面对符号链接文件时, * 获取的是指向的目标文件的属性 * fstat: 通过文件描述符获取属性 * lstat: 通过文件路径获取属性,面对符号链接文件时, */ int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct stat *buf); struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ // 文件唯一标识,身份证号 mode_t st_mode; /* protection */ // st_mode: 文件权限+文件类型 // 文件权限 // 七种文件类型:dcb-lsp nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ // 在linux下,与windows不同,size值仅仅是属性 // 不能实际体现占用磁盘大小,详见 big.c blksize_t st_blksize; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ };文件访问权限st_mode是一个16位的二进制数,文件类型,文件权限,特殊权限。umask作用:防止产生权限过松的文件。0666 &~umaskumask也是一个终端命令,可以查看和设置。mode_t umask(mode_t mask);文件权限的更改/管理/** * 更改文件权限 */ int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode);粘住位t位,例如/tmp目录。文件系统:FAT, UFS文件或数据的存储格式。FAT:静态存储的单链表struct node_st{ int next[N]; char data[N][SIZE]; };UFS: 缺点:不善于处理大量的小文件,因为每个文件都有一个inode,占用空间。面试题:不用比较,比较两个uint32_t的大小使用位图硬链接,符号链接硬链接ln bigfile bigfile_link与目录项是同义词相当于目录项又弄了一份,使用ls -i可以看到inode号相同。限制:不能给分区建立,不能给目录建立符号链接ln -s bigfile_link bigfile_s优点:可以跨分区,可以给目录建立int link(const char *oldpath, const char *newpath); /** * 只有没有引用的数据才会真正删除 * 可以利用这一点创建匿名文件 */ int unlink(const char *pathname); int remove(const char *pathname); /** * 改变文件的路径或者名字 */ int rename(const char *oldpath, const char *newpath);utime/** * 更改文件最后读/写的时间 */ int utime(const char *filename, const struct utimbuf *times); struct utimbuf { time_t actime; /* access time */ time_t modtime; /* modification time */ }; struct time_t { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ };目录的创建和销毁mkdir, rmdirint mkdir(const char *pathname, mode_t mode); /** * 只有目录为空才能删除 */ int rmdir(const char *pathname);更改当前工作路径cd, pwd/** * 改变当前工作路径 * 可以突破假根目录 * 但是不能突破chroot */ int chdir(const char *path); int fchdir(int fd); /** * 获取当前工作路径 */ long getcwd(char *buf, unsigned long size);分析目录/读取目录内容/** * 法一 * 解析模式/通配符 * * @prarm: pattern 匹配模式 * @prarm: flags 匹配标志 * @prarm: errfunc 错误回调函数 * @prarm: pglob 匹配结果 * * @return 匹配的文件数量 */ int glob(const char *restrict pattern, int flags, int (*errfunc)(const char *epath, int eerrno), glob_t *restrict pglob); /** * 释放glob_t结构体 */ void globfree(glob_t *pglob); /** * 与argc, argv类似 */ typedef struct { size_t gl_pathc; /* Count of paths matched so far */ char **gl_pathv; /* List of matched pathnames */ size_t gl_offs; /* Slots to reserve in gl_pathv */ } glob_t; /** * 法二 */ /** * 打开一个目录 * 返回一个指向DIR结构体的指针 * 是堆区,需要 closedir 释放 */ DIR *opendir(const char *name); DIR *fdopendir(int fd); /** * 关闭一个目录 */ int closedir(DIR *dirp); /** * 读取一个目录 * * 返回指针指向静态区 */ struct dirent *readdir(DIR *dirp); int readdir_r(DIR *restrict dirp, struct dirent *restrict entry, struct dirent **restrict result); struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all file system types */ char d_name[256]; /* filename */ }; /** * 重置一个目录 */ void rewinddir(DIR *dirp); void seekdir(DIR *dirp, long offset); long telldir(DIR *dirp); /** * du 命令 * 以字节为单位,统计目录下所有文件的大小 * */ 作业:用另一套函数实现mydu系统数据文件和信息不同环境可能有区别,以具体查询为准,这里以Linux为例/etc/passwd/** * 通过用户名获取用户信息 */ struct passwd *getpwuid(uid_t uid); /** * 通过用户ID获取用户信息 */ struct passwd *getpwnam(const char *name); struct passwd { char *pw_name; /* username */ char *pw_passwd; /* user password */ uid_t pw_uid; /* user ID */ gid_t pw_gid; /* group ID */ char *pw_gecos; /* user information */ char *pw_dir; /* home directory */ char *pw_shell; /* shell program */ };/etc/group/** * 通过组ID获取组信息 */ struct group *getgrgid(gid_t gid); /** * 通过组名获取组信息 */ struct group *getgrnam(const char *name); struct group { char *gr_name; /* group name */ char *gr_passwd; /* group password */ gid_t gr_gid; /* group ID */ char **gr_mem; /* group members */ };/etc/shadowll显示root用户也不可读写,但是只有root用户才可读写这样是提醒你,即便是root用户,也不要随便读写这个文件密码hash - 混淆,不可逆如果原串一样,hash值也一样防备管理员监守自盗加密 - 解密加密为了安全,攻击成本大于收益安全?穷举:口令随机校验(第一遍明明对了给你报错,让你连续两遍成功输入正确)推荐书籍:《应用密码学》/** * 获得用户的密码信息 */ struct *spwd getspnam(const char *name); /** * 加密密码 * * @prarm: key 密码 * @prarm: salt 盐 杂字串 * * 默认 md5 加密方式 */ char *crypt(const char *key, const char *salt); struct spwd { char *sp_namp; /* login name */ char *sp_pwdp; /* encrypted password */ long sp_lstchg; /* last change */ long sp_min; /* min days between changes */ long sp_max; /* max days between changes */ long sp_warn; /* warning days before password expires */ long sp_inact; /* days before account inactive */ long sp_expire; /* days since 1970-01-01 until account expires */ unsigned long sp_flag; /* reserved */ }; /** * 输入提示符 */ char *getpass(const char *prompt);时间戳机器喜欢大整数 time_t人类喜欢字符串 char *程序员喜欢结构体 struct tm/** * 从内核获取以秒为单位的一个时戳 * 从 UTC 1970年1月1日0时0分0秒 到现在的秒数 */ time_t time(time_t *t); // eg: 两种用法 time_t stamp; time(&stamp); stamp=time(NULL); /** * 将时间戳转换为结构体 */ struct tm *gmtime(const time_t *timep); struct tm *localtime(const time_t *timep); sturct tm { int tm_sec; /* seconds */ int tm_min; /* minutes */ int tm_hour; /* hours */ int tm_mday; /* day of the month */ int tm_mon; /* month */ int tm_year; /* year */ int tm_wday; /* day of the week */ int tm_yday; /* day in the year */ int tm_isdst; /* daylight saving time */ /* daylight 夏令时调整 */ }; /** * 将结构体转换为时间戳 * ! 没有 const,可能更改 tm */ time_t mktime(struct tm *tm); /** * 格式化输出时间 */ size_t strftime(char *s, size_t max, const char *format, const struct tm *tm); // eg strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);进程环境main函数int main(int argc, char *argv[]);进程的终止正常终止:从main函数返回调用exitvoid exit(int status);status & 0377 有符号的char -128~127调用_exit或者_Exit(系统调用)exit与_exit _Exit的区别_exit不执行atexit注册的函数,不刷新stdio缓冲区这样可以防止错误扩散最后一个线程从其启动例程返回最后一个线程调用了pthread_exit异常终止调用abort接到一个信号并终止最后一个线程对其取消请求作出响应/** * 注册一个函数,当进程终止时调用 * * 钩子函数:逆序执行 * 可以进行资源释放 */ int atexit(void (*function)(void));// 钩子函数命令行参数的分析#include <unistd.h> extern char *optarg; // 选项参数 // optind: 下一个要处理的参数的索引 extern int optind, opterr, optopt; int getopt(int argc, char *const argv[], const char *optstring); int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex);环境变量KEY = VALVE可以通过export命令查看char *getenv(const char *name); /* * change or add * * @prarm: overwrite 是否覆盖 * * 覆盖时是释放原来的空间,重新分配 */ int setenv(const char *name, const char *value, int overwrite); int unsetenv(const char *name); /* * 和getenv一样的作用,change or add * 用法不一样,且没有const修饰 */ int putenv(char *string);C程序的存储空间布局pmap命令,查看进程空间布局库动态库静态库手工装载库void *dlopen(const char *filename, int flag); char *dlerror(void); int dlclose(void *handle); void *dlsym(void *handle, const char *symbol); // Link with -ldl函数之间正常的跳转goto无法跨函数跳转。/* * 设置跳转点 * * @return 0 说明是在设置跳转点 * @return 非0 说明是通过 longjmp 返回 */ int setjmp(jmp_buf env); /* * 跳转到跳转点 * * @prarm: env 跳转点 * @prarm: val 传递给 setjmp 的值 */ void longjmp(jmp_buf env, int val);资源的获取及控制ulimit -a// get/set resource limits int getrlimit(int resource, struct rlimit *rlim); int setrlimit(int resource, const struct rlimit *rlim); // 普通用户不能设置超过硬限制 // root 用户可以 升高/降低 硬限制 struct rlimit { rlim_t rlim_cur; /* soft limit */ rlim_t rlim_max; /* hard limit */ };