公司的asterisk系統已經發生了兩次crash,檢查日志,都是在日志文件寫滿到2G后自動執行轉儲時,日志還在寫繼續寫入而導致的。google以后,發現了下面這邊文章,贊!
解決了文件大小限于2G的問題,轉帖到自己的空間保留。
突破Linux上面ftell函數2GB的文件大小限制
http://www.demix.cn/h?z=28507
在 32 位元的 Linux 上面寫超過 2GB 的檔案會發生錯誤,甚至導致程式終止執行。
這是因為 Linux 的系統內部處理檔案時用的指標定義為 long,而 long 在 32 位元的系統上的大小為 32 位元,因此最大只能支援 2^31-1 = 2,147,483,647 bytes 等於是 2GB 扣掉 1 byte 的檔案大小
64 位元的系統 (例如 AMD64 或 IA64) 則因為 long 定義成 64 位元,所以不會有問題..
# if __WORDSIZE == 64
typedef long int int64_t;
# endif
不過在 FreeBSD 上面,即使是 32 位元的系統,也不會有 2GB 檔案大小的限制,這是因為 FreeBSD 內部處理檔案時,本來就是使用 64 位元的數字當作指標,所以不會有問題
因此在 32 位元的 Linux 上面,程式需要作一些額外處理才能正確寫超過 2GB 的檔案
我們先寫一個小程式來測試一下 (large.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
void sig_xfsz(int sig)
{
printf("ERROR: SIGXFSZ (%d) signal received!\n", sig);
}
int main()
{
int i, fd;
char dummy[4096];
signal( SIGXFSZ, sig_xfsz );
unlink("large.log");
fd = open("large.log", O_CREAT|O_WRONLY, 0644 );
bzero( dummy, 4096 );
/* 2GB = 4KB x 524288 */
for( i = 0 ; i < 524287 ; i++ )
write( fd, dummy, 4096 );
write( fd, dummy, 4095 );
printf("large.log: 2147483647 bytes\n");
if( write( fd, dummy, 1 ) < 0 )
printf("ERROR: %s [errno:%d]\n",strerror(errno),errno);
else
printf("large.log: 2147483648 bytes\n");
close(fd);
exit(0);
}
在 32 位元的 Linux 下面,以上程式編譯后若沒有特殊處理,執行結果如下:
# gcc -o large32 large.c
# ./large32
large.log: 2147483647 bytes
ERROR: SIGXFSZ (25) signal received!
ERROR: File too large [errno:27]
在寫第 2147483648 byte 的時候,程式會收到 signal SIGXFSZ,同時 write() 會回傳 -1 錯誤,errno 則為 27 (File too large)。更甚者,如果程式沒有像上面一樣去處理 SIGXFSZ 的話,內定的 signal handler 甚至會造成程式停止執行并產生 core dump
接下來,我們在編譯同一個程式的時候加入 -D_FILE_OFFSET_BITS=64 再試看看:
# gcc -D_FILE_OFFSET_BITS=64 -o large64 large.c
# ./large64
large.log: 2147483647 bytes
large.log: 2147483648 bytes
果然順利突破 2GB 的限制了!
而同樣的程式在 32 位元的 FreeBSD 下面,不論有沒有加這個定義,跑起來都是正確的
不過處理這些大檔案的時候,除了編譯程式時的參數不同外,有些函數的使用上也要作一些調整,例如 fseek() 與 ftell() 這兩個原本使用到 long integer 當作 offset 的函數:
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
只要系統是 32 位元,即使是在 FreeBSD 下面,都需要改為使用 off_t 的版本:
int fseeko(FILE *stream, off_t offset, int whence);
off_t ftello(FILE *stream);
在 Linux 下面,如果 _FILE_OFFSET_BITS 定義為 64,則 off_t 這個型態會自動轉成 64 位元的大小(在 FreeBSD 上面,off_t 本來就是 64 位元的大小)
每種系統支援大於 2GB 的檔案讀寫所需要的編譯選項都會有一些差異,即使是同樣是 Linux 也會因為 32 位元或 64 位元而有不同。有一個簡單的方法可以判斷,就是利用 glibc 提供的 getconf 來取得編譯(compile)以及連結(linking)時所需的參數:
# getconf LFS_CFLAGS
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
# getconf LFS_LDFLAGS?
#
上面是在 32 位元的 Redhat Linux 上面跑出來的結果,代表的是在這個系統上,若要讓程式支援 2GB 的檔案讀寫,編譯(compile)時需要加上 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 這兩個參數,連結(linking)時則不用加任何參數
解決了文件大小限于2G的問題,轉帖到自己的空間保留。
突破Linux上面ftell函數2GB的文件大小限制
http://www.demix.cn/h?z=28507
在 32 位元的 Linux 上面寫超過 2GB 的檔案會發生錯誤,甚至導致程式終止執行。
這是因為 Linux 的系統內部處理檔案時用的指標定義為 long,而 long 在 32 位元的系統上的大小為 32 位元,因此最大只能支援 2^31-1 = 2,147,483,647 bytes 等於是 2GB 扣掉 1 byte 的檔案大小
64 位元的系統 (例如 AMD64 或 IA64) 則因為 long 定義成 64 位元,所以不會有問題..
# if __WORDSIZE == 64
typedef long int int64_t;
# endif
不過在 FreeBSD 上面,即使是 32 位元的系統,也不會有 2GB 檔案大小的限制,這是因為 FreeBSD 內部處理檔案時,本來就是使用 64 位元的數字當作指標,所以不會有問題
因此在 32 位元的 Linux 上面,程式需要作一些額外處理才能正確寫超過 2GB 的檔案
我們先寫一個小程式來測試一下 (large.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
void sig_xfsz(int sig)
{
printf("ERROR: SIGXFSZ (%d) signal received!\n", sig);
}
int main()
{
int i, fd;
char dummy[4096];
signal( SIGXFSZ, sig_xfsz );
unlink("large.log");
fd = open("large.log", O_CREAT|O_WRONLY, 0644 );
bzero( dummy, 4096 );
/* 2GB = 4KB x 524288 */
for( i = 0 ; i < 524287 ; i++ )
write( fd, dummy, 4096 );
write( fd, dummy, 4095 );
printf("large.log: 2147483647 bytes\n");
if( write( fd, dummy, 1 ) < 0 )
printf("ERROR: %s [errno:%d]\n",strerror(errno),errno);
else
printf("large.log: 2147483648 bytes\n");
close(fd);
exit(0);
}
在 32 位元的 Linux 下面,以上程式編譯后若沒有特殊處理,執行結果如下:
# gcc -o large32 large.c
# ./large32
large.log: 2147483647 bytes
ERROR: SIGXFSZ (25) signal received!
ERROR: File too large [errno:27]
在寫第 2147483648 byte 的時候,程式會收到 signal SIGXFSZ,同時 write() 會回傳 -1 錯誤,errno 則為 27 (File too large)。更甚者,如果程式沒有像上面一樣去處理 SIGXFSZ 的話,內定的 signal handler 甚至會造成程式停止執行并產生 core dump
接下來,我們在編譯同一個程式的時候加入 -D_FILE_OFFSET_BITS=64 再試看看:
# gcc -D_FILE_OFFSET_BITS=64 -o large64 large.c
# ./large64
large.log: 2147483647 bytes
large.log: 2147483648 bytes
果然順利突破 2GB 的限制了!
而同樣的程式在 32 位元的 FreeBSD 下面,不論有沒有加這個定義,跑起來都是正確的
不過處理這些大檔案的時候,除了編譯程式時的參數不同外,有些函數的使用上也要作一些調整,例如 fseek() 與 ftell() 這兩個原本使用到 long integer 當作 offset 的函數:
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
只要系統是 32 位元,即使是在 FreeBSD 下面,都需要改為使用 off_t 的版本:
int fseeko(FILE *stream, off_t offset, int whence);
off_t ftello(FILE *stream);
在 Linux 下面,如果 _FILE_OFFSET_BITS 定義為 64,則 off_t 這個型態會自動轉成 64 位元的大小(在 FreeBSD 上面,off_t 本來就是 64 位元的大小)
每種系統支援大於 2GB 的檔案讀寫所需要的編譯選項都會有一些差異,即使是同樣是 Linux 也會因為 32 位元或 64 位元而有不同。有一個簡單的方法可以判斷,就是利用 glibc 提供的 getconf 來取得編譯(compile)以及連結(linking)時所需的參數:
# getconf LFS_CFLAGS
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
# getconf LFS_LDFLAGS?
#
上面是在 32 位元的 Redhat Linux 上面跑出來的結果,代表的是在這個系統上,若要讓程式支援 2GB 的檔案讀寫,編譯(compile)時需要加上 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 這兩個參數,連結(linking)時則不用加任何參數