Make it possible to specify what timezone to parse timestamps in
This commit is contained in:
		
							parent
							
								
									427467931c
								
							
						
					
					
						commit
						4772add9d0
					
				
							
								
								
									
										6
									
								
								ftp.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								ftp.go
									
									
									
									
									
								
							@ -30,6 +30,9 @@ type ServerConn struct {
 | 
			
		||||
	// Do not use EPSV mode
 | 
			
		||||
	DisableEPSV bool
 | 
			
		||||
 | 
			
		||||
	// Timezone that the server is in
 | 
			
		||||
	Location *time.Location
 | 
			
		||||
 | 
			
		||||
	conn          *textproto.Conn
 | 
			
		||||
	host          string
 | 
			
		||||
	timeout       time.Duration
 | 
			
		||||
@ -83,6 +86,7 @@ func DialTimeout(addr string, timeout time.Duration) (*ServerConn, error) {
 | 
			
		||||
		host:     remoteAddr.IP.String(),
 | 
			
		||||
		timeout:  timeout,
 | 
			
		||||
		features: make(map[string]string),
 | 
			
		||||
		Location: time.UTC,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, _, err = c.conn.ReadResponse(StatusReady)
 | 
			
		||||
@ -374,7 +378,7 @@ func (c *ServerConn) List(path string) (entries []*Entry, err error) {
 | 
			
		||||
	scanner := bufio.NewScanner(r)
 | 
			
		||||
	now := time.Now()
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		entry, err := parser(scanner.Text(), now)
 | 
			
		||||
		entry, err := parser(scanner.Text(), now, c.Location)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			entries = append(entries, entry)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								parse.go
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								parse.go
									
									
									
									
									
								
							@ -10,7 +10,7 @@ import (
 | 
			
		||||
 | 
			
		||||
var errUnsupportedListLine = errors.New("Unsupported LIST line")
 | 
			
		||||
 | 
			
		||||
type parseFunc func(string, time.Time) (*Entry, error)
 | 
			
		||||
type parseFunc func(string, time.Time, *time.Location) (*Entry, error)
 | 
			
		||||
 | 
			
		||||
var listLineParsers = []parseFunc{
 | 
			
		||||
	parseRFC3659ListLine,
 | 
			
		||||
@ -25,7 +25,7 @@ var dirTimeFormats = []string{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseRFC3659ListLine parses the style of directory line defined in RFC 3659.
 | 
			
		||||
func parseRFC3659ListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
func parseRFC3659ListLine(line string, now time.Time, loc *time.Location) (*Entry, error) {
 | 
			
		||||
	iSemicolon := strings.Index(line, ";")
 | 
			
		||||
	iWhitespace := strings.Index(line, " ")
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ func parseRFC3659ListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
		switch key {
 | 
			
		||||
		case "modify":
 | 
			
		||||
			var err error
 | 
			
		||||
			e.Time, err = time.Parse("20060102150405", value)
 | 
			
		||||
			e.Time, err = time.ParseInLocation("20060102150405", value, loc)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@ -69,7 +69,7 @@ func parseRFC3659ListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
 | 
			
		||||
// parseLsListLine parses a directory line in a format based on the output of
 | 
			
		||||
// the UNIX ls command.
 | 
			
		||||
func parseLsListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
func parseLsListLine(line string, now time.Time, loc *time.Location) (*Entry, error) {
 | 
			
		||||
 | 
			
		||||
	// Has the first field a length of 10 bytes?
 | 
			
		||||
	if strings.IndexByte(line, ' ') != 10 {
 | 
			
		||||
@ -88,7 +88,7 @@ func parseLsListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
			Type: EntryTypeFolder,
 | 
			
		||||
			Name: scanner.Remaining(),
 | 
			
		||||
		}
 | 
			
		||||
		if err := e.setTime(fields[3:6], now); err != nil {
 | 
			
		||||
		if err := e.setTime(fields[3:6], now, loc); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -105,7 +105,7 @@ func parseLsListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
		if err := e.setSize(fields[2]); err != nil {
 | 
			
		||||
			return nil, errUnsupportedListLine
 | 
			
		||||
		}
 | 
			
		||||
		if err := e.setTime(fields[4:7], now); err != nil {
 | 
			
		||||
		if err := e.setTime(fields[4:7], now, loc); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -135,7 +135,7 @@ func parseLsListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
		return nil, errors.New("Unknown entry type")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := e.setTime(fields[5:8], now); err != nil {
 | 
			
		||||
	if err := e.setTime(fields[5:8], now, loc); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -144,14 +144,14 @@ func parseLsListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
 | 
			
		||||
// parseDirListLine parses a directory line in a format based on the output of
 | 
			
		||||
// the MS-DOS DIR command.
 | 
			
		||||
func parseDirListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
func parseDirListLine(line string, now time.Time, loc *time.Location) (*Entry, error) {
 | 
			
		||||
	e := &Entry{}
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	// Try various time formats that DIR might use, and stop when one works.
 | 
			
		||||
	for _, format := range dirTimeFormats {
 | 
			
		||||
		if len(line) > len(format) {
 | 
			
		||||
			e.Time, err = time.Parse(format, line[:len(format)])
 | 
			
		||||
			e.Time, err = time.ParseInLocation(format, line[:len(format)], loc)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				line = line[len(format):]
 | 
			
		||||
				break
 | 
			
		||||
@ -188,7 +188,7 @@ func parseDirListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
// by hostedftp.com
 | 
			
		||||
// -r--------   0 user group     65222236 Feb 24 00:39 UABlacklistingWeek8.csv
 | 
			
		||||
// (The link count is inexplicably 0)
 | 
			
		||||
func parseHostedFTPLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
func parseHostedFTPLine(line string, now time.Time, loc *time.Location) (*Entry, error) {
 | 
			
		||||
	// Has the first field a length of 10 bytes?
 | 
			
		||||
	if strings.IndexByte(line, ' ') != 10 {
 | 
			
		||||
		return nil, errUnsupportedListLine
 | 
			
		||||
@ -202,14 +202,14 @@ func parseHostedFTPLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Set link count to 1 and attempt to parse as Unix.
 | 
			
		||||
	return parseLsListLine(fields[0]+" 1 "+scanner.Remaining(), now)
 | 
			
		||||
	return parseLsListLine(fields[0]+" 1 "+scanner.Remaining(), now, loc)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseListLine parses the various non-standard format returned by the LIST
 | 
			
		||||
// FTP command.
 | 
			
		||||
func parseListLine(line string, now time.Time) (*Entry, error) {
 | 
			
		||||
func parseListLine(line string, now time.Time, loc *time.Location) (*Entry, error) {
 | 
			
		||||
	for _, f := range listLineParsers {
 | 
			
		||||
		e, err := f(line, now)
 | 
			
		||||
		e, err := f(line, now, loc)
 | 
			
		||||
		if err != errUnsupportedListLine {
 | 
			
		||||
			return e, err
 | 
			
		||||
		}
 | 
			
		||||
@ -222,11 +222,11 @@ func (e *Entry) setSize(str string) (err error) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Entry) setTime(fields []string, now time.Time) (err error) {
 | 
			
		||||
func (e *Entry) setTime(fields []string, now time.Time, loc *time.Location) (err error) {
 | 
			
		||||
	if strings.Contains(fields[2], ":") { // contains time
 | 
			
		||||
		thisYear, _, _ := now.Date()
 | 
			
		||||
		timeStr := fmt.Sprintf("%s %s %d %s GMT", fields[1], fields[0], thisYear, fields[2])
 | 
			
		||||
		e.Time, err = time.Parse("_2 Jan 2006 15:04 MST", timeStr)
 | 
			
		||||
		timeStr := fmt.Sprintf("%s %s %d %s", fields[1], fields[0], thisYear, fields[2])
 | 
			
		||||
		e.Time, err = time.ParseInLocation("_2 Jan 2006 15:04", timeStr, loc)
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
			On unix, `info ls` shows:
 | 
			
		||||
@ -248,8 +248,8 @@ func (e *Entry) setTime(fields []string, now time.Time) (err error) {
 | 
			
		||||
		if len(fields[2]) != 4 {
 | 
			
		||||
			return errors.New("Invalid year format in time string")
 | 
			
		||||
		}
 | 
			
		||||
		timeStr := fmt.Sprintf("%s %s %s 00:00 GMT", fields[1], fields[0], fields[2])
 | 
			
		||||
		e.Time, err = time.Parse("_2 Jan 2006 15:04 MST", timeStr)
 | 
			
		||||
		timeStr := fmt.Sprintf("%s %s %s 00:00", fields[1], fields[0], fields[2])
 | 
			
		||||
		e.Time, err = time.ParseInLocation("_2 Jan 2006 15:04", timeStr, loc)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -84,7 +84,7 @@ var listTestsFail = []unsupportedLine{
 | 
			
		||||
 | 
			
		||||
func TestParseValidListLine(t *testing.T) {
 | 
			
		||||
	for _, lt := range listTests {
 | 
			
		||||
		entry, err := parseListLine(lt.line, now)
 | 
			
		||||
		entry, err := parseListLine(lt.line, now, time.UTC)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("parseListLine(%v) returned err = %v", lt.line, err)
 | 
			
		||||
			continue
 | 
			
		||||
@ -106,7 +106,7 @@ func TestParseValidListLine(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestParseUnsupportedListLine(t *testing.T) {
 | 
			
		||||
	for _, lt := range listTestsFail {
 | 
			
		||||
		_, err := parseListLine(lt.line, now)
 | 
			
		||||
		_, err := parseListLine(lt.line, now, time.UTC)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			t.Errorf("parseListLine(%v) expected to fail", lt.line)
 | 
			
		||||
		}
 | 
			
		||||
@ -136,7 +136,7 @@ func TestSettime(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		entry := &Entry{}
 | 
			
		||||
		entry.setTime(strings.Fields(test.line), now)
 | 
			
		||||
		entry.setTime(strings.Fields(test.line), now, time.UTC)
 | 
			
		||||
 | 
			
		||||
		if !entry.Time.Equal(test.expected) {
 | 
			
		||||
			t.Errorf("setTime(%v).Time = %v, want %v", test.line, entry.Time, test.expected)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user