msync的' length`参数不起作用

时间:2017-06-13 10:28:13

标签: c linux mmap

我将文件映射到String。

int fd = open(FILE_PATH, O_RDWR);
struct stat s;
int status = fstat(fd, &s);
char *f = (char*) mmap (0, s.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

然后我cJSON解析f并进行一些修改。

cJSON *root = cJSON_Parse(f);
//some JSON operation

完成后,我从cJSON重新生成了字符串,并尝试将其写回磁盘。

char* rendered = cJSON_Print(root);
memcpy(f, rendered, strlen(rendered));
msync(f, strlen(renderer), MS_SYNC);

mmap或msync都没有错误。

我检查了文件内容,发现它正确地更改为我使用cJSON库修改的内容。

但是,文件未完成。更具体地说,它写回磁盘的大小(我使用Sublime检查)不是我放在length msync参数中的大小,即。 strlen(rendered),但是文件的原始大小,即strlen(f)

然后我尝试用length 512或其他任何方式硬编码128,但我发现所有这些都不起作用。从mmap写回文件的大小仍然是mmaped char的原始大小。

但是在msync的手册中,它说:

  

对应于从addr开始并具有长度长度的内存区域的文件部分将被更新。

所以我感到困惑,任何人都可以告诉我如何分配我想要刷回磁盘的地址长度?

1 个答案:

答案 0 :(得分:0)

感谢在评论中鼓励我的人们,抱歉,我对手册的阅读不好。

msync无法扩展您映射的大小,也不能mmap大小超过文件大小。

所以这就是想法:

  1. 增加文件大小
  2. 去映射
  3. remmap
  4. 将重新映射的f与新内容进行msync同步
  5. 我实现了resize_remap功能

    result_t file_remap_resize(int* fd, char** f, int new_size){
       if(ftruncate(*fd, new_size) == -1){
          printf("failed to resize\n");
          return ERR_CODE;
       }
       if(munmap(*f, sizeof(*f)) == -1){
          printf("failed to unmap\n");
          return ERR_CODE;
       }
       *f = (char*)mmap (0, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
       if(!f){
          printf("failed to remap\n");
          return ERR_CODE;
       }
       return SUCCESS
    }
    

    然后程序就像:

    char* rendered = cJSON_Print(root);
    file_remap_resize(&fd, &f, strlen(rendered));
    memcpy(f, rendered, strlen(rendered));
    msync(f, strlen(renderer), MS_SYNC);
    

    它有效!

    修改后的文件可以刷回磁盘!