Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sdk/python: fix rename hardlink #5573

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions .github/scripts/hypo/fs_sdk_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,14 @@ def test_issue_1424(self):
state.readline(file=v2, mode='r', offset=1708, user='root', whence=0)
state.teardown()

# def test_issue_1425(self):
# # SEE: https://github.com/juicedata/jfs/issues/1425
# state = JuicefsMachine()
# v1 = state.init_folders()
# v2 = state.create_file(content=b'a', file_name='a', parent=v1, umask=18, user='root')
# v3 = state.mkdir(mode=0, parent=v1, subdir='b', umask=18, user='root')
# state.rename_dir(entry=v3, new_entry_name=v2, parent=v1, umask=18, user='root')
# state.teardown()
def test_issue_1425(self):
# SEE: https://github.com/juicedata/jfs/issues/1425
state = JuicefsMachine()
v1 = state.init_folders()
v2 = state.create_file(content=b'a', file_name='a', parent=v1, umask=18, user='root')
v3 = state.mkdir(mode=0, parent=v1, subdir='b', umask=18, user='root')
state.rename_dir(entry=v3, new_entry_name=v2, parent=v1, umask=18, user='root')
state.teardown()

def test_issue_1442(self):
# SEE: https://github.com/juicedata/jfs/issues/1442
Expand All @@ -149,14 +149,14 @@ def test_issue_1442(self):
state.set_xattr(file=v2, flag=0, name='user.0', user='root', value=b'\x01\x01\x00\x01')
state.teardown()

# def test_issue_1443(self):
# # SEE: https://github.com/juicedata/jfs/issues/1443
# state = JuicefsMachine()
# v1 = state.init_folders()
# v2 = state.create_file(content=b'bcb', file_name='bcba', parent=v1, umask=18, user='root')
# v3 = state.hardlink(src_file=v2, link_file_name='a', parent=v1, umask=18, user='root')
# state.rename_file(entry=v2, new_entry_name=v3, parent=v1, umask=18, user='root')
# state.teardown()
def test_issue_1443(self):
# SEE: https://github.com/juicedata/jfs/issues/1443
state = JuicefsMachine()
v1 = state.init_folders()
v2 = state.create_file(content=b'bcb', file_name='bcba', parent=v1, umask=18, user='root')
v3 = state.hardlink(src_file=v2, link_file_name='a', parent=v1, umask=18, user='root')
state.rename_file(entry=v2, new_entry_name=v3, parent=v1, umask=18, user='root')
state.teardown()

def test_issue_1449(self):
# SEE: https://github.com/juicedata/jfs/issues/1449
Expand Down
10 changes: 10 additions & 0 deletions pkg/meta/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,16 @@ func (m *redisMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentD
if err := tx.Watch(ctx, keys...).Err(); err != nil {
return err
}
if dino > 0 {
if ino == dino {
return errno(nil)
}
if typ == TypeDirectory && dtyp != TypeDirectory {
return syscall.ENOTDIR
} else if typ != TypeDirectory && dtyp == TypeDirectory {
return syscall.EISDIR
}
}

keys = []string{m.inodeKey(parentSrc), m.inodeKey(parentDst), m.inodeKey(ino)}
if dino > 0 {
Expand Down
75 changes: 40 additions & 35 deletions pkg/meta/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,8 @@ func retriveUrlConnsOptions(murl string) (string, int, int, int, int) {

var vOpenConns int = 0
var vIdleConns int = runtime.GOMAXPROCS(-1) * 2
var vIdleTime int = 300
var vLifeTime int = 0
var vIdleTime int = 300
var vLifeTime int = 0

if optIndex != -1 {
baseurl := murl[:optIndex]
Expand All @@ -307,11 +307,11 @@ func retriveUrlConnsOptions(murl string) (string, int, int, int, int) {
}
if vals.Has("max_idle_time") {
vIdleTime, _ = strconv.Atoi(vals.Get("max_idle_time"))
vals.Del("max_idle_time");
vals.Del("max_idle_time")
}
if vals.Has("max_life_time") {
vLifeTime, _ = strconv.Atoi(vals.Get("max_life_time"))
vals.Del("max_life_time");
vals.Del("max_life_time")
}
optsurl = vals.Encode()
}
Expand Down Expand Up @@ -1245,17 +1245,17 @@ func (m *dbMeta) upsertSlice(s *xorm.Session, inode Ino, indx uint32, buf []byte
driver := m.Name()
if driver == "sqlite3" || driver == "postgres" {
_, err = s.Exec(`
INSERT INTO jfs_chunk (inode, indx, slices)
VALUES (?, ?, ?)
ON CONFLICT (inode, indx)
DO UPDATE SET slices=jfs_chunk.slices || ?`, inode, indx, buf, buf)
INSERT INTO jfs_chunk (inode, indx, slices)
VALUES (?, ?, ?)
ON CONFLICT (inode, indx)
DO UPDATE SET slices=jfs_chunk.slices || ?`, inode, indx, buf, buf)
} else {
var r sql.Result
r, err = s.Exec(`
INSERT INTO jfs_chunk (inode, indx, slices)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE
slices=concat(slices, ?)`, inode, indx, buf, buf)
INSERT INTO jfs_chunk (inode, indx, slices)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE
slices=concat(slices, ?)`, inode, indx, buf, buf)
n, _ := r.RowsAffected()
*insert = n == 1 // https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
}
Expand Down Expand Up @@ -2052,31 +2052,36 @@ func (m *dbMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentDst
dn.Parent = parentSrc
}
}
} else if de.Inode == se.Inode {
return nil
} else if se.Type == TypeDirectory && de.Type != TypeDirectory {
return syscall.ENOTDIR
} else if de.Type == TypeDirectory {
if se.Type != TypeDirectory {
return syscall.EISDIR
}
exist, err := s.Exist(&edge{Parent: de.Inode})
if err != nil {
return err
}
if exist {
return syscall.ENOTEMPTY
}
dpn.Nlink--
dstnlink--
dupdate = true
if trash > 0 {
dn.Parent = trash
}
} else {
if de.Type == TypeDirectory {
exist, err := s.Exist(&edge{Parent: de.Inode})
if err != nil {
return err
}
if exist {
return syscall.ENOTEMPTY
}
dpn.Nlink--
dstnlink--
dupdate = true
if trash > 0 {
dn.Parent = trash
}
} else {
if trash == 0 {
dn.Nlink--
if de.Type == TypeFile && dn.Nlink == 0 {
opened = m.of.IsOpen(dn.Inode)
}
defer func() { m.of.InvalidateChunk(dino, invalidateAttrOnly) }()
} else if dn.Parent > 0 {
dn.Parent = trash
if trash == 0 {
dn.Nlink--
if de.Type == TypeFile && dn.Nlink == 0 {
opened = m.of.IsOpen(dn.Inode)
}
defer func() { m.of.InvalidateChunk(dino, invalidateAttrOnly) }()
} else if dn.Parent > 0 {
dn.Parent = trash
}
}
if ctx.Uid() != 0 && dpn.Mode&01000 != 0 && ctx.Uid() != dpn.Uid && ctx.Uid() != dn.Uid {
Expand Down
6 changes: 6 additions & 0 deletions pkg/meta/tkv.go
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,12 @@ func (m *kvMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentDst
tattr.Parent = parentSrc
}
}
} else if dino == ino {
return nil
} else if typ == TypeDirectory && dtyp != TypeDirectory {
return syscall.ENOTDIR
} else if typ != TypeDirectory && dtyp == TypeDirectory {
return syscall.EISDIR
} else {
if dtyp == TypeDirectory {
if tx.exist(m.entryKey(dino, "")) {
Expand Down
7 changes: 6 additions & 1 deletion sdk/java/libjfs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -870,11 +870,16 @@ func jfs_rmr(pid int64, h int64, cpath *C.char) int32 {

//export jfs_rename
func jfs_rename(pid int64, h int64, oldpath *C.char, newpath *C.char) int32 {
return jfs_rename0(pid, h, oldpath, newpath, meta.RenameNoReplace)
}

//export jfs_rename0
func jfs_rename0(pid int64, h int64, oldpath *C.char, newpath *C.char, flags uint32) int32 {
w := F(h)
if w == nil {
return EINVAL
}
return errno(w.Rename(w.withPid(pid), C.GoString(oldpath), C.GoString(newpath), meta.RenameNoReplace))
return errno(w.Rename(w.withPid(pid), C.GoString(oldpath), C.GoString(newpath), flags))
}

//export jfs_truncate
Expand Down
2 changes: 1 addition & 1 deletion sdk/python/juicefs/juicefs/juicefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def rmdir(self, path):

def rename(self, old, new):
"""Rename the file or directory old to new."""
self.lib.jfs_rename(c_int64(_tid()), c_int64(self.h), _bin(old), _bin(new), c_uint32(0))
self.lib.jfs_rename0(c_int64(_tid()), c_int64(self.h), _bin(old), _bin(new), c_uint32(0))

def listdir(self, path, detail=False):
"""Return a list containing the names of the entries in the directory given by path."""
Expand Down
Loading