未验证 提交 5c348843 编写于 作者: D Davies Liu 提交者: GitHub

support case-insensi in Windows (#303)

上级 5d64490e
......@@ -138,7 +138,11 @@ func mount(c *cli.Context) error {
}
logger.Infof("Meta address: %s", addr)
var rc = meta.RedisConfig{Retries: 10, Strict: true}
var rc = meta.RedisConfig{
Retries: 10,
Strict: true,
CaseInsensi: strings.HasSuffix(mp, ":") && runtime.GOOS == "windows",
}
m, err := meta.NewRedisMeta(addr, &rc)
if err != nil {
logger.Fatalf("Meta: %s", err)
......
......@@ -16,6 +16,8 @@
package main
import (
"strings"
"github.com/juicedata/juicefs/pkg/chunk"
"github.com/juicedata/juicefs/pkg/fs"
"github.com/juicedata/juicefs/pkg/meta"
......@@ -56,5 +58,6 @@ func mount_main(conf *vfs.Config, m meta.Meta, store chunk.ChunkStore, c *cli.Co
if err != nil {
logger.Fatalf("Initialize failed: %s", err)
}
winfsp.Serve(conf, jfs, c.String("o"), c.Float64("file-cache-to"), c.Bool("as-root"), c.Int("delay-close"))
winfsp.Serve(conf, jfs, c.String("o"), c.Float64("file-cache-to"), c.Bool("as-root"), c.Int("delay-close"),
strings.HasSuffix(conf.Mountpoint, ":"))
}
......@@ -93,8 +93,9 @@ return {ino, redis.call('GET', "i" .. tostring(ino))}
// RedisConfig is config for Redis client.
type RedisConfig struct {
Strict bool // update ctime
Retries int
Strict bool // update ctime
Retries int
CaseInsensi bool
}
type redisMeta struct {
......@@ -458,13 +459,25 @@ func (r *redisMeta) Summary(ctx Context, inode Ino, summary *Summary) syscall.Er
return 0
}
func (r *redisMeta) resolveCase(ctx Context, parent Ino, name string) *Entry {
var entries []*Entry
_ = r.Readdir(ctx, parent, 0, &entries)
for _, e := range entries {
n := string(e.Name)
if strings.EqualFold(name, n) {
return e
}
}
return nil
}
func (r *redisMeta) Lookup(ctx Context, parent Ino, name string, inode *Ino, attr *Attr) syscall.Errno {
var foundIno Ino
var encodedAttr []byte
var err error
entryKey := r.entryKey(parent)
if len(r.shaLookup) > 0 && attr != nil {
if len(r.shaLookup) > 0 && attr != nil && !r.conf.CaseInsensi {
var res interface{}
res, err = r.rdb.EvalSha(ctx, r.shaLookup, []string{entryKey, name}).Result()
if err != nil {
......@@ -502,10 +515,19 @@ func (r *redisMeta) Lookup(ctx Context, parent Ino, name string, inode *Ino, att
} else {
var buf []byte
buf, err = r.rdb.HGet(ctx, entryKey, name).Bytes()
if err == nil {
_, foundIno = r.parseEntry(buf)
}
if err == redis.Nil && r.conf.CaseInsensi {
e := r.resolveCase(ctx, parent, name)
if e != nil {
foundIno = e.Inode
err = nil
}
}
if err != nil {
return errno(err)
}
_, foundIno = r.parseEntry(buf)
if attr != nil {
encodedAttr, err = r.rdb.Get(ctx, r.inodeKey(foundIno)).Bytes()
}
......@@ -895,6 +917,8 @@ func (r *redisMeta) mknod(ctx Context, parent Ino, name string, _type uint8, mod
return err
} else if err == nil {
return syscall.EEXIST
} else if err == redis.Nil && r.conf.CaseInsensi && r.resolveCase(ctx, parent, name) != nil {
return syscall.EEXIST
}
now := time.Now()
......@@ -947,6 +971,13 @@ func (r *redisMeta) Create(ctx Context, parent Ino, name string, mode uint16, cu
func (r *redisMeta) Unlink(ctx Context, parent Ino, name string) syscall.Errno {
buf, err := r.rdb.HGet(ctx, r.entryKey(parent), name).Bytes()
if err == redis.Nil && r.conf.CaseInsensi {
if e := r.resolveCase(ctx, parent, name); e != nil {
name = string(e.Name)
buf = r.packEntry(e.Attr.Typ, e.Inode)
err = nil
}
}
if err != nil {
return errno(err)
}
......@@ -1037,6 +1068,13 @@ func (r *redisMeta) Rmdir(ctx Context, parent Ino, name string) syscall.Errno {
return syscall.ENOTEMPTY
}
buf, err := r.rdb.HGet(ctx, r.entryKey(parent), name).Bytes()
if err == redis.Nil && r.conf.CaseInsensi {
if e := r.resolveCase(ctx, parent, name); e != nil {
name = string(e.Name)
buf = r.packEntry(e.Attr.Typ, e.Inode)
err = nil
}
}
if err != nil {
return errno(err)
}
......@@ -1161,6 +1199,13 @@ func (r *redisMeta) Rmr(ctx Context, parent Ino, name string) syscall.Errno {
func (r *redisMeta) Rename(ctx Context, parentSrc Ino, nameSrc string, parentDst Ino, nameDst string, inode *Ino, attr *Attr) syscall.Errno {
buf, err := r.rdb.HGet(ctx, r.entryKey(parentSrc), nameSrc).Bytes()
if err == redis.Nil && r.conf.CaseInsensi {
if e := r.resolveCase(ctx, parentSrc, nameSrc); e != nil {
nameSrc = string(e.Name)
buf = r.packEntry(e.Attr.Typ, e.Inode)
err = nil
}
}
if err != nil {
return errno(err)
}
......@@ -1172,6 +1217,13 @@ func (r *redisMeta) Rename(ctx Context, parentSrc Ino, nameSrc string, parentDst
return 0
}
buf, err = r.rdb.HGet(ctx, r.entryKey(parentDst), nameDst).Bytes()
if err == redis.Nil && r.conf.CaseInsensi {
if e := r.resolveCase(ctx, parentDst, nameDst); e != nil {
nameDst = string(e.Name)
buf = r.packEntry(e.Attr.Typ, e.Inode)
err = nil
}
}
if err != nil && err != redis.Nil {
return errno(err)
}
......
......@@ -262,6 +262,38 @@ func TestRedisClient(t *testing.T) {
}
}
func TestCaseIncensi(t *testing.T) {
var conf = RedisConfig{CaseInsensi: true}
m, err := NewRedisMeta("redis://127.0.0.1:6379/6", &conf)
if err != nil {
t.Logf("redis is not available: %s", err)
t.Skip()
}
_ = m.Init(Format{Name: "test"}, true)
ctx := Background
var inode Ino
var attr = &Attr{}
_ = m.Create(ctx, 1, "foo", 0755, 0, &inode, attr)
if st := m.Create(ctx, 1, "Foo", 0755, 0, &inode, attr); st != syscall.EEXIST {
t.Fatalf("create should fail with EEXIST")
}
if st := m.Lookup(ctx, 1, "Foo", &inode, attr); st != 0 {
t.Fatalf("lookup Foo should be OK")
}
if st := m.Rename(ctx, 1, "Foo", 1, "bar", &inode, attr); st != 0 {
t.Fatalf("rename Foo to bar should be OK")
}
if st := m.Unlink(ctx, 1, "Bar"); st != 0 {
t.Fatalf("unlink Bar should be OK")
}
if st := m.Mkdir(ctx, 1, "Foo", 0755, 0, 0, &inode, attr); st != 0 {
t.Fatalf("mkdir Foo should be OK")
}
if st := m.Rmdir(ctx, 1, "foo"); st != 0 {
t.Fatalf("rmdir foo should be OK")
}
}
func TestCompaction(t *testing.T) {
var conf RedisConfig
m, err := NewRedisMeta("redis://127.0.0.1:6379/8", &conf)
......
......@@ -22,7 +22,6 @@ import (
"os"
"path"
"runtime"
"strings"
"sync"
"syscall"
"time"
......@@ -558,7 +557,7 @@ func (j *juice) Releasedir(path string, fh uint64) (e int) {
return
}
func Serve(conf *vfs.Config, fs_ *fs.FileSystem, fuseOpt string, fileCacheTo float64, asRoot bool, delayClose int) error {
func Serve(conf *vfs.Config, fs_ *fs.FileSystem, fuseOpt string, fileCacheTo float64, asRoot bool, delayClose int, caseInsensi bool) error {
var jfs juice
jfs.conf = conf
jfs.fs = fs_
......@@ -577,7 +576,7 @@ func Serve(conf *vfs.Config, fs_ *fs.FileSystem, fuseOpt string, fileCacheTo flo
if fuseOpt != "" {
options += "," + fuseOpt
}
host.SetCapCaseInsensitive(strings.Contains(conf.Mountpoint, ":"))
host.SetCapCaseInsensitive(caseInsensi)
host.SetCapReaddirPlus(true)
logger.Debugf("mount point: %s, options: %s", conf.Mountpoint, options)
_ = host.Mount(conf.Mountpoint, []string{"-o", options})
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册