Does the C standard consider that there are one or two 'struct uperms_entry' types in this header?

In C1, they refer to the same type. C99 §6.2.1 defines the scopes that exist:

2 For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope. Different entities designated by the same identifier either have different scopes, or are in different name spaces. There are four kinds of scopes: function, file, block, and function prototype. (A function prototype is a declaration of a function that declares the types of its parameters.)

Function scope only applies to labels (as explicitly stated later in the same section). Block scope applies to identifiers declared in blocks - blocks are created by compound-statements, iteration-statements and selection-statements (and not by struct declarations or compound initialisers). Function prototype scope applies to identifiers declared within a function prototype declaration.

None of these apply to your example - all of the mentions of struct uperms_entry in your example are at file scope.

C99 §6.7.2.3 says:

1 All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type. The type is incomplete until the closing brace of the list defining the content, and complete thereafter.

This is pretty clear, and applies to your case.

Paragraph 8 of that section applies to the first mention of struct uperms_entry:

8 If a type specifier of the form struct-or-union identifier occurs other than as part of one of the above forms, and no other declaration of the identifier as a tag is visible, then it declares an incomplete structure or union type, and declares the identifier as the tag of that type.

So at that point it's declared as an incomplete type at file scope. Paragraph 6 applies to the second mention of struct uperms_entry:

6 A type specifier of the form struct-or-union identifieropt { struct-declaration-list } or enum identifier { enumerator-list } or enum identifier { enumerator-list , } declares a structure, union, or enumerated type. The list defines the structure content, union content, or enumeration content. If an identifier is provided, the type specifier also declares the identifier to be the tag of that type.

So after the } at the end of that typedef declaration, it's now a complete type.

The adjunct questions are moot.


1. I believe that this is not the case in C++, however.

Well, C99 6.2.5.22 says

... A structure or union type of unknown content (as described in 6.7.2.3) is an incomplete type. It is completed, for all declarations of that type, by declaring the same structure or union tag with its defining content later in the same scope.

Which would mean they're the same type for your case.