使用mmap将文件映射到虚拟地址空间进行操作

简介: 使用mmap将文件映射到虚拟地址空间进行操作

文章目录

使用mmap将文件映射到进程的虚拟地址空间,对内存的操作,直接反应到文件中。

相关概念:

代码参考:

执行验证

代码获取文件的元数据

文件的元数据

相关使用函数

代码实现

执行


使用mmap将文件映射到进程的虚拟地址空间,对内存的操作,直接反应到文件中。

相关概念:

Linux od命令用于输出文件内容。


  • od指令会读取所给予的文件的内容,并将其内容以八进制字码呈现出来。

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);


  • 头文件需要包含<sys/mman.h>
  • 功能:映射文件或设备到内存空间
  • 参数:
  • addr:映射后的虚拟地址空间的地址(一般为NULL)

  • length:映射的长度

  • prot:

  • PROT_NONE Pages may not be accessed.
  • PROT_EXEC Pages may be executed.
  • PROT_READ Pages may be read.
  • PROT_WRITE Pages may be written.
  • flags:


  • MAP_SHARED:
  • MAP_PRIVATE:
  • MAP_ANONYMOUS: 不支持文件映射
  • fd:-1

  • offset:0

  • 返回值:
  • MAP_FAILED 错误 errno被设置
  • 成功返回映射区域的地址

int munmap(void *addr, size_t length);

  • 功能:解除内存映射
  • 参数:
  • addr:是mmap(2)的返回值
  • length:同mmap(2)函数中的length
  • 返回值:
  • 0 成功
  • -1 失败 errno被设置

代码参考:

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
  int fd;
  //以读写方式打开文件
  fd=open(argv[1],O_RDWR);
  if(fd==-1){
  perror("open");
  return 1;
  }
  //建立映射
  void *p=mmap(NULL,6,\
  PROT_READ|PROT_WRITE,
  MAP_SHARED,fd,0);
  if(p==MAP_FAILED){
  perror("mmap");
  return 2;
  }
  printf("success...\n");
  //关闭文件
  close(fd);
  //对内存的操作
  int *q=(int *)p;
  q[0]=0x30313233;
  //解除映射
  munmap(p,6);
  return 0;
}


执行验证

20200204094016464.png

代码获取文件的元数据

文件的元数据

文件的元数据就是文件的属性,使用

ls -l [文件名]#查看

20200204094651879.png

相关使用函数

  • 如何获取一个文件的元数据?

使用系统调用stat(2)获取文件的元数据。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
功能:获取文件的状态信息
参数:
path:指定了文件的名字
buf:将文件的状态信息存储到buf指定的空间里。
返回值:
-1  错误   errno被设置
0  成功
struct stat{
  dev_t   st_dev;  /* ID of device containing file */
        ino_t   st_ino;     /* inode number */
        mode_t  st_mode;    /* protection */
        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 */
  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 */
};


  • 如何将uid的数字转换为用户的名字?
getpwuid(3)
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
功能:获取用户的信息
参数:
uid:指定用户的uid
返回值:
返回一个指向struct passwd结构体的指针
NULL 找不到这个用户的信息或错误产生 如果是产生错误,errno被设置


/etc/passwd文件的内容

这个文件里存放的是系统的所有用户的信息。


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 */
};


  • 如何通过gid获取组名?
getgrnam(3)
getgrgid(3)
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
功能:获取一条组信息
参数:
gid:指定的组id
返回值:
返回一个指向struct group结构体的指针
NULL 找不到这个组的信息或错误产生 如果是产生错误,errno被设置.


struct group{
        char   *gr_name;       /* group name */
           char   *gr_passwd;     /* group password */
           gid_t   gr_gid;        /* group ID */
           char  **gr_mem;        /* group members */
};


  • 组信息存放在/etc/group文件中
  • 20200204095113628.png
  • 将长整型的时间转换为字符串格式的时间


ctime(3)
#include <time.h>
char *ctime(const time_t *timep);
功能:将长整型的时间转换为字符串格式
参数:
timep:长整型的时间
返回值:
NULL   错误
字符串


代码实现

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
int main(int argc,char *argv[]){
  struct stat sbuf;
  struct passwd *p;
  int s; 
  //获取指定文件的元数据
  s=stat(argv[1],&sbuf);
  if(s==-1){//获取文件的元数据失败
  perror("stat");
  return 1;
  }
  printf("size:%ld\n",sbuf.st_size);
  printf("hard links:%d\n",\
  sbuf.st_nlink);  
  printf("inode number:%lu\n",\
  sbuf.st_ino);
  //printf("uid:%d\n",sbuf.st_uid);
  p=getpwuid(sbuf.st_uid);
  if(p==NULL){
  return 2;
  }
  printf("username:%s\n",p->pw_name);
  //printf("gid:%d\n",sbuf.st_gid);
  struct group *q=\
  getgrgid(sbuf.st_gid);
  printf("group name:%s\n",q->gr_name);
  char *st=ctime(&sbuf.st_atime);
  printf("time:%s\n",st);
  printf("mode:%o\n",sbuf.st_mode);
#if 0
  if(S_ISREG(sbuf.st_mode))printf("-");
  if(S_ISDIR(sbuf.st_mode))printf("d");
  printf("\n");
#endif
  switch(sbuf.st_mode&S_IFMT){
  case S_IFREG:
    printf("-");
    break;
  case S_IFDIR:
    printf("d");
    break;
  default:
    break;
  }
  printf("\n");
  //打印出属主的权限
  if(sbuf.st_mode&S_IRUSR)
  printf("r");
  else 
  printf("-");
  if(sbuf.st_mode&S_IWUSR)
  printf("w");
  else
  printf("-");
  printf("\n");
#if 0
  switch(sbuf.st_mode&00700){
  case S_IRUSR:
    printf("r");
    break;
  case S_IWUSR:
    printf("w");
    break;
  case S_IXUSR:
    printf("x");
    break;
  default:
    break;
  }
#endif
  return 0;
}


执行

20200204095315253.png

相关文章
|
6月前
|
存储 Linux 编译器
进程的虚拟地址空间
进程的虚拟地址空间
|
Unix 程序员 Linux
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
266 0
|
3月前
|
存储 C语言
【C语言】进程间通信之存储映射区mmap
【C语言】进程间通信之存储映射区mmap
42 0
|
6月前
mmap匿名映射区
mmap匿名映射区
|
6月前
|
存储 缓存 安全
深入理解内存映射:mmap映射的背后原理以及和共享内存的差异
深入理解内存映射:mmap映射的背后原理以及和共享内存的差异
2937 0
|
6月前
|
缓存 Linux
内存学习(八):块分配器1
内存学习(八):块分配器1
67 0
|
6月前
|
Linux
内存学习(四):内存映射3
内存学习(四):内存映射3
74 0
|
6月前
|
缓存 Linux
内存学习(四):内存映射5
内存学习(四):内存映射5
50 0
|
6月前
|
消息中间件 存储 缓存
Linux内存映射mmap
Linux内存映射mmap
81 0
|
6月前
|
索引
虚拟地址与物理内存地址是如何映射的
虚拟地址与物理内存地址是如何映射的