2016-12-16 53 views
1

我打開巨大的(11GB)文件的mmap它memmory,並不能搜索的字符串的文件中的strstr上巨大mmapped文件

我的代碼是

if ((fd = open("l", O_RDONLY)) < 0)  err_sys("Cant open file"); 
if (fstat(fd, &statbuf) < 0)    err_sys("Cant get file size"); 
printf("size is %ld\n", statbuf.st_size); 

if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) err_sys("Cant mmap"); 
printf("src pointer is at %ld\n", src); 

char * index = strstr(src, "bin/bash"); 
printf("needle is at %ld\n", index); 

它適用於小文件,但在巨大的來源返回0.我應該使用什麼函數來搜索巨大的mmapped文件?

輸出是:

size is 11111745740 
src pointer is at 140357526544384 
needle is at 0 
+0

你確定該文件包含'「斌/慶典」'呢? – EOF

+2

您是否將您的程序編譯爲32位程序?你是否啓用了大文件支持?你編程的操作系統是什麼? 「失敗」是什麼意思?如果其中一個系統調用失敗,那麼之後的「errno」的值是多少?請向我們提供這些信息。 – fuz

+0

另外,'%ld'不是打印指針的正確格式化說明符,也不是'off_t'。 – fuz

回答

3

你不應該使用strstr()在內存映射文件搜索文本:

  • 如果是二進制文件,它極有可能包含空字節即會過早停止搜索。這可能是你觀察到的。
  • 如果文件是純文本但不包含匹配,strstr將繼續掃描超出文件末尾,通過嘗試讀取未映射的內存來調用未定義的行爲。

你也可以使用具有同等語義的功能,但應用到原始內存,而不是C字符串,memmem(),可在Linux和BSD系統:

void *memmem(const void *p1, size_t size1, const void *p2, size_t size2); 

請注意,還使用了錯誤printf格式:它應該是%psrcindex,你可能更願意打印偏移爲ptrdiff_tunsigned long long

if ((fd = open("l", O_RDONLY)) < 0) 
     err_sys("Cannot open file"); 
    if (fstat(fd, &statbuf) < 0) 
     err_sys("Cannot get file size"); 

    printf("size is %llu\n", (unsigned long long)statbuf.st_size); 

    if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) 
     err_sys("Cannot mmap"); 

    printf("src pointer is at %p\n", (void*)src); 

    char *index = memmem(src, statbuf.st_size, "bin/bash", strlen("bin/bash")); 
    printf("needle is at %p\n", (void*)index); 

    if (index != NULL) 
     printf("needle is at offset %llu\n", (unsigned long long)(index - src)); 

如果memmem不可用你的平臺上,下面是一個簡單的實現:

#include <string.h> 

void *memmem(const void *haystack, size_t n1, const void *needle, size_t n2) { 
    const unsigned char *p1 = haystack; 
    const unsigned char *p2 = needle; 

    if (n2 == 0) 
     return (void*)p1; 
    if (n2 > n1) 
     return NULL; 

    const unsigned char *p3 = p1 + n1 - n2 + 1; 
    for (const unsigned char *p = p1; (p = memchr(p, *p2, p3 - p)) != NULL; p++) { 
     if (!memcmp(p, p2, n2)) 
      return (void*)p; 
    } 

    return NULL; 
}  
+0

您是否在尋找Linux和BSD函數['memmem()'](http://man7.org/linux/man-pages/man3/memmem.3.html)?它沒有在POSIX中指定,並且似乎沒有在Windows上提供。 –

+0

@JonathanLeffler:的確,這個函數在一些但不是所有的Unix系統上都可用。 C標準有'memchr()','memcpy()','memcmp()','memmove()'......包含'memmem()'和其他一些有用的Posix函數比如'strdup()','getline()'等是有意義的。 – chqrlie