124 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package conf
 | |
| 
 | |
| import (
 | |
| 	`errors`
 | |
| 	`io/fs`
 | |
| 	`os`
 | |
| 	`os/user`
 | |
| 	`strconv`
 | |
| )
 | |
| 
 | |
| // chmod applies the PermSpec.Mode to path.
 | |
| func (p *PermSpec) chmod(path string, isNew bool) (err error) {
 | |
| 
 | |
| 	if p.Mode == nil || (!isNew && p.explicitMode == false) {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if err = os.Chmod(path, *p.Mode); err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // chown applies the Permspec.User and PermSpec.Group to path.
 | |
| func (p *PermSpec) chown(path string) (err error) {
 | |
| 
 | |
| 	/*
 | |
| 		ORIGINALLY, I thought I'd have to fetch the original UID/GID from fs.FileInfo.Sys().
 | |
| 		Linux uses https://pkg.go.dev/syscall?GOOS=linux#Stat_t
 | |
| 		macOS uses a https://pkg.go.dev/syscall?GOOS=darwin#Stat_t
 | |
| 		Windows uses a https://pkg.go.dev/syscall?GOOS=windows#Win32FileAttributeData which is completely useless.
 | |
| 		(And AIX, Plan9, JS don't have a Stat_t.)
 | |
| 		But per os.Chown, a -1 means "do not change", which is what we want.
 | |
| 	*/
 | |
| 
 | |
| 	if (p.realUid == -1) || (p.realGid == -1) {
 | |
| 		// This evaluates as a no-op.
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if err = os.Chown(path, p.realUid, p.realGid); err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // setMissing populates missing information from a PermSpec. It should only be invoked by the parent Perms.SetMissing.
 | |
| func (p *PermSpec) setMissing(isDir bool) (err error) {
 | |
| 
 | |
| 	var tmpUser *user.User
 | |
| 	var tmpGroup *user.Group
 | |
| 	var unameUnknown user.UnknownUserError
 | |
| 	// var uidUnknown user.UnknownUserIdError
 | |
| 	var gnameUnknown user.UnknownGroupError
 | |
| 	// var gidUnknown user.UnknownGroupIdError
 | |
| 
 | |
| 	if p.idsSet {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// MODE
 | |
| 	if p.Mode == nil {
 | |
| 		p.Mode = new(fs.FileMode)
 | |
| 		if isDir {
 | |
| 			*p.Mode = fs.FileMode(0o0700)
 | |
| 		} else {
 | |
| 			*p.Mode = fs.FileMode(0o0600)
 | |
| 		}
 | |
| 	} else {
 | |
| 		p.explicitMode = true
 | |
| 	}
 | |
| 
 | |
| 	// OWNER/GROUP
 | |
| 	// If nil, no change from current on-disk.
 | |
| 	switch p.User {
 | |
| 	case "":
 | |
| 		p.realUid = p.parent.curUid
 | |
| 	case "-1":
 | |
| 		p.realUid = -1
 | |
| 	default:
 | |
| 		// Lookup, try username first then uid.
 | |
| 		if tmpUser, err = user.Lookup(p.User); err != nil {
 | |
| 			if errors.As(err, &unameUnknown) {
 | |
| 				err = nil
 | |
| 				if tmpUser, err = user.LookupId(p.User); err != nil {
 | |
| 					return
 | |
| 				}
 | |
| 			} else {
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 		if p.realUid, err = strconv.Atoi(tmpUser.Uid); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	switch p.Group {
 | |
| 	case "":
 | |
| 		p.realGid = p.parent.curGid
 | |
| 	case "-1":
 | |
| 		p.realGid = -1
 | |
| 	default:
 | |
| 		// Lookup, try groupname first then gid.
 | |
| 		if tmpGroup, err = user.LookupGroup(p.Group); err != nil {
 | |
| 			if errors.As(err, &gnameUnknown) {
 | |
| 				err = nil
 | |
| 				if tmpGroup, err = user.LookupGroupId(p.Group); err != nil {
 | |
| 					return
 | |
| 				}
 | |
| 			} else {
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 		if p.realGid, err = strconv.Atoi(tmpGroup.Gid); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	p.idsSet = true
 | |
| 
 | |
| 	return
 | |
| }
 | 
