117 wiersze
2.2 KiB
Go
117 wiersze
2.2 KiB
Go
package ftp
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
|
|
"ftp-server/database"
|
|
|
|
"github.com/spf13/afero"
|
|
)
|
|
|
|
// loggingFs 带日志功能的文件系统包装器
|
|
type loggingFs struct {
|
|
afero.Fs
|
|
db *database.DB
|
|
username string
|
|
}
|
|
|
|
// loggingFile 带日志功能的文件包装器
|
|
type loggingFile struct {
|
|
afero.File
|
|
fs *loggingFs
|
|
name string
|
|
flags int
|
|
written int64
|
|
read int64
|
|
logged bool
|
|
}
|
|
|
|
// newLoggingFs 创建带日志的文件系统
|
|
func newLoggingFs(base afero.Fs, db *database.DB, username string) *loggingFs {
|
|
return &loggingFs{
|
|
Fs: base,
|
|
db: db,
|
|
username: username,
|
|
}
|
|
}
|
|
|
|
// GetHandle 实现 ftpserverlib.ClientDriverExtentionFileTransfer 接口
|
|
// flags: os.O_RDONLY 表示下载, os.O_WRONLY/os.O_CREATE 表示上传
|
|
func (fs *loggingFs) GetHandle(name string, flags int, offset int64) (interface {
|
|
io.Reader
|
|
io.Writer
|
|
io.Seeker
|
|
io.Closer
|
|
}, error) {
|
|
file, err := fs.Fs.OpenFile(name, flags, 0666)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 如果有偏移量(断点续传),先 Seek
|
|
if offset > 0 {
|
|
if _, err := file.Seek(offset, 0); err != nil {
|
|
file.Close()
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return &loggingFile{
|
|
File: file,
|
|
fs: fs,
|
|
name: name,
|
|
flags: flags,
|
|
logged: false,
|
|
}, nil
|
|
}
|
|
|
|
func (f *loggingFile) Write(p []byte) (int, error) {
|
|
n, err := f.File.Write(p)
|
|
f.written += int64(n)
|
|
return n, err
|
|
}
|
|
|
|
func (f *loggingFile) Read(p []byte) (int, error) {
|
|
n, err := f.File.Read(p)
|
|
f.read += int64(n)
|
|
return n, err
|
|
}
|
|
|
|
func (f *loggingFile) Close() error {
|
|
err := f.File.Close()
|
|
|
|
// 避免重复记录
|
|
if f.logged {
|
|
return err
|
|
}
|
|
f.logged = true
|
|
|
|
if f.fs.db == nil {
|
|
return err
|
|
}
|
|
|
|
// 判断是上传还是下载
|
|
isWrite := (f.flags & os.O_WRONLY) != 0 || (f.flags & os.O_RDWR) != 0 || (f.flags & os.O_CREATE) != 0
|
|
|
|
if isWrite && f.written > 0 {
|
|
f.fs.db.AddLog(&database.FTPLog{
|
|
Username: f.fs.username,
|
|
Action: "upload",
|
|
FilePath: f.name,
|
|
FileSize: f.written,
|
|
Status: "success",
|
|
})
|
|
} else if !isWrite && f.read > 0 {
|
|
f.fs.db.AddLog(&database.FTPLog{
|
|
Username: f.fs.username,
|
|
Action: "download",
|
|
FilePath: f.name,
|
|
FileSize: f.read,
|
|
Status: "success",
|
|
})
|
|
}
|
|
|
|
return err
|
|
}
|