1 /* 2 * Copyright (c) 2019 Darren Tucker 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <sys/types.h> 18 #include <sys/stat.h> 19 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #define TMPFILE "utimensat.tmp" 28 #define TMPFILE2 "utimensat.tmp2" 29 30 #ifndef AT_SYMLINK_NOFOLLOW 31 # define AT_SYMLINK_NOFOLLOW 0x80000000 32 #endif 33 34 int utimensat(int, const char *, const struct timespec[2], int); 35 36 void 37 fail(char *msg, long expect, long got) 38 { 39 int saved_errno = errno; 40 41 if (expect == got && got == 0) 42 fprintf(stderr, "utimensat: %s: %s\n", msg, 43 strerror(saved_errno)); 44 else 45 fprintf(stderr, "utimensat: %s: expected %ld got %ld\n", 46 msg, expect, got); 47 exit(1); 48 } 49 50 int 51 main(void) 52 { 53 int fd; 54 struct stat sb; 55 struct timespec ts[2]; 56 57 if ((fd = open(TMPFILE, O_CREAT, 0600)) == -1) 58 fail("open", 0, 0); 59 close(fd); 60 61 ts[0].tv_sec = 12345678; 62 ts[0].tv_nsec = 23456789; 63 ts[1].tv_sec = 34567890; 64 ts[1].tv_nsec = 45678901; 65 if (utimensat(AT_FDCWD, TMPFILE, ts, AT_SYMLINK_NOFOLLOW) == -1) 66 fail("utimensat", 0, 0); 67 68 if (stat(TMPFILE, &sb) == -1) 69 fail("stat", 0, 0 ); 70 if (sb.st_atime != 12345678) 71 fail("st_atime", 0, 0 ); 72 if (sb.st_mtime != 34567890) 73 fail("st_mtime", 0, 0 ); 74 #if 0 75 /* 76 * Results expected to be rounded to the nearest microsecond. 77 * Depends on timestamp precision in kernel and filesystem so 78 * disabled by default. 79 */ 80 if (sb.st_atim.tv_nsec != 23456000) 81 fail("atim.tv_nsec", 23456000, sb.st_atim.tv_nsec); 82 if (sb.st_mtim.tv_nsec != 45678000) 83 fail("mtim.tv_nsec", 45678000, sb.st_mtim.tv_nsec); 84 #endif 85 86 if (rename(TMPFILE, TMPFILE2) == -1) 87 fail("rename", 0, 0); 88 if (symlink(TMPFILE2, TMPFILE) == -1) 89 fail("symlink", 0, 0); 90 91 if (utimensat(AT_FDCWD, TMPFILE, ts, AT_SYMLINK_NOFOLLOW) != -1) 92 fail("utimensat followed symlink", 0, 0); 93 94 if (!(unlink(TMPFILE) == 0 && unlink(TMPFILE2) == 0)) 95 fail("unlink", 0, 0); 96 exit(0); 97 } 98