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


我不清楚使用mmap标志时MAP_PRIVATE的工作原理。我可以将大于文件length大小的fd传递给mmap吗?之后,我可以读写超出文件大小但在length范围内的内存吗?

我正在编写一些代码来计算文件的MD5。我决定编写仅将数据作为void*size_t len进行操作的函数,而不是使用标准库流函数。以前,我使用malloc并将文件复制到一些malloc的内存中,然后再使用它们,但是事实证明,对于大文件来说,这相当慢,而且一旦我发现关于mmap的知识,那将是非常愚蠢的。

我要解决的问题是,在计算任何数据的MD5之前,使用malloc的先前解决方案some padding and information is appended to the data that will be hashed.我只需要计算需要附加多少数据,然后realloc进行写入。现在,我预先计算需要添加多少数据,并将此增加的长度传递给mmap。在小文件上,这可以正常工作,但在大文件上尝试写入超出文件大小的地址会导致分段错误。

这就是我要尝试做的:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/mman.h>
#include <sys/stat.h>


// The Data + length struct
struct data{
        void* s;
        size_t len;
};

//mmap on opened file descriptor into a data struct
struct data* data_ffile(int fd)
{
        struct data* ret = malloc(sizeof(struct data));

        //Get the length of the file
        struct stat desc;
        fstat(fd, &desc);
        ret->len = (size_t)desc.st_size;

        //Calculate the length after appending
        size_t new_len =  ret->len + 1;
        if((new_len % 64) > 56)
                new_len += (64 * 2) - (new_len % 64);
        else if((new_len % 64) <= 56)
                new_len += 64 - (new_len % 64);

        //Map the file with the increased length
        ret->s = mmap(NULL, new_len, PROT_READ | PROT_WRITE,
                      MAP_PRIVATE, fd, 0);

        if(ret->s == MAP_FAILED) exit(-1);

        return ret;
}

//Append a character to the mmap'ed data
void data_addchar(struct data* w, unsigned char c)
{
        ((char*)w->s)[w->len++] = c;
        return;
}

void md5_append(struct data* md)
{
        data_addchar(md, 0x80);

        while((md->len % 64) != 56){
                data_addchar(md, (char)0);
        }
}

int main(int argc, char** argv)
{
        int fd = open(argv[1], O_RDONLY);
        struct data* in = data_ffile(fd);
        close(fd);

        md5_append(in);
}


我对mmap有基本的误解吗?

最佳答案

我可以将长度大于文件fd的长度传递给mmap吗?之后,我可以读写超出文件大小但在长度以内的内存吗?


这些都记录在mmap POSIX specification中:


  系统应始终在页面末尾对所有部分页面进行零填充。
  宾语。此外,系统绝不会写出任何修改的内容
  对象最后一页超出其末尾的部分。
  地址范围内的引用从pa开始,并持续到
  len字节到对象结束后的整个页面
  传递SIGBUS信号。



是的,您可以mmap大于文件大小的长度,并且
访问文件末尾以外的任何页面(最后一个页面(可能是部分页面)除外)将导致SIGBUS

07-24 09:46
查看更多