この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
?