Skip to content

path/filepath: Split should trim trailing path separator else a Split stalemate occurs. #9928

Closed
@odeke-em

Description

@odeke-em
  1. What version of Go are you using (go version)?
  2. What operating system and processor architecture are you using?
go version go1.2.1 linux/386
Linux emmanuel-HP-G50-Notebook-PC 3.13.0-39-generic #66-Ubuntu SMP Tue Oct 28 13:31:23 UTC 2014 i686 athlon i686 GNU/Linux
go version go1.3 darwin/amd64
Darwin 14.1.0 Darwin Kernel Version 14.1.0: Mon Dec 22 23:10:38 PST 2014; root:xnu-2782.10.72~2/RELEASE_X86_64 x86_64

filepath.Split returns a dir and base when given a path 'p'. If the path has no trailing separator, it behaves as expected producing dir and base. If p has a trailing path separator e.g 'p/', filepath.Split should return 'p' as the dir, and '' as the base. However, filepath.Split always returns the original value as the dir and '' as the base value, instead of 'p', '' e.g in http://play.golang.org/p/fswqGij8Hu

This behaviour causes an infinite loop when walking up a path. My use case is trying to find the least non existant path starting from the end of a path. In the code excerpt below:

  • The first function is my work-around to solve the problem by always trimming the excess '/'.
  • The second function illustrates the issue and never exits since it is stuck at the original path being the dir.
  • Assumption is that a "" signifies no existant path was found.
package main

import (
    "fmt"
    "os"
    "path/filepath"
    "strings"
)

var PathSeparator = fmt.Sprintf("%c", os.PathSeparator)

func leastNonExistantRootPatched(p string) string {
    last := ""
    for p != "" {
        fInfo, _ := os.Stat(p)
        if fInfo != nil {
            break
        }
        last = p
        p, _ = filepath.Split(strings.TrimRight(p, PathSeparator))
        fmt.Println("Still spinning: ", p)
    }
    return last
}

func leastNonExistantRootInfinite(p string) string {
    last := ""
    for p != "" {
        fInfo, _ := os.Stat(p)
        if fInfo != nil {
            break
        }
        last = p
        p, _ = filepath.Split(p)
        fmt.Println("Still spinning: ", p)
    }
    return last
}

func main() {
    leastNonExistantRootPatched("/mnt/ghosting/symver/projects/gophers/alophering/change.go")
    leastNonExistantRootInfinite("/mnt/ghosting/symver/projects/gophers/alophering/change.go/")
}

Please contrast this with the behaviour of Python

>>> import os
>>> os.path.split('/mnt/ghosting/gophers/alophering/change.go/')
('/mnt/ghosting/gophers/alophering/change.go', '') # Notice the trailing slash was removed
>>> os.path.split('/mnt/ghosting/gophers/alophering/change.go')
('/mnt/ghosting/gophers/alophering', 'change.go')

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions