Skip to content

Commit 7681b0e

Browse files
hasufellBodigrim
authored andcommitted
Use ByteString for GroupEntry/UserEntry
No PosixString instance for now. Not sure if it's interesting.
1 parent 059099f commit 7681b0e

File tree

4 files changed

+777
-52
lines changed

4 files changed

+777
-52
lines changed

System/Posix/User.hsc

Lines changed: 90 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE Trustworthy, CApiFFI #-}
1+
{-# LANGUAGE Trustworthy, CApiFFI, PatternSynonyms, ViewPatterns #-}
22
-----------------------------------------------------------------------------
33
-- |
44
-- Module : System.Posix.User
@@ -25,13 +25,25 @@ module System.Posix.User (
2525
getEffectiveUserName,
2626

2727
-- *** The group database
28-
GroupEntry(..),
28+
groupName,
29+
groupPassword,
30+
groupID,
31+
groupMembers,
32+
pattern GroupEntry,
2933
getGroupEntryForID,
3034
getGroupEntryForName,
3135
getAllGroupEntries,
3236

3337
-- *** The user database
34-
UserEntry(..),
38+
userName,
39+
userPassword,
40+
userID,
41+
userGroupID,
42+
userGecos,
43+
homeDirectory,
44+
userShell,
45+
pattern UserEntry,
46+
3547
getUserEntryForID,
3648
getUserEntryForName,
3749
getAllUserEntries,
@@ -53,6 +65,12 @@ import Foreign.C
5365
import Foreign.Ptr
5466
import Foreign.Marshal
5567
import Foreign.Storable
68+
import System.Posix.User.Common ( UserEntry, GroupEntry
69+
#if defined(HAVE_PWD_H)
70+
, unpackUserEntry, unpackGroupEntry, LKUPTYPE(..), CPasswd, CGroup
71+
#endif
72+
)
73+
import qualified System.Posix.User.Common as User
5674

5775
#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
5876
#if defined(freebsd_HOST_OS)
@@ -63,19 +81,13 @@ import Control.Exception
6381
#endif
6482
import Control.Monad
6583
import System.IO.Error
84+
import qualified Data.ByteString.Char8 as C8
6685

6786
#if !defined(HAVE_PWD_H)
6887
import System.IO.Error ( ioeSetLocation )
6988
import GHC.IO.Exception ( unsupportedOperation )
7089
#endif
7190

72-
#if defined(HAVE_PWD_H)
73-
74-
-- internal types
75-
data {-# CTYPE "struct passwd" #-} CPasswd
76-
data {-# CTYPE "struct group" #-} CGroup
77-
78-
#endif // HAVE_PWD_H
7991

8092
#if !defined(HAVE_PWD_H)
8193

@@ -204,7 +216,6 @@ getEffectiveUserName = ioError (ioeSetLocation unsupportedOperation "getEffectiv
204216
-- lot of complexity by deprecating the "get all" functions and simply
205217
-- always returning an empty list.
206218
--
207-
data LKUPTYPE = GETONE | GETALL
208219

209220
#if defined(HAVE_GETPWENT)
210221
pwlock :: MVar ()
@@ -371,13 +382,28 @@ getEffectiveUserName = do
371382
-- -----------------------------------------------------------------------------
372383
-- The group database (grp.h)
373384

374-
data GroupEntry =
375-
GroupEntry {
376-
groupName :: String, -- ^ The name of this group (gr_name)
377-
groupPassword :: String, -- ^ The password for this group (gr_passwd)
378-
groupID :: GroupID, -- ^ The unique numeric ID for this group (gr_gid)
379-
groupMembers :: [String] -- ^ A list of zero or more usernames that are members (gr_mem)
380-
} deriving (Show, Read, Eq)
385+
groupName :: GroupEntry -> String
386+
groupName (GroupEntry gn _ _ _) = gn
387+
388+
groupPassword :: GroupEntry -> String
389+
groupPassword (GroupEntry _ gp _ _) = gp
390+
391+
groupID :: GroupEntry -> GroupID
392+
groupID (GroupEntry _ _ id' _) = id'
393+
394+
groupMembers :: GroupEntry -> [String]
395+
groupMembers (GroupEntry _ _ _ gm) = gm
396+
397+
-- | Manually constructing 'GroupEntry' in String modules is discouraged. It will truncate
398+
-- Chars to 8bit. Use 'System.Posix.User.ByteString' instead.
399+
pattern GroupEntry :: String -- ^ The name of this group (gr_name)
400+
-> String -- ^ The password for this group (gr_passwd)
401+
-> GroupID -- ^ The unique numeric ID for this group (gr_gid)
402+
-> [String] -- ^ A list of zero or more usernames that are members (gr_mem)
403+
-> GroupEntry
404+
pattern GroupEntry gn gp gi gm <- User.GroupEntry (C8.unpack -> gn) (C8.unpack -> gp) gi (fmap C8.unpack -> gm) where
405+
GroupEntry gn gp gi gm = User.GroupEntry (C8.pack gn) (C8.pack gp) gi (C8.pack <$> gm)
406+
{-# COMPLETE GroupEntry #-}
381407

382408
#if !defined(HAVE_PWD_H)
383409

@@ -474,30 +500,57 @@ grBufSize = 1024
474500
#endif
475501
#endif
476502

477-
unpackGroupEntry :: Ptr CGroup -> IO GroupEntry
478-
unpackGroupEntry ptr = do
479-
name <- (#peek struct group, gr_name) ptr >>= peekCAString
480-
passwd <- (#peek struct group, gr_passwd) ptr >>= peekCAString
481-
gid <- (#peek struct group, gr_gid) ptr
482-
mem <- (#peek struct group, gr_mem) ptr
483-
members <- peekArray0 nullPtr mem >>= mapM peekCAString
484-
return (GroupEntry name passwd gid members)
485-
486503
#endif // HAVE_PWD_H
487504

488505
-- -----------------------------------------------------------------------------
489506
-- The user database (pwd.h)
490507

491-
data UserEntry =
492-
UserEntry {
493-
userName :: String, -- ^ Textual name of this user (pw_name)
494-
userPassword :: String, -- ^ Password -- may be empty or fake if shadow is in use (pw_passwd)
495-
userID :: UserID, -- ^ Numeric ID for this user (pw_uid)
496-
userGroupID :: GroupID, -- ^ Primary group ID (pw_gid)
497-
userGecos :: String, -- ^ Usually the real name for the user (pw_gecos)
498-
homeDirectory :: String, -- ^ Home directory (pw_dir)
499-
userShell :: String -- ^ Default shell (pw_shell)
500-
} deriving (Show, Read, Eq)
508+
userName :: UserEntry -> String
509+
userName (UserEntry n _ _ _ _ _ _) = n
510+
511+
userPassword :: UserEntry -> String
512+
userPassword (UserEntry _ p _ _ _ _ _) = p
513+
514+
userID :: UserEntry -> UserID
515+
userID (UserEntry _ _ id' _ _ _ _) = id'
516+
517+
userGroupID :: UserEntry -> GroupID
518+
userGroupID (UserEntry _ _ _ gid _ _ _) = gid
519+
520+
userGecos :: UserEntry -> String
521+
userGecos (UserEntry _ _ _ _ ge _ _) = ge
522+
523+
homeDirectory :: UserEntry -> String
524+
homeDirectory (UserEntry _ _ _ _ _ hd _) = hd
525+
526+
userShell :: UserEntry -> String
527+
userShell (UserEntry _ _ _ _ _ _ us) = us
528+
529+
-- | Manually constructing 'UserEntry' in String modules is discouraged. It will truncate
530+
-- Chars to 8bit. Use 'System.Posix.User.ByteString' instead.
531+
pattern UserEntry :: String -- ^ Textual name of this user (pw_name)
532+
-> String -- ^ Password -- may be empty or fake if shadow is in use (pw_passwd)
533+
-> UserID -- ^ Numeric ID for this user (pw_uid)
534+
-> GroupID -- ^ Primary group ID (pw_gid)
535+
-> String -- ^ Usually the real name for the user (pw_gecos)
536+
-> String -- ^ Home directory (pw_dir)
537+
-> String -- ^ Default shell (pw_shell)
538+
-> UserEntry
539+
pattern UserEntry un up ui ugi ug hd us <- User.UserEntry (C8.unpack -> un)
540+
(C8.unpack -> up)
541+
ui
542+
ugi
543+
(C8.unpack -> ug)
544+
(C8.unpack -> hd)
545+
(C8.unpack -> us) where
546+
UserEntry un up ui ugi ug hd us = User.UserEntry (C8.pack un)
547+
(C8.pack up)
548+
ui
549+
ugi
550+
(C8.pack ug)
551+
(C8.pack hd)
552+
(C8.pack us)
553+
{-# COMPLETE UserEntry #-}
501554

502555
-- | @getUserEntryForID uid@ calls @getpwuid_r@ to obtain
503556
-- the @UserEntry@ information associated with @UserID@
@@ -621,20 +674,6 @@ doubleAllocWhileERANGE loc enttype initlen unpack action =
621674
ioError $ flip ioeSetErrorString ("no such " ++ enttype)
622675
$ mkIOError doesNotExistErrorType loc Nothing Nothing
623676

624-
unpackUserEntry :: Ptr CPasswd -> IO UserEntry
625-
unpackUserEntry ptr = do
626-
name <- (#peek struct passwd, pw_name) ptr >>= peekCAString
627-
passwd <- (#peek struct passwd, pw_passwd) ptr >>= peekCAString
628-
uid <- (#peek struct passwd, pw_uid) ptr
629-
gid <- (#peek struct passwd, pw_gid) ptr
630-
#ifdef HAVE_NO_PASSWD_PW_GECOS
631-
gecos <- return "" -- pw_gecos does not exist on android
632-
#else
633-
gecos <- (#peek struct passwd, pw_gecos) ptr >>= peekCAString
634-
#endif
635-
dir <- (#peek struct passwd, pw_dir) ptr >>= peekCAString
636-
shell <- (#peek struct passwd, pw_shell) ptr >>= peekCAString
637-
return (UserEntry name passwd uid gid gecos dir shell)
638677

639678
-- Used when a function returns NULL to indicate either an error or
640679
-- EOF, depending on whether the global errno is nonzero.

0 commit comments

Comments
 (0)