Что для этого есть?
Тот факт, что у GLIBC не было возможности #define USE_FCNTL_NOT_FCNTL64
, говорит о многом. Правильно это или нет, но большинство производителей наборов инструментов OS +, похоже, решили, что нацеливание на бинарные файлы для старых версий своих систем из более новых не является приоритетом.
Путь наименьшего сопротивления состоит в том, чтобы поддерживать виртуальную машину вокруг самой старой инструментальной цепочки OS +, которая создает ваш проект. Используйте это для создания двоичных файлов всякий раз, когда вы думаете, что двоичный файл будет запущен в старой системе.
Но...
- Если вы считаете, что ваше использование относится к подмножеству вызовов fcntl (), на которые не влияет изменение размера смещения (то есть вы не используете блокировки диапазона байтов)
- ИЛИ готовы проверить ваш код на предмет смещения, чтобы использовать определение структуры с обратной совместимостью
- И не боятся вуду
... тогда продолжайте читать.
Имя другое, и fcntl является вариативным без vffcntl, который принимает va_list. В таких ситуациях вы не можете пересылать вызов вариативной функции.
... затем, чтобы применить упомянутый трюк с упаковкой, вам нужно построчно пройти через интерфейс fcntl () документации, распакуйте вариативное число, как это было бы, а затем вызовите упакованную версию с новым вызовом вариативного числа.
К счастью, это не так уж и сложно (fcntl принимает 0 или 1 аргумент с задокументированными типами). Чтобы попытаться избавить кого-то от неприятностей, вот код для этого. Не забудьте передать компоновщику --wrap = fcntl64 (-Wl, - wrap = fcntl64, если ld не вызывается напрямую):
asm (".symver fcntl64, fcntl@GLIBC_2.2.5");
extern "C" int __wrap_fcntl64(int fd, int cmd, ...)
{
int result;
va_list va;
va_start(va, cmd);
switch (cmd) {
//
// File descriptor flags
//
case F_GETFD: goto takes_void;
case F_SETFD: goto takes_int;
// File status flags
//
case F_GETFL: goto takes_void;
case F_SETFL: goto takes_int;
// File byte range locking, not held across fork() or clone()
//
case F_SETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_SETLKW: goto takes_flock_ptr_INCOMPATIBLE;
case F_GETLK: goto takes_flock_ptr_INCOMPATIBLE;
// File byte range locking, held across fork()/clone() -- Not POSIX
//
case F_OFD_SETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_OFD_SETLKW: goto takes_flock_ptr_INCOMPATIBLE;
case F_OFD_GETLK: goto takes_flock_ptr_INCOMPATIBLE;
// Managing I/O availability signals
//
case F_GETOWN: goto takes_void;
case F_SETOWN: goto takes_int;
case F_GETOWN_EX: goto takes_f_owner_ex_ptr;
case F_SETOWN_EX: goto takes_f_owner_ex_ptr;
case F_GETSIG: goto takes_void;
case F_SETSIG: goto takes_int;
// Notified when process tries to open or truncate file (Linux 2.4+)
//
case F_SETLEASE: goto takes_int;
case F_GETLEASE: goto takes_void;
// File and directory change notification
//
case F_NOTIFY: goto takes_int;
// Changing pipe capacity (Linux 2.6.35+)
//
case F_SETPIPE_SZ: goto takes_int;
case F_GETPIPE_SZ: goto takes_void;
// File sealing (Linux 3.17+)
//
case F_ADD_SEALS: goto takes_int;
case F_GET_SEALS: goto takes_void;
// File read/write hints (Linux 4.13+)
//
case F_GET_RW_HINT: goto takes_uint64_t_ptr;
case F_SET_RW_HINT: goto takes_uint64_t_ptr;
case F_GET_FILE_RW_HINT: goto takes_uint64_t_ptr;
case F_SET_FILE_RW_HINT: goto takes_uint64_t_ptr;
default:
fprintf(stderr, "fcntl64 workaround got unknown F_XXX constant")
}
takes_void:
va_end(va);
return fcntl64(fd, cmd);
takes_int:
result = fcntl64(fd, cmd, va_arg(va, int));
va_end(va);
return result;
takes_flock_ptr_INCOMPATIBLE:
//
// !!! This is the breaking case: the size of the flock
// structure changed to accommodate larger files. If you
// need this, you'll have to define a compatibility struct
// with the older glibc and make your own entry point using it,
// then call fcntl64() with it directly (bear in mind that has
// been remapped to the old fcntl())
//
fprintf(stderr, "fcntl64 hack can't use glibc flock directly");
exit(1);
takes_f_owner_ex_ptr:
result = fcntl64(fd, cmd, va_arg(va, struct f_owner_ex*));
va_end(va);
return result;
takes_uint64_t_ptr:
result = fcntl64(fd, cmd, va_arg(va, uint64_t*));
va_end(va);
return result;
}
Обратите внимание, что в зависимости от того, на какой версии вы фактически работаете, вам может потребоваться #ifdef некоторые из этих разделов флагов, если они недоступны.
Это влияет на множество приложений ... страница руководства для fcntl () показывает, что это точка входа для небольшого набора подфункций.
... и это, вероятно, должно стать уроком для людей: избегайте создания таких функций "кухонной мойки" путем разнообразного злоупотребления.
person
HostileFork says dont trust SE
schedule
20.10.2019