在freebsd 7上快速修复32位(2GB限制)fseekftell

在freebsd 7上快速修复32位(2GB限制)fseekftell,第1张

概述我在FreeBSD上有旧的32位C/C++程序,它被数百名用户远程使用,其作者无法修复它.它是以不安全的方式编写的,所有文件偏移都在内部存储为无符号32位偏移量,并且ftell / fseek函数在使用时.在FreeBSD 7(软件的主机平台)中,它是 means that ftell and fseek uses 32-bit signed long: int fseek(FILE *strea 我在FreeBSD上有旧的32位C/C++程序,它被数百名用户远程使用,其作者无法修复它.它是以不安全的方式编写的,所有文件偏移都在内部存储为无符号32位偏移量,并且ftell / fseek函数在使用时.在FreeBSD 7(软件的主机平台)中,它是 means that ftell and fseek uses 32-bit signed long:
int fseek(file *stream,long offset,int whence); long ftell(file *stream);

我需要快速修复程序,因为一些内部数据文件在收集数据13年后突然达到2 ^ 31文件大小(2 147 483 7yy字节),并且内部fseek / ftell断言现在对任何请求都失败了.

在FreeBSD7世界中,有2GB文件的fseeko / ftello Hack.

int fseeko(file *stream,off_t offset,int whence); off_t ftello(file *stream);

这里的off_t类型没有明确定义;我现在所知道的,它有8字节的大小,看起来像长long或无符号long long(我不知道哪一个).

是否足够(可以处理多达4 GB的文件)并且可以安全地搜索和替换所有ftell到ftello,并且所有fseek到fseeko(sed -i’s / ftell / ftello’,如果可能的话)它们的用法是:

unsigned long offset1,offset2; //32bit offset1 = (compute + it) * in + some - arithmetic; fseek(file,SEEK_END); fseek(file,4,SEEK_END); // or other small int constant offset2 = ftell(file); fseek(file,offset1,SEEK_SET);  // No usage of SEEK_CUR

和这些电话的组合.

off_t的签名是什么?
将64位off_t分配到无符号32位偏移量是安全的吗?它适用于2 GB到4 GB范围内的字节吗?

除了ftell / fseek之外,哪些函数可以用于偏移?

解决方法 FreeBSD fseeko() and ftello()记录为POSIX.1-2001兼容,即 off_t is a signed integer type.

在FreeBSD 7上,你可以放心地做到:

off_t          actual_offset;unsigned long  stored_offset;if (actual_offset >= (off_t)0 && actual_offset < (off_t)4294967296.0)    stored_offset = (unsigned long)actual_offset;else    some_fatal_error("Unsupportable file offset!");

(在LP64体系结构上,上面的内容很愚蠢,因为off_t和long都是64位有符号整数.即使这样也会安全;只是愚蠢,因为可以支持所有可能的文件偏移.)

人们经常被这种情况所困扰的是,必须使用off_t完成偏移计算.也就是说,将结果转换为off_t是不够的,必须将算术中使用的值转换为off_t. (从技术上讲,你只需要确保每个算术运算都是以off_t精度完成的,但是我发现如果我只是试图并转换所有的 *** 作数就更容易记住规则.)例如:

off_t          offset;unsigned long  some,values,used;offset = (off_t)some * (off_t)value + (off_t)used;fseeko(file,offset,SEEK_SET);

通常,偏移计算用于查找特定记录中的字段;算术趋于保持不变.我真的建议你将搜索 *** 作移动到辅助函数,如果可能的话:

int fseek_to(file *const file,const unsigned long some,const unsigned long values,const unsigned long used){    const off_t  offset = (off_t)some * (off_t)value + (off_t)used;    if (offset < (off_t)0 || offset >= (off_t)4294967296.0)        fatal_error("Offset exceeds 4GB; I must abort!");    return fseeko(file,SEEK_SET);}

现在,如果你碰巧处于一个幸运的位置,你知道所有的偏移都是对齐的(对于某个整数,比如4),你可以给自己几年的时间来重写应用程序,通过使用以上:

#define BIG_N 4int fseek_to(file *const file,const unsigned long used){    const off_t  offset = (off_t)some * (off_t)value + (off_t)used;    if (offset < (off_t)0)        fatal_error("Offset is negative; I must abort!");    if (offset >= (off_t)(BIG_N * 2147483648.0))        fatal_error("Offset is too large; I must abort!");    if ((offset % BIG_N) && (offset >= (off_t)2147483648.0))        fatal_error("Offset is not a multiple of BIG_N; I must abort!");    return fseeko(file,SEEK_SET);}int fseek_big(file *const file,const unsigned long position){    off_t  offset;    if (position >= 2147483648ul)        offset = (off_t)2147483648ul               + (off_t)BIG_N * (off_t)(position - 2147483648ul);    else        offset = (off_t)position;    return fseeko(file,SEEK_SET);}unsigned long ftell_big(file *const file){    off_t  offset;    offset = ftello(file);    if (offset < (off_t)0)        fatal_error("Offset is negative; I must abort!");    if (offset < (off_t)2147483648ul)        return (unsigned long)offset;    if (offset % BIG_N)        fatal_error("Offset is not a multiple of BIG_N; I must abort!");    if (offset >= (off_t)(BIG_N * 2147483648.0))        fatal_error("Offset is too large; I must abort!");    return (unsigned long)2147483648ul         + (unsigned long)((offset - (off_t)2147483648ul) / (off_t)BIG_N);}

逻辑很简单:如果offset小于231,则按原样使用.否则,它由值231 BIG_N×(偏移-231)表示.唯一的要求是偏移231及以上始终是BIG_N的倍数.

显然,你必须只使用上面三个函数 – 加上你需要的fseek_to()变体,只要它们做同样的检查,只需使用不同的参数和公式进行偏移计算 – 你可以支持文件大小高达2147483648 BIG_N×2147483647.对于BIG_N == 4,即10 GiB(少于4个字节;准确地说是10,737,418,236个字节).

有问题吗?

编辑澄清:

首先用调用fseek_pos(文件,位置)替换你的fseek(文件,位置,SEEK_SET),

static inline voID fseek_pos(file *const file,const unsigned long position){    if (fseeko(file,(off_t)position,SEEK_SET))        fatal_error("Cannot set file position!");}

和fseek(文件,SEEK_END)调用fseek_end(文件,位置)(对称性 – 我假设这个位置通常是一个文字整数常量),

static inline voID fseek_end(file *const file,const off_t relative){    if (fseeko(file,relative,SEEK_END))        fatal_error("Cannot set file position!");}

最后,调用ftell_pos(文件)的ftell(文件):

static inline unsigned long ftell_pos(file *const file){    off_t position;    position = ftello(file);    if (position == (off_t)-1)        fatal_error("Lost file position!");    if (position < (off_t)0 || position >= (off_t)4294967296.0)        fatal_error("file position outsIDe the 4GB range!");    return (unsigned long)position;}

由于在您的体系结构和OS上,unsigned long是32位无符号整数类型而off_t是64位有符号整数类型,因此这为您提供了完整的4GB范围.

对于偏移计算,定义一个或多个类似的函数

static inline voID fseek_to(file *const file,const off_t term1,const off_t term2,const off_t term3){    const off_t position = term1 * term2 + term3;    if (position < (off_t)0 || position >= (off_t)4294967296.0)        fatal_error("file position outsIDe the 4GB range!");    if (fseeko(file,position,SEEK_SET))        fatal_error("Cannot set file position!");}

对于每个偏移计算算法,定义一个fseek_to变量.命名参数以使算法有意义.如上所述,使参数const off_t,因此算术中不需要额外的强制转换.只有参数和const off_t position =定义计算算法的行在变量函数之间变化.

有问题吗?

总结

以上是内存溢出为你收集整理的在freebsd 7上快速修复32位(2GB限制)fseek / ftell全部内容,希望文章能够帮你解决在freebsd 7上快速修复32位(2GB限制)fseek / ftell所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1248102.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存