TFile::Open() fails with non-canonical filename (double slashes)

I had a user provide a “non-canonical” file path for ROOT output from our simulation framework, and the job was aborted because new TFile returned an object which was not IsOpen() (I suspect that IsZombie() was set, but that’s not what we test for).

Specifically, an action like this (note the leading “//”):

TFile* myfile = new TFile("//Users/kelsey/test-data/double-slash.root");
if (!myfile.IsOpen()) {
  cerr << "ERROR: Unable to open file!" << endl;
  ::exit(2);
}

will generate the error message and exit the program.

Does ROOT provide functionality to canonicalize a file path (similar to realpath() in <stdlib.h>)? I looked at TUnixSystem::ExpandPathName(), but it doesn’t address duplicated slashes. I can’t use realpath() directly, because the latter only works for existing files, not when creating new files.


Please read tips for efficient and successful posting and posting code

ROOT Version: 6.12, 6.18
Platform: CentOS7, MacOSX
Compiler: GCC, LLVM (Clang)


The check I usually use is:
if ((!myfile) || myfile->IsZombie()) { delete myfile; // what's up, doc?

A brutal fix for your problem … always (“unconditionally”) use:
TFile(TString("file://") + "the original directory someone tries, even with two // in front")

It sounds like “IsZombie()” is better than “IsOpen()”. I’ll keep that in mind.

For the second part, you suggest

So you’re saying that using

TFile("file:///Users/kelsey/data/myfile.root","RECREATE")

or

TFile("file:////Users/kelsey/data/myfile.root","RECREATE")

will both work, and both open a new file on a local filesystem? … Yup, it does work for the leading slashes issue. This is a fine solution for our code.

What happens if the double slashes appear in the middle of the path somewhere (as can happen with envvar substitution in a shell script)? … It looks like it does. I gave it a path with embedded double slashes, as well as a “…” cycle, and the output file ended up in the right place with no error.

Does the URL parsing do canonicalization in a way that TFile itself does not? Is there a way to call the code that does that at the user level, or is embedded in TFile? I’d like to do “file path cleanup” for writing out other file types, as well as cleaning up whatever ugly path the user specified, for printing out.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.