Compare commits
No commits in common. "master" and "v0.1.0" have entirely different histories.
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -11,7 +11,3 @@ updates:
|
|||||||
interval: "daily"
|
interval: "daily"
|
||||||
assignees:
|
assignees:
|
||||||
- "jlaffaye"
|
- "jlaffaye"
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
69
.github/workflows/codeql-analysis.yml
vendored
69
.github/workflows/codeql-analysis.yml
vendored
@ -1,69 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "master" ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ "master" ]
|
|
||||||
schedule:
|
|
||||||
- cron: '20 19 * * 2'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'go' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4.1.7
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v3
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
|
|
||||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
||||||
# queries: security-extended,security-and-quality
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
||||||
|
|
||||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
|
||||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
|
||||||
|
|
||||||
# - run: |
|
|
||||||
# echo "Run, Build Application using script"
|
|
||||||
# ./location_of_script_within_repo/buildscript.sh
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@64e61baeac852f409b48440cebec029a2d978f90
|
|
7
.github/workflows/golangci-lint.yaml
vendored
7
.github/workflows/golangci-lint.yaml
vendored
@ -5,12 +5,9 @@ jobs:
|
|||||||
golangci-lint:
|
golangci-lint:
|
||||||
name: lint
|
name: lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: read # for actions/checkout to fetch code
|
|
||||||
pull-requests: read # for golangci/golangci-lint-action to fetch pull requests
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v2
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86
|
uses: golangci/golangci-lint-action@v2
|
||||||
with:
|
with:
|
||||||
only-new-issues: true
|
only-new-issues: true
|
||||||
|
12
.github/workflows/unit_tests.yaml
vendored
12
.github/workflows/unit_tests.yaml
vendored
@ -5,12 +5,12 @@ jobs:
|
|||||||
name: test
|
name: test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@master
|
||||||
- name: Setup go
|
- name: Setup go
|
||||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: 1.17
|
||||||
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/go/pkg/mod
|
~/go/pkg/mod
|
||||||
@ -21,9 +21,9 @@ jobs:
|
|||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test -v -covermode=count -coverprofile=coverage.out
|
run: go test -v -covermode=count -coverprofile=coverage.out
|
||||||
- name: Convert coverage to lcov
|
- name: Convert coverage to lcov
|
||||||
uses: jandelgado/gcov2lcov-action@c680c0f7c7442485f1749eb2a13e54a686e76eb5
|
uses: jandelgado/gcov2lcov-action@v1.0.8
|
||||||
- name: Coveralls
|
- name: Coveralls
|
||||||
uses: coverallsapp/github-action@643bc377ffa44ace6394b2b5d0d3950076de9f63
|
uses: coverallsapp/github-action@v1.1.2
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.github_token }}
|
github-token: ${{ secrets.github_token }}
|
||||||
path-to-lcov: coverage.lcov
|
path-to-lcov: coverage.lcov
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
[](https://github.com/jlaffaye/ftp/actions/workflows/unit_tests.yaml)
|
[](https://github.com/jlaffaye/ftp/actions/workflows/unit_tests.yaml)
|
||||||
[](https://coveralls.io/github/jlaffaye/ftp?branch=master)
|
[](https://coveralls.io/github/jlaffaye/ftp?branch=master)
|
||||||
[](https://github.com/jlaffaye/ftp/actions/workflows/golangci-lint.yaml)
|
|
||||||
[](https://github.com/jlaffaye/ftp/actions/workflows/codeql-analysis.yml)
|
|
||||||
[](http://goreportcard.com/report/jlaffaye/ftp)
|
[](http://goreportcard.com/report/jlaffaye/ftp)
|
||||||
[](https://pkg.go.dev/github.com/jlaffaye/ftp)
|
[](https://pkg.go.dev/github.com/jlaffaye/ftp)
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ func (mock *ftpMock) listen() {
|
|||||||
if cmdParts[1] == "multiline-dir" {
|
if cmdParts[1] == "multiline-dir" {
|
||||||
mock.printfLine("250-File data\r\n Type=dir;Size=0; multiline-dir\r\n Modify=20201213202400; multiline-dir\r\n250 End")
|
mock.printfLine("250-File data\r\n Type=dir;Size=0; multiline-dir\r\n Modify=20201213202400; multiline-dir\r\n250 End")
|
||||||
} else {
|
} else {
|
||||||
mock.printfLine("250-File data\r\n Type=file;Size=42;Modify=20201213202400; magic-file\r\n \r\n250 End")
|
mock.printfLine("250-File data\r\n Type=file;Size=42;Modify=20201213202400; magic-file\r\n250 End")
|
||||||
}
|
}
|
||||||
case "NLST":
|
case "NLST":
|
||||||
if mock.dataConn == nil {
|
if mock.dataConn == nil {
|
||||||
|
90
ftp.go
90
ftp.go
@ -11,7 +11,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -529,26 +528,9 @@ func (c *ServerConn) pasv() (host string, port int, err error) {
|
|||||||
|
|
||||||
// Make the IP address to connect to
|
// Make the IP address to connect to
|
||||||
host = strings.Join(pasvData[0:4], ".")
|
host = strings.Join(pasvData[0:4], ".")
|
||||||
|
|
||||||
if c.host != host {
|
|
||||||
if cmdIP := net.ParseIP(c.host); cmdIP != nil {
|
|
||||||
if dataIP := net.ParseIP(host); dataIP != nil {
|
|
||||||
if isBogusDataIP(cmdIP, dataIP) {
|
|
||||||
return c.host, port, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return host, port, nil
|
return host, port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBogusDataIP(cmdIP, dataIP net.IP) bool {
|
|
||||||
// Logic stolen from lftp (https://github.com/lavv17/lftp/blob/d67fc14d085849a6b0418bb3e912fea2e94c18d1/src/ftpclass.cc#L769)
|
|
||||||
return dataIP.IsMulticast() ||
|
|
||||||
cmdIP.IsPrivate() != dataIP.IsPrivate() ||
|
|
||||||
cmdIP.IsLoopback() != dataIP.IsLoopback()
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDataConnPort returns a host, port for a new data connection
|
// getDataConnPort returns a host, port for a new data connection
|
||||||
// it uses the best available method to do so
|
// it uses the best available method to do so
|
||||||
func (c *ServerConn) getDataConnPort() (string, int, error) {
|
func (c *ServerConn) getDataConnPort() (string, int, error) {
|
||||||
@ -577,24 +559,7 @@ func (c *ServerConn) openDataConn() (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.options.tlsConfig != nil {
|
if c.options.tlsConfig != nil {
|
||||||
// We don't use tls.DialWithDialer here (which does Dial, create
|
return tls.DialWithDialer(&c.options.dialer, "tcp", addr, c.options.tlsConfig)
|
||||||
// the Client and then do the Handshake) because it seems to
|
|
||||||
// hang with some FTP servers, namely proftpd and pureftpd.
|
|
||||||
//
|
|
||||||
// Instead we do Dial, create the Client and wait for the first
|
|
||||||
// Read or Write to trigger the Handshake.
|
|
||||||
//
|
|
||||||
// This means that if we are uploading a zero sized file, we
|
|
||||||
// need to make sure we do the Handshake explicitly as Write
|
|
||||||
// won't have been called. This is done in StorFrom().
|
|
||||||
//
|
|
||||||
// See: https://github.com/jlaffaye/ftp/issues/282
|
|
||||||
conn, err := c.options.dialer.Dial("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tlsConn := tls.Client(conn, c.options.tlsConfig)
|
|
||||||
return tlsConn, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.options.dialer.Dial("tcp", addr)
|
return c.options.dialer.Dial("tcp", addr)
|
||||||
@ -784,10 +749,6 @@ func (c *ServerConn) GetEntry(path string) (entry *Entry, err error) {
|
|||||||
if len(l) > 0 && l[0] == ' ' {
|
if len(l) > 0 && l[0] == ' ' {
|
||||||
l = l[1:]
|
l = l[1:]
|
||||||
}
|
}
|
||||||
// Some severs seem to send a blank line at the end which we ignore
|
|
||||||
if l == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e, err = parseNextRFC3659ListLine(l, c.options.location, e); err != nil {
|
if e, err = parseNextRFC3659ListLine(l, c.options.location, e); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -828,7 +789,7 @@ func (c *ServerConn) CurrentDir() (string, error) {
|
|||||||
end := strings.LastIndex(msg, "\"")
|
end := strings.LastIndex(msg, "\"")
|
||||||
|
|
||||||
if start == -1 || end == -1 {
|
if start == -1 || end == -1 {
|
||||||
return "", errors.New("unsupported PWD response format")
|
return "", errors.New("unsuported PWD response format")
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg[start+1 : end], nil
|
return msg[start+1 : end], nil
|
||||||
@ -951,21 +912,8 @@ func (c *ServerConn) StorFrom(path string, r io.Reader, offset uint64) error {
|
|||||||
// response otherwise if the failure is not due to a connection problem,
|
// response otherwise if the failure is not due to a connection problem,
|
||||||
// for example the server denied the upload for quota limits, we miss
|
// for example the server denied the upload for quota limits, we miss
|
||||||
// the response and we cannot use the connection to send other commands.
|
// the response and we cannot use the connection to send other commands.
|
||||||
if n, err := io.Copy(conn, r); err != nil {
|
if _, err := io.Copy(conn, r); err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = multierror.Append(errs, err)
|
||||||
} else if n == 0 {
|
|
||||||
// If we wrote no bytes and got no error, make sure we call
|
|
||||||
// tls.Handshake on the connection as it won't get called
|
|
||||||
// unless Write() is called. (See comment in openDataConn()).
|
|
||||||
//
|
|
||||||
// ProFTP doesn't like this and returns "Unable to build data
|
|
||||||
// connection: Operation not permitted" when trying to upload
|
|
||||||
// an empty file without this.
|
|
||||||
if do, ok := conn.(interface{ Handshake() error }); ok {
|
|
||||||
if err := do.Handshake(); err != nil {
|
|
||||||
errs = multierror.Append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := conn.Close(); err != nil {
|
if err := conn.Close(); err != nil {
|
||||||
@ -1094,38 +1042,6 @@ func (c *ServerConn) Walk(root string) *Walker {
|
|||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search returns all the directories matching the search pattern
|
|
||||||
func (c *ServerConn) Search(pattern string) ([]string, error) {
|
|
||||||
_, message, err := c.cmd(StatusCommandOK, "SITE SEARCH %s", pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs := make([]string, 0)
|
|
||||||
re := regexp.MustCompile(`^[^\/]*(?P<Path>\/.*) \(.*\).*$`)
|
|
||||||
for _, msg := range strings.Split(message, "\n") {
|
|
||||||
if re.MatchString(msg) {
|
|
||||||
msgs = append(msgs, re.ReplaceAllString(msg, "${Path}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return msgs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search returns all the directories matching the search pattern
|
|
||||||
func (c *ServerConn) Searches(patterns []string) ([]string, error) {
|
|
||||||
msgs := make([]string, 0)
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
msg, err := c.Search(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return msgs, err
|
|
||||||
}
|
|
||||||
msgs = append(msgs, msg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return msgs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoOp issues a NOOP FTP command.
|
// NoOp issues a NOOP FTP command.
|
||||||
// NOOP has no effects and is usually used to prevent the remote FTP server to
|
// NOOP has no effects and is usually used to prevent the remote FTP server to
|
||||||
// close the otherwise idle connection.
|
// close the otherwise idle connection.
|
||||||
|
22
ftp_test.go
22
ftp_test.go
@ -1,22 +0,0 @@
|
|||||||
package ftp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBogusDataIP(t *testing.T) {
|
|
||||||
for _, tC := range []struct {
|
|
||||||
cmd, data net.IP
|
|
||||||
bogus bool
|
|
||||||
}{
|
|
||||||
{net.IPv4(192, 168, 1, 1), net.IPv4(192, 168, 1, 1), false},
|
|
||||||
{net.IPv4(192, 168, 1, 1), net.IPv4(1, 1, 1, 1), true},
|
|
||||||
{net.IPv4(10, 65, 1, 1), net.IPv4(1, 1, 1, 1), true},
|
|
||||||
{net.IPv4(10, 65, 25, 1), net.IPv4(10, 65, 8, 1), false},
|
|
||||||
} {
|
|
||||||
if got, want := isBogusDataIP(tC.cmd, tC.data), tC.bogus; got != want {
|
|
||||||
t.Errorf("%s,%s got %t, wanted %t", tC.cmd, tC.data, got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
6
go.mod
6
go.mod
@ -1,10 +1,10 @@
|
|||||||
module git.siteop.biz/brouzouf/ftp
|
module github.com/jlaffaye/ftp
|
||||||
|
|
||||||
go 1.23.2
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.8.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
9
go.sum
9
go.sum
@ -1,3 +1,4 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
@ -6,9 +7,13 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
|||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
2
parse.go
2
parse.go
@ -24,8 +24,6 @@ var listLineParsers = []parseFunc{
|
|||||||
var dirTimeFormats = []string{
|
var dirTimeFormats = []string{
|
||||||
"01-02-06 03:04PM",
|
"01-02-06 03:04PM",
|
||||||
"2006-01-02 15:04",
|
"2006-01-02 15:04",
|
||||||
"01-02-2006 03:04PM",
|
|
||||||
"01-02-2006 15:04",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseRFC3659ListLine parses the style of directory line defined in RFC 3659.
|
// parseRFC3659ListLine parses the style of directory line defined in RFC 3659.
|
||||||
|
@ -68,9 +68,7 @@ var listTests = []line{
|
|||||||
// DOS DIR command output
|
// DOS DIR command output
|
||||||
{"08-07-15 07:50PM 718 Post_PRR_20150901_1166_265118_13049.dat", "Post_PRR_20150901_1166_265118_13049.dat", 718, EntryTypeFile, newTime(2015, time.August, 7, 19, 50)},
|
{"08-07-15 07:50PM 718 Post_PRR_20150901_1166_265118_13049.dat", "Post_PRR_20150901_1166_265118_13049.dat", 718, EntryTypeFile, newTime(2015, time.August, 7, 19, 50)},
|
||||||
{"08-10-15 02:04PM <DIR> Billing", "Billing", 0, EntryTypeFolder, newTime(2015, time.August, 10, 14, 4)},
|
{"08-10-15 02:04PM <DIR> Billing", "Billing", 0, EntryTypeFolder, newTime(2015, time.August, 10, 14, 4)},
|
||||||
{"08-07-2015 07:50PM 718 Post_PRR_20150901_1166_265118_13049.dat", "Post_PRR_20150901_1166_265118_13049.dat", 718, EntryTypeFile, newTime(2015, time.August, 7, 19, 50)},
|
|
||||||
{"08-10-2015 02:04PM <DIR> Billing", "Billing", 0, EntryTypeFolder, newTime(2015, time.August, 10, 14, 4)},
|
|
||||||
|
|
||||||
// dir and file names that contain multiple spaces
|
// dir and file names that contain multiple spaces
|
||||||
{"drwxr-xr-x 3 110 1002 3 Dec 02 2009 spaces dir name", "spaces dir name", 0, EntryTypeFolder, newTime(2009, time.December, 2)},
|
{"drwxr-xr-x 3 110 1002 3 Dec 02 2009 spaces dir name", "spaces dir name", 0, EntryTypeFolder, newTime(2009, time.December, 2)},
|
||||||
{"-rwxr-xr-x 3 110 1002 1234567 Dec 02 2009 file name", "file name", 1234567, EntryTypeFile, newTime(2009, time.December, 2)},
|
{"-rwxr-xr-x 3 110 1002 1234567 Dec 02 2009 file name", "file name", 1234567, EntryTypeFile, newTime(2009, time.December, 2)},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user