"math/rand"
"net/http"
"os"
+ "path/filepath"
"runtime"
- "strings"
"time"
)
defer func() { _ = l.Sync() }()
logger := l.Sugar()
- if !(strings.HasSuffix(*configDir, "/") || strings.HasSuffix(*configDir, "\\")) {
- *configDir = *configDir + "/"
- }
-
if *init {
- if _, err := os.Stat(*configDir + "/config.yaml"); os.IsNotExist(err) {
+ if _, err := os.Stat(filepath.Join(*configDir, "/config.yaml")); os.IsNotExist(err) {
if err := os.MkdirAll(*configDir, 0750); err != nil {
logger.Fatal(err)
}
}
if _, err := os.Stat(*configDir); os.IsNotExist(err) {
- logger.Fatalw("Configuration directory not found", "path", configDir)
+ logger.Fatalw("Configuration directory not found. Correct the path or re-run with -init to generate initial config.", "path", configDir)
}
srv, err := hotline.NewServer(*configDir, *basePort, logger, &hotline.OSFileStore{})
}
for _, dirEntry := range entries {
if dirEntry.IsDir() {
- if err := os.MkdirAll(dst+"/"+dirEntry.Name(), 0777); err != nil {
+ if err := os.MkdirAll(filepath.Join(dst, dirEntry.Name()), 0777); err != nil {
panic(err)
}
- subdirEntries, _ := cfgTemplate.ReadDir(src + "/" + dirEntry.Name())
+ subdirEntries, _ := cfgTemplate.ReadDir(filepath.Join(src, dirEntry.Name()))
for _, subDirEntry := range subdirEntries {
- f, err := os.Create(dst + "/" + dirEntry.Name() + "/" + subDirEntry.Name())
+ f, err := os.Create(filepath.Join(dst, dirEntry.Name(), subDirEntry.Name()))
if err != nil {
return err
}
- srcFile, err := cfgTemplate.Open(src + "/" + dirEntry.Name() + "/" + subDirEntry.Name())
+ srcFile, err := cfgTemplate.Open(filepath.Join(src, dirEntry.Name(), subDirEntry.Name()))
if err != nil {
return err
}
f.Close()
}
} else {
- f, err := os.Create(dst + "/" + dirEntry.Name())
+ f, err := os.Create(filepath.Join(dst, dirEntry.Name()))
if err != nil {
return err
}
- srcFile, err := cfgTemplate.Open(src + "/" + dirEntry.Name())
+ srcFile, err := cfgTemplate.Open(filepath.Join(src, dirEntry.Name()))
if err != nil {
return err
}
"encoding/binary"
"errors"
"io"
- "path"
+ "path/filepath"
"strings"
)
-const pathSeparator = "/" // File path separator TODO: make configurable to support Windows
-
// FilePathItem represents the file or directory portion of a delimited file path (e.g. foo and bar in "/foo/bar")
// 00 00
// 09
out = append(out, string(i.Name))
}
- return path.Join(out...)
+ return filepath.Join(out...)
}
func readPath(fileRoot string, filePath, fileName []byte) (fullPath string, err error) {
}
}
- fullPath = path.Join(
+ fullPath = filepath.Join(
"/",
fileRoot,
fp.String(),
- path.Join("/", string(fileName)),
+ filepath.Join("/", string(fileName)),
)
return fullPath, nil
import (
"encoding/binary"
"fmt"
- "strings"
+ "path/filepath"
)
// File transfer types
var pathSegments []string
pathData := fu.FileNamePath
+ // TODO: implement scanner interface instead?
for i := uint16(0); i < pathItemLen; i++ {
segLen := pathData[2]
pathSegments = append(pathSegments, string(pathData[3:3+segLen]))
pathData = pathData[3+segLen:]
}
- return strings.Join(pathSegments, pathSeparator)
+ return filepath.Join(pathSegments...)
}
}
var fileTypes = map[string]fileType{
- "sit": {
+ ".sit": {
TypeCode: "SIT!",
CreatorCode: "SIT!",
},
- "pdf": {
+ ".pdf": {
TypeCode: "PDF ",
CreatorCode: "CARO",
},
- "gif": {
+ ".gif": {
TypeCode: "GIFf",
CreatorCode: "ogle",
},
- "txt": {
+ ".txt": {
TypeCode: "TEXT",
CreatorCode: "ttxt",
},
- "zip": {
+ ".zip": {
TypeCode: "ZIP ",
CreatorCode: "SITx",
},
- "tgz": {
+ ".tgz": {
TypeCode: "Gzip",
CreatorCode: "SITx",
},
- "hqx": {
+ ".hqx": {
TypeCode: "TEXT",
CreatorCode: "SITx",
},
- "jpg": {
+ ".jpg": {
TypeCode: "JPEG",
CreatorCode: "ogle",
},
- "img": {
+ ".jpeg": {
+ TypeCode: "JPEG",
+ CreatorCode: "ogle",
+ },
+ ".img": {
TypeCode: "rohd",
CreatorCode: "ddsk",
},
- "sea": {
+ ".sea": {
TypeCode: "APPL",
CreatorCode: "aust",
},
- "mov": {
+ ".mov": {
TypeCode: "MooV",
CreatorCode: "TVOD",
},
- "incomplete": { // Partial file upload
+ ".incomplete": { // Partial file upload
TypeCode: "HTft",
CreatorCode: "HTLC",
},
"io/fs"
"os"
"path"
- "strings"
+ "path/filepath"
)
const (
incompleteFileSuffix = ".incomplete"
- infoForkNameTemplate = "%s.info_%s" // template string for info fork filenames
- rsrcForkNameTemplate = "%s.rsrc_%s" // template string for resource fork filenames
+ infoForkNameTemplate = ".info_%s" // template string for info fork filenames
+ rsrcForkNameTemplate = ".rsrc_%s" // template string for resource fork filenames
)
// fileWrapper encapsulates the data, info, and resource forks of a Hotline file and provides methods to manage the files.
}
func newFileWrapper(fs FileStore, path string, dataOffset int64) (*fileWrapper, error) {
- pathSegs := strings.Split(path, pathSeparator)
- dir := strings.Join(pathSegs[:len(pathSegs)-1], pathSeparator)
- fName := pathSegs[len(pathSegs)-1]
+ dir := filepath.Dir(path)
+ fName := filepath.Base(path)
f := fileWrapper{
fs: fs,
name: fName,
path: dir,
dataPath: path,
dataOffset: dataOffset,
- rsrcPath: fmt.Sprintf(rsrcForkNameTemplate, dir+"/", fName),
- infoPath: fmt.Sprintf(infoForkNameTemplate, dir+"/", fName),
- incompletePath: dir + "/" + fName + incompleteFileSuffix,
+ rsrcPath: filepath.Join(dir, fmt.Sprintf(rsrcForkNameTemplate, fName)),
+ infoPath: filepath.Join(dir, fmt.Sprintf(infoForkNameTemplate, fName)),
+ incompletePath: filepath.Join(dir, fName+incompleteFileSuffix),
ffo: &flattenedFileObject{},
}
}
func (f *fileWrapper) rsrcForkName() string {
- return fmt.Sprintf(rsrcForkNameTemplate, "", f.name)
+ return fmt.Sprintf(rsrcForkNameTemplate, f.name)
}
func (f *fileWrapper) infoForkName() string {
- return fmt.Sprintf(infoForkNameTemplate, "", f.name)
+ return fmt.Sprintf(infoForkNameTemplate, f.name)
}
func (f *fileWrapper) creatorCode() []byte {
"strings"
)
-func downcaseFileExtension(filename string) string {
- splitStr := strings.Split(filename, ".")
- ext := strings.ToLower(
- splitStr[len(splitStr)-1],
- )
-
- return ext
-}
-
-func fileTypeFromFilename(fn string) fileType {
- ft, ok := fileTypes[downcaseFileExtension(fn)]
+func fileTypeFromFilename(filename string) fileType {
+ fileExt := strings.ToLower(filepath.Ext(filename))
+ ft, ok := fileTypes[fileExt]
if ok {
return ft
}
return ft, nil
}
-func getFileNameList(filePath string) (fields []Field, err error) {
- files, err := os.ReadDir(filePath)
+func getFileNameList(path string) (fields []Field, err error) {
+ files, err := os.ReadDir(path)
if err != nil {
return fields, nil
}
}
if fileInfo.Mode()&os.ModeSymlink != 0 {
- resolvedPath, err := os.Readlink(filePath + "/" + file.Name())
+ resolvedPath, err := os.Readlink(filepath.Join(path, file.Name()))
if err != nil {
return fields, err
}
- rFile, err := os.Stat(filePath + "/" + resolvedPath)
+ rFile, err := os.Stat(filepath.Join(path, resolvedPath))
if errors.Is(err, os.ErrNotExist) {
continue
}
}
if rFile.IsDir() {
- dir, err := ioutil.ReadDir(filePath + "/" + file.Name())
+ dir, err := ioutil.ReadDir(filepath.Join(path, file.Name()))
if err != nil {
return fields, err
}
}
} else if file.IsDir() {
- dir, err := ioutil.ReadDir(filePath + "/" + file.Name())
+ dir, err := ioutil.ReadDir(filepath.Join(path, file.Name()))
if err != nil {
return fields, err
}
continue
}
- hlFile, err := newFileWrapper(&OSFileStore{}, filePath+"/"+file.Name(), 0)
+ hlFile, err := newFileWrapper(&OSFileStore{}, path+"/"+file.Name(), 0)
if err != nil {
return nil, err
}
"math/rand"
"net"
"os"
- "path"
"path/filepath"
"runtime/debug"
"strings"
return nil, err
}
- server.Agreement, err = os.ReadFile(configDir + agreementFile)
+ server.Agreement, err = os.ReadFile(filepath.Join(configDir, agreementFile))
if err != nil {
return nil, err
}
- if server.FlatNews, err = os.ReadFile(configDir + "MessageBoard.txt"); err != nil {
+ if server.FlatNews, err = os.ReadFile(filepath.Join(configDir, "MessageBoard.txt")); err != nil {
return nil, err
}
- if err := server.loadThreadedNews(configDir + "ThreadedNews.yaml"); err != nil {
+ if err := server.loadThreadedNews(filepath.Join(configDir, "ThreadedNews.yaml")); err != nil {
return nil, err
}
- if err := server.loadConfig(configDir + "config.yaml"); err != nil {
+ if err := server.loadConfig(filepath.Join(configDir, "config.yaml")); err != nil {
return nil, err
}
- if err := server.loadAccounts(configDir + "Users/"); err != nil {
+ if err := server.loadAccounts(filepath.Join(configDir, "Users/")); err != nil {
return nil, err
}
- server.Config.FileRoot = configDir + "Files/"
+ server.Config.FileRoot = filepath.Join(configDir, "Files")
*server.NextGuestID = 1
return err
}
err = ioutil.WriteFile(
- s.ConfigDir+"ThreadedNews.yaml",
+ filepath.Join(s.ConfigDir, "ThreadedNews.yaml"),
out,
0666,
)
}
s.Accounts[login] = &account
- return s.FS.WriteFile(s.ConfigDir+"Users/"+login+".yaml", out, 0666)
+ return s.FS.WriteFile(filepath.Join(s.ConfigDir, "Users", login+".yaml"), out, 0666)
}
func (s *Server) UpdateUser(login, newLogin, name, password string, access []byte) error {
// update renames the user login
if login != newLogin {
- err := os.Rename(s.ConfigDir+"Users/"+login+".yaml", s.ConfigDir+"Users/"+newLogin+".yaml")
+ err := os.Rename(filepath.Join(s.ConfigDir, "Users", login+".yaml"), filepath.Join(s.ConfigDir, "Users", newLogin+".yaml"))
if err != nil {
return err
}
if err != nil {
return err
}
- if err := os.WriteFile(s.ConfigDir+"Users/"+newLogin+".yaml", out, 0666); err != nil {
+
+ if err := os.WriteFile(filepath.Join(s.ConfigDir, "Users", newLogin+".yaml"), out, 0666); err != nil {
return err
}
delete(s.Accounts, login)
- return s.FS.Remove(s.ConfigDir + "Users/" + login + ".yaml")
+ return s.FS.Remove(filepath.Join(s.ConfigDir, "Users", login+".yaml"))
}
func (s *Server) connectedUsers() []Field {
// loadAccounts loads account data from disk
func (s *Server) loadAccounts(userDir string) error {
- matches, err := filepath.Glob(path.Join(userDir, "*.yaml"))
+ matches, err := filepath.Glob(filepath.Join(userDir, "*.yaml"))
if err != nil {
return err
}
)
if fu.IsFolder == [2]byte{0, 1} {
- if _, err := os.Stat(dstPath + "/" + fu.FormattedPath()); os.IsNotExist(err) {
- if err := os.Mkdir(dstPath+"/"+fu.FormattedPath(), 0777); err != nil {
+ if _, err := os.Stat(filepath.Join(dstPath, fu.FormattedPath())); os.IsNotExist(err) {
+ if err := os.Mkdir(filepath.Join(dstPath, fu.FormattedPath()), 0777); err != nil {
return err
}
}
nextAction := dlFldrActionSendFile
// Check if we have the full file already. If so, send dlFldrAction_NextFile to client to skip.
- _, err = os.Stat(dstPath + "/" + fu.FormattedPath())
+ _, err = os.Stat(filepath.Join(dstPath, fu.FormattedPath()))
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
}
}
// Check if we have a partial file already. If so, send dlFldrAction_ResumeFile to client to resume upload.
- incompleteFile, err := os.Stat(dstPath + "/" + fu.FormattedPath() + incompleteFileSuffix)
+ incompleteFile, err := os.Stat(filepath.Join(dstPath, fu.FormattedPath()+incompleteFileSuffix))
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
}
return err
}
- filePath := dstPath + "/" + fu.FormattedPath()
+ filePath := filepath.Join(dstPath, fu.FormattedPath())
hlFile, err := newFileWrapper(s.FS, filePath, 0)
if err != nil {
"io/fs"
"math/rand"
"os"
+ "path/filepath"
"strings"
"testing"
"time"
Config: &Config{
FileRoot: func() string {
path, _ := os.Getwd()
- return path + "/test/config/Files"
+ return filepath.Join(path, "/test/config/Files")
}(),
},
},