2016-02-26 82 views
1

我正在嘗試在文件系統(例如ext2)中搜索特定字節(例如0xAB)的項目。我能用malloc(),realloc()memchr()找到我需要的東西,但它看起來很慢,所以我正在使用mmap()進行調查。我試圖做的是找到一個特定的字節,然後將它們複製到一個結構中,所以我有兩個問題:(1)使用mmap()最好的策略,(2)爲什麼不是下面的代碼工作(我得到EINVAL錯誤)?使用mmap()來搜索大文件(〜1TB)

UPDATE:下面的程序編譯和運行,但我仍然有一對夫婦的問題:
1),它不會顯示在大文件正確的文件大小(顯示1GB的閃存驅動器大小正確,而不是32GB)* 。
2)它沒有正確地搜索映射**。

*是否THIS是使用stat64()獲得正確尺寸的可能解決方案?如果是這樣,是我在我的Makefile中添加的東西嗎?我沒有使用makefiles太多,所以我不知道如何添加類似的東西。
**這甚至是正確的搜索方式嗎?

#define _LARGEFILE64_SOURCE 

#include <stdio.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <errno.h> 
#define handle_error(msg) \ 
do { perror(msg); exit(EXIT_FAILURE); } while (0) 

int main(int argc, char **argv) { 

    int fd = open("/dev/sdb1", O_RDONLY); 

    if(fd < 0) { 
     printf("Error %s\n", strerror(errno)); 
     return -1; 
    } 

    const char * map; 

    off64_t size; 
    size = lseek64(fd, 0, SEEK_END); 
    printf("file size: %llu\n", size); 
    lseek64(fd, 0, SEEK_SET);  

    map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); 
    if (map == MAP_FAILED) { handle_error("mmap error"); } 

    printf("Searching for magic numbers...\n"); 
    for (i=0; i < size; i++) { 
    if(map[i] == 0X53 && map[i + 1] == 0XEF) { 
     if ((map[i-32] == 0X00 && map[i-31] == 0X00) ||    
      (map[i-32] == 0X01 && map[i-31] == 0X00) || 
      (map[i-32] == 0X02 && map[i-31] == 0X00)) { 
      if(j <= 5) { 
       printf("superblock %d found\n", j); 
       ++j; 
      } else break; 

    int q; 
    for(q=0; q<j; q++) { 
     printf("SUPERBLOCK[%d]: %d\n", q+1, sb_pos[q]); 
    } 

    fclose(fd); 
    munmap(map, size); 
    return 0; 
} 

感謝您的幫助。

+0

你應該檢查errno變量來理解爲什麼mmap失敗 –

+0

你讀過[THIS](http://stackoverflow.com/questions/10088962/mmap-returns-einval)的問題嗎? – Shark

+0

它可能會失敗,因爲它無法找到您請求的長度的連續內存條(「大小」)。 – Shark

回答

0

我剛剛注意到我正在使用fopen(),我應該使用open()嗎?

是的,你應該使用open()而不是fopen()。這就是你得到EINVAL錯誤的原因。

fopen(「/ dev/sdb1」,O_RDONLY);

此代碼是完全不正確的。 O_RDONLY是應該與open()系統調用一起使用但不與fopen()一起使用的標誌libc函數

您還應該注意,只有在具有大型虛擬地址空間的平臺上運行大型文件時,纔可以使用mmaping大型文件。很明顯:你應該有足夠的虛擬內存來解決你的文件。談到英特爾,它應該只有x86_64,而不是x86_32。

我還沒有試圖用真正的大文件(> 4G)做到這一點。可能需要將一些額外的標誌傳遞給open()系統調用。

0

我工作的一個項目,試圖在文件系統來搜索特定的字節(例如是0xAB)(例如EXT2)

給mmap()一個大文件到內存是完全錯誤的方法在你的情況。你只需要通過固定大小的塊(大約1MB)逐步處理文件。你可以使用mmap()或只讀()到你的內部緩衝區 - 這並不重要。但是如果你只是想順序處理一個文件,那麼把整個文件存入內存是完全不必要的。

1

mmap是處理搜索大文件的一種非常有效的方法,特別是在可以使用內部結構的情況下(例如,在大文件上使用mmap,固定大小的記錄經過排序後可以執行二進制搜索,並且只有與讀取的記錄對應的頁面纔會被觸摸)。

在你的情況下,你需要編譯64位並啓用大文件支持(並使用open(2))。

如果您的/dev/sdb1是設備而不是文件,我不認爲stat(2)會顯示實際大小。 stat爲我的盒子上的這些設備返回大小0。我認爲你需要以另一種方式獲得尺寸。

關於地址空間:x86-64使用2^48字節的虛擬地址空間,即256個TiB。你不能使用所有這些,但在大多數進程中很容易〜127 TiB的連續地址空間。

+0

是的,/ dev/sdb1將是一個設備,並且程序在64位Ubuntu機器上運行。如果我在32GB USB驅動器上使用以下內容,我會得到一個1493172224: 'int fd = open(「/ dev/sdb1」,O_RDONLY | O_LARGEFILE); ... off_t size; size = lseek64(fd,0,SEEK_END);倒退(fd);' – user2341909