简体   繁体   English

查找与文件名关联的目录的文件描述符

[英]Find file descriptor of directory associated with filename

I am trying to write a function that allows users to change file timestamps with nanosecond precision.我正在尝试编写一个函数,允许用户以纳秒精度更改文件时间戳。 After some research , I found the function utimensat() which allows me to do this.经过一番研究,我发现了允许我这样做的函数utimensat() However the problem is that the function takes an argument int dirfd which is a file descriptor of the directory the file resides in.但是问题是该函数接受一个参数int dirfd ,它是文件所在目录的文件描述符。

Using a filename would it be possible to somehow find the file descriptor of the directory a file is in?使用文件名是否有可能以某种方式找到文件所在目录的文件描述符?

For example if a file test.txt is located in /home/user/files/test.txt , how could I get the file descriptor of the directory test.txt is in?例如,如果文件test.txt位于/home/user/files/test.txt ,我怎么能得到目录test.txt的文件描述符? aka the files directory.又名files目录。

There are multiple ways to achieve the desired result, and the simplest one doesn't involve opening a directory at all.有多种方法可以达到预期的效果,最简单的一种根本不需要打开目录。

static void set_time(const char *file, struct timespec *tvals)
{
    if (utimensat(AT_FDCWD, file, tvals, 0) != 0)
        err_sysrem("failed to set time on %s: ", file);
}

This uses the magic number AT_FDCWD which means that the file name argument to the function is interpreted 'as normal'.这使用了幻数AT_FDCWD ,这意味着函数的文件名参数被解释为“正常”。 This is the recommended option for command line arguments that are file names.这是作为文件名的命令行参数的推荐选项。

If you are processing a directory with opendir() , readdir() , closedir() from <dirent.h> , then you can use dirfd() to get the directory file descriptor associated with the DIR * structure for the current directory.如果您使用<dirent.h>中的opendir()readdir()closedir()处理目录,则可以使用dirfd()获取与当前目录的DIR *结构关联的目录文件描述符。 You can use that to set the file modification times.您可以使用它来设置文件修改时间。

If you still want to open the directory, then you can use dirname() to find the name of the directory for a given file name (and you may also use basename() to find the name of the file within the directory).如果您仍想打开该目录,则可以使用dirname()查找给定文件名的目录名称(也可以使用basename()查找目录中的文件名)。 Be careful;当心; there are a lot of possibilities for what the implementation does according to POSIX.根据 POSIX,实现的功能有很多可能性。 You should usually create a duplicate of the file name before passing the duplicate string to dirname() .您通常应该在将重复的字符串传递给dirname()之前创建文件名的副本。 You can call basename() on a string before calling dirname() on the string.您可以在对字符串调用dirname()之前对字符串调用basename() You can then use open() to open the directory for reading only — possibly using O_SEARCH (not widely available) or using O_RDONLY as the open mode.然后,您可以使用open()以只读方式打开目录 - 可能使用O_SEARCH (未广泛使用)或使用O_RDONLY作为打开模式。 Don't forget to close the directory after you're finished with it, nor to free the copy of the filename that you used.完成后不要忘记关闭目录,也不要忘记释放您使用的文件名的副本。

Here's the source code ft97.c for a program ft97 which will set the time stamps on a file to the chosen time – defaulting to the current time.这是ft97程序的源代码ft97.c ,它将文件上的时间戳设置为所选时间——默认为当前时间。

#include "posixver.h"
#include <fcntl.h>           /* AT_FDCWD on macOS Monterey 12.4 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "stderr.h"
#include "timespec_io.h"

static char optstr[] = "a:hm:t:V";
static char usestr[] = "[-hV] [-a atime] [-m mtime] [-t time] file ...";
static char hlpstr[] =
    "  -a atime  Use this time for the access time (default: now)\n"
    "  -h        Print this help message and exit\n"
    "  -m mtime  Use this time for the modification time (default: now)\n"
    "  -t time   Use this time value for both access and modification time\n"
    "  -V        Print version information and exit\n"
    ;

static void set_time(const char *file, struct timespec *tvals)
{
    if (utimensat(AT_FDCWD, file, tvals, 0) != 0)
        err_sysrem("failed to set time on %s: ", file);
}

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);

    struct timespec tvals[2];
    clock_gettime(CLOCK_REALTIME, &tvals[0]);
    tvals[1] = tvals[0];
    int opt;

    while ((opt = getopt(argc, argv, optstr)) != -1)
    {
        switch (opt)
        {
        case 'a':
            if (scn_timespec(optarg, &tvals[0]) != 0)
                err_error("failed to parse '%s' as a time\n", optarg);
            break;
        case 'h':
            err_help(usestr, hlpstr);
        /*NOTREACHED*/
        case 'm':
            if (scn_timespec(optarg, &tvals[1]) != 0)
                err_error("failed to parse '%s' as a time\n", optarg);
            break;
        case 'V':
            err_version("FT97", &"@(#)$Revision$ ($Date$)"[4]);
        /*NOTREACHED*/
        case 't':
            if (scn_timespec(optarg, &tvals[0]) != 0)
                err_error("failed to parse '%s' as a time\n", optarg);
            tvals[1] = tvals[0];
            break;
        default:
            err_usage(usestr);
            /*NOTREACHED*/
        }
    }

    if (argc == optind)
        err_usage(usestr);

    for (int i = optind; i < argc; i++)
        set_time(argv[i], tvals);

    return 0;
}

You can find the non-standard headers and corresponding source code in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c , stderr.h , posixver.h , timespec_io.c and timespec_io.h in the src/libsoq sub-directory.您可以在 GitHub 上的我的SOQ (堆栈溢出问题)存储库中找到非标准标头和相应的源代码,作为src/libsoq子目录中的文件stderr.cstderr.hposixver.htimespec_io.ctimespec_io.h -目录。

To get a file descriptor to a directory in c, simply open the "."要获取 c 中目录的文件描述符,只需打开“。” file of the directory and get the file descriptor from that, as you would a normal file.目录的文件并从中获取文件描述符,就像普通文件一样。

Here's an example这是一个例子

#include <stdio.h>

int main(int argc, char** argv) {   
    FILE* file = fopen("/path/to/directory/of/file/.", "r");
    int fd = fileno(file);
    
    //Do what you want with the file descriptor

    return 0;       
}

Note that the function fileno only works in POSIX compliant systems.请注意,函数 fileno 仅适用于 POSIX 兼容系统。 Thankfully, it appears that you are considering the forward slashes in your file path.值得庆幸的是,您似乎正在考虑文件路径中的正斜杠。

Hope this helps!希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM