wip
This commit is contained in:
@@ -195,6 +195,111 @@ func (s *Store) DeleteCollection(user, collection string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// cleanupLegacy moves a user's data from the old flat layout (cal-*/card-* dirs
|
||||
// directly under user/root, and files/<username>) into the new structured col/
|
||||
// subdirectory layout (<user>/col/calendars/*, <user>/col/addressbooks/*,
|
||||
// <user>/col/files).
|
||||
func cleanupLegacy(dataDir, username string) error {
|
||||
username = filepath.Base(username) // sanitize path traversal
|
||||
userRoot := filepath.Join(dataDir, username)
|
||||
|
||||
// 1 - Move cal-*/card-* flat directories into col/calendars/ / col/addressbooks/
|
||||
entries, err := os.ReadDir(userRoot)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() || e.Name() == "col" {
|
||||
continue
|
||||
}
|
||||
name := e.Name()
|
||||
var dst string
|
||||
switch {
|
||||
case strings.HasPrefix(name, "cal-"):
|
||||
dst = filepath.Join(userRoot, "col", "calendars", strings.TrimPrefix(name, "cal-"))
|
||||
case strings.HasPrefix(name, "card-"):
|
||||
dst = filepath.Join(userRoot, "col", "addressbooks", strings.TrimPrefix(name, "card-"))
|
||||
default:
|
||||
continue
|
||||
}
|
||||
if _, err := os.Stat(dst); err == nil {
|
||||
continue // already migrated
|
||||
}
|
||||
os.MkdirAll(filepath.Dir(dst), 0o755)
|
||||
if err := os.Rename(filepath.Join(userRoot, name), dst); err != nil {
|
||||
return fmt.Errorf("moving %s to %q: %w", name, dst, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - Move files/<username>/* into <user>/col/files/
|
||||
oldFilesRoot := filepath.Join(dataDir, "files", username)
|
||||
if stat, err := os.Stat(oldFilesRoot); err == nil && stat.IsDir() {
|
||||
dstFiles := filepath.Join(userRoot, "col", "files")
|
||||
os.MkdirAll(dstFiles, 0o755)
|
||||
|
||||
subEntries, err := os.ReadDir(oldFilesRoot)
|
||||
if err == nil {
|
||||
for _, s := range subEntries {
|
||||
src := filepath.Join(oldFilesRoot, s.Name())
|
||||
dst := filepath.Join(dstFiles, s.Name())
|
||||
if s.IsDir() {
|
||||
os.MkdirAll(filepath.Dir(dst), 0o755)
|
||||
}
|
||||
os.Rename(src, dst)
|
||||
}
|
||||
}
|
||||
os.RemoveAll(oldFilesRoot)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MigrateDataDir iterates all user data directories under dataDir and calls
|
||||
// cleanupLegacy on each, handling both old flat-layout users (data/<username>/cal-*/...)
|
||||
// and old files-direct-layout users (data/files/<username>/).
|
||||
func MigrateDataDir(dataDir string) error {
|
||||
users, err := os.ReadDir(dataDir)
|
||||
if errors.Is(err, os.ErrNotExist) || len(users) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var dirs []string
|
||||
// Collect all directories under data/ (excluding "col" which is the new layout, and non-dirs like nidus.db)
|
||||
for _, e := range users {
|
||||
if !e.IsDir() {
|
||||
continue
|
||||
}
|
||||
name := e.Name()
|
||||
if name == "files" {
|
||||
// Collect all user dirs under data/files/ (legacy flat layout)
|
||||
fileUsers, err2 := os.ReadDir(filepath.Join(dataDir, "files"))
|
||||
if err2 == nil {
|
||||
for _, fu := range fileUsers {
|
||||
if fu.IsDir() {
|
||||
dirs = append(dirs, fu.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if name != "col" {
|
||||
dirs = append(dirs, name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, user := range dirs {
|
||||
if err := cleanupLegacy(dataDir, user); err != nil {
|
||||
return fmt.Errorf("migrating %q: %w", user, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sanitize removes path-traversal characters from a path segment.
|
||||
func sanitize(s string) string {
|
||||
s = filepath.Base(s)
|
||||
|
||||
Reference in New Issue
Block a user