func (is *ImageStoreFS) ValidateRepo(name string) (bool, error) {
	dir := path.Join(is.rootDir, name)
	if !is.DirExists(dir) {
		return false, errors.ErrRepoNotFound
	}
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		is.log.Error().Err(err).Str("dir", dir).Msg("unable to read directory")
		return false, errors.ErrRepoNotFound
	}
	if len(files) < 3 {
		return false, errors.ErrRepoBadVersion
	}
	found := map[string]bool{
		"blobs":               false,
		ispec.ImageLayoutFile: false,
		"index.json":          false,
	}
	for _, file := range files {
		if file.Name() == "blobs" && !file.IsDir() {
			return false, nil
		}
		found[file.Name()] = true
	}
	for k, v := range found {
		if !v && k != BlobUploadDir {
			return false, nil
		}
	}
	buf, err := ioutil.ReadFile(path.Join(dir, ispec.ImageLayoutFile))
	if err != nil {
		return false, err
	}
	var il ispec.ImageLayout
	if err := json.Unmarshal(buf, &il); err != nil {
		return false, err
	}
	if il.Version != ispec.ImageLayoutVersion {
		return false, errors.ErrRepoBadVersion
	}
	return true, nil
}
ValidateRepo validates that the repository layout is complaint with the OCI repo layout.
package storage
import (
	"bytes"
	"context"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"github.com/anuvu/zot/errors"
	zlog "github.com/anuvu/zot/pkg/log"
	apexlog "github.com/apex/log"
	guuid "github.com/gofrs/uuid"
	godigest "github.com/opencontainers/go-digest"
	ispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/opencontainers/umoci"
	"github.com/opencontainers/umoci/oci/casext"
	"github.com/rs/zerolog"
)
const (
	BlobUploadDir = ".uploads"
	schemaVersion = 2
	gcDelay       = 1 * time.Hour
)
type BlobUpload struct {
	StoreName string
	ID        string
}
type StoreController struct {
	DefaultStore ImageStore
	SubStore     map[string]ImageStore
}
type ImageStoreFS struct {
	rootDir     string
	lock        *sync.RWMutex
	blobUploads map[string]BlobUpload
	cache       *Cache
	gc          bool
	dedupe      bool
	log         zerolog.Logger
}
func (is *ImageStoreFS) RootDir() string {
	return is.rootDir
}
func (is *ImageStoreFS) DirExists(d string) bool {
	fi, err := os.Stat(d)
	if err != nil && os.IsNotExist(err) {
		return false
	}
	if !fi.IsDir() {
		return false
	}
	return true
}
func getRoutePrefix(name string) string {
	names := strings.SplitN(name, "/", 2)
	if len(names) != 2 {  
		if len(names) == 1 {
			return "/"
		}
	}
	return fmt.Sprintf("/%s", names[0])
}
func (sc StoreController) GetImageStore(name string) ImageStore {
	if sc.SubStore != nil {
		prefixName := getRoutePrefix(name)
		imgStore, ok := sc.SubStore[prefixName]
		if !ok {
			imgStore = sc.DefaultStore
		}
		return imgStore
	}
	return sc.DefaultStore
}
func NewImageStore(rootDir string, gc bool, dedupe bool, log zlog.Logger) ImageStore {
	if _, err := os.Stat(rootDir); os.IsNotExist(err) {
		if err := os.MkdirAll(rootDir, 0700); err != nil {
			log.Error().Err(err).Str("rootDir", rootDir).Msg("unable to create root dir")
			return nil
		}
	}
	is := &ImageStoreFS{
		rootDir:     rootDir,
		lock:        &sync.RWMutex{},
		blobUploads: make(map[string]BlobUpload),
		gc:          gc,
		dedupe:      dedupe,
		log:         log.With().Caller().Logger(),
	}
	if dedupe {
		is.cache = NewCache(rootDir, "cache", log)
	}
	if gc {
		apexlog.SetLevel(apexlog.DebugLevel)
		apexlog.SetHandler(apexlog.HandlerFunc(func(entry *apexlog.Entry) error {
			e := log.Debug()
			for k, v := range entry.Fields {
				e = e.Interface(k, v)
			}
			e.Msg(entry.Message)
			return nil
		}))
	}
	return is
}
func (is *ImageStoreFS) RLock() {
	is.lock.RLock()
}
func (is *ImageStoreFS) RUnlock() {
	is.lock.RUnlock()
}
func (is *ImageStoreFS) Lock() {
	is.lock.Lock()
}
func (is *ImageStoreFS) Unlock() {
	is.lock.Unlock()
}
func (is *ImageStoreFS) initRepo(name string) error {
	repoDir := path.Join(is.rootDir, name)
	err := ensureDir(path.Join(repoDir, "blobs"), is.log)
	if err != nil {
		is.log.Error().Err(err).Msg("error creating blobs subdir")
		return err
	}
	err = ensureDir(path.Join(repoDir, BlobUploadDir), is.log)
	if err != nil {
		is.log.Error().Err(err).Msg("error creating blob upload subdir")
		return err
	}
	ilPath := path.Join(repoDir, ispec.ImageLayoutFile)
	if _, err := os.Stat(ilPath); err != nil {
		il := ispec.ImageLayout{Version: ispec.ImageLayoutVersion}
		buf, err := json.Marshal(il)
		if err != nil {
			is.log.Panic().Err(err).Msg("unable to marshal JSON")
		}
		if err := ioutil.WriteFile(ilPath, buf, 0644); err != nil {  
			is.log.Error().Err(err).Str("file", ilPath).Msg("unable to write file")
			return err
		}
	}
	indexPath := path.Join(repoDir, "index.json")
	if _, err := os.Stat(indexPath); err != nil {
		index := ispec.Index{}
		index.SchemaVersion = 2
		buf, err := json.Marshal(index)
		if err != nil {
			is.log.Panic().Err(err).Msg("unable to marshal JSON")
		}
		if err := ioutil.WriteFile(indexPath, buf, 0644); err != nil {  
			is.log.Error().Err(err).Str("file", indexPath).Msg("unable to write file")
			return err
		}
	}
	return nil
}
func (is *ImageStoreFS) InitRepo(name string) error {
	is.Lock()
	defer is.Unlock()
	return is.initRepo(name)
}