baudehlo / node-fs-ext

Extras missing from node's fs module
MIT License
101 stars 45 forks source link

Get the file owner in a platform-independent way #26

Open prantlf opened 10 years ago

prantlf commented 10 years ago

fs.stat returns the owner IDs on POSIX platforms only. The stat.uid and stat.gid members are always zero on Windows and there are no stat members exposing the user and group SIDs there.

Would you accept implementation of a method retrieving the file owner information in the fs-ext module? (I'd probably add the both user and group information, sync and async methods and fs.chown wrappers for the sake of completeness.)

I suggest adding a dedicated function, extending the fs.stat or wrapping the fs.stat:

fs.getownership
{ uid, gid /* POSIX */, usid, gsid /* Windows */ }

fs.stat
{ /* all from fs.stat */, usid, gsid /* Windows */ }

fs.stat2
{ /* all from fs.stat, uid and gid as SIDs on Windows */ }

Node.js does not provide a native way to resolve a user/group ID to the name or other information, which is usually wanted. The rest of the scenario - resolving the user and group IDs to the information - would be probably delegated to platform-specific modules.

There is a function getpwnam available on POSIX systems and exposed by the node-posix module:

fs.stat -> stat.uid -> posix.getpwnam
// { name, passwd, uid, gecos (fullname+), shell, dir }
fs.stat -> stat.gid -> posix.getgrnam
// { name, passwd, gid, members }

The file ownership is not enquired by the fstat on Windows, but using authorization and network APIs:

CreateFile -> filehandle -> GetSecurityInfo -> usersid ->
  LookupAccountSid -> username -> NetUserGetInfo
// { name, passwd, usid, fullname, dir }
CreateFile -> filehandle -> GetSecurityInfo -> groupsid ->
  LookupAccountSid -> groupname -> NetGroupGetUsers
// { name, gsid, members }
baudehlo commented 10 years ago

Yes that sounds like a good addition to the library.

It might be worth checking what Perl does with stat() on Windows. If it "just works" then I suggest we provide a patched fs.stat rather than a new function.

prantlf commented 10 years ago

Thanks! Good idea to look at the others like Perl. Perl and Ruby just return what the stat/fstat from MSVCRT does, which is documented to return zeros for uid and gid. Node.js calls NtQueryInformationFile, but esentially behaves the same way - sets the uid and gid to zeros too. It appears that the uid and gid (among the other members of stats) are unused on Windows.

My first choice was to set the Windows equivalents for the user and group identifiers there - SIDs. Having a POSIX-compatibility module - getpwnam and getpwuid, e.g., which would also work with SIDs, it would complete the scenario. However, SIDs are not integers, which would mean breaking the current type of the uid and gid members.

Creating another members for the SIDs or another methods to return the ownership would not break the type contract of the interface, but also leave it useless n Windows. Adding new members like usid and gsid to stats wouldn't break it but when getting to chown and fchown, the problem will be back. Adding new methods or new members to stats leaves the original MSVCRT behavior would mean that a multi-platform code would need to call different methods from different modules, which I'd like to to avoid. It'd practically mean creating another module like fs-compat offering just a single interface working in all environments...

Perl, Ruby and node.js don't offer multiplatform interface to get/set the file owner and/or to resolve user IDs and user names, although they partially offer the POSIX interface for that. Because both POSIX and Windows have the concept of IDs and JavaScript is not a strong-typed language, setting strings to the uid and gid members would technically work. Sending the values to chown or to the Windows implementation of getpwuid would also work, as long as the values are taken "as-is". As long as nobody tries to parse them as integers or use them in a computation - which is unlikely - it would work.

I'm still undecided what the best interface would be. Setting strings like "S-1-5-18" to uid which contains usually integers like 1000 is bad, but the uid and gid are nicely connected to other functions, that if there were a multiplatform implementation of the POSIX interface, I'd need no other wrapper; just the fs and posix modules - in this case fs-ext and posix-ext or fs-compat and posix-compat modules, e.g. That's why I find reusing the uid and gid so appealing, but I'm not sure if it is the right way to provide multiplatform support for this, or if the fs-ext is the right module for this. What do you think?

prantlf commented 10 years ago

I have the extensions using SIDs almost ready:

process: getuid, getgid, getgroups
fs:      stat, lstat, fstat, chown, lchown, fchown
posix:   getpwnam, getpwuid, getgrnam, getgrgid

It goes beyond the scope of the fs-ext. Spinning off process-ext and posix-ext modules might be too many small modules for the single purpuse - cross-platform uid handling. I'm thinking about having posix-ext providing extensions to process and posix. (There is a posix module already.) The usage could look like:

var posix = require("posix-ext"),
    process = posix.process,
    fs = require("fs-ext"); // or posix.fs

The fs-related extensions could be either in fs-ext or in posix-ext. What do you think?

alessioalex commented 10 years ago

@baudehlo any updates on this issue?

prantlf commented 10 years ago

Instead of this code:

var posix = require("posix-ext"); // depends on posix (optional)
var fs = require("fs-ext"); // depends on fs (core)

I use this as a workaround:

var posix = require("posix-ext");
var fs = posix.fs; // implementation copied from fs-ext

I checked the fs-ext extension to the posix-ext module too, but still allowing the integration with fs-ext. Let's see if it's just temporarily or not...

CaptainFreak commented 6 years ago

So is it available ? If yes, then please tell me how to use it for getting owner name.