Extend ls2json reader
by also parsing the link target, permissions, group and owner.
This commit is contained in:
@ -58,12 +58,12 @@ components:
|
|||||||
description: The path of the file.
|
description: The path of the file.
|
||||||
type: string
|
type: string
|
||||||
example: ./logs/last.log
|
example: ./logs/last.log
|
||||||
objectType:
|
entryType:
|
||||||
description: The type of the object (file).
|
description: The type of the object (file). See the man page `info ls` for all the meanings.
|
||||||
type: string
|
type: string
|
||||||
minLength: 1
|
minLength: 1
|
||||||
maxLength: 1
|
maxLength: 1
|
||||||
enum: ["d", "l", "-"]
|
enum: ["-", "a", "A", "b", "c", "C", "d", "D", "l", "M", "n", "p", "P", "s", "w", "?"]
|
||||||
default: "-"
|
default: "-"
|
||||||
size:
|
size:
|
||||||
description: The size of the file in bytes.
|
description: The size of the file in bytes.
|
||||||
|
@ -114,12 +114,25 @@ type UpdateFileSystemRequest struct {
|
|||||||
// FilePath specifies the path of a file and is part of the UpdateFileSystemRequest.
|
// FilePath specifies the path of a file and is part of the UpdateFileSystemRequest.
|
||||||
type FilePath string
|
type FilePath string
|
||||||
|
|
||||||
|
// EntryType specifies the type of the object (file/link/directory/..)
|
||||||
|
type EntryType string
|
||||||
|
|
||||||
|
// These are the common entry types. You find others in the man pages `info ls`.
|
||||||
|
const (
|
||||||
|
EntryTypeRegularFile EntryType = "-"
|
||||||
|
EntryTypeLink EntryType = "l"
|
||||||
|
)
|
||||||
|
|
||||||
// FileHeader specifies the information provided for listing a File.
|
// FileHeader specifies the information provided for listing a File.
|
||||||
type FileHeader struct {
|
type FileHeader struct {
|
||||||
Name FilePath `json:"name"`
|
Name FilePath `json:"name"`
|
||||||
ObjectType string `json:"objectType"`
|
EntryType EntryType `json:"entryType"`
|
||||||
Size int `json:"size"`
|
LinkTarget FilePath `json:"linkTarget,omitempty"`
|
||||||
ModificationTime int `json:"modificationTime"`
|
Size int `json:"size"`
|
||||||
|
ModificationTime int `json:"modificationTime"`
|
||||||
|
Permissions string `json:"permissions"`
|
||||||
|
Owner string `json:"owner"`
|
||||||
|
Group string `json:"group"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// File is a DTO for transmitting file contents. It is part of the UpdateFileSystemRequest.
|
// File is a DTO for transmitting file contents. It is part of the UpdateFileSystemRequest.
|
||||||
|
@ -9,12 +9,13 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
log = logging.GetLogger("nullio")
|
log = logging.GetLogger("nullio")
|
||||||
pathLineRegex = regexp.MustCompile(`(.*):$`)
|
pathLineRegex = regexp.MustCompile(`(.*):$`)
|
||||||
headerLineRegex = regexp.MustCompile(`([dl-])[-rwxXsS]{9} \d* .*? .*? +(\d+) (\d+) (.*)$`)
|
headerLineRegex = regexp.MustCompile(`([-aAbcCdDlMnpPsw?])([-rwxXsStT]{9})([+ ])\d+ (.+?) (.+?) +(\d+) (\d+) (.*)$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ls2JsonWriter implements io.Writer.
|
// Ls2JsonWriter implements io.Writer.
|
||||||
@ -93,20 +94,9 @@ func (w *Ls2JsonWriter) writeLine(line []byte) (count int, err error) {
|
|||||||
|
|
||||||
matches = headerLineRegex.FindSubmatch(line)
|
matches = headerLineRegex.FindSubmatch(line)
|
||||||
if matches != nil {
|
if matches != nil {
|
||||||
size, err1 := strconv.Atoi(string(matches[2]))
|
response, err1 := w.parseFileHeader(matches)
|
||||||
timestamp, err2 := strconv.Atoi(string(matches[3]))
|
|
||||||
if err1 != nil || err2 != nil {
|
|
||||||
return 0, fmt.Errorf("could not parse file details: %w %+v", err1, err2)
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err1 := json.Marshal(dto.FileHeader{
|
|
||||||
Name: dto.FilePath(append(w.latestPath, matches[4]...)),
|
|
||||||
ObjectType: string(matches[1][0]),
|
|
||||||
Size: size,
|
|
||||||
ModificationTime: timestamp,
|
|
||||||
})
|
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return 0, fmt.Errorf("could not marshal file header: %w", err)
|
return 0, err1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip the first leading comma
|
// Skip the first leading comma
|
||||||
@ -118,7 +108,7 @@ func (w *Ls2JsonWriter) writeLine(line []byte) (count int, err error) {
|
|||||||
|
|
||||||
count, err1 = w.Target.Write(response)
|
count, err1 = w.Target.Write(response)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
err = fmt.Errorf("could not write to target: %w", err)
|
err = fmt.Errorf("could not write to target: %w", err1)
|
||||||
} else if count == len(response) {
|
} else if count == len(response) {
|
||||||
count = len(line)
|
count = len(line)
|
||||||
}
|
}
|
||||||
@ -126,3 +116,48 @@ func (w *Ls2JsonWriter) writeLine(line []byte) (count int, err error) {
|
|||||||
|
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Ls2JsonWriter) parseFileHeader(matches [][]byte) ([]byte, error) {
|
||||||
|
entryType := dto.EntryType(matches[1][0])
|
||||||
|
permissions := string(matches[2])
|
||||||
|
acl := string(matches[3])
|
||||||
|
if acl == "+" {
|
||||||
|
permissions += "+"
|
||||||
|
}
|
||||||
|
|
||||||
|
owner := string(matches[4])
|
||||||
|
group := string(matches[5])
|
||||||
|
size, err1 := strconv.Atoi(string(matches[6]))
|
||||||
|
timestamp, err2 := strconv.Atoi(string(matches[7]))
|
||||||
|
if err1 != nil || err2 != nil {
|
||||||
|
return nil, fmt.Errorf("could not parse file details: %w %+v", err1, err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := dto.FilePath(append(w.latestPath, matches[8]...))
|
||||||
|
linkTarget := dto.FilePath("")
|
||||||
|
if entryType == dto.EntryTypeLink {
|
||||||
|
parts := strings.Split(string(name), " -> ")
|
||||||
|
const NumberOfPartsInALink = 2
|
||||||
|
if len(parts) == NumberOfPartsInALink {
|
||||||
|
name = dto.FilePath(parts[0])
|
||||||
|
linkTarget = dto.FilePath(parts[1])
|
||||||
|
} else {
|
||||||
|
log.Error("could not split link into name and target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := json.Marshal(dto.FileHeader{
|
||||||
|
Name: name,
|
||||||
|
EntryType: entryType,
|
||||||
|
LinkTarget: linkTarget,
|
||||||
|
Size: size,
|
||||||
|
ModificationTime: timestamp,
|
||||||
|
Permissions: permissions,
|
||||||
|
Owner: owner,
|
||||||
|
Group: group,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not marshal file header: %w", err)
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
@ -39,7 +39,8 @@ func (s *Ls2JsonTestSuite) TestLs2JsonWriter_WriteFile() {
|
|||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.writer.Close()
|
s.writer.Close()
|
||||||
|
|
||||||
s.Equal("{\"files\": [{\"name\":\"flag\",\"objectType\":\"-\",\"size\":0,\"modificationTime\":1660763446}]}",
|
s.Equal("{\"files\": [{\"name\":\"flag\",\"entryType\":\"-\",\"size\":0,\"modificationTime\":1660763446"+
|
||||||
|
",\"permissions\":\"rw-rw-r--\",\"owner\":\"kali\",\"group\":\"kali\"}]}",
|
||||||
s.buf.String())
|
s.buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,23 +53,40 @@ func (s *Ls2JsonTestSuite) TestLs2JsonWriter_WriteRecursive() {
|
|||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.writer.Close()
|
s.writer.Close()
|
||||||
|
|
||||||
s.Equal("{\"files\": [{\"name\":\"./dir\",\"objectType\":\"d\",\"size\":4096,\"modificationTime\":1660764411},"+
|
s.Equal("{\"files\": ["+
|
||||||
"{\"name\":\"./flag\",\"objectType\":\"-\",\"size\":0,\"modificationTime\":1660763446},"+
|
"{\"name\":\"./dir\",\"entryType\":\"d\",\"size\":4096,\"modificationTime\":1660764411,"+
|
||||||
"{\"name\":\"./dir/another.txt\",\"objectType\":\"-\",\"size\":3,\"modificationTime\":1660764366}]}",
|
"\"permissions\":\"rwxrwxr-x\",\"owner\":\"kali\",\"group\":\"kali\"},"+
|
||||||
|
"{\"name\":\"./flag\",\"entryType\":\"-\",\"size\":0,\"modificationTime\":1660763446,"+
|
||||||
|
"\"permissions\":\"rw-rw-r--\",\"owner\":\"kali\",\"group\":\"kali\"},"+
|
||||||
|
"{\"name\":\"./dir/another.txt\",\"entryType\":\"-\",\"size\":3,\"modificationTime\":1660764366,"+
|
||||||
|
"\"permissions\":\"rw-rw-r--\",\"owner\":\"kali\",\"group\":\"kali\"}"+
|
||||||
|
"]}",
|
||||||
s.buf.String())
|
s.buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Ls2JsonTestSuite) TestLs2JsonWriter_WriteRemaining() {
|
func (s *Ls2JsonTestSuite) TestLs2JsonWriter_WriteRemaining() {
|
||||||
input1 := "total 4\n-rw-rw-r-- 1 kali kali 3 1660764366 another.txt\n-rw-rw-r-- 1 kal"
|
input1 := "total 4\n-rw-rw-r-- 1 kali kali 3 1660764366 an.txt\n-rw-rw-r-- 1 kal"
|
||||||
_, err := s.writer.Write([]byte(input1))
|
_, err := s.writer.Write([]byte(input1))
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Equal("{\"files\": [{\"name\":\"another.txt\",\"objectType\":\"-\",\"size\":3,\"modificationTime\":1660764366}",
|
s.Equal("{\"files\": [{\"name\":\"an.txt\",\"entryType\":\"-\",\"size\":3,\"modificationTime\":1660764366,"+
|
||||||
s.buf.String())
|
"\"permissions\":\"rw-rw-r--\",\"owner\":\"kali\",\"group\":\"kali\"}", s.buf.String())
|
||||||
|
|
||||||
input2 := "i kali 0 1660763446 flag\n"
|
input2 := "i kali 0 1660763446 flag\n"
|
||||||
_, err = s.writer.Write([]byte(input2))
|
_, err = s.writer.Write([]byte(input2))
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.writer.Close()
|
s.writer.Close()
|
||||||
s.Equal("{\"files\": [{\"name\":\"another.txt\",\"objectType\":\"-\",\"size\":3,\"modificationTime\":1660764366},"+
|
s.Equal("{\"files\": [{\"name\":\"an.txt\",\"entryType\":\"-\",\"size\":3,\"modificationTime\":1660764366,"+
|
||||||
"{\"name\":\"flag\",\"objectType\":\"-\",\"size\":0,\"modificationTime\":1660763446}]}", s.buf.String())
|
"\"permissions\":\"rw-rw-r--\",\"owner\":\"kali\",\"group\":\"kali\"},"+
|
||||||
|
"{\"name\":\"flag\",\"entryType\":\"-\",\"size\":0,\"modificationTime\":1660763446,"+
|
||||||
|
"\"permissions\":\"rw-rw-r--\",\"owner\":\"kali\",\"group\":\"kali\"}]}", s.buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Ls2JsonTestSuite) TestLs2JsonWriter_WriteLink() {
|
||||||
|
input1 := "total 4\nlrw-rw-r-- 1 kali kali 3 1660764366 another.txt -> /bin/bash\n"
|
||||||
|
_, err := s.writer.Write([]byte(input1))
|
||||||
|
s.NoError(err)
|
||||||
|
s.writer.Close()
|
||||||
|
s.Equal("{\"files\": [{\"name\":\"another.txt\",\"entryType\":\"l\",\"linkTarget\":\"/bin/bash\",\"size\":3,"+
|
||||||
|
"\"modificationTime\":1660764366,\"permissions\":\"rw-rw-r--\",\"owner\":\"kali\",\"group\":\"kali\"}]}",
|
||||||
|
s.buf.String())
|
||||||
}
|
}
|
||||||
|
@ -155,8 +155,10 @@ func (s *E2ETestSuite) TestListFileSystem_Nomad() {
|
|||||||
s.Require().Equal(len(listFilesResponse.Files), 1)
|
s.Require().Equal(len(listFilesResponse.Files), 1)
|
||||||
fileHeader := listFilesResponse.Files[0]
|
fileHeader := listFilesResponse.Files[0]
|
||||||
s.Equal(dto.FilePath("./"+tests.DefaultFileName), fileHeader.Name)
|
s.Equal(dto.FilePath("./"+tests.DefaultFileName), fileHeader.Name)
|
||||||
s.Equal("-", fileHeader.ObjectType)
|
s.Equal(dto.EntryTypeRegularFile, fileHeader.EntryType)
|
||||||
s.Equal(0, fileHeader.Size)
|
s.Equal("user", fileHeader.Owner)
|
||||||
|
s.Equal("user", fileHeader.Group)
|
||||||
|
s.Equal("rwxr--r--", fileHeader.Permissions)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user