working commit
This commit is contained in:
@@ -46,6 +46,7 @@ type Config struct {
|
||||
Keypath string `json:"keypath,omitempty" yaml:"keypath"`
|
||||
X509Cert string `json:"-" yaml:"-"`
|
||||
X509Key string `json:"-" yaml:"-"`
|
||||
Datadir string `json:"datadir"`
|
||||
}
|
||||
|
||||
func NewConfig() *Config {
|
||||
@@ -76,7 +77,7 @@ func NewConfig() *Config {
|
||||
Logpath: logpath,
|
||||
Runpath: runpath,
|
||||
Version: version,
|
||||
|
||||
Datadir: datadir,
|
||||
//Certpath: certpath,
|
||||
//Keypath: keypath,
|
||||
}
|
||||
|
||||
+23
-4
@@ -10,12 +10,20 @@
|
||||
|
||||
package descr
|
||||
|
||||
const AnonymousID = "10000000-0000-0000-0000-000000000001"
|
||||
const (
|
||||
AnonimousUsername = "anonymous"
|
||||
AnonymousID = "10000000-0000-0000-0000-000000000001"
|
||||
ServerUsername = "server"
|
||||
ServerID = "10000000-0000-0000-0000-000000000002"
|
||||
|
||||
InitUsername = "mstore"
|
||||
InitID = "10000000-0000-0000-0000-000000000005"
|
||||
)
|
||||
|
||||
type Grant struct {
|
||||
ID string `json:"id" db:"id"`
|
||||
AccountID string `json:"accountID" db:"account_id"`
|
||||
Operation string `json:"operation" db:"operation"`
|
||||
Right string `json:"right" db:"right"`
|
||||
Pattern string `json:"pattern" db:"pattern"`
|
||||
CreatedAt string `json:"createdAt" db:"created_at"`
|
||||
UpdatedAt string `json:"updatedAt" db:"updated_at"`
|
||||
@@ -24,7 +32,7 @@ type Grant struct {
|
||||
}
|
||||
|
||||
type GrantShort struct {
|
||||
Operation string `json:"operation" db:"operation"`
|
||||
Right string `json:"right" db:"right"`
|
||||
Pattern string `json:"pattern" db:"pattern"`
|
||||
CreatedAt string `json:"createdAt" db:"created_at"`
|
||||
UpdatedAt string `json:"updatedAt" db:"updated_at"`
|
||||
@@ -33,5 +41,16 @@ type GrantShort struct {
|
||||
}
|
||||
|
||||
const (
|
||||
GrantCreateAccount = "createAccount"
|
||||
// Accounts
|
||||
RightReadAccounts = "readAccounts" // GetAccount, ListAccounts
|
||||
RightWriteAccounts = "writeAccounts" // CreateAccount, UpdateAccount, DeleteAccount
|
||||
// Frants
|
||||
RightReadGrants = "readGrants" // Like account operation
|
||||
RightWriteGrants = "writeGrants"
|
||||
// Files
|
||||
RightWriteFiles = "writeFiles" // FileInfo, GetFile, ListFiles
|
||||
RightReadFiles = "readFiles" // PutFile, DeleteFile
|
||||
// Images: manifests, layers
|
||||
RightReadImages = "readImages" // ManifestInfo, GetManifest, BlobInfo, GetBlob
|
||||
RightWriteImages = "writeImages" // other opearion
|
||||
)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||
*
|
||||
* This work is published and licensed under a Creative Commons
|
||||
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
*
|
||||
* Distribution of this work is permitted, but commercial use and
|
||||
* modifications are strictly prohibited.
|
||||
*/
|
||||
package descr
|
||||
|
||||
type Server struct {
|
||||
SchemeCreated bool `json:"SchemeCreated"`
|
||||
AnonymousCreated bool `json:"AnonymousCreated"`
|
||||
InituserCreated bool `json:"inituserCreated"`
|
||||
SchemeCreatedAt string `json:"inituserCreatedAt"`
|
||||
}
|
||||
@@ -9,10 +9,12 @@ import (
|
||||
"mstore/app/router"
|
||||
)
|
||||
|
||||
func (hand *Handler) CheckGrant(ctx context.Context, accountID, grant, subject string) (bool, error) {
|
||||
func (hand *Handler) CheckRight(ctx context.Context, accountID, right, subject string) (bool, error) {
|
||||
var err error
|
||||
var res bool
|
||||
hand.logg.Debugf("CheckRight %s: %s %s", accountID, right, subject)
|
||||
|
||||
res = true
|
||||
return res, err
|
||||
}
|
||||
|
||||
@@ -22,9 +24,13 @@ func (hand *Handler) CreateAccount(rctx *router.Context) {
|
||||
|
||||
params := &operator.CreateAccountParams{}
|
||||
err = rctx.BindJSON(params)
|
||||
if err != nil {
|
||||
hand.SendError(rctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
operatorID, _ := rctx.GetString(userTag)
|
||||
opEnable, err := hand.CheckGrant(rctx.Ctx, operatorID, descr.GrantCreateAccount, params.Username)
|
||||
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, descr.RightWriteAccounts, params.Username)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("CreateAccount error: %v", err)
|
||||
hand.SendError(rctx, err)
|
||||
@@ -36,10 +42,6 @@ func (hand *Handler) CreateAccount(rctx *router.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
hand.SendError(rctx, err)
|
||||
return
|
||||
}
|
||||
res, err := hand.oper.CreateAccount(rctx.Ctx, operatorID, params)
|
||||
if err != nil {
|
||||
hand.logg.Errorf("CreateAccount error: %v", err)
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||
*
|
||||
* This work is published and licensed under a Creative Commons
|
||||
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
*
|
||||
* Distribution of this work is permitted, but commercial use and
|
||||
* modifications are strictly prohibited.
|
||||
*/
|
||||
package handler
|
||||
|
||||
import (
|
||||
|
||||
+17
-8
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||
*
|
||||
* This work is published and licensed under a Creative Commons
|
||||
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
*
|
||||
* Distribution of this work is permitted, but commercial use and
|
||||
* modifications are strictly prohibited.
|
||||
*/
|
||||
package maindb
|
||||
|
||||
import (
|
||||
@@ -8,9 +17,9 @@ import (
|
||||
|
||||
func (db *Database) InsertGrant(ctx context.Context, grant *descr.Grant) error {
|
||||
var err error
|
||||
request := `INSERT INTO grants(id, account_id, operation, pattern, created_at, updated_at, created_by, updated_by)
|
||||
request := `INSERT INTO grants(id, account_id, right, pattern, created_at, updated_at, created_by, updated_by)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`
|
||||
_, err = db.db.Exec(request, grant.ID, grant.AccountID, grant.Operation, grant.Pattern,
|
||||
_, err = db.db.Exec(request, grant.ID, grant.AccountID, grant.Right, grant.Pattern,
|
||||
grant.CreatedAt, grant.UpdatedAt, grant.CreatedBy, grant.UpdatedBy)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -67,12 +76,12 @@ func (db *Database) GetGrantByID(ctx context.Context, id string) (bool, *descr.G
|
||||
return true, res, err
|
||||
}
|
||||
|
||||
func (db *Database) GetGrantByAccoundIDOperationPattern(ctx context.Context, accountID, operation, pattern string) (bool, *descr.Grant, error) {
|
||||
func (db *Database) GetGrantByAccoundIDRightPattern(ctx context.Context, accountID, right, pattern string) (bool, *descr.Grant, error) {
|
||||
var err error
|
||||
res := &descr.Grant{}
|
||||
request := `SELECT * FROM grants WHERE account_id = $1 AND operation = $2 AND pattern = $3 LIMIT 1`
|
||||
request := `SELECT * FROM grants WHERE account_id = $1 AND right = $2 AND pattern = $3 LIMIT 1`
|
||||
dbRes := make([]descr.Grant, 0)
|
||||
err = db.db.Select(&dbRes, request, accountID, operation, pattern)
|
||||
err = db.db.Select(&dbRes, request, accountID, right, pattern)
|
||||
if err != nil {
|
||||
return false, res, err
|
||||
}
|
||||
@@ -84,10 +93,10 @@ func (db *Database) GetGrantByAccoundIDOperationPattern(ctx context.Context, acc
|
||||
return true, res, err
|
||||
}
|
||||
|
||||
func (db *Database) DeleteGrantByAccountIDOperationPattern(ctx context.Context, accountID, operation, pattern string) error {
|
||||
func (db *Database) DeleteGrantByAccountIDRightPattern(ctx context.Context, accountID, right, pattern string) error {
|
||||
var err error
|
||||
request := `DELETE FROM grants WHERE account_id = $1 AND operation = $2 AND pattern = $3`
|
||||
_, err = db.db.Exec(request, accountID, operation, pattern)
|
||||
request := `DELETE FROM grants WHERE account_id = $1 AND right = $2 AND pattern = $3`
|
||||
_, err = db.db.Exec(request, accountID, right, pattern)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||
*
|
||||
* This work is published and licensed under a Creative Commons
|
||||
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
*
|
||||
* Distribution of this work is permitted, but commercial use and
|
||||
* modifications are strictly prohibited.
|
||||
*/
|
||||
|
||||
package maindb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"mstore/app/descr"
|
||||
"mstore/pkg/auxpwd"
|
||||
"mstore/pkg/auxtool"
|
||||
"mstore/pkg/auxuuid"
|
||||
)
|
||||
|
||||
func (db *Database) WriteAnonymous(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
now := auxtool.TimeNow()
|
||||
password := auxtool.RandomString(64)
|
||||
passhash := auxpwd.MakeSHA256Hash([]byte(password))
|
||||
accountDescr := &descr.Account{
|
||||
ID: auxuuid.NewUUID(),
|
||||
Username: descr.AnonimousUsername,
|
||||
Passhash: passhash,
|
||||
Disabled: false,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertAccount(ctx, accountDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grantDescr := &descr.Grant{
|
||||
ID: auxuuid.NewUUID(),
|
||||
AccountID: accountDescr.ID,
|
||||
Right: descr.RightReadFiles,
|
||||
Pattern: "*",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertGrant(ctx, grantDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grantDescr = &descr.Grant{
|
||||
ID: auxuuid.NewUUID(),
|
||||
AccountID: accountDescr.ID,
|
||||
Right: descr.RightReadFiles,
|
||||
Pattern: "*",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertGrant(ctx, grantDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
func (db *Database) WriteInituser(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
now := auxtool.TimeNow()
|
||||
passhash := auxpwd.MakeSHA256Hash([]byte(descr.InitUsername))
|
||||
accountDescr := &descr.Account{
|
||||
ID: auxuuid.NewUUID(),
|
||||
Username: descr.AnonimousUsername,
|
||||
Passhash: passhash,
|
||||
Disabled: false,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertAccount(ctx, accountDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Files
|
||||
grantDescr := &descr.Grant{
|
||||
ID: auxuuid.NewUUID(),
|
||||
AccountID: accountDescr.ID,
|
||||
Right: descr.RightReadFiles,
|
||||
Pattern: "*",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertGrant(ctx, grantDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grantDescr = &descr.Grant{
|
||||
ID: auxuuid.NewUUID(),
|
||||
AccountID: accountDescr.ID,
|
||||
Right: descr.RightWriteFiles,
|
||||
Pattern: "*",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertGrant(ctx, grantDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Images
|
||||
grantDescr = &descr.Grant{
|
||||
ID: auxuuid.NewUUID(),
|
||||
AccountID: accountDescr.ID,
|
||||
Right: descr.RightReadImages,
|
||||
Pattern: "*",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertGrant(ctx, grantDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grantDescr = &descr.Grant{
|
||||
ID: auxuuid.NewUUID(),
|
||||
AccountID: accountDescr.ID,
|
||||
Right: descr.RightWriteImages,
|
||||
Pattern: "*",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
CreatedBy: descr.ServerID,
|
||||
UpdatedBy: descr.ServerID,
|
||||
}
|
||||
err = db.InsertGrant(ctx, grantDescr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
|
||||
}
|
||||
+10
-2
@@ -110,8 +110,12 @@ func (oper *Operator) GetAccount(ctx context.Context, params *GetAccountParams)
|
||||
}
|
||||
for _, grantDescrs := range grantDescrs {
|
||||
grantShorts := descr.GrantShort{
|
||||
Operation: grantDescrs.Operation,
|
||||
Right: grantDescrs.Right,
|
||||
Pattern: grantDescrs.Pattern,
|
||||
CreatedAt: grantDescrs.CreatedAt,
|
||||
UpdatedAt: grantDescrs.UpdatedAt,
|
||||
CreatedBy: grantDescrs.CreatedBy,
|
||||
UpdatedBy: grantDescrs.UpdatedBy,
|
||||
}
|
||||
accountShort.Grants = append(accountShort.Grants, grantShorts)
|
||||
}
|
||||
@@ -253,8 +257,12 @@ func (oper *Operator) ListAccounts(ctx context.Context, params *ListAccountsPara
|
||||
}
|
||||
for _, grantDescrs := range grantDescrs {
|
||||
grantShorts := descr.GrantShort{
|
||||
Operation: grantDescrs.Operation,
|
||||
Right: grantDescrs.Right,
|
||||
Pattern: grantDescrs.Pattern,
|
||||
CreatedAt: grantDescrs.CreatedAt,
|
||||
UpdatedAt: grantDescrs.UpdatedAt,
|
||||
CreatedBy: grantDescrs.CreatedBy,
|
||||
UpdatedBy: grantDescrs.UpdatedBy,
|
||||
}
|
||||
accountShort.Grants = append(accountShort.Grants, grantShorts)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
type CreateGrantParams struct {
|
||||
AccountID string `json:"accountID"`
|
||||
Operation string `json:"operation"`
|
||||
Right string `json:"operation"`
|
||||
Pattern string `json:"pattern"`
|
||||
}
|
||||
type CreateGrantResult struct {
|
||||
@@ -26,7 +26,7 @@ func (oper *Operator) CreateGrant(ctx context.Context, params *CreateGrantParams
|
||||
err := fmt.Errorf("Empty accountId parameters")
|
||||
return res, err
|
||||
}
|
||||
if params.Operation == "" {
|
||||
if params.Right == "" {
|
||||
err := fmt.Errorf("Empty operation parameter")
|
||||
return res, err
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func (oper *Operator) CreateGrant(ctx context.Context, params *CreateGrantParams
|
||||
return res, err
|
||||
}
|
||||
|
||||
grantExists, _, err := oper.mdb.GetGrantByAccoundIDOperationPattern(ctx, params.AccountID, params.Operation, params.Pattern)
|
||||
grantExists, _, err := oper.mdb.GetGrantByAccoundIDRightPattern(ctx, params.AccountID, params.Right, params.Pattern)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (oper *Operator) CreateGrant(ctx context.Context, params *CreateGrantParams
|
||||
grantDescr := &descr.Grant{
|
||||
ID: auxuuid.NewUUID(),
|
||||
AccountID: params.AccountID,
|
||||
Operation: params.Operation,
|
||||
Right: params.Right,
|
||||
Pattern: params.Pattern,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
|
||||
+71
-12
@@ -11,20 +11,26 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"mstore/app/config"
|
||||
"mstore/app/descr"
|
||||
"mstore/app/handler"
|
||||
"mstore/app/logger"
|
||||
"mstore/app/maindb"
|
||||
"mstore/app/operator"
|
||||
"mstore/app/service"
|
||||
"mstore/app/storage"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
@@ -35,6 +41,7 @@ type Server struct {
|
||||
hand *handler.Handler
|
||||
logg *logger.Logger
|
||||
stor *storage.Storage
|
||||
stat descr.Server
|
||||
}
|
||||
|
||||
func NewServer() (*Server, error) {
|
||||
@@ -95,50 +102,102 @@ func (srv *Server) Configure() error {
|
||||
|
||||
func (srv *Server) Build() error {
|
||||
var err error
|
||||
srv.logg.Infof("Server build")
|
||||
srv.logg.Infof("Server building")
|
||||
|
||||
confDump := srv.conf.String()
|
||||
srv.logg.Infof("Current server configuration is:\n%s\n", confDump)
|
||||
|
||||
if srv.conf.AsDaemon {
|
||||
logdir := filepath.Dir(srv.conf.Logpath)
|
||||
srv.logg.Infof("Create log directory %s", logdir)
|
||||
srv.logg.Infof("Creating log directory %s", logdir)
|
||||
err = os.MkdirAll(logdir, 0750)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rundir := filepath.Dir(srv.conf.Runpath)
|
||||
srv.logg.Infof("Create run directory %s", rundir)
|
||||
srv.logg.Infof("Creating run directory %s", rundir)
|
||||
err = os.MkdirAll(rundir, 0750)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Creating datadir
|
||||
datadir := srv.conf.Datadir
|
||||
srv.logg.Infof("Creating data directory %s ", datadir)
|
||||
err = os.MkdirAll(datadir, 0750)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read state file
|
||||
statefilePath := filepath.Join(srv.conf.Datadir, "server.yaml")
|
||||
stateData, err := ioutil.ReadFile(statefilePath)
|
||||
if err != nil {
|
||||
err = yaml.Unmarshal(stateData, &srv.stat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Creating database
|
||||
dbdir := srv.conf.Database.Basepath
|
||||
srv.logg.Infof("Create database directory %s ", dbdir)
|
||||
srv.logg.Infof("Creating database directory %s ", dbdir)
|
||||
err = os.MkdirAll(dbdir, 0750)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mdb := maindb.NewDatabase(dbdir)
|
||||
srv.logg.Infof("Open main database")
|
||||
srv.logg.Infof("Opening main database")
|
||||
err = mdb.OpenDatabase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srv.logg.Infof("Initialize main database")
|
||||
err = mdb.InitDatabase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srv.mdb = mdb
|
||||
|
||||
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
// Created db scheme
|
||||
if !srv.stat.SchemeCreated {
|
||||
srv.logg.Infof("Initialize main database")
|
||||
err = mdb.InitDatabase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srv.stat.SchemeCreated = true
|
||||
}
|
||||
// Created anonymous user
|
||||
if !srv.stat.AnonymousCreated {
|
||||
srv.logg.Infof("Creating anonimous user")
|
||||
err = mdb.WriteAnonymous(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srv.stat.AnonymousCreated = true
|
||||
}
|
||||
if !srv.stat.InituserCreated {
|
||||
srv.logg.Infof("Creating init user")
|
||||
err = srv.mdb.WriteAnonymous(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srv.stat.InituserCreated = true
|
||||
}
|
||||
|
||||
// Write status file
|
||||
stateData, err = yaml.Marshal(srv.stat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(statefilePath, stateData, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Creating storage
|
||||
srv.logg.Infof("Create storage directory")
|
||||
datadir := srv.conf.Database.Basepath
|
||||
srv.logg.Infof("Creating storage directory")
|
||||
datadir = srv.conf.Database.Basepath
|
||||
err = os.MkdirAll(datadir, 0750)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package auxtool
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func FileExists(name string) bool {
|
||||
fileStat, err := os.Stat(name)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if fileStat.IsDir() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func DirExists(name string) bool {
|
||||
fileStat, err := os.Stat(name)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return fileStat.IsDir()
|
||||
}
|
||||
Reference in New Issue
Block a user