* that these offsets are seekable to entry with the right inode.
*/
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
void usage()
{
- fprintf(stderr, "usage: t_dir_offset2: <dir> [bufsize]\n");
+ fprintf(stderr, "usage: t_dir_offset2: <dir> [[bufsize] [-|+]<filename> [-v]]\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
- int fd;
+ int fd, fd2 = -1;
char buf[BUF_SIZE];
int nread, bufsize = BUF_SIZE;
struct linux_dirent64 *d;
int bpos, total, i;
off_t lret;
int retval = EXIT_SUCCESS;
+ const char *filename = NULL;
+ int exists = 0, found = 0;
+ int modify = 0, verbose = 0;
if (argc > 2) {
bufsize = atoi(argv[2]);
usage();
if (bufsize > BUF_SIZE)
bufsize = BUF_SIZE;
+
+ if (argc > 3) {
+ filename = argv[3];
+ /* +<filename> creates, -<filename> removes */
+ if (filename[0] == '+')
+ modify = 1;
+ else if (filename[0] == '-')
+ modify = -1;
+ if (modify)
+ filename++;
+ if (argc > 4 && !strcmp(argv[4], "-v"))
+ verbose = 1;
+ }
} else if (argc < 2) {
usage();
}
exit(EXIT_FAILURE);
}
+ if (filename) {
+ exists = !faccessat(fd, filename, F_OK, AT_SYMLINK_NOFOLLOW);
+ if (!exists && errno != ENOENT) {
+ perror("faccessat");
+ exit(EXIT_FAILURE);
+ }
+ }
+
total = 0;
for ( ; ; ) {
nread = syscall(SYS_getdents64, fd, buf, bufsize);
exit(EXIT_FAILURE);
}
+ if (modify && fd2 < 0 && total == 0) {
+ printf("getdents at offset 0 returned %d bytes\n", nread);
+
+ /* create/unlink entry after first getdents */
+ if (modify > 0) {
+ if (openat(fd, filename, O_CREAT, 0600) < 0) {
+ perror("openat");
+ exit(EXIT_FAILURE);
+ }
+ exists = 1;
+ printf("created entry %s\n", filename);
+ } else if (modify < 0) {
+ if (unlinkat(fd, filename, 0) < 0) {
+ perror("unlinkat");
+ exit(EXIT_FAILURE);
+ }
+ exists = 0;
+ printf("unlinked entry %s\n", filename);
+ }
+
+ /*
+ * Old fd may not return new entry and may return stale
+ * entries which is allowed. Keep old fd open and open
+ * a new fd to check for stale or missing entries later.
+ */
+ fd2 = open(argv[1], O_RDONLY | O_DIRECTORY);
+ if (fd2 < 0) {
+ perror("open fd2");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (nread == 0) {
+ if (fd2 < 0 || fd == fd2)
+ break;
+
+ /* Re-iterate with new fd leaving old fd open */
+ fd = fd2;
+ total = 0;
+ found = 0;
+ continue;
+ }
+
if (nread == 0)
break;
}
d_off_history[total] = d->d_off;
d_ino_history[total] = d->d_ino;
+ if (filename) {
+ if (verbose)
+ printf("entry #%d: %s (d_ino=%lld, d_off=%lld)\n",
+ i, d->d_name, (long long int)d->d_ino,
+ (long long int)d->d_off);
+ if (!strcmp(filename, d->d_name))
+ found = 1;
+ }
bpos += d->d_reclen;
}
}
+ if (filename) {
+ if (exists == found) {
+ printf("entry %s %sfound as expected\n", filename, found ? "" : "not ");
+ } else {
+ fprintf(stderr, "%s entry %s\n",
+ exists ? "missing" : "stale", filename);
+ exit(EXIT_FAILURE);
+ }
+ }
+
/* check if seek works correctly */
d = (struct linux_dirent64 *)buf;
for (i = total - 1; i >= 0; i--)