一、Xmind整理:
进程的五态图:
内存分布图:
注:栈区:存储局部变量,形参(上边打错了!!!)
虚拟内存和物理内存:
进程的STAT:
二、课上练习:
练习1:将课上的文件权限提取修改成循环方式
#include <stdio.h>
#include <head.h>
void get_filePermission(mode_t m)
{
//方法一:
/*
for(int i=0;i<9;i++)
{
if((m&(0400>>i))==0)
{
putchar('-');
continue;
}
//能运行到当前位置,则代表对应位置有权限
//需要判断是r w x当中的哪一个
switch(i%3)
{
case 0:putchar('r');break;
case 1:putchar('w');break;
case 2:putchar('x');break;
}
}
*/
//方法二:
char buf[]="rwx";
for(int i=0;i<9;i++)
{
if((m&(0400>>i))==0)
{
putchar('-');
continue;
}
printf("%c",buf[i%3]);
}
return;
}
int main(int argc, const char *argv[])
{
struct stat buf;
if(stat("./2.png", &buf) < 0)
{
ERR_MSG("stat");
return -1;
}
//文件的类型和权限
printf("mode: 0%o\n", buf.st_mode);
get_filePermission(buf.st_mode);
//文件的硬链接数
printf("link: %ld\n", buf.st_nlink);
//文件的所属用户
printf("uid: %d\n", buf.st_uid);
//文件所属组用户
printf("gid: %d\n", buf.st_gid);
//文件大小
printf("size: %ld\n", buf.st_size);
//文件的修改时间
printf("time: %ld\n", buf.st_ctime);
return 0;
}
练习2:提取文件的类型
mode_t st_mode 本质上是一个unsigned int类型,里面存储了文件的类型和权限。
方法1:
man 2 stat --> st_mode --->see inode(7)
man 7 inode -->
S_ISREG(m) is it a regular file? -
S_ISDIR(m) directory? d
S_ISCHR(m) character device? c
S_ISBLK(m) block device? b
S_ISFIFO(m) FIFO (named pipe)? p
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) l
S_ISSOCK(m) socket? (Not in POSIX.1-1996.) s
若是该类型文件,则返回真,否则返回假
void get_fileType(mode_t m)
{
if(S_ISREG(m))
putchar('-');
else if(S_ISDIR(m))
putchar('d');
else if(S_ISCHR(m))
putchar('c');
return ;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
void get_fileType(mode_t m)
{
if(S_ISREG(m))
putchar('-');
else if(S_ISDIR(m))
putchar('d');
else if(S_ISCHR(m))
putchar('c');
else if(S_ISBLK(m))
putchar('b');
else if(S_ISFIFO(m))
putchar('p');
else if(S_ISLNK(m))
putchar('l');
else if(S_ISSOCK(m))
putchar('s');
return;
}
int main(int argc, const char *argv[])
{
struct stat buf;
if(stat("./2.png", &buf) < 0)
{
ERR_MSG("stat");
return -1;
}
//文件的类型和权限
printf("mode: 0%o\n", buf.st_mode);
get_fileType(buf.st_mode);
//文件的硬链接数
printf("link: %ld\n", buf.st_nlink);
//文件的所属用户
printf("uid: %d\n", buf.st_uid);
//文件所属组用户
printf("gid: %d\n", buf.st_gid);
//文件大小
printf("size: %ld\n", buf.st_size);
//文件的修改时间
printf("time: %ld\n", buf.st_ctime);
return 0;
}
方法2:
mode 0040775
S_IFMT 0170000 bit mask for the file type bit field
mode 0040775 ---> 000 100 000 111 111 101
S_IFMT 0170000 ---> 001 111 000 000 000 000 &
------------------------------
000 100 000 000 000 000 ---> 040000
与下列宏进行比较,与哪个相同,就是对应类型文件
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
mode: 0100664 ---> 001 000 000 110 110 100
S_IFMT 0170000 ---> 001 111 000 000 000 000 &
------------------------------
001 000 000 000 000 000 ---> 0100000
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <time.h>
void get_fileType(mode_t m)
{
switch(m&S_IFMT)
{
case S_IFSOCK:putchar('s');break;
case S_IFLNK:putchar('l');break;
case S_IFREG:putchar('-');break;
case S_IFDIR:putchar('d');break;
case S_IFCHR:putchar('c');break;
case S_IFBLK:putchar('b');break;
case S_IFIFO:putchar('p');break;
}
return;
}
int main(int argc, const char *argv[])
{
struct stat buf;
if(stat("./2.png", &buf) < 0)
{
ERR_MSG("stat");
return -1;
}
//文件的类型和权限
printf("0%o ", buf.st_mode);
get_fileType(buf.st_mode);
//文件的硬链接数
printf("%ld ", buf.st_nlink);
//文件的所属用户
printf("%d ", buf.st_uid);
struct passwd* pwd=getpwuid(buf.st_uid);
if(NULL==pwd)
{
ERR_MSG("getpwuid");
return -1;
}
printf("%s ",pwd->pw_name);
//文件所属组用户
printf("%d ", buf.st_gid);
struct group* grp=getgrgid(buf.st_gid);
if(NULL==grp)
{
ERR_MSG("getgrgid");
return -1;
}
printf("%s ",grp->gr_name);
//文件大小
printf("%ld ", buf.st_size);
//文件的修改时间
struct tm* info=NULL;
info=localtime(&buf.st_mtime);
//printf("%ld ",buf.st_ctime);
printf("%02d %02d %02d:%02d ",info->tm_mon+1,info->tm_mday,info->tm_hour,info->tm_min);
printf("2.png\n");
return 0;
}
练习3:提取文件所属用户名
uid_t st_uid; /* User ID of owner */ 用户的uid
getpwuid函数
功能:通过uid号获取用户的信息
原型:
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
参数:
gid_t gid:指定gid号;
返回值:
成功,返回结构体指针;
失败,返回NULL;更新errno;
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
struct group* grp = getgrgid(buf.st_gid);
if(NULL == grp)
{
ERR_MSG("getgrgid");
return -1;
}
printf("%s\n", grp->gr_name);
完整代码示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <head.h>
//获取文件权限
void get_filePermission(mode_t m) //mode_t m = buf.st_mode
{
char buf[] = "rwx";
for(int i=0; i<9; i++)
{
if( (m & (0400>>i)) == 0)
{
putchar('-');
continue;
}
//能运行到当前位置,则代表对应位置有权限
//需要判断是r w x中的哪一个
/*
switch(i%3)
{
case 0:
putchar('r');
break;
case 1:
putchar('w');
break;
case 2:
putchar('x');
break;
}
*/
printf("%c", buf[i%3]);
}
return;
}
//获取文件类型
void get_fileType(mode_t m) //mode_t m = buf.st_mode
{
switch(m & S_IFMT)
{
case S_IFSOCK: putchar('s'); break;
case S_IFLNK: putchar('l'); break;
case S_IFREG: putchar('-'); break;
case S_IFDIR: putchar('d'); break;
}
return;
}
int main(int argc, const char *argv[])
{
struct stat buf;
if(stat("./01_fileno.c", &buf) < 0)
{
ERR_MSG("stat");
return -1;
}
//文件的类型和权限
//printf("mode: 0%o\n", buf.st_mode);
get_fileType(buf.st_mode);
get_filePermission(buf.st_mode);
//文件的硬链接数
//printf("link: %ld\n", buf.st_nlink);
printf(" %ld", buf.st_nlink);
//文件的所属用户
//printf("uid: %d\n", buf.st_uid);
//将uid转换成名字
struct passwd* pwd = getpwuid(buf.st_uid);
if(NULL == pwd)
{
ERR_MSG("getpwuid");
return -1;
}
printf(" %s", pwd->pw_name);
//文件所属组用户
//printf("gid: %d\n", buf.st_gid);
//将gid转换成名字
struct group* grp = getgrgid(buf.st_gid);
if(NULL == grp)
{
ERR_MSG("getgrgid");
return -1;
}
printf(" %s", grp->gr_name);
//文件大小
//printf("size: %ld\n", buf.st_size);
printf(" %ld", buf.st_size);
//文件的修改时间
printf(" time: %ld\n", buf.st_ctime);
//文件的名字
return 0;
}
练习4:opendir
功能:打开一个目录文件
原型:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数:
char *name:指定要打开的目录的路径以及名字;
返回值:
成功,返回指针;
失败,返回NULL,更新errno;
练习5:closedir
功能:关闭目录
原型:
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
返回值:
成功,返回0;
失败,返回-1,更新errno;
练习6:readdir
功能:读取目录
原型:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
返回值:
成功,返回结构体指针:
失败,返回NULL; 更新errno;
目录读取完毕,返回NULL,不更新errno;
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};
练习7:打印当前路径下所有文件的名字,除了隐藏文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <dirent.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
DIR* dp=opendir("./");
if(NULL==dp)
{
ERR_MSG("opendir");
return -1;
}
printf("opendir success\n");
int i=0;
while(1)
{
struct dirent* rp=readdir(dp);
if(NULL==rp)
{
if(0==errno)
{
printf("目录读取完毕\n");
break;
}
else
{
ERR_MSG("readdir");
return -1;
}
}
//判断是否是隐藏文件:以.字符开头
if(rp->d_name[0]!='.') //*(rp->d_name)
printf("[%d]%s\n",++i,rp->d_name);
}
if(closedir(dp)<0)
{
ERR_MSG("closedir");
return -1;
}
return 0;
}
练习8:fork
功能:创建一个子进程
原型:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
返回值:
成功, >0 , 在父进程中,返回创建的子进程的pid号;
=0, 在子进程中,返回0;
失败,返回-1,更新errno,且没有子进程被创建
注意:
1.fork函数创建的子进程,会克隆父进程用户空间的所有资源,以及PC寄存器的值。所以子进程不会运行执行过的fork函数以及fork函数以上的代码。
(ps :PC寄存器中存储着下一次该运行到哪一行代码)
2.父子进程的虚拟地址空间不是同一块,但是由于子进程是从父进程拷贝过来的,所以fork完毕的一瞬间,父子进程的用户空间长得完全一致。
3.父子进程映射的物理地址不是同一块空间。
①写时拷贝:当父子进程均不修改其中的内容的时候,此时映射的物理地址是同一块空间。若某个进程要修改其中的内容的时候,此时才会真正的申请一块新的物理地址空间给子进程的虚拟地址映射。
例题:任务1:验证虚拟地址相不相同
任务2:验证映射的物理地址相不相同
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
printf("__%d__\n",__LINE__);
int a=10;
//创建一个子进程
pid_t cpid=fork(); //在fork以下的这段代码,父子进程均运行
if(cpid>0)//在父进程中,该条件为真
{
a=20;
printf("cpid=%d a=%d %p %d\n",cpid,a,&a,__LINE__);
}
else if(0==cpid)//在子进程中,该条件为真
{
sleep(1);//主动放弃CPU资源
printf("cpid=%d a=%d %p %d\n",cpid,a,&a,__LINE__);
}
else
{
perror("fork");
return -1;
}
while(1)
{
sleep(1);
}
return 0;
}
三、课后作业:
1.从终端获取一个文件的路径以及名字。
若该文件是目录文件,则将该文件下的所有文件的属性显示到终端,类似ls -l该文件夹
若该文件不是目录文件,则显示该文件的属性到终端上,类似ls -l这单个文件
#include <stdio.h>
#include <string.h>
#include <head.h>
void get_fileType(mode_t m)
{
if(S_ISREG(m))
putchar('-');
else if(S_ISDIR(m))
putchar('d');
else if(S_ISCHR(m))
putchar('c');
else if(S_ISBLK(m))
putchar('b');
else if(S_ISFIFO(m))
putchar('p');
else if(S_ISLNK(m))
putchar('l');
else if(S_ISSOCK(m))
putchar('s');
return;
}
void get_filePermission(mode_t m)
{
for(int i=0;i<9;i++)
{
if((m&(0400>>i))==0)
{
putchar('-');
continue;
}
//能运行到当前位置,则代表对应位置有权限
//需要判断是r w x当中的哪一个
switch(i%3)
{
case 0:putchar('r');break;
case 1:putchar('w');break;
case 2:putchar('x');break;
}
}
return;
}
int getstat(char *str)
{ struct stat buf;
if(stat(str, &buf) < 0)
{
ERR_MSG("stat");
return -1;
}
//文件的类型和权限
printf("0%o ", buf.st_mode);
get_fileType(buf.st_mode);
//文件的硬链接数
printf("%ld ", buf.st_nlink);
//文件的所属用户
//printf("uid: %d\n", buf.st_uid);
//将uid转换成名字
struct passwd* pwd = getpwuid(buf.st_uid);
if(NULL == pwd)
{
ERR_MSG("getpwuid");
return -1;
}
printf("%s ", pwd->pw_name);
//文件所属组用户
//printf("gid: %d\n", buf.st_gid);
//将gid转换成名字
struct group* grp = getgrgid(buf.st_gid);
if(NULL == grp)
{
ERR_MSG("getgrgid");
return -1;
}
printf("%s ", grp->gr_name);
//文件大小
printf("%ld ", buf.st_size);
//文件的修改时间
struct tm* info=NULL;
info=localtime(&buf.st_mtime);
//printf("%ld ",buf.st_ctime);
printf("%02d %02d %02d:%02d ",info->tm_mon+1,info->tm_mday,info->tm_hour,info->tm_min);
printf("%s\n",str);
}
int main(int argc, const char *argv[])
{
char str[20]="";
printf("please enter a filename:");
scanf("%s",str);
struct stat buf;
if(stat(str,&buf) < 0)
{
ERR_MSG("stat");
return -1;
}
if((buf.st_mode & S_IFMT) == S_IFDIR)
{
DIR * dp = opendir(str);
if(NULL == dp)
{
ERR_MSG("opendir");
return -1;
}
printf("open success \n");
struct dirent *rp = NULL;
int i=0;
while(1)
{
rp = readdir(dp);
if(NULL == rp)
{
if(0 == errno)
{
printf("读取完毕\n");break;
}
else
{
perror("readdir");
return -1;
}
}
if(*(rp->d_name) != '.')
getstat(rp->d_name);
// printf("[%d]%s\n",++i,rp->d_name);
}
closedir(dp);
}
else
getstat(str);
return 0;
}
2.文件IO函数实现,拷贝文件。子进程先拷贝后半部分,父进程再拷贝前半部分。允许使用sleep函数。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
int fd_r = open("./1.txt",O_RDONLY);
if(fd_r < 0)
{
ERR_MSG("open");
return -1;
}
int fd_w = open("./2.txt",O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd_w < 0)
{
ERR_MSG("open");
return -1;
}
off_t len = lseek(fd_r,0,SEEK_END);
pid_t cpid = fork();
if(cpid > 0)
{
sleep(1);
lseek(fd_r,len/2,SEEK_SET);
lseek(fd_w,len/2,SEEK_SET);
char c;
for(int i=len/2;i<len;i++)
{
if(read(fd_r,&c,1) == 0)
{
break;
}
write(fd_w,&c,1);
}
}
if(0 == cpid)
{
lseek(fd_r,0,SEEK_SET);
lseek(fd_w,0,SEEK_SET);
char a;
for(int j=0;j<len/2;j++)
{
if(read(fd_r,&a,1) == 0)
{
break;
}
write(fd_w,&a,1);
}
}
close(fd_r);
close(fd_w);
return 0;
}