具有自己的文件偏移量的重复文件描述符

发布于 2024-08-08 05:14:23 字数 373 浏览 9 评论 0原文

如何从现有文件描述符创建新文件描述符,使得新描述符不共享文件表中相同的内部文件结构/条目?具体来说,诸如文件偏移量(最好是权限、共享和模式)之类的属性不应在新旧文件描述符之间共享。

在 Windows 和 Linux 下,dup() 都会复制文件描述符,但两个描述符仍然指向进程文件表中的相同文件结构。对任一描述符的任何查找也会调整其他描述符的位置。

注意

此后我收到了针对 Windows 和 Linux 的答案,并且对问题的调整有点过于频繁,这使得人们很难回答。我将调整我的投票并接受涵盖 Windows Linux 的最干净的答案。向所有人道歉,我对 SO 范式仍然很陌生。感谢您的精彩回答!

How can one create a new file descriptor from an existing file descriptor such that the new descriptor does not share the same internal file structure/entry in the file table? Specifically attributes such as file offset (and preferably permissions, sharing and modes) should not be shared between the new and old file descriptors.

Under both Windows and Linux, dup() will duplicate the file descriptor, but both descriptors still point to the same file structure in the process' file table. Any seeking on either descriptor will adjust the position for the other descriptors as well.

Note

I've since received answers for both Windows and Linux and adjusted the question a little too often, which has made it difficult for people to answer. I'll adjust my votes and accept the cleanest answer which covers both Windows and Linux. Apologies to all, I'm still new to the SO paradigm. Thanks for the great answers!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

香草可樂 2024-08-15 05:14:23

所以基本上,你真正想要的是给定一个文件描述符,并基本上再次打开同一个文件,以获得单独的位置、共享、模式等。你想在 Windows 上执行此操作(其中“文件描述符“基本上是一个外来对象,根本不是操作系统或运行时库直接使用的东西。

令人惊讶的是,至少有一种方法可以做到这一点使用 MS VC++。除了两个步骤之外,它的所有步骤都仅使用 Win32 API,因此移植到其他编译器/库应该相当合理(我认为这两个函数的大多数供应版本都是用于将 Unix 风格的文件描述符转换为本机 Win32 文件句柄,并将本机 Win32 文件句柄转换回 Unix 样式文件描述符。

  1. 使用 _get_osfhandle() 将文件描述符转换为本机文件句柄
  2. 。使用 GetFileInformationByHandleEx(FILE_NAME_INFO)1
  3. 使用 CreateFile 打开该文件的新句柄
  4. 使用 _open_osfhandle() 为该句柄创建一个文件描述符

,我们有一个新的文件描述符引用同一个文件,但具有自己的权限、位置等。

在问题结束时,您听起来好像您也想要“权限”,但这似乎没有任何实际意义——权限附加到文件本身,而不是附加到文件本身的方式文件已打开,因此打开或重新打开该文件不会影响该文件的权限。如果您确实想知道,可以使用 GetFileInformationByHandle 获取它,但请注意 Windows 中的文件权限与 Unix 中的(传统)文件权限有很大不同。 Unix 对所有文件都具有所有者/组/世界权限,并且大多数系统也具有 ACL(尽管它们的工作方式有更多变化)。 Windows 要么根本没有权限(例如 FAT 或 FAT32 上的文件),要么使用 ACL(例如 NTFS 上的文件),但没有什么真正等同于大多数人在 Unix 上习惯的传统所有者/组/世界权限。

也许您使用“权限”来指代文件是否打开以进行读取、写入或两者兼而有之。得到这个比前面的任何一个都要丑陋得多。问题是大部分内容都在库中,而不是 Win32 中,因此可能没有办法在编译器之间实现接近可移植的功能。使用 MS VC++ 9.0 SP1(不保证任何其他编译器),您可以执行以下操作:

#include <stdio.h>

int get_perms(int fd) {
    int i;
 FILE * base = __iob_func();

    for (i=0; i<_IOB_ENTRIES; i++) 
        if (base[i]._file == fd)
            return base[i]._flag;     // we've found our file
    return 0; // file wasn't found.
}

由于这涉及一些探索,我编写了一个快速测试来验证它是否确实有效:

#ifdef TEST
#include <io.h>

void show_perms(int perms, char const *caption) { 
 printf("File opened for %s\n", caption);
 printf("Read permission = %d\n", (perms & _IOREAD)!=0);
 printf("Write permission = %d\n", (perms & _IOWRT)!=0);
}

int main(int argc, char **argv) { 
 FILE *file1, *file2;
 int perms1, perms2;

 file1=fopen(argv[1], "w");
 perms1 = get_perms(_fileno(file1));
 fclose(file1);

 file2=fopen(argv[1], "r");
 perms2 = get_perms(_fileno(file2));
 fclose(file2);

 show_perms(perms1, "writing");
 show_perms(perms2, "reading");
 return 0;
}
#endif

结果似乎表明成功:

File opened for writing
Read permission = 0
Write permission = 1
File opened for reading
Read permission = 1
Write permission = 0

然后您可以根据 _IOREAD、_IOWRT 和 _IORW(在 stdio.h 中定义)测试返回的标志。尽管我之前发出过警告,但我可能应该指出,我怀疑(尽管我当然不能保证)库的这一部分相当稳定,因此发生重大更改的真正机会可能相当小。

然而,在另一个方向上,它基本上不可能与任何其他库一起工作。它可以(但当然不能保证)与使用 MS 库的其他编译器一起工作,例如使用 MS VC++ 作为后端的 Intel、MinGW 或 Comeau。其中,我想说最有可能起作用的是 Comeau,最不可能的是 MinGW(但这只是猜测;很有可能它不适用于其中任何一个)。

  1. 需要可再发行的 Win32 FileID API 库

So basically, what you really want is to be given a file descriptor, and basically open the same file over again, to get a separate position, sharing, mode, etc. And you want to do this on Windows (where the "file descriptor" is basically a foreign object, not something used directly by the OS or the run-time library at all.

Amazingly enough, there is a way to do that, at least with MS VC++. All but two steps of it use only the Win32 API so porting to other compilers/libraries should be fairly reasonable (I think most supply versions of those two functions). Those are for converting a Unix-style file descriptor to a native Win32 file handle, and converting a native Win32 file handle back to a Unix-style file descriptor.

  1. Convert file-descriptor to native file handle with _get_osfhandle()
  2. Get a name for the file with GetFileInformationByHandleEx(FILE_NAME_INFO)1
  3. Use CreateFile to open a new handle to that file
  4. Create a file descriptor for that handle with _open_osfhandle()

Et voilà, we have a new file descriptor referring to the same file, but with its own permissions, position, etc.

Toward the end of your question, you make it sound like you also want the "permissions", but that doesn't seem to make any real sense -- the permissions attach to the file itself, not to how the file is opened, so opening or reopening the file has no effect on the file's permissions. If you really want to know the, you can get it with GetFileInformationByHandle, but be aware that file permissions in Windows are quite a bit different from the (traditional) file permissions in Unix. Unix has owner/group/world permissions on all files, and most systems also have ACLs (though there's more variation in how they work). Windows either has no permissions at all (e.g., files on FAT or FAT32) or else uses ACLs (e.g., files on NTFS), but nothing that's really equivalent to the traditional owner/group/world permissions most people are accustomed to on Unix.

Perhaps you're using "permissions" to refer to whether the file was open for reading, writing, or both. Getting that is considerably uglier than any of the preceding. The problem is that most of it is in the library, not Win32, so there's probably no way to do it that will be even close to portable between compilers. With MS VC++ 9.0 SP1 (not guaranteed for any other compiler) you can do this:

#include <stdio.h>

int get_perms(int fd) {
    int i;
 FILE * base = __iob_func();

    for (i=0; i<_IOB_ENTRIES; i++) 
        if (base[i]._file == fd)
            return base[i]._flag;     // we've found our file
    return 0; // file wasn't found.
}

Since this involved some spelunking, I wrote a quick test to verify that it might actually work:

#ifdef TEST
#include <io.h>

void show_perms(int perms, char const *caption) { 
 printf("File opened for %s\n", caption);
 printf("Read permission = %d\n", (perms & _IOREAD)!=0);
 printf("Write permission = %d\n", (perms & _IOWRT)!=0);
}

int main(int argc, char **argv) { 
 FILE *file1, *file2;
 int perms1, perms2;

 file1=fopen(argv[1], "w");
 perms1 = get_perms(_fileno(file1));
 fclose(file1);

 file2=fopen(argv[1], "r");
 perms2 = get_perms(_fileno(file2));
 fclose(file2);

 show_perms(perms1, "writing");
 show_perms(perms2, "reading");
 return 0;
}
#endif

And the results seem to indicate success:

File opened for writing
Read permission = 0
Write permission = 1
File opened for reading
Read permission = 1
Write permission = 0

You can then test that returned flag against _IOREAD, _IOWRT, and _IORW, which are defined in stdio.h. Despite my previous warnings, I should probably point out that I suspect (though I certainly can't guarantee) that this part of the library is fairly stable, so the real chances of major changes are probably fairly minimal.

In the other direction, however, there's basically no chance at all that it'll work with any other library. It could (but certainly isn't guaranteed to) work with the other compilers that use the MS library, such as Intel, MinGW or Comeau using MS VC++ as its back-end. Of those, I'd say the most likely to work would be Comeau, and the least likely MinGW (but that's only a guess; there's a good chance it won't work with any of them).

  1. Requires the redistributable Win32 FileID API Library
愁杀 2024-08-15 05:14:23

因此,我建议您多读一点。 dup() 和相关函数用于在文件描述符表中创建指向打开文件表中相同条目的重复值。这是旨在具有相同的偏移量。如果您调用open(),您将在打开文件表中创建一个新条目。

创建文件描述符的副本没有任何意义,并且新文件描述符在打开的文件表中具有不同的偏移量(这似乎与“重复”一词的含义相矛盾)。

我不确定你的问题实际上是什么。我的意思是,它与副本不是一回事。您可以阅读:

/proc/self/fd/[descriptor]

并获取用于打开该文件描述符的字符串;请记住,这可能会带来一些陷阱,其中一些陷阱实际上是您在再次调用 open() 的观察中注意到的。

也许你可以解释一下,我可以尝试更新以提供帮助。

So, I recommend reading up on this a little more. The dup() and related functions serve to create a duplicate value in the file descriptor table pointing to the same entry in the open file table. This is intended to have the same offset. If you call open(), you will create a new entry the open file table.

It doesn't make any sense to create a duplicate of a file descriptor and that new file descriptor have a different offset in the open file table (this seems to contradict what the word "duplicate" means).

I'm not sure what your question is actually. I mean, it isn't the same thing as a duplicate. You could read:

/proc/self/fd/[descriptor]

and get the string that was used to open that file descriptor; bear in mind this may provide some pitfalls, some of which you actually noted in your observation of calling open() again.

Maybe you can explain a little more and I can try to update to help.

浅暮の光 2024-08-15 05:14:23

为什么不在 Windows 上使用 open() 或 CreateFile() 再次打开文件呢?这为您提供了不同访问权限和单独偏移的所有自由。

当然,这有一个缺点,即您无法以独占方式打开文件,但它很简单地解决了您的问题。

Why don't you just open the file a second time with open() or CreateFile() on windows? This gives you all freedom of different access rights and separate offset.

This of course has the drawback that you you can not open the file exclusively, but it solves your problem very simply.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文