package library import ( "path" "strings" "unicode/utf8" "pipu/api/internal/platform/apperr" ) // normalizeExcludedDirs accepts literal paths relative to the storage root, not globs. func normalizeExcludedDirs(dirs []string) ([]string, error) { invalid := func() ([]string, error) { return nil, apperr.Validation("excluded_dirs", "validation.excluded_dirs_invalid", "use up to 100 relative folder paths without .., one per entry", nil) } if len(dirs) > 100 { return invalid() } out := []string{} seen := map[string]bool{} for _, dir := range dirs { dir = strings.ReplaceAll(strings.TrimSpace(dir), "\\", "/") if dir == "" || strings.HasPrefix(dir, "/") || strings.ContainsAny(dir, "\x00\r\n") || utf8.RuneCountInString(dir) > 1000 || (len(dir) > 1 && dir[1] == ':') { return invalid() } for _, part := range strings.Split(dir, "/") { if part == ".." { return invalid() } } dir = path.Clean(dir) if dir == "." { return invalid() } if !seen[dir] { out = append(out, dir) seen[dir] = true } } return out, nil } func pathExcluded(rel string, dirs []string) bool { for _, dir := range dirs { if rel == dir || strings.HasPrefix(rel, dir+"/") { return true } } return false }