我正在尝试编写一个处理ustar档案的便携式程序。对于设备文件,这些存档存储主要和次要设备编号。但是,POSIX中列出的struct stat
仅包含一个st_rdev
使用“设备ID(如果文件是字符或块特殊)”描述的类型dev_t
的成员。“
如何以便携方式在st_rdev
返回的一对主设备号和次设备号以及一个stat()
成员之间进行转换?
答案 0 :(得分:4)
虽然所有POSIX编程接口都使用设备号(类型为dev_t
),但FUZxxl在对此答案的评论中指出了常见的UStar文件格式 - 最常见的tar归档格式 - 将设备编号分为主要和次要。 (它们通常编码为每个七个八进制数字,因此出于兼容性原因,应限制为21位无符号主要和21位无符号次要。这也意味着将设备编号映射到主要或仅次要不是可靠的方法。)
以下内容包括在Jonathon Reinhart's answer上展开文件,在网上挖掘各种系统手册页和文档(适用于makedev()
,major()
和minor()
),加上对这个问题的评论。
#if defined(custom_makedev) && defined(custom_major) && defined(custom_minor)
/* Already defined */
#else
#undef custom_makedev
#undef custom_major
#undef custom_minor
#if defined(__linux__) || defined(__GLIBC__)
/* Linux, Android, and other systems using GNU C library */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_WIN32)
/* 32- and 64-bit Windows. VERIFY: These are just a guess! */
#define custom_makedev(dmajor, dminor) ((((unsigned int)dmajor << 8) & 0xFF00U) | ((unsigned int)dminor & 0xFFFF00FFU))
#define custom_major(devnum) (((unsigned int)devnum & 0xFF00U) >> 8)
#define custom_minor(devnum) ((unsigned int)devnum & 0xFFFF00FFU)
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
/* FreeBSD, OpenBSD, NetBSD, and DragonFlyBSD */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(__APPLE__) && defined(__MACH__)
/* Mac OS X */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_AIX) || defined (__osf__)
/* AIX, OSF/1, Tru64 Unix */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(hpux)
/* HP-UX */
#include <sys/sysmacros.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(sun)
/* Solaris */
#include <sys/types.h>
#include <sys/mkdev.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#else
/* Unknown OS. Try a the BSD approach. */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#if defined(makedev) && defined(major) && defined(minor)
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#endif
#endif
#if !defined(custom_makedev) || !defined(custom_major) || !defined(custom_minor)
#error Unknown OS: please add definitions for custom_makedev(), custom_major(), and custom_minor(), for device number major/minor handling.
#endif
#endif
可以从现有的具有UStar格式功能的归档器中收集其他定义。在我看来,与每个OS /架构上的现有实现的兼容性是最重要的。
以上内容应涵盖使用GNU C库,Linux(包括Android),FreeBSD,OpenBSD,NetBSD,DragonFlyBSD,Mac OS X,AIX,Tru64,HP-UX和Solaris的所有系统,以及任何定义宏的系统<sys/types.h>
包括在内。在Windows部分中,我不确定。
据我了解,Windows对所有普通文件使用设备0,对设备使用HANDLE
(无效指针类型)。我完全不确定上述逻辑是否在Windows上是合理的,但许多较旧的系统将设备号的8个最低有效位置为次要,接下来的8位为主要,并且约定似乎是任何剩余的位将被放入(没有转移)成为次要的。使用对设备的引用来检查现有的UStar格式tar档案会很有用,但我个人根本不使用Windows。
如果未检测到系统,并且系统未使用BSD样式包含来定义宏,则上述操作将错误地停止编译。 (我个人会添加编译时机制,可以帮助找到正确的标头定义,例如使用find
,xargs
和grep
,如果发生这种情况,建议发送另外上游也是。touch empty.h ; cpp -dM empty.h ; rm -f empty.h
应显示所有预定义的宏,以帮助识别操作系统和/或C库。)
最初,POSIX声明dev_t
必须是算术类型(因此,理论上,它可能是某些系统上float
或double
的某种变体),但是{{3说它必须是整数类型。我敢打赌这意味着没有已知的POSIX-y系统曾经使用过浮点dev_t
类型。看起来Windows使用void指针或HANDLE
类型,但Windows无论如何都不符合POSIX。
答案 1 :(得分:3)
在定义major()
后使用minor()
和BSD_SOURCE
宏。
未指定makedev(),major()和minor()函数 POSIX.1,但存在于许多其他系统上。
答案 2 :(得分:2)
我有一个基于古典版ls
的Minix程序,但是从那以后我修改了很多 mangled 。它具有以下代码来检测主要和次要宏 - 以及一些关于(现在)古老系统的评论。它假定GCC的最新版本可用于支持#pragma GCC diagnostic ignored
等。您必须非常努力(例如clang -Weverything
)才能使-Wunused-macros
选项生效,除非您明确包含它
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
/* Defines to ensure major and minor macros are available */
#define _DARWIN_C_SOURCE /* In <sys/types.h> on MacOS X */
#define _BSD_SOURCE /* In <sys/sysmacros.h> via <sys/types.h> on Linux (Ubuntu 12.0.4) */
#define __EXTENSIONS__ /* Maybe beneficial on Solaris */
#pragma GCC diagnostic pop
/* From Solaris 2.6 sys/sysmacros.h
**
** WARNING: The device number macros defined here should not be used by
** device drivers or user software. [...] Application software should make
** use of the library routines available in makedev(3). [...] Macro
** routines bmajor(), major(), minor(), emajor(), eminor(), and makedev()
** will be removed or their definitions changed at the next major release
** following SVR4.
**
** #define O_BITSMAJOR 7 -- # of SVR3 major device bits
** #define O_BITSMINOR 8 -- # of SVR3 minor device bits
** #define O_MAXMAJ 0x7f -- SVR3 max major value
** #define O_MAXMIN 0xff -- SVR3 max major value
**
** #define L_BITSMAJOR 14 -- # of SVR4 major device bits
** #define L_BITSMINOR 18 -- # of SVR4 minor device bits
** #define L_MAXMAJ 0x3fff -- SVR4 max major value
** #define L_MAXMIN 0x3ffff -- MAX minor for 3b2 software drivers.
** -- For 3b2 hardware devices the minor is restricted to 256 (0-255)
*/
/* AC_HEADER_MAJOR:
** - defines MAJOR_IN_MKDEV if found in sys/mkdev.h
** - defines MAJOR_IN_SYSMACROS if found in sys/macros.h
** - otherwise, hope they are in sys/types.h
*/
#if defined MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#elif defined(MAJOR_MINOR_MACROS_IN_SYS_TYPES_H)
/* MacOS X 10.2 - for example */
/* MacOS X 10.5 requires -D_DARWIN_C_SOURCE or -U_POSIX_C_SOURCE - see above */
#elif defined(USE_CLASSIC_MAJOR_MINOR_MACROS)
#define major(x) ((x>>8) & 0x7F)
#define minor(x) (x & 0xFF)
#else
/* Hope the macros are in <sys/types.h> or otherwise magically visible */
#endif
#define MAJOR(x) ((long)major(x))
#define MINOR(x) ((long)minor(x))
你有理由不会那么热衷于'希望宏是......神奇可见'代码的一部分。
对AC_HEADER_MAJOR
的引用是autoconf
中推断此信息的宏。如果您有config.h
生成的autoconf
文件,则会很有用。
请注意,POSIX pax
命令定义ustar
格式,并指定它在信息中包含 devmajor 和 devminor ,但添加:
...分别表示字符特殊文件和块特殊文件。在这种情况下, devmajor 和 devminor 字段应包含定义设备的信息,其格式未由此卷POSIX.1-2008指定。实现可以将设备规范映射到它们自己的本地规范,或者可以忽略该条目。
这意味着没有完全可移植的方式来表示数字。这并非完全不合理(但这是令人讨厌的);主要和次要设备数量的含义因平台而异,也未指定。任何通过ustar
格式创建块或字符设备的尝试只有在源和目标机器运行相同(相同版本的)操作系统时才能合理可靠地工作 - 尽管它们通常可以在相同的版本中移植操作系统。