The problem is that opendir does not just take a snapshot of the current directory. Any files added to the directory after the call to opendir may or may not show up when you iterate over the entries with readdir
So say you have a.gz,b.gz,c.gz in your directory. You do an opendir and then start iterating.
The first entry returned will be a.gz, so you call gunzip. This will first create a file a, then remove a.gz.
Depending on the filesystem, this new file a may now be returned by one of your following readdir calls, even though it was not in the directory when you did the opendir
Here's a _possible_ way how this could be implemented internally.
So a directory has a number of records consisting of a filename and an inode number. When you do an opendir the opendir code will remember what directory it's iterating over, as well as the position it's at. Then after you do a readdir, which returns a.gz, the pointer will point to item 1 instead of item 0.
Now the gunzip happens, and creates the new file:
Then the gunzip finishes and removes a.gz
The next readdir will return b.gz and move the pointer to item 2. Then gzip creates a new file for that item..
And after removing the original...
The next readdir returns c.gz in the same fashion.
After that however, readdir finds the new item a and returns it, which is what causes your problem. b and c are never returned cause they occupy positions that readdir already processed.
All this is just a long way of explaining why readdir may or may not return files that get created or deleted while you are iterating over the directory.