Người ta có những gì đòi hỏi cho điều này?
Thực tế là GLIBC không có cách nào để #define USE_FCNTL_NOT_FCNTL64
nói nhiều. Dù đúng hay sai, hầu hết các nhà sản xuất chuỗi công cụ OS + dường như đã quyết định rằng việc nhắm mục tiêu nhị phân cho các phiên bản cũ hơn của hệ thống của họ từ phiên bản mới hơn không phải là ưu tiên cao.
Con đường ít kháng cự nhất là giữ một máy ảo xung quanh chuỗi công cụ OS + lâu đời nhất xây dựng dự án của bạn. Sử dụng điều đó để tạo nhị phân bất cứ khi nào bạn nghĩ rằng nhị phân sẽ được chạy trên một hệ thống cũ.
Nhưng...
- Nếu bạn tin rằng tập quán của bạn nằm trong tập hợp con của các lệnh gọi fcntl () không bị ảnh hưởng bởi thay đổi kích thước bù (nghĩa là bạn không sử dụng khóa phạm vi byte)
- HOẶC sẵn sàng kiểm tra mã của bạn cho các trường hợp bù để sử dụng định nghĩa cấu trúc tương thích ngược
- VÀ không sợ voodoo
... Sau đó tiếp tục đọc.
Tên là khác nhau, và fcntl là matrixdic mà không có vffcntl có một va_list. Trong những tình huống như vậy, bạn không thể chuyển tiếp một lời gọi của hàm matrixdic.
... sau đó để áp dụng thủ thuật gói được đề cập , bạn phải truy cập từng dòng thông qua tài liệu giao diện của fcntl (), giải nén các từ khóa như nó sẽ, và sau đó gọi phiên bản được bao bọc bằng một lệnh gọi kiểu mới.
May mắn thay, đó không phải là một trường hợp khó khăn (fcntl có 0 hoặc 1 đối số với các loại tài liệu). Để thử cứu bất kỳ ai khác một số rắc rối, đây là mã cho điều đó. Hãy chắc chắn chuyển --wrap = fcntl64 cho trình liên kết ( -Wl, - quấn = fcntl64 nếu không gọi trực tiếp 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;
}
Lưu ý rằng tùy thuộc vào phiên bản bạn thực sự xây dựng, bạn có thể phải #ifdef một số phần cờ đó nếu chúng không khả dụng.
Điều này ảnh hưởng đến khá nhiều ứng dụng ... trang hướng dẫn cho fcntl () cho thấy đó là điểm khởi đầu cho một vũ trụ nhỏ của các chức năng phụ
... Và nó có lẽ nên là một bài học cho mọi người: tránh tạo ra các chức năng "bồn rửa nhà bếp" như vậy thông qua lạm dụng dao động.