C 我可以映射长度大于文件大小的文件吗?

C 我可以映射长度大于文件大小的文件吗?,c,file,segmentation-fault,mmap,C,File,Segmentation Fault,Mmap,我不太明白使用MAP_PRIVATE标志时mmap是如何工作的。我可以将大于文件fd大小的长度传递给mmap吗?执行此操作后,是否可以写入和读取超出文件大小但在长度范围内的内存 我正在写一些计算文件MD5的代码。我决定编写只将数据作为void*和size_t len处理的函数,而不是使用标准的库流函数。以前,我使用malloc并在使用它们之前将文件复制到一些malloc'ed内存中,但对于大文件来说,这被证明是相当缓慢的,而且一旦我发现了mmap,这是相当愚蠢的 我要处理的问题是,在计算任何数据

我不太明白使用MAP_PRIVATE标志时mmap是如何工作的。我可以将大于文件fd大小的长度传递给mmap吗?执行此操作后,是否可以写入和读取超出文件大小但在长度范围内的内存

我正在写一些计算文件MD5的代码。我决定编写只将数据作为void*和size_t len处理的函数,而不是使用标准的库流函数。以前,我使用malloc并在使用它们之前将文件复制到一些malloc'ed内存中,但对于大文件来说,这被证明是相当缓慢的,而且一旦我发现了mmap,这是相当愚蠢的

我要处理的问题是,在计算任何数据的MD5之前,使用以前的malloc解决方案,我只需计算需要追加多少数据,然后realloc和write。现在,我正在预先计算需要追加多少数据,并将增加的长度传递给mmap。在小文件上,这可以正常工作,但在大文件上,尝试写入文件大小以外的地址会导致分段错误

这大概就是我想要做的:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
我对mmap有基本的误解吗

我可以将大于文件fd大小的长度传递给mmap吗?执行此操作后,是否可以写入和读取超出文件大小但在长度范围内的内存

这些都记录在mmap POSIX中:

系统应始终在报告末尾零填充任何部分页面 对象此外,系统不得写出任何修改的 对象最后一页中超出其结尾的部分。 地址范围内的引用,从pa开始,持续到 在对象结束后,将产生len字节到整页的结果 在SIGBUS信号的传输中

是的,您可以使用大于文件大小的mmap长度,以及 访问文件末尾以外的任何页面(最后一个可能的部分页面除外)将导致SIGBUS。
@kaylum我对问题进行了编辑,使代码示例可编译。为了简洁易读,我省略了错误处理和内存处理。这个例子再现了我遇到的问题,即在带有大文件的data_addchar上有一个segfault。我使用的文件是650MBIs,如果我映射的长度大于文件的大小并且需要额外的页面,这也是正确的吗?@David,对不起,我不太明白。我以为我正好回答了你的问题。如果文件长度为8190字节,一个页面长度为4096字节,并且您映射了3个页面,那么访问字节[0..8191]第二个页面超出文件末尾2个字节就可以了,访问第三个页面(不包括文件的任何部分)将生成SIGBUS。
#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);
}