Source file 
src/os/user/lookup_unix.go
     1  
     2  
     3  
     4  
     5  
     6  
     7  package user
     8  
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"errors"
    13  	"io"
    14  	"os"
    15  	"strconv"
    16  	"strings"
    17  )
    18  
    19  
    20  type lineFunc func(line []byte) (v any, err error)
    21  
    22  
    23  
    24  
    25  
    26  
    27  
    28  func readColonFile(r io.Reader, fn lineFunc, readCols int) (v any, err error) {
    29  	rd := bufio.NewReader(r)
    30  
    31  	
    32  	for {
    33  		var isPrefix bool
    34  		var wholeLine []byte
    35  
    36  		
    37  		
    38  		
    39  		for {
    40  			var line []byte
    41  			line, isPrefix, err = rd.ReadLine()
    42  
    43  			if err != nil {
    44  				
    45  				
    46  				if err == io.EOF {
    47  					err = nil
    48  				}
    49  				return nil, err
    50  			}
    51  
    52  			
    53  			
    54  			if !isPrefix && len(wholeLine) == 0 {
    55  				wholeLine = line
    56  				break
    57  			}
    58  
    59  			wholeLine = append(wholeLine, line...)
    60  
    61  			
    62  			
    63  			if !isPrefix || bytes.Count(wholeLine, []byte{':'}) >= readCols {
    64  				break
    65  			}
    66  		}
    67  
    68  		
    69  		
    70  		
    71  		wholeLine = bytes.TrimSpace(wholeLine)
    72  		if len(wholeLine) == 0 || wholeLine[0] == '#' {
    73  			continue
    74  		}
    75  		v, err = fn(wholeLine)
    76  		if v != nil || err != nil {
    77  			return
    78  		}
    79  
    80  		
    81  		for ; isPrefix; _, isPrefix, err = rd.ReadLine() {
    82  			if err != nil {
    83  				
    84  				if err == io.EOF {
    85  					err = nil
    86  				}
    87  				return nil, err
    88  			}
    89  		}
    90  	}
    91  }
    92  
    93  func matchGroupIndexValue(value string, idx int) lineFunc {
    94  	var leadColon string
    95  	if idx > 0 {
    96  		leadColon = ":"
    97  	}
    98  	substr := []byte(leadColon + value + ":")
    99  	return func(line []byte) (v any, err error) {
   100  		if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 3 {
   101  			return
   102  		}
   103  		
   104  		parts := strings.SplitN(string(line), ":", 4)
   105  		if len(parts) < 4 || parts[0] == "" || parts[idx] != value ||
   106  			
   107  			
   108  			
   109  			
   110  			parts[0][0] == '+' || parts[0][0] == '-' {
   111  			return
   112  		}
   113  		if _, err := strconv.Atoi(parts[2]); err != nil {
   114  			return nil, nil
   115  		}
   116  		return &Group{Name: parts[0], Gid: parts[2]}, nil
   117  	}
   118  }
   119  
   120  func findGroupId(id string, r io.Reader) (*Group, error) {
   121  	if v, err := readColonFile(r, matchGroupIndexValue(id, 2), 3); err != nil {
   122  		return nil, err
   123  	} else if v != nil {
   124  		return v.(*Group), nil
   125  	}
   126  	return nil, UnknownGroupIdError(id)
   127  }
   128  
   129  func findGroupName(name string, r io.Reader) (*Group, error) {
   130  	if v, err := readColonFile(r, matchGroupIndexValue(name, 0), 3); err != nil {
   131  		return nil, err
   132  	} else if v != nil {
   133  		return v.(*Group), nil
   134  	}
   135  	return nil, UnknownGroupError(name)
   136  }
   137  
   138  
   139  
   140  func matchUserIndexValue(value string, idx int) lineFunc {
   141  	var leadColon string
   142  	if idx > 0 {
   143  		leadColon = ":"
   144  	}
   145  	substr := []byte(leadColon + value + ":")
   146  	return func(line []byte) (v any, err error) {
   147  		if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 6 {
   148  			return
   149  		}
   150  		
   151  		parts := strings.SplitN(string(line), ":", 7)
   152  		if len(parts) < 6 || parts[idx] != value || parts[0] == "" ||
   153  			parts[0][0] == '+' || parts[0][0] == '-' {
   154  			return
   155  		}
   156  		if _, err := strconv.Atoi(parts[2]); err != nil {
   157  			return nil, nil
   158  		}
   159  		if _, err := strconv.Atoi(parts[3]); err != nil {
   160  			return nil, nil
   161  		}
   162  		u := &User{
   163  			Username: parts[0],
   164  			Uid:      parts[2],
   165  			Gid:      parts[3],
   166  			Name:     parts[4],
   167  			HomeDir:  parts[5],
   168  		}
   169  		
   170  		
   171  		
   172  		
   173  		u.Name, _, _ = strings.Cut(u.Name, ",")
   174  		return u, nil
   175  	}
   176  }
   177  
   178  func findUserId(uid string, r io.Reader) (*User, error) {
   179  	i, e := strconv.Atoi(uid)
   180  	if e != nil {
   181  		return nil, errors.New("user: invalid userid " + uid)
   182  	}
   183  	if v, err := readColonFile(r, matchUserIndexValue(uid, 2), 6); err != nil {
   184  		return nil, err
   185  	} else if v != nil {
   186  		return v.(*User), nil
   187  	}
   188  	return nil, UnknownUserIdError(i)
   189  }
   190  
   191  func findUsername(name string, r io.Reader) (*User, error) {
   192  	if v, err := readColonFile(r, matchUserIndexValue(name, 0), 6); err != nil {
   193  		return nil, err
   194  	} else if v != nil {
   195  		return v.(*User), nil
   196  	}
   197  	return nil, UnknownUserError(name)
   198  }
   199  
   200  func lookupGroup(groupname string) (*Group, error) {
   201  	f, err := os.Open(groupFile)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	defer f.Close()
   206  	return findGroupName(groupname, f)
   207  }
   208  
   209  func lookupGroupId(id string) (*Group, error) {
   210  	f, err := os.Open(groupFile)
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  	defer f.Close()
   215  	return findGroupId(id, f)
   216  }
   217  
   218  func lookupUser(username string) (*User, error) {
   219  	f, err := os.Open(userFile)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	defer f.Close()
   224  	return findUsername(username, f)
   225  }
   226  
   227  func lookupUserId(uid string) (*User, error) {
   228  	f, err := os.Open(userFile)
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  	defer f.Close()
   233  	return findUserId(uid, f)
   234  }
   235  
View as plain text