Skip to content

Commit 8e9aa1e

Browse files
committed
ghost: fix lstree
lstree returns should include the root path.
1 parent 87c7766 commit 8e9aa1e

File tree

4 files changed

+70
-98
lines changed

4 files changed

+70
-98
lines changed

overlord/ghost.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ func (ghost *Ghost) handleFstatRequest(req *Request) error {
572572
result["is_dir"] = fileInfo.IsDir()
573573
result["perm"] = fileInfo.Mode().Perm()
574574
result["size"] = fileInfo.Size()
575-
result["mod_time"] = fileInfo.ModTime().Unix()
575+
result["mtime"] = fileInfo.ModTime().Unix()
576576
isSymlink := (fileInfo.Mode() & os.ModeSymlink) != 0
577577
result["is_symlink"] = isSymlink
578578

@@ -1492,20 +1492,12 @@ func (ghost *Ghost) ListTree(path string) ([]map[string]interface{}, error) {
14921492
return err
14931493
}
14941494

1495-
relPath, err := filepath.Rel(path, filePath)
1496-
if err != nil {
1497-
return err
1498-
}
1499-
if relPath == "." {
1500-
return nil
1501-
}
15021495
isSymlink := (info.Mode() & os.ModeSymlink) != 0
15031496
entry := map[string]interface{}{
1504-
"name": info.Name(),
15051497
"path": filePath,
15061498
"size": info.Size(),
15071499
"perm": info.Mode().Perm(),
1508-
"mod_time": info.ModTime().Unix(),
1500+
"mtime": info.ModTime().Unix(),
15091501
"is_dir": info.IsDir(),
15101502
"is_symlink": isSymlink,
15111503
}

py/ghost.py

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,26 @@ def timeout_handler(x):
847847
self._last_ping = self.Timestamp()
848848
self.SendRequest('ping', {}, timeout_handler, _PING_TIMEOUT)
849849

850+
def _Fstat(self, path):
851+
if not os.path.isabs(path):
852+
raise RuntimeError(f"absolute path required: {path}")
853+
854+
entry = {'exists': os.path.exists(path)}
855+
if entry['exists']:
856+
stat_info = os.lstat(path)
857+
entry['path'] = path
858+
entry['perm'] = stat_info.st_mode
859+
entry['size'] = stat_info.st_size
860+
entry['mtime'] = int(stat_info.st_mtime)
861+
entry['is_dir'] = os.path.isdir(path)
862+
entry['is_symlink'] = stat.S_ISLNK(stat_info.st_mode)
863+
864+
if entry['is_symlink']:
865+
entry['link_target'] = os.readlink(path)
866+
entry['is_dir'] = False
867+
868+
return entry
869+
850870
def HandleListTreeRequest(self, msg):
851871
"""Handle a request to list directory contents recursively."""
852872
payload = msg['payload']
@@ -862,46 +882,20 @@ def HandleListTreeRequest(self, msg):
862882
raise RuntimeError(f"No such file or directory: {path}")
863883

864884
entries = []
885+
entries.append(self._Fstat(path))
865886
for root, dirs, files in os.walk(path):
866887
for file in files:
867888
file_path = os.path.join(root, file)
868889
try:
869-
file_stat = os.lstat(file_path)
870-
entry = {
871-
'name': file,
872-
'path': file_path,
873-
'size': file_stat.st_size,
874-
'perm': file_stat.st_mode,
875-
'mtime': int(file_stat.st_mtime),
876-
'is_dir': False,
877-
'is_symlink': stat.S_ISLNK(file_stat.st_mode),
878-
}
879-
if entry['is_symlink']:
880-
entry['link_target'] = os.readlink(file_path)
881-
882-
entries.append(entry)
890+
entries.append(self._Fstat(file_path))
883891
except OSError as e:
884892
logging.exception(e)
885893
pass
886894

887895
for dir in dirs:
888896
dir_path = os.path.join(root, dir)
889897
try:
890-
dir_stat = os.lstat(dir_path)
891-
entry = {
892-
'name': dir,
893-
'path': dir_path,
894-
'size': dir_stat.st_size,
895-
'perm': dir_stat.st_mode,
896-
'mtime': int(dir_stat.st_mtime),
897-
'is_dir': True,
898-
'is_symlink': stat.S_ISLNK(dir_stat.st_mode),
899-
}
900-
if entry['is_symlink']:
901-
entry['is_dir'] = False
902-
entry['link_target'] = os.readlink(dir_path)
903-
904-
entries.append(entry)
898+
entries.append(self._Fstat(dir_path))
905899
except OSError:
906900
pass
907901

@@ -924,21 +918,7 @@ def HandleFstatRequest(self, msg):
924918
path = os.path.expanduser(path)
925919

926920
try:
927-
result = {'exists': os.path.exists(path)}
928-
929-
if result['exists']:
930-
stat_info = os.stat(path)
931-
result['is_dir'] = os.path.isdir(path)
932-
result['perm'] = stat_info.st_mode
933-
result['size'] = stat_info.st_size
934-
result['mod_time'] = int(stat_info.st_mtime)
935-
result['is_symlink'] = stat.S_ISLNK(stat_info.st_mode)
936-
937-
if result['is_symlink']:
938-
result['link_target'] = os.readlink(path)
939-
result['iis_dir'] = False
940-
941-
self.SendResponse(msg, SUCCESS, result)
921+
self.SendResponse(msg, SUCCESS, self._Fstat(path))
942922
except Exception as e:
943923
self.SendErrorResponse(msg, str(e))
944924

py/ovl.py

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
_CERT_DIR = os.path.expanduser('~/.config/ovl')
4343

4444
_DEBUG = False
45+
_DEBUG_NO_KILL = True
4546
_ESCAPE = '~'
4647
_BUFSIZ = 8192
4748
_DEFAULT_HTTPS_PORT = 443
@@ -746,6 +747,29 @@ def ParseMethodSubCommands(cls):
746747
return cls
747748

748749

750+
class FileEntry:
751+
"""Class to represent a file entry with its metadata."""
752+
753+
def __init__(self, path, perm=0o644, is_symlink=False, link_target='', is_dir=False):
754+
self.path = path
755+
self.perm = perm
756+
self.is_symlink = is_symlink
757+
self.link_target = link_target
758+
self.is_dir = is_dir
759+
760+
def __repr__(self):
761+
return f"{self.ftype} {self.path} {oct(self.perm)[2:]} {self.link_target}"
762+
763+
@property
764+
def name(self):
765+
return os.path.basename(self.path.rstrip('/'))
766+
767+
@property
768+
def ftype(self):
769+
if self.is_dir:
770+
return 'd'
771+
return 'l' if self.is_symlink else 'f'
772+
749773
@ParseMethodSubCommands
750774
class OverlordCliClient:
751775
"""Overlord command line interface client."""
@@ -912,7 +936,7 @@ def CheckDaemon(self):
912936
self._state = DaemonState.FromDict(self._server.State())
913937
sha1sum = GetVersionDigest()
914938

915-
if sha1sum != self._state.version_sha1sum:
939+
if sha1sum != self._state.version_sha1sum and not _DEBUG_NO_KILL:
916940
print('ovl server is out of date. killing...')
917941
KillGraceful(self._server.GetPid())
918942
self.StartServer()
@@ -1125,27 +1149,6 @@ def KillSSHTunnel(self):
11251149
if self._state.ssh_pid is not None:
11261150
KillGraceful(self._state.ssh_pid)
11271151

1128-
# FileEntry class to represent file entries
1129-
class FileEntry:
1130-
"""Class to represent a file entry with its metadata."""
1131-
1132-
def __init__(self, path, perm=0o644, is_symlink=False, link_target='', is_dir=False):
1133-
self.path = path
1134-
self.perm = perm
1135-
self.is_symlink = is_symlink
1136-
self.link_target = link_target
1137-
self.is_dir = is_dir
1138-
1139-
@property
1140-
def name(self):
1141-
return os.path.basename(self.path.rstrip('/'))
1142-
1143-
@property
1144-
def ftype(self):
1145-
if self.is_dir:
1146-
return 'd'
1147-
return 'l' if self.is_symlink else 'f'
1148-
11491152
def _SizeToHuman(self, size_in_bytes):
11501153
"""Convert size in bytes to human readable format.
11511154
@@ -1318,7 +1321,7 @@ def _LsTree(self, path):
13181321
is_symlink = entry.get('is_symlink', False)
13191322
link_target = entry.get('link_target', '')
13201323

1321-
entries.append(self.FileEntry(
1324+
entries.append(FileEntry(
13221325
path=file_path,
13231326
perm=perm,
13241327
is_symlink=is_symlink,
@@ -1710,7 +1713,7 @@ def _LocalLsTree(self, path):
17101713
is_symlink = os.path.islink(path)
17111714
link_target = os.readlink(path) if is_symlink else ''
17121715

1713-
return [self.FileEntry(
1716+
return [FileEntry(
17141717
path=path,
17151718
perm=perm,
17161719
is_symlink=is_symlink,
@@ -1728,7 +1731,7 @@ def _LocalLsTree(self, path):
17281731
is_symlink = os.path.islink(dir_path)
17291732
link_target = os.readlink(dir_path) if is_symlink else ''
17301733

1731-
results.append(self.FileEntry(
1734+
results.append(FileEntry(
17321735
path=dir_path,
17331736
perm=perm,
17341737
is_symlink=is_symlink,
@@ -1744,7 +1747,7 @@ def _LocalLsTree(self, path):
17441747
is_symlink = os.path.islink(file_path)
17451748
link_target = os.readlink(file_path) if is_symlink else ''
17461749

1747-
results.append(self.FileEntry(
1750+
results.append(FileEntry(
17481751
path=file_path,
17491752
perm=perm,
17501753
is_symlink=is_symlink,

py/ovl_unittest.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# Add scripts directory to Python path
1010
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
1111

12-
from ovl import OverlordCliClient
12+
from ovl import OverlordCliClient, FileEntry
1313

1414

1515
class FileSystemTestCase(unittest.TestCase):
@@ -60,15 +60,15 @@ def _build_file_entries(self, base_path, structure, path_prefix=""):
6060
abs_path = os.path.join(base_path, full_path)
6161

6262
if info["is_dir"]:
63-
entries.append(self.cli.FileEntry(path=abs_path, is_dir=True))
63+
entries.append(FileEntry(path=abs_path, is_dir=True))
6464
if "children" in info:
6565
entries.extend(
6666
self._build_file_entries(
6767
base_path, info["children"], full_path
6868
)
6969
)
7070
else:
71-
entries.append(self.cli.FileEntry(path=abs_path, is_dir=False))
71+
entries.append(FileEntry(path=abs_path, is_dir=False))
7272

7373
return entries
7474

@@ -124,28 +124,31 @@ def Fstat(self, path):
124124
if self.remote_exists and self.remote_is_dir:
125125
return {
126126
"exists": True,
127+
"path": path,
127128
"is_dir": True,
128129
"mode": 0o755,
129130
"size": 4096,
130-
"modTime": "2023-01-01T00:00:00Z",
131+
"mtime": "2023-01-01T00:00:00Z",
131132
}
132133
elif self.remote_exists and not self.remote_is_dir:
133134
return {
134135
"exists": True,
136+
"path": path,
135137
"is_dir": False,
136138
"mode": 0o644,
137139
"size": 1024,
138-
"modTime": "2023-01-01T00:00:00Z",
140+
"mtime": "2023-01-01T00:00:00Z",
139141
}
140142
else:
141143
return {"exists": False}
142144
elif path == os.path.join(self.user_home, "single_file"):
143145
return {
144146
"exists": True,
147+
"path": path,
145148
"is_dir": False,
146149
"mode": 0o644,
147150
"size": 1024,
148-
"modTime": "2023-01-01T00:00:00Z",
151+
"mtime": "2023-01-01T00:00:00Z",
149152
}
150153
return {"exists": False}
151154

@@ -443,42 +446,36 @@ def LsTree(self, path):
443446
path = os.path.join(self.remote_root, path)
444447

445448
if path == os.path.join(self.remote_root, "single_file"):
446-
return [self.cli.FileEntry(path=path, is_dir=False)]
449+
return [FileEntry(path=path, is_dir=False)]
447450
elif path == os.path.join(self.remote_root, "some_dir"):
448451
# Create a list to hold all entries
449452
entries = []
450453

451-
# Add the root directory entry
452-
entries.append(self.cli.FileEntry(path=path, is_dir=True))
454+
entries.append(FileEntry(path=path, is_dir=True))
453455

454-
# Add entry for a/b file
455456
entries.append(
456-
self.cli.FileEntry(
457+
FileEntry(
457458
path=os.path.join(path, "a/b"), is_dir=False
458459
)
459460
)
460461

461-
# Add entry for a directory
462462
entries.append(
463-
self.cli.FileEntry(
463+
FileEntry(
464464
path=os.path.join(path, "a"), is_dir=True
465465
)
466466
)
467467

468-
# Add entry for a/c directory
469468
entries.append(
470-
self.cli.FileEntry(
469+
FileEntry(
471470
path=os.path.join(path, "a/c"), is_dir=True
472471
)
473472
)
474473

475-
# Add entry for a/c/d file
476474
entries.append(
477-
self.cli.FileEntry(
475+
FileEntry(
478476
path=os.path.join(path, "a/c/d"), is_dir=False
479477
)
480478
)
481-
482479
return entries
483480
else:
484481
raise RuntimeError("ls: No such file or directory")

0 commit comments

Comments
 (0)