// NewUserEditHistoryFile returns a special read file that contains a text
// representation of the file edit history for the logged-in user.
970318
func NewUserEditHistoryFile(folder *Folder) *SpecialReadFile {
	return &SpecialReadFile{
		read: func(ctx context.Context) ([]byte, time.Time, error) {
			return libfs.GetEncodedUserEditHistory(ctx, folder.fs.config)
		},
		fs: folder.fs,
	}
}
322203
func NewArchiveRelTimeFile(
	fs *FS, handle *tlfhandle.Handle, filename string,
	entryValid *time.Duration) *SpecialReadFile {
	*entryValid = 0
	return &SpecialReadFile{
		read: func(ctx context.Context) ([]byte, time.Time, error) {
			data, isRel, err := libfs.FileDataFromRelativeTimeString(
				ctx, fs.config, handle, filename)
			if err != nil {
				return nil, time.Time{}, err
			}
			if !isRel {
				panic("ArchiveRelTimeFile should only be used with " +
					"reltime file names")
			}
			return data, time.Time{}, nil
		},
	}
}
1151661
func (c SimpleFSClient) SimpleFSFolderEditHistory(ctx context.Context, path Path) (res FSFolderEditHistory, err error) {
	__arg := SimpleFSFolderEditHistoryArg{Path: path}
	err = c.Cli.Call(ctx, "keybase.1.SimpleFS.simpleFSFolderEditHistory", []interface{}{__arg}, &res)
	return
}
83105
func GetEncodedTlfEditHistory(ctx context.Context, config libkbfs.Config,
	folderBranch data.FolderBranch) (
	data []byte, t time.Time, err error) {
	edits, err := config.KBFSOps().GetEditHistory(ctx, folderBranch)
	if err != nil {
		return nil, time.Time{}, err
	}

	data, err = PrettyJSON(edits)
	return data, time.Time{}, err
}
1280399
func (s *MigrationService) UserMigrationArchiveURL(ctx context.Context, id int64) (string, error) {
	url := fmt.Sprintf("user/migrations/%v/archive", id)

	req, err := s.client.NewRequest("GET", url, nil)
	if err != nil {
		return "", err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeMigrationsPreview)

	m := &UserMigration{}

	var loc string
	originalRedirect := s.client.client.CheckRedirect
	s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		loc = req.URL.String()
		return http.ErrUseLastResponse
	}
	defer func() {
		s.client.client.CheckRedirect = originalRedirect
	}()
	resp, err := s.client.Do(ctx, req, m)
	if err == nil {
		return "", errors.New("expected redirect, none provided")
	}
	loc = resp.Header.Get("Location")
	return loc, nil
}
357291
func NewUserInfoWithPermissionLevel(User *sharing.UserInfo, PermissionLevel *PaperDocPermissionLevel) *UserInfoWithPermissionLevel {
	s := new(UserInfoWithPermissionLevel)
	s.User = User
	s.PermissionLevel = PermissionLevel
	return s
}
1330613
func NewConfigFile(fn string) *ConfigFile {
	return &ConfigFile{
		AuthConfigs: make(map[string]AuthConfig),
		HTTPHeaders: make(map[string]string),
		filename:    fn,
		version:     2,
	}
}
1165045
func NewUserHistory(log logger.Logger, vlog *libkb.VDebugLog) *UserHistory {
	return &UserHistory{
		histories: make(map[tlfKey]writersByRevision),
		log:       log,
		vlog:      vlog,
	}
}
297716
func NewUserNotAllowedError(image string, onbuild bool) error {
	var msg string
	if onbuild {
		msg = fmt.Sprintf("image %q includes at least one ONBUILD instruction that sets the user to a user that is not allowed", image)
	} else {
		msg = fmt.Sprintf("image %q must specify a user that is numeric and within the range of allowed users", image)
	}
	return Error{
		Message:    msg,
		ErrorCode:  UserNotAllowedError,
		Suggestion: fmt.Sprintf("modify image %q to use a numeric user within the allowed range, or build without the allowed UIDs paremeter set", image),
	}
}
413732
func (fl *FolderList) userChanged(ctx context.Context, _, newUser kbname.NormalizedUsername) {
	var fs []*Folder
	func() {
		fl.mu.Lock()
		defer fl.mu.Unlock()
		for _, tlf := range fl.folders {
			if tlf, ok := tlf.(*TLF); ok {
				fs = append(fs, tlf.folder)
			}
		}
	}()
	for _, f := range fs {
		f.TlfHandleChange(ctx, nil)
	}
	if newUser != kbname.NormalizedUsername("") {
		fl.fs.config.KBFSOps().ForceFastForward(ctx)
	}
}
1012698
func NewLogFile(name string, file *os.File) (*LogFile, error) {
	rw := &LogFile{
		file: file,
		name: name,
	}
	if file == nil {
		if err := rw.Rotate(); err != nil {
			return nil, err
		}
	}
	return rw, nil
}
855457
func (n *Narcissus) NewPasswdUser(user string) (p *PasswdUser, err error) {
	p = &PasswdUser{
		augeasPath: "/files/etc/passwd/" + user,
	}
	err = n.Parse(p)
	return
}
1200386
func (c *collectorImpl) GetUserRecords() map[string]*collector.UserRecord {
	c.Lock()
	defer c.Unlock()

	if len(c.Users) == 0 {
		return nil
	}

	retval := c.Users
	c.Users = map[string]*collector.UserRecord{}
	return retval
}
987580
func NewErrorFile(fs *FS, entryValid *time.Duration) *SpecialReadFile {
	*entryValid = 0
	return &SpecialReadFile{read: libfs.GetEncodedErrors(fs.config)}
}
336524
func NewUserId(name, comment, email string) *UserId {
	// RFC 4880 doesn't deal with the structure of userid strings; the
	// name, comment and email form is just a convention. However, there's
	// no convention about escaping the metacharacters and GPG just refuses
	// to create user ids where, say, the name contains a '('. We mirror
	// this behaviour.

	if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
		return nil
	}

	uid := new(UserId)
	uid.Name, uid.Comment, uid.Email = name, comment, email
	uid.Id = name
	if len(comment) > 0 {
		if len(uid.Id) > 0 {
			uid.Id += " "
		}
		uid.Id += "("
		uid.Id += comment
		uid.Id += ")"
	}
	if len(email) > 0 {
		if len(uid.Id) > 0 {
			uid.Id += " "
		}
		uid.Id += "<"
		uid.Id += email
		uid.Id += ">"
	}
	return uid
}
1040825
func UserHomeDir() string {
	// user.Current() returns nil if cross-compiled e.g. on mac for linux
	if usr, _ := user.Current(); usr != nil {
		return usr.HomeDir
	}
	return os.Getenv("HOME")
}
1729
func NewFromFile(path string) (PolicyList, error) {
	// File format is one map per line.  This allows easy concatenation of files,
	// comments in files, and identification of errors by line number.
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	pl := make(PolicyList, 0)

	decoder := abac.Codecs.UniversalDecoder()

	i := 0
	unversionedLines := 0
	for scanner.Scan() {
		i++
		p := &abac.Policy{}
		b := scanner.Bytes()

		// skip comment lines and blank lines
		trimmed := strings.TrimSpace(string(b))
		if len(trimmed) == 0 || strings.HasPrefix(trimmed, "#") {
			continue
		}

		decodedObj, _, err := decoder.Decode(b, nil, nil)
		if err != nil {
			if !(runtime.IsMissingVersion(err) || runtime.IsMissingKind(err) || runtime.IsNotRegisteredError(err)) {
				return nil, policyLoadError{path, i, b, err}
			}
			unversionedLines++
			// Migrate unversioned policy object
			oldPolicy := &v0.Policy{}
			if err := runtime.DecodeInto(decoder, b, oldPolicy); err != nil {
				return nil, policyLoadError{path, i, b, err}
			}
			if err := abac.Scheme.Convert(oldPolicy, p, nil); err != nil {
				return nil, policyLoadError{path, i, b, err}
			}
			pl = append(pl, p)
			continue
		}

		decodedPolicy, ok := decodedObj.(*abac.Policy)
		if !ok {
			return nil, policyLoadError{path, i, b, fmt.Errorf("unrecognized object: %#v", decodedObj)}
		}
		pl = append(pl, decodedPolicy)
	}

	if unversionedLines > 0 {
		klog.Warningf("Policy file %s contained unversioned rules. See docs/admin/authorization.md#abac-mode for ABAC file format details.", path)
	}

	if err := scanner.Err(); err != nil {
		return nil, policyLoadError{path, -1, nil, err}
	}
	return pl, nil
}