- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在 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 世界中,fseeko
/ftello
hack 用于 2GB+ 文件。
int
fseeko(FILE *stream, off_t offset, int whence);
off_t
ftello(FILE *stream);
这里的off_t
类型没有明确定义;我现在所知道的是,它有 8 字节大小,看起来像 long long
或 unsigned long long
(我不知道是哪个)。
是否足够(最多处理 4 GB 文件)并且安全地搜索和替换所有 ftell
到 ftello
,以及所有 fseek
到 fseeko
(sed -i 's/ftell/ftello'
,与 seek 相同),如果可能的话,它们的用法是:
unsigned long offset1,offset2; //32bit
offset1 = (compute + it) * in + some - arithmetic;
fseek(file, 0, 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
来完成。 .也就是说,将 result 转换为 off_t
是不够的, 你必须投 values
用于算术 off_t
. (从技术上讲,您只需要确保每个算术运算都以 off_t
的精度完成,但我发现如果我只是将所有操作数都用 punt 和 cast 来记住规则会更容易。)例如:
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, offset, SEEK_SET);
}
现在,如果你碰巧处于一个幸运的位置,你知道所有的偏移量都是对齐的(到某个整数,比如 4),你可以给自己几年更多的时间来重写应用程序,方法是使用上面的扩展:
#define BIG_N 4
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)
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, offset, 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, offset, 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 × (offset - 231 )。唯一的要求是偏移量 231 及以上始终是 BIG_N 的倍数。
显然,您必须仅使用上述三个函数——加上您需要的任何 fseek_to() 变体,只要它们进行相同的检查,只需使用不同的参数和公式进行偏移量计算 --,您可以支持最大 2147483648 + BIG_N × 2147483647 的文件大小。对于 BIG_N==4,即 10 GiB (少了 4 个字节;准确地说是 10,737,418,236 个字节)。
有问题吗?
编辑澄清:
从更换您的 fseek(file, position, SEEK_SET)
开始调用电话 fseek_pos(file, position)
,
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(file, position, SEEK_END)
调用电话 fseek_end(file, position)
(为了对称——我假设这个位置通常是一个字面整数常量),
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(file)
调用电话 ftell_pos(file)
:
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;
}
因为在你的架构和操作系统上 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 =
定义计算算法的行因变体函数而异。
有问题吗?
关于c - 在 freebsd 7 上快速修复 32 位(2GB 限制)fseek/ftell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24472361/
我有一个 ServiceBusQueue(SBQ),它获取大量消息负载。我有一个具有 accessRights(manage) 的 ServiceBusTrigger(SBT),它不断轮询来自 SBQ
在下面给出的结果集中,有 2 个唯一用户 (id),并且查询中可能会出现更多此类用户: 这是多连接查询: select id, name, col1Code, col2Code, col2Va
我正在用 Python 2.7.3 编写一个带有 GRequests 的小脚本和 lxml 可以让我从各种网站收集一些收藏卡价格并进行比较。问题是其中一个网站限制了请求的数量,如果我超过它,就会发回
我想知道何时实际使用删除级联或删除限制以及更新级联或更新限制。我对使用它们或在我的数据库中应用感到很困惑。 最佳答案 在外键约束上使用级联运算符是一个热门话题。 理论上,如果您知道删除父对象也将自动删
下面是我的输出,我只想显示那些重复的名字。每个名字都是飞行员,数字是飞行员驾驶的飞机类型。我想显示驾驶不止一架飞机的飞行员的姓名。我正在使用 sql*plus PIL_PILOTNAME
我正在评估不同的移动框架,我认为 nativescript 是一个不错的选择。但我不知道开发过程是否存在限制。例如,我对样式有限制(这并不重要),但我想知道将来我是否可以有限制并且不能使用某些 nat
我正在尝试使用 grails 数据绑定(bind)将一些表单参数映射到我的模型中,但我认为在映射嵌入式集合方面可能存在一些限制。 例如,如果我提交一些这样的参数,那么映射工作正常: //this wo
是否可以将 django 自过滤器起的时间限制为 7 天。如果日期超过 7 天,则不应用过滤器 最佳答案 timesince 的源代码位于 django/django/utils/timesince.
我想在我的网站上嵌入一个 PayPal 捐赠按钮。但问题是我住在伊朗——这个国家受到制裁,人们不使用国际银行账户或主要信用卡。 有什么想法吗?请帮忙! 问候 沮丧 最佳答案 您可以在伊朗境内使用为伊朗
这是我的查询 select PhoneNumber as _data,PhoneType as _type from contact_phonenumbers where ContactID = 3
这个问题在这里已经有了答案: What is the maximum number of parameters passed to $in query in MongoDB? (4 个答案) 关闭
我的一个项目的 AndroidManifest.xml 变得越来越大(> 1000 行),因为我必须对某些文件类型使用react并且涵盖所有情况变得越来越复杂。我想知道 list 大小是否有任何限制。
在使用 Sybase、Infomix、DB2 等其他数据库产品多年后使用 MySQL 5.1 Enterprise 时;我遇到了 MySQL 不会做的事情。例如,它只能为 SELECT 查询生成 EX
这个问题在这里已经有了答案: What is the maximum number of parameters passed to $in query in MongoDB? (4 个回答) 关闭5年
通常我们是在{$apache}/conf/httpd.conf中设置Apache的参数,然而我们并没有发现可以设置日志文件大小的配置指令,通过参考http://httpd.apache.org/do
我正在搜索最大的 Android SharedPreferences 键值对,但找不到任何好的答案。其次,我想问一下,如果我有一个键,它的字符串值限制是多少。多少字符可以放入其中。如果我需要频繁更改值
我目前正在试验 SoundCloud API,并注意到我对/tracks 资源的 GET 请求一次从不返回超过 200 个结果。关于这个的几个问题: 这个限制是故意的吗? 有没有办法增加这个限制? 如
我正在与一家名为 Dwolla 的金融技术公司合作,该公司提供了一个 API,用于将银行信息附加到用户并收取/发送 ACH 付款。 他们需要我将我的 TLS 最低版本升级到 1.2(禁用 TLS 1.
我在 PHP 中有一个多维数组,如下所示: $array = Array ( [0] => Array ( [bill] => 1 ) [1] => Array ( [
我在获取下一个查询的第一行时遇到了问题: Select mar.Title MarketTitle, ololo.NUMBER, ololo.Title from Markets mar JOIN(
我是一名优秀的程序员,十分优秀!