There is some magic going on when it comes to stat() or lstat().
Basically, stat() can either be a regular function, an inline
function that calls __xstat(_STAT_VER, ...) or a macro that does
the same as the inline func. Don't ask why is that, just read the
documentation in sys/stat.h and make sure you have a bucket next
to you. Anyway, currently there will not be both stat and __xstat
symbols at the same time, as one of them gets overwritten to the
other one during compilation. But this is not true anymore once
we start chaining our mocking libraries. Therefore we need a
wrapper that calls desired function from glibc.
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
errno = ENOMEM;
return -1;
}
- ret = real___lxstat(ver, newpath, sb);
+ ret = VIR_MOCK_CALL_LSTAT(ver, newpath, sb);
free(newpath);
} else if (STRPREFIX(path, fakedevicedir0)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(9, 0);
return 0;
} else {
- ret = real___lxstat(ver, path, sb);
+ ret = VIR_MOCK_CALL_LSTAT(ver, path, sb);
}
return ret;
}
errno = ENOMEM;
return -1;
}
- ret = real_lstat(newpath, sb);
+ ret = VIR_MOCK_CALL_LSTAT(_STAT_VER, newpath, sb);
free(newpath);
} else if (STRPREFIX(path, fakedevicedir0)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(9, 0);
return 0;
} else {
- ret = real_lstat(path, sb);
+ ret = VIR_MOCK_CALL_LSTAT(_STAT_VER, path, sb);
}
return ret;
}
errno = ENOMEM;
return -1;
}
- ret = real___xstat(ver, newpath, sb);
+ ret = VIR_MOCK_CALL_STAT(ver, newpath, sb);
free(newpath);
} else if (STRPREFIX(path, fakedevicedir0)) {
sb->st_mode = S_IFBLK;
sb->st_rdev = makedev(9, 0);
return 0;
} else {
- ret = real___xstat(ver, path, sb);
+ ret = VIR_MOCK_CALL_STAT(ver, path, sb);
}
return ret;
}
if (!(newpath = strdup(path)))
return -1;
}
- ret = real_stat(newpath, sb);
+ ret = VIR_MOCK_CALL_STAT(_STAT_VER, newpath, sb);
free(newpath);
return ret;
}
# endif
# include <stdlib.h>
# include <stdio.h>
+# include <sys/stat.h>
# include "internal.h"
static void (*real_##name)(void); \
void name(void)
+static inline int
+callStat(int (*realStat)(const char *, struct stat *),
+ int (*realXstat)(int, const char *, struct stat *),
+ int __ver, const char *__filename, struct stat *__stat_buf)
+{
+ if (!realXstat) {
+ if (__ver == _STAT_VER) {
+ return realStat(__filename, __stat_buf);
+ } else {
+ fprintf(stderr, "Not handled __xstat(ver=%d)", __ver);
+ abort();
+ }
+ }
+
+ return realXstat(__ver, __filename, __stat_buf);
+}
+
+# define VIR_MOCK_CALL_STAT(__ver, __filename, __stat_buf) \
+ callStat(real_stat, real___xstat, __ver, __filename, __stat_buf)
+# define VIR_MOCK_CALL_LSTAT(__ver, __filename, __stat_buf) \
+ callStat(real_lstat, real___lxstat, __ver, __filename, __stat_buf)
+
/*
* The VIR_MOCK_WRAP_NNN_MMM() macros are intended for use in the
* individual test suites. The define a stub implementation of
/* If there is a config file for the device within virpcitestdata dir,
* symlink it. Otherwise create a dummy config file. */
- if ((real_stat && real_stat(configSrc, &sb) == 0) ||
- (real___xstat && real___xstat(_STAT_VER, configSrc, &sb) == 0)) {
+ if (VIR_MOCK_CALL_STAT(_STAT_VER, configSrc, &sb) == 0) {
/* On success, copy @configSrc into the destination (a copy,
* rather than a symlink, is required since we write into the
* file, and parallel VPATH builds must not stomp on the
char *newpath;
if (getrealpath(&newpath, path) < 0)
return -1;
- ret = real___lxstat(ver, newpath, sb);
+ ret = VIR_MOCK_CALL_LSTAT(ver, newpath, sb);
VIR_FREE(newpath);
} else {
- ret = real___lxstat(ver, path, sb);
+ ret = VIR_MOCK_CALL_LSTAT(ver, path, sb);
}
return ret;
}
char *newpath;
if (getrealpath(&newpath, path) < 0)
return -1;
- ret = real_lstat(newpath, sb);
+ ret = VIR_MOCK_CALL_LSTAT(_STAT_VER, newpath, sb);
VIR_FREE(newpath);
} else {
- ret = real_lstat(path, sb);
+ ret = VIR_MOCK_CALL_LSTAT(_STAT_VER, path, sb);
}
return ret;
}
char *newpath;
if (getrealpath(&newpath, path) < 0)
return -1;
- ret = real___xstat(ver, newpath, sb);
+ ret = VIR_MOCK_CALL_STAT(ver, newpath, sb);
VIR_FREE(newpath);
} else {
- ret = real___xstat(ver, path, sb);
+ ret = VIR_MOCK_CALL_STAT(ver, path, sb);
}
return ret;
}
char *newpath;
if (getrealpath(&newpath, path) < 0)
return -1;
- ret = real_stat(newpath, sb);
+ ret = VIR_MOCK_CALL_STAT(_STAT_VER, newpath, sb);
VIR_FREE(newpath);
} else {
- ret = real_stat(path, sb);
+ ret = VIR_MOCK_CALL_STAT(_STAT_VER, path, sb);
}
return ret;
}