Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

nsIZipWriter.open gives NS_ERROR_FILE_NOT_FOUND?

12 views
Skip to first unread message

John J. Barton

unread,
May 12, 2008, 12:55:06 AM5/12/08
to
I am trying call nsIZipWriter.open(nsIFile, obscureFlags). It gives a
bizarre error: NS_ERROR_FILE_NOT_FOUND. I'm like "well, that's good,
because if it existed I'd be real surprised".

var xpi = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
var path = this.name;
path = path.replace(/\//g, "\\"); // HACK!
xpi.initWithPath(path);

var Cif = Components.interfaces.nsIFile;
writer.open(xpi, Cif.PR_RDWR | Cif.PR_CREATE_FILE | Cif.PR_TRUNCATE);

Any ideas?

John.

Gavin Sharp

unread,
May 12, 2008, 1:01:30 AM5/12/08
to John J. Barton, dev-pl...@lists.mozilla.org
On Mon, May 12, 2008 at 12:55 AM, John J. Barton
<johnj...@johnjbarton.com> wrote:
> I am trying call nsIZipWriter.open(nsIFile, obscureFlags). It gives a
> bizarre error: NS_ERROR_FILE_NOT_FOUND. I'm like "well, that's good,
> because if it existed I'd be real surprised".

> var Cif = Components.interfaces.nsIFile;
> writer.open(xpi, Cif.PR_RDWR | Cif.PR_CREATE_FILE | Cif.PR_TRUNCATE);

Those PR_* constants don't exist on Components.interfaces.nsIFile
(Components.interfaces.nsIFile.PR_CREATE_FILE is undefined), so you're
effectively passing in 0.

Open() throws NS_ERROR_FILE_NOT_FOUND if the file doesn't exist and
you don't pass in PR_CREATE_FILE:
http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/modules/libjar/zipwriter/src/nsZipWriter.cpp&rev=1.2&mark=281,282#264

I don't think the flags are defined anywhere that's easily accessible
from JS. You probably need to just redefine them in JS based on their
definitions in C++:
http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/nsprpub/pr/include/prio.h&rev=3.40#612

Some examples:
http://mxr.mozilla.org/seamonkey/search?string=PR_&find=\.js&findi=&filter=&hitlimit=&tree=seamonkey

Gavin

John J. Barton

unread,
May 12, 2008, 1:17:38 AM5/12/08
to
Gavin Sharp wrote:
> On Mon, May 12, 2008 at 12:55 AM, John J. Barton
> <johnj...@johnjbarton.com> wrote:
>> I am trying call nsIZipWriter.open(nsIFile, obscureFlags). It gives a
>> bizarre error: NS_ERROR_FILE_NOT_FOUND. I'm like "well, that's good,
>> because if it existed I'd be real surprised".
>
>> var Cif = Components.interfaces.nsIFile;
>> writer.open(xpi, Cif.PR_RDWR | Cif.PR_CREATE_FILE | Cif.PR_TRUNCATE);
>
> Those PR_* constants don't exist on Components.interfaces.nsIFile
> (Components.interfaces.nsIFile.PR_CREATE_FILE is undefined), so you're
> effectively passing in 0.
>
> Open() throws NS_ERROR_FILE_NOT_FOUND if the file doesn't exist and
> you don't pass in PR_CREATE_FILE:
> http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/modules/libjar/zipwriter/src/nsZipWriter.cpp&rev=1.2&mark=281,282#264

Please, can't error messages say what they mean?

>
> I don't think the flags are defined anywhere that's easily accessible
> from JS.

Bug 433295 has been added to the database

John J. Barton

unread,
May 12, 2008, 1:26:23 AM5/12/08
to
Gavin Sharp wrote:
> On Mon, May 12, 2008 at 12:55 AM, John J. Barton
> <johnj...@johnjbarton.com> wrote:
>> I am trying call nsIZipWriter.open(nsIFile, obscureFlags). It gives a
>> bizarre error: NS_ERROR_FILE_NOT_FOUND. I'm like "well, that's good,
>> because if it existed I'd be real surprised".
>
>> var Cif = Components.interfaces.nsIFile;
>> writer.open(xpi, Cif.PR_RDWR | Cif.PR_CREATE_FILE | Cif.PR_TRUNCATE);
>
> Those PR_* constants don't exist on Components.interfaces.nsIFile
> (Components.interfaces.nsIFile.PR_CREATE_FILE is undefined), so you're
> effectively passing in 0.

Thanks Gavin.

Gavin Sharp

unread,
May 12, 2008, 1:32:33 AM5/12/08
to John J. Barton, dev-pl...@lists.mozilla.org
On Mon, May 12, 2008 at 1:17 AM, John J. Barton
<johnj...@johnjbarton.com> wrote:
>> Open() throws NS_ERROR_FILE_NOT_FOUND if the file doesn't exist and
>> you don't pass in PR_CREATE_FILE:
>> http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/modules/libjar/zipwriter/src/nsZipWriter.cpp&rev=1.2&mark=281,282#264
>
> Please, can't error messages say what they mean?

Given the current methods used to propagate exceptions through
XPCOM/xpconnect? Not really - at least not without a lot of overhead.
There's almost always going to be room for improvement for how
detailed the exception messages are. I think there's a balance to be
had between the performance and footprint overhead of propagating
unique textual descriptions for every possible exceptional
circumstance, and the confusion caused by difficult to debug error
messages. I think you're right that in a lot of cases the current
setup is suboptimal (e.g. trying to find the source of a generic
NS_ERROR_FAILURE can often be frustrating).

In this particular case, the error code made it fairly obvious what
the problem was once you looked at the implementation of the method
you were calling. Learning how to find that implementation using
LXR/MXR perhaps isn't as easy as it should be, but it's certainly a
skill worth learning for those cases when you encounter mysterious
behavior.

Gavin

John J. Barton

unread,
May 12, 2008, 1:51:51 AM5/12/08
to

If that is so, why not just avoid all of the overhead of exceptions?
Simply abort execution and print the stack trace for all exceptions.
Then with a simple tool to map the stack trace to LXR/MXR, I will be
quickly lead to the test that failed. This seems more sensible than
error messages that are designed incomplete.

John.

Neil

unread,
May 12, 2008, 5:18:00 AM5/12/08
to
John J. Barton wrote:

> var xpi = Components.classes["@mozilla.org/file/local;1"]
> .createInstance(Components.interfaces.nsILocalFile);
> var path = this.name;
> path = path.replace(/\//g, "\\"); // HACK!

Why might you need to do that? Unless someone's passing you bogus data,
all internal file paths should use native path separators and all URIs
should use forward slashes and the conversion functions switch as necessary.

--
Warning: May contain traces of nuts.

Mike Shaver

unread,
May 12, 2008, 10:36:25 AM5/12/08
to John J. Barton, dev-pl...@lists.mozilla.org
On Mon, May 12, 2008 at 1:17 AM, John J. Barton
<johnj...@johnjbarton.com> wrote:
> > Open() throws NS_ERROR_FILE_NOT_FOUND if the file doesn't exist and
> > you don't pass in PR_CREATE_FILE:
> > http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/modules/libjar/zipwriter/src/nsZipWriter.cpp&rev=1.2&mark=281,282#264
>
> Please, can't error messages say what they mean?

That _is_ what the error means: you've asked it to open a file
(without CREATE it means to open an existing one) and the file doesn't
exist. You get something very similar from open(2). A better API
might have separated open and create, but without that I don't think
you're going to get much of a better error.

Mike

John J. Barton

unread,
May 12, 2008, 11:16:14 AM5/12/08
to

If the message had been:

"The file "+file.path+" was not found (or its directory does not exist)
and the flags "+(PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE)+" didn't permit
creating it."

then I could have cut a half-hour off my coding. (not count whining in
the newsgroup). When I got NS_ERROR_FILE_NOT_FOUND what could I do? Well
first I had to check that the file name input was what I expected by
comparing my input to the file system. Then I had to change my code to
print the file name just before the open() call to verify that the
string I sent to open() was the same one as I gave my program. Then I
had to re-read the documentation for nsIFile because I still can't
believe that it won't take file names with forward slashes. Then I
re-read the example code for nsIZipWriter but since it is incomplete I
edited the wiki. I didn't read the exception parts because, after a few
thousand examples of exception documentation like:
NS_ERROR_FILE_NOT_FOUND: the file was not found.
I eventually learned that this is a waste time. Finally I went back and
printed everything in the method. When PR_RDWR came back zero, I fixed it.

The method returns an int, which could be an index in to large string
table either online or downloaded by developers and populated by
build-processing of the C++ code. The C++ code could replace
return NS_ERROR_FILE_NOT_FOUND;
with
return NS_ERROR("The file %s...", mFile->Path, aIoFlags);

John J. Barton

unread,
May 12, 2008, 11:24:36 AM5/12/08
to

When I send file names from my command line I use forward slashes. On
every other cross platform tool I have used, forward slashes work for
file names in code. In these tools, backslashes often are the quoting
character. (Forward slashes work fine windows). Since my command line
tools are cross platform, I have to write platform-dependent code in
mozilla to convert my platform independent strings in to platform
dependent strings for their platform-dependent API.

John.

John J. Barton

unread,
May 12, 2008, 11:47:55 AM5/12/08
to
Oh, and by the way, nsIZipWriter requires forward slashes:
File and directory names should use slashes ("/") as separators and
should not begin with a slash.
http://developer.mozilla.org/en/docs/nsIZipWriter

Dave Townsend

unread,
May 12, 2008, 12:19:49 PM5/12/08
to

That is referring to the entry names passed when adding a file/directory
to the zip. The zip format specifies that / is the standard directory
separator there.

When initialising an nsILocalFile with a path I believe you are supposed
to use native path separators, though I guess it might auto fix when not.

I'm intrigued by your comment on the zipwriter documentation: "The
argument nyZipFilePath isn't a path but rather it has to be an nsIFile
instance. It's not clear what state that object should be in". What
states are you referring to?

John J. Barton

unread,
May 12, 2008, 12:50:24 PM5/12/08
to
Dave Townsend wrote:
> When initialising an nsILocalFile with a path I believe you are supposed
> to use native path separators, though I guess it might auto fix when not.
>

I'd guess not, based on trying it.

> I'm intrigued by your comment on the zipwriter documentation: "The
> argument nyZipFilePath isn't a path but rather it has to be an nsIFile
> instance. It's not clear what state that object should be in". What
> states are you referring to?
>

I'm referring to the complete set of states of nsIFile, whatever they
may be, which are unknown to me. Because if I knew those states, maybe I
could puzzle out what the example code was doing. In others words "I
don't know".

Try to imagine not knowing anything about nsIFile. Then read
http://developer.mozilla.org/en/docs/nsIFile
Now explain nsIFile. I believe you will be able to tell me much about
what nsIFile is not, and lots of obscure rules about UTF.

Now I guess that nsIFile represents a full path to a file or directory.
It is largely equivalent to a string file name, except that it has to be
initialized in an OS-dependent fashion. Like a string file name, nothing
stored nsIFile relates to physical storage. Operations on nsIFile like
"create" and "copyTo" do change the state of physical storage, but not
the state of nsIFile object.

John.


Sergey Yanovich

unread,
May 12, 2008, 1:11:17 PM5/12/08
to
John J. Barton wrote:

> The method returns an int, which could be an index in to large string
> table either online or downloaded by developers and populated by
> build-processing of the C++ code. The C++ code could replace
> return NS_ERROR_FILE_NOT_FOUND;
> with
> return NS_ERROR("The file %s...", mFile->Path, aIoFlags);

This proposed behavior doesn't correspond with the role nsresult plays
in XPCOM. The type is an *indicator* of XPCOM method success/failure, as
different from a *description* of XPCOM method failure. Method author
may or may not use different codes in different situations. It is
generally not safe to make any conclusions based on nsresult with a
notable exception of passing it to NS_SUCCEED/NS_FAILED.

It is also important that nsresult is a 32bit integer, so
return NS_ERROR_FILE_NOT_FOUND;
is roughly equivalent to a single machine instruction
mov eax, NS_ERROR_FILE_NOT_FOUND
and has no side effect. At the same time,


return NS_ERROR("The file %s...", mFile->Path, aIoFlags);

involves string manipulations call, and is several orders of magnitude
slower. In addition, it will allocate a string, which will require a
huge framework and extra overhead to be freed properly.

This issue is best addressed by C++ exceptions, which are in the agenda
on a post-mozilla-2 timeframe.

--
Sergey Yanovich

Dave Townsend

unread,
May 12, 2008, 1:13:01 PM5/12/08
to
John J. Barton wrote:
> Dave Townsend wrote:
>> When initialising an nsILocalFile with a path I believe you are
>> supposed to use native path separators, though I guess it might auto
>> fix when not.
>>
>
> I'd guess not, based on trying it.
>
>> I'm intrigued by your comment on the zipwriter documentation: "The
>> argument nyZipFilePath isn't a path but rather it has to be an nsIFile
>> instance. It's not clear what state that object should be in". What
>> states are you referring to?
>>
>
> I'm referring to the complete set of states of nsIFile, whatever they
> may be, which are unknown to me. Because if I knew those states, maybe I
> could puzzle out what the example code was doing. In others words "I
> don't know".
>
> Try to imagine not knowing anything about nsIFile. Then read
> http://developer.mozilla.org/en/docs/nsIFile
> Now explain nsIFile. I believe you will be able to tell me much about
> what nsIFile is not, and lots of obscure rules about UTF.

Ok thanks, I've tried to improve on the summary to that page to try to
introduce the object better.

> Now I guess that nsIFile represents a full path to a file or directory.
> It is largely equivalent to a string file name, except that it has to be
> initialized in an OS-dependent fashion. Like a string file name, nothing
> stored nsIFile relates to physical storage. Operations on nsIFile like
> "create" and "copyTo" do change the state of physical storage, but not
> the state of nsIFile object.

Yes an nsIFile does just represent a location in the filesystem, which
thankfully for all modern systems is a string path, however in most
cases you need not use OS dependant code for initialising it, you can
get an nsIFile from the directory service or a file picker, both of
which are cross platform (mostly) and will let you use the filesystem
without worrying about platform specific path representations.

John J. Barton

unread,
May 12, 2008, 1:33:47 PM5/12/08
to Sergey Yanovich

Its worth it. NS_ERROR can be a macro that returns a 32bit integer key
for a table created by a compile time tool. Developer builds can get
real error messages; user builds get a key and a method that links that
key to an online copy of the message table. The user message would not
have values for paths and flags, but it would be better than "NS_ERROR".

> This issue is best addressed by C++ exceptions, which are in the agenda
> on a post-mozilla-2 timeframe.

As in Mozilla-2 or as in Mozilla-3?

Boris Zbarsky

unread,
May 12, 2008, 1:50:55 PM5/12/08
to
John J. Barton wrote:
> Now I guess that nsIFile represents a full path to a file or directory.

It represents a location where a file can be. Or you can think of it as
a file identifier. You're correct that that API documentation could say
this more explicitly. Patches very much accepted!

> It is largely equivalent to a string file name

This was not the case in the past on Mac OS. It is the case now on all
of our supported platforms. There is no guarantee that it will be the
case in the future.

An nsIFile is exactly what the documentation says:

47 * This is the only correct cross-platform way to specify a file.
48 * Strings are not such a way. If you grew up on windows or unix, you
49 * may think they are. Welcome to reality.

As I said, now that Macs also use Unix, strings would also work. For
the time being. It's not clear whether baking in such an assumption is
a good idea.

It seems that the only problem here is the "file == string" mindset of
the reader of this API, but that could be just me.


> except that it has to be initialized in an OS-dependent fashion.

If you create one by contract, this is correct, since the information
needed to identify a file differs on different OSes. But creating an
nsIFile by contract is not the right way to go, in general. The right
way to get one is via the directory service, I would say.

-Boris

John J Barton

unread,
May 12, 2008, 3:03:40 PM5/12/08
to
Dave Townsend wrote:
> Ok thanks, I've tried to improve on the summary to that page to try to
> introduce the object better.
>

Much better, thanks!

John J. Barton

unread,
May 13, 2008, 12:51:17 PM5/13/08
to
Boris Zbarsky wrote:
> John J. Barton wrote:
>> Now I guess that nsIFile represents a full path to a file or directory.
>
> It represents a location where a file can be. Or you can think of it as
> a file identifier. You're correct that that API documentation could say
> this more explicitly. Patches very much accepted!
>
>> It is largely equivalent to a string file name
>
> This was not the case in the past on Mac OS. It is the case now on all
> of our supported platforms. There is no guarantee that it will be the
> case in the future.

Do all platforms support file:// URLS?

John.

Boris Zbarsky

unread,
May 13, 2008, 1:34:11 PM5/13/08
to
John J. Barton wrote:
> Do all platforms support file:// URLS?

Define "support"? On OS9, as I recall, there were files that could not be
specified with a file:// URI. That is, the mapping from file:// URIs (and file
paths in general) to actual files was one-to-many, not one-to-one.

-Boris

Jeff Walden

unread,
May 13, 2008, 2:21:59 PM5/13/08
to Boris Zbarsky
Boris Zbarsky wrote:
> John J. Barton wrote:
>> It is largely equivalent to a string file name
>
> This was not the case in the past on Mac OS. It is the case now on all
> of our supported platforms. There is no guarantee that it will be the
> case in the future.

Well, not quite -- numerous properties and methods (not just .exists) behave differently based on whether the file exists or not. For example, normalize() will, on Linux and I think OS X, use realpath and perhaps even produce a path entirely outside the file's original path, such that |(oldFile = file.clone(), file.normalize(), oldFile.parent != file.parent)| is true. On Windows we do string munging to remove '.' and '..' components. This is part of the reason, for example, that I can't use normalize() at the code at the following location to remove canceling components from HTTP paths:

http://bonsai.mozilla.org/cvsblame.cgi?file=/mozilla/netwerk/test/httpserver/httpd.js&rev=1.12&mark=1960-1980#1955

(The other part of the reason is that on Windows nsILocalFile.appendRelativePath flatly contradicts its API and allows paths containing '.' and '..'.)

Another hazard is isDirectory(), which does an existence-and-is-directory check rather than a string check on at least some platforms. There are a bunch of hazards like this which I've encountered in practice, and the only way to know what will happen is to test or read the source code of every implementation. The IDL documentation is incomplete and inexact at times to the point of being useless.


> An nsIFile is exactly what the documentation says:
>
> 47 * This is the only correct cross-platform way to specify a file.
> 48 * Strings are not such a way. If you grew up on windows or unix, you
> 49 * may think they are. Welcome to reality.
>
> As I said, now that Macs also use Unix, strings would also work. For
> the time being. It's not clear whether baking in such an assumption is
> a good idea.

I like the idea of an object encapsulating the string to define helper methods in only one location. Given that files as a shared resource are inherently racy, I think the only reasonable thing is for files to be represented by wrappers around strings (and never, except for .exists or other non-string-based information like .lastModifiedTime, have behavior which depends upon the file existing).


> It seems that the only problem here is the "file == string" mindset of
> the reader of this API, but that could be just me.

The only problem as I see it is that the API tries to have it both ways and never specifies precisely which way it is in all the method and property descriptions. I'd have to reimplement stuff if it's specified to be existence-based, but that would be better than having to reimplement anyway just because it's not clear everyone does the right thing.

I sooo look forward to fully specifying and exactly implementing the behaviors of nsIFile and nsILocalFile when we get the chance to break ABI compatibility. As it is right now, I don't really believe it's possible to safely and securely trust the checks our Windows file implementation makes.

Jeff

Boris Zbarsky

unread,
May 13, 2008, 2:37:56 PM5/13/08
to
Jeff Walden wrote:
> The only problem as I see it is that the API tries to have it both ways
> and never specifies precisely which way it is in all the method and
> property descriptions.

Well, ok. That's a problem too, as is the fact that the implementations don't
agree with the documentation. We do have bugs covering this.

> I sooo look forward to fully specifying and exactly implementing the
> behaviors of nsIFile and nsILocalFile

Amen.

-Boris

0 new messages