파일 설명자를 통해 "익명" 심볼릭 링크의 타임스탬프 변경

파일 설명자를 통해 "익명" 심볼릭 링크의 타임스탬프 변경

futime*함수 계열의 구현은 다음과 같습니다.

utimensat(fd, NULL, time, 0)

그리고 lutime*그것들은 사용됩니다

utimensat(AT_FDCWD, path, time, AT_SYMLINK_NOFOLLOW)

내 추측은 "심볼릭 링크를 참조하는 파일 설명자 가져오기" 섹션에서 나왔습니다.https://man7.org/linux/man-pages/man7/symlink.7.html그게 다야 :

int fd = open(path, O_PATH | O_NOFOLLOW);
utimensat(fd, NULL, time, AT_SYMLINK_NOFOLLOW);

그것은 두 세계 모두에서 최고여야 하지만 슬프게도 그렇지 않습니다.

다음 변형을 시도해 보세요.

#define _GNU_SOURCE

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syscall.h>

#define __NR_openat 257
#define __NR_utimensat 280

struct flags
{
   char o_path;
   char o_nofollow;
   char at_symlink_nofollow;
};

int isX(char c, int flag)
{
    return c == 'x' ? flag : 0;
}

int main(int argc, const char *argv[])
{
    assert(argc == 3);
    const char *path = argv[1];
    assert(strlen(argv[2]) == 3);
    struct flags flags = * (const struct flags *) argv[2];

    // Open the file without following symbolic links
    int fd = openat(AT_FDCWD, path,
        isX(flags.o_path, O_PATH) |
        isX(flags.o_nofollow, O_NOFOLLOW));
    if (fd == -1) {
        perror("open");
        return EXIT_FAILURE;
    }

    // Prepare the time values for access and modification times
    struct timespec times[2] = {
        {
            .tv_sec = 0,
            .tv_nsec = 0,
        },
        {
            .tv_sec = 0,
            .tv_nsec = 0,
        },
    };

    // Update file times using utimensat
    if (syscall(__NR_utimensat, fd, NULL, times,
        isX(flags.at_symlink_nofollow, AT_SYMLINK_NOFOLLOW)) == -1)
    {
        perror("utimensat");
        close(fd);
        return EXIT_FAILURE;
    }

    close(fd);
    printf("File timestamps updated successfully.\n");
    return EXIT_SUCCESS;
}

그리고 스크립트

rm -f foo bar
touch foo
ln -s foo bar

for f in foo bar; do
    for y in ooo oox oxo xoo oxx xxo xxx; do
        echo -n "$f $y: "
        ./a.out "$f" "$y";
    done;
done
ls -la foo bar

불행하게도 심볼릭 링크 자체에 타임스탬프를 설정하는 조합이 없다는 것을 알게 될 것입니다:

$ ./flutimes.sh
foo ooo: File timestamps updated successfully.
foo oox: utimensat: Invalid argument
foo oxo: File timestamps updated successfully.
foo xoo: utimensat: Bad file descriptor
foo oxx: utimensat: Invalid argument
foo xxo: utimensat: Bad file descriptor
foo xxx: utimensat: Invalid argument
bar ooo: File timestamps updated successfully.
bar oox: utimensat: Invalid argument
bar oxo: open: Symbolic link loop
bar xoo: utimensat: Bad file descriptor
bar oxx: open: Symbolic link loop
bar xxo: utimensat: Bad file descriptor
bar xxx: utimensat: Invalid argument

작동하지 않는 이유가 있는지 묻고 있는 것 같습니다. 후자를 지원하는 모든 시스템 호출과 함께 작업하면서 좋은 친구가 되어서 O_PATH | O_NOFOLLOW는 안 되며, 그렇게 되어야 할까요 ? AT_SYMLINK_NOFOLLOW아니면 O_PATH비슷한걸로 교체하는게 나을까요 O_METADATA_ONLY?

관련 정보