On Thu, May 12, 2016 at 14:33:08 +0200, Michal Privoznik wrote:
On 11.05.2016 17:15, Peter Krempa wrote:
> On Tue, May 10, 2016 at 17:24:13 +0200, Michal Privoznik wrote:
[...]
>> +static void
>> +printFile(const char *output,
>> + const char *file)
>> +{
>> + FILE *fp;
>> + const char *testname = getenv("VIR_TEST_MOCK_TESTNAME");
>> +
>> + if (!progname) {
>> + progname = getenv("VIR_TEST_MOCK_PROGNAME");
>> +
>> + if (!progname)
>> + return;
>> + }
>> +
>> + if (!(fp = realfopen(output, "a"))) {
>> + fprintf(stderr, "Unable to open %s: %s\n", output,
strerror(errno));
>> + abort();
>
> I'm a bit worried that if this wrapper fails the testsuite will abort.
> Couldn't we just skip creating/opening the file at this point? You can
> always error out in the phase where the file is checked.
But how would I know then that this has failed? Note that this should
also work in case a single test is ran. Why is aborting each test that
failed to open the file a bad thing anyway?
In such case it's more than likely that the file will fail to be opened
even for the analysis.
>
>> + }
>> +
>> + if (flock(fileno(fp), LOCK_EX) < 0) {
>> + fprintf(stderr, "Unable to lock %s: %s\n", output,
strerror(errno));
>> + fclose(fp);
>> + abort();
>
> Won't there be a possibility of collision if two tests are running in
> parallel?
I don't know what you mean. That's why I lock the file here so that
there's no collision.
Never mind. I re-read the man page for flock and noticed that LOCK_EX
whithout LOCK_NB will actually block until the lock is released.
[...]
>> +
>> +static void
>> +cutOffLastComponent(char *path)
>> +{
>> + char *base = path, *p = base;
>> +
>> + while (*p) {
>> + if (*p == '/')
>> + base = p;
>> + p++;
>> + }
>> +
>> + if (base != p)
>> + *base = '\0';
>
> We already have a function like this:
> virStorageFileRemoveLastPathComponent.
>
> Also 'strrchr' instead of the while loop?
Hm.. okay. I can expose the function. I've looked around virfile.c and
haven't find anything. I didn't check storage driver sources though.
src/util/virstoragefile.c AFAIK
>> static void
>> checkPath(const char *path)
>> {
>> + char *fullPath = NULL;
>> + char *relPath = NULL;
>> + char *crippledPath = NULL;
>> +
>> + if (path[0] != '/' &&
>> + asprintf(&relPath, "./%s", path) < 0)
>> + goto error;
>> +
>> + /* Le sigh. Both canonicalize_file_name() and realpath()
>> + * expect @path to exist otherwise they return an error. So
>> + * if we are called over an non-existent file, this could
>> + * return an error. In that case do our best and hope we will
>> + * catch possible error. */
>
> You can always stat the file to check if it exists before trying to get
> it's canonical path.
Why? if stat() succeeds so does canonicalize_file_name() and vice versa.
Therefore I think calling stat() would be just redundant.
Hmm, fair enough.
>
>> + if ((fullPath = canonicalize_file_name(relPath ? relPath : path))) {
>> + path = fullPath;
>> + } else {
>> + /* Yeah, our worst nightmares just became true. Path does
>> + * not exist. Cut off the last component and retry. */
>> + if (!(crippledPath = strdup(relPath ? relPath : path)))
>> + goto error;
>
> So if the parrent directory won't exist either you will attempt to do
> the checking in the non-canonical path?
>
> Maybe you could try to match the paths according to getcwd() to resolve
> relative paths at first or maybe do this in a loop until you find an
> existing object. (I'm mostly worried about paths like
> ../../../../../../something/that/does/not/exist where at least the root
> directory should be accessible)
I think this is overcomplicated approach.
Hmm, let's see if it will bite in the future then.