mirror of
https://github.com/nxshock/simplefileshare.git
synced 2025-04-11 23:55:24 +05:00
Import project
This commit is contained in:
parent
f0e39831c2
commit
1b0cbbf5cd
32
PKGBUILD
Normal file
32
PKGBUILD
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
pkgname=simplefileshare
|
||||||
|
pkgver=0.1.0
|
||||||
|
pkgrel=0
|
||||||
|
pkgdesc="Simple file share"
|
||||||
|
arch=('x86_64' 'aarch64')
|
||||||
|
license=('GPL')
|
||||||
|
url="https://github.com/nxshock/$pkgname"
|
||||||
|
makedepends=('go' 'git')
|
||||||
|
options=('!strip')
|
||||||
|
backup=("etc/$pkgname.toml")
|
||||||
|
source=("git+https://github.com/nxshock/$pkgname.git")
|
||||||
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "$srcdir/$pkgname"
|
||||||
|
|
||||||
|
export CGO_CPPFLAGS="${CPPFLAGS}"
|
||||||
|
export CGO_CFLAGS="${CFLAGS}"
|
||||||
|
export CGO_CXXFLAGS="${CXXFLAGS}"
|
||||||
|
export CGO_LDFLAGS="${LDFLAGS}"
|
||||||
|
|
||||||
|
go build -o $pkgname -buildmode=pie -trimpath -ldflags="-linkmode=external -s -w"
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "$srcdir/$pkgname"
|
||||||
|
|
||||||
|
install -Dm755 "$pkgname" "$pkgdir/usr/bin/$pkgname"
|
||||||
|
install -Dm644 "$pkgname.conf" "$pkgdir/etc/$pkgname.conf"
|
||||||
|
install -Dm644 "$pkgname.service" "$pkgdir/usr/lib/systemd/system/$pkgname.service"
|
||||||
|
install -Dm644 "$pkgname.sysusers" "$pkgdir/usr/lib/sysusers.d/$pkgname.conf"
|
||||||
|
}
|
47
config.go
Normal file
47
config.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var config *Config
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
ListenAddress string
|
||||||
|
StoragePath string
|
||||||
|
RemoveFilePeriod uint // hours
|
||||||
|
LogLevel log.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
func initConfig() error {
|
||||||
|
log.Debugln("Сonfig initialization started.")
|
||||||
|
defer log.Debugln("Сonfig initialization finished.")
|
||||||
|
|
||||||
|
var configFilePath string
|
||||||
|
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
configFilePath = defaultConfigFilePath
|
||||||
|
} else {
|
||||||
|
configFilePath = os.Args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := toml.DecodeFile(configFilePath, &config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
stat, err := os.Stat(config.StoragePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("os.Stat(config.StoragePath): %v", err)
|
||||||
|
}
|
||||||
|
if !stat.IsDir() {
|
||||||
|
return errors.New("StoragePath is not a dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
5
consts_linux.go
Normal file
5
consts_linux.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultConfigFilePath = "/etc/simplefileshare.conf"
|
||||||
|
)
|
5
consts_windows.go
Normal file
5
consts_windows.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultConfigFilePath = "simplefileshare.conf"
|
||||||
|
)
|
117
handlers.go
Normal file
117
handlers.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleRoot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.RequestURI != "/" {
|
||||||
|
http.Error(w, "", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileInfo struct {
|
||||||
|
Name string
|
||||||
|
Size string
|
||||||
|
Date string
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []FileInfo
|
||||||
|
|
||||||
|
err := filepath.Walk(config.StoragePath, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
data = append(data, FileInfo{filepath.Base(path), sizeToApproxHuman(info.Size()), info.ModTime().Format("02.01.2006 15:04")})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = templates.ExecuteTemplate(w, "index.htm", data)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "POST" {
|
||||||
|
http.Error(w, "wrong method", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := r.ParseMultipartForm(32 << 20)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, header, err := r.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
filePath := filepath.Join(config.StoragePath, header.Filename)
|
||||||
|
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
|
||||||
|
http.Error(w, "файл с таким именем уже существует", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(f, file)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleDownload(w http.ResponseWriter, r *http.Request) {
|
||||||
|
filename := filepath.Base(r.FormValue("filename"))
|
||||||
|
|
||||||
|
if filename == "" {
|
||||||
|
http.Error(w, `"filename" field can not be empty`, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(filepath.Join(config.StoragePath, filename))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
fileStat, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename))
|
||||||
|
w.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(filename)))
|
||||||
|
w.Header().Set("Accept-Ranges", "none")
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(int(fileStat.Size())))
|
||||||
|
|
||||||
|
io.CopyBuffer(w, f, make([]byte, 4096))
|
||||||
|
}
|
178
index.htm
Normal file
178
index.htm
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
|
<title>File Storage</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
font-family: Verdana;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #444;
|
||||||
|
margin: .5em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #fafafa;
|
||||||
|
display: flex;
|
||||||
|
justify-content: start;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #07a;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg, img {
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: #eee;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
padding: .5em;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
background-color: #eee;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
padding: .5em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-top: 1em;
|
||||||
|
font-size: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:hover {
|
||||||
|
background-color: #dde;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
border: 1px solid #777;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-child(2), td:nth-child(3) {
|
||||||
|
width: 10em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
width: calc(100% - 1em);
|
||||||
|
}
|
||||||
|
|
||||||
|
form > input {
|
||||||
|
width: calc(100% - 2em);
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: .5em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin: 0;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="file"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin: 0;
|
||||||
|
padding: .5em;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<span>File Storage</span>
|
||||||
|
<label>
|
||||||
|
<input id="file-uploader" type="file" id="upload-button">
|
||||||
|
Загрузить файл
|
||||||
|
</label>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<table>
|
||||||
|
<col width="*">
|
||||||
|
<col width="0">
|
||||||
|
<col width="0">
|
||||||
|
<tr>
|
||||||
|
<th>Имя</th>
|
||||||
|
<th>Размер</th>
|
||||||
|
<th>Дата</th>
|
||||||
|
</tr>
|
||||||
|
{{range .}} <tr>
|
||||||
|
<td><a href="/download?filename={{.Name}}">{{.Name}}</a></td>
|
||||||
|
<td><pre>{{.Size}}</pre></td>
|
||||||
|
<td>{{.Date}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}} </table>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function myProgressHandler(event) {
|
||||||
|
var p = Math.floor(event.loaded/event.total*100);
|
||||||
|
document.querySelector("label").innerHTML = 'Загрузка: ' + p + '%...';
|
||||||
|
}
|
||||||
|
|
||||||
|
function myOnLoadHandler(event) {
|
||||||
|
const response = event.currentTarget;
|
||||||
|
if (response.status != 200) {
|
||||||
|
alert('Ошибка при загрузке файла:\n' + response.responseText);
|
||||||
|
}
|
||||||
|
document.querySelector("label").innerHTML = 'Загрузка завершена.';
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("file-uploader").addEventListener('change', (e) => {
|
||||||
|
var file = document.getElementById("file-uploader").files[0];
|
||||||
|
var formData = new FormData;
|
||||||
|
formData.append('file', file);
|
||||||
|
var ajax = new XMLHttpRequest;
|
||||||
|
ajax.upload.addEventListener("progress", myProgressHandler, false);
|
||||||
|
ajax.addEventListener('load', myOnLoadHandler, false);
|
||||||
|
ajax.open('POST', '/upload', true);
|
||||||
|
ajax.send(formData);
|
||||||
|
});
|
||||||
|
</script>
|
53
main.go
Normal file
53
main.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetOutput(os.Stderr)
|
||||||
|
log.SetFormatter(&logrus.TextFormatter{ForceColors: true, DisableTimestamp: true})
|
||||||
|
log.SetLevel(log.ErrorLevel)
|
||||||
|
|
||||||
|
err := initConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("initConfig:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetLevel(config.LogLevel)
|
||||||
|
|
||||||
|
err = initTemplates()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("initTemplates:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.RemoveFilePeriod > 0 {
|
||||||
|
go removeOldFilesThread(config.StoragePath, time.Duration(config.RemoveFilePeriod)*time.Hour)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.HandleFunc("/", HandleRoot)
|
||||||
|
http.HandleFunc("/upload", HandleUpload)
|
||||||
|
http.HandleFunc("/download", HandleDownload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
go func() {
|
||||||
|
err := http.ListenAndServe(config.ListenAddress, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
|
<-c
|
||||||
|
log.Debugln("Stop signal received.")
|
||||||
|
}
|
10
simplefileshare.conf
Normal file
10
simplefileshare.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# HTTP-server listen address
|
||||||
|
ListenAddress = ":8000"
|
||||||
|
|
||||||
|
# File storage path
|
||||||
|
StoragePath = "files"
|
||||||
|
|
||||||
|
# File removing period (hours)
|
||||||
|
RemoveFilePeriod = 1
|
||||||
|
|
||||||
|
LogLevel = "debug"
|
41
simplefileshare.service
Normal file
41
simplefileshare.service
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=simplefileshare service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=simplefileshare
|
||||||
|
ExecStart=/usr/bin/simplefileshare
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
|
||||||
|
SecureBits=keep-caps
|
||||||
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
DevicePolicy=closed
|
||||||
|
IPAccounting=true
|
||||||
|
LockPersonality=true
|
||||||
|
MemoryDenyWriteExecute=true
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateDevices=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectClock=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
ProtectHome=true
|
||||||
|
ProtectHostname=true
|
||||||
|
ProtectKernelLogs=true
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectKernelTunables=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=
|
||||||
|
RemoveIPC=true
|
||||||
|
RestrictNamespaces=true
|
||||||
|
RestrictRealtime=true
|
||||||
|
RestrictSUIDSGID=true
|
||||||
|
SystemCallArchitectures=native
|
||||||
|
SystemCallFilter=@system-service
|
||||||
|
SystemCallFilter=~@resources
|
||||||
|
UMask=0027
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
1
simplefileshare.sysusers
Normal file
1
simplefileshare.sysusers
Normal file
@ -0,0 +1 @@
|
|||||||
|
u simplefileshare - "simplefileshare user"
|
27
templates.go
Normal file
27
templates.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"html/template"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed index.htm
|
||||||
|
var templatesFS embed.FS
|
||||||
|
|
||||||
|
var templates *template.Template
|
||||||
|
|
||||||
|
func initTemplates() error {
|
||||||
|
log.Debugln("Templates initialization started.")
|
||||||
|
defer log.Debugln("Templates initialization finished.")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
templates, err = template.ParseFS(templatesFS, "*.htm")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
templatesFS = embed.FS{} // free memory
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
28
utils.go
Normal file
28
utils.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func sizeToApproxHuman(s int64) string {
|
||||||
|
t := []struct {
|
||||||
|
Name string
|
||||||
|
Val int64
|
||||||
|
}{
|
||||||
|
{"EiB", 1 << 60},
|
||||||
|
{"PiB", 1 << 50},
|
||||||
|
{"TiB", 1 << 40},
|
||||||
|
{"GiB", 1 << 30},
|
||||||
|
{"MiB", 1 << 20},
|
||||||
|
{"KiB", 1 << 10}}
|
||||||
|
|
||||||
|
var v float64
|
||||||
|
for i := 0; i < len(t); i++ {
|
||||||
|
v = float64(s) / float64(t[i].Val)
|
||||||
|
if v < 1.0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%.1f %s", v, t[i].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%.1f KiB", v)
|
||||||
|
}
|
44
walker.go
Normal file
44
walker.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func removeOldFilesThread(path string, olderThan time.Duration) {
|
||||||
|
ticker := time.NewTicker(olderThan)
|
||||||
|
|
||||||
|
for _ = range ticker.C {
|
||||||
|
log.Debugln("Removing old files...")
|
||||||
|
err := removeOldFiles(path, olderThan)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
log.Debugln("Removing old files completed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeOldFiles(path string, olderThan time.Duration) error {
|
||||||
|
return filepath.Walk(config.StoragePath, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.ModTime().Add(olderThan).Before(time.Now()) {
|
||||||
|
log.WithField("filepath", path).Debugln("Removing file...")
|
||||||
|
err := os.Remove(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user