or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authorizers.mdfilesystems.mdhandlers.mdindex.mdioloop.mdservers.mdutilities.md

filesystems.mddocs/

0

# File System Interface

1

2

Cross-platform filesystem abstraction providing virtualized access to local and remote filesystems with security controls. pyftpdlib's filesystem interface enables secure, chrooted access to directories while maintaining compatibility across different operating systems and filesystem types.

3

4

## Capabilities

5

6

### Abstracted File System

7

8

Main filesystem interface providing cross-platform file operations with virtual chroot functionality and security controls.

9

10

```python { .api }

11

class AbstractedFS:

12

def __init__(self, root, cmd_channel):

13

"""

14

Initialize filesystem interface.

15

16

Parameters:

17

- root: root directory path (user's home directory)

18

- cmd_channel: associated FTPHandler instance

19

"""

20

21

# Properties

22

@property

23

def root(self):

24

"""Get root directory path."""

25

26

@property

27

def cwd(self):

28

"""Get current working directory (relative to root)."""

29

30

# Path manipulation methods

31

def ftpnorm(self, ftppath):

32

"""

33

Normalize FTP path by resolving . and .. components.

34

35

Parameters:

36

- ftppath: FTP path string

37

38

Returns:

39

- Normalized FTP path

40

"""

41

42

def ftp2fs(self, ftppath):

43

"""

44

Convert FTP path to filesystem path.

45

46

Parameters:

47

- ftppath: FTP path (relative to user root)

48

49

Returns:

50

- Absolute filesystem path

51

"""

52

53

def fs2ftp(self, fspath):

54

"""

55

Convert filesystem path to FTP path.

56

57

Parameters:

58

- fspath: absolute filesystem path

59

60

Returns:

61

- FTP path relative to user root

62

"""

63

64

def validpath(self, path):

65

"""

66

Check if path is within user's accessible area.

67

68

Parameters:

69

- path: filesystem path to validate

70

71

Returns:

72

- True if path is valid and accessible

73

"""

74

75

# File operations

76

def open(self, filename, mode):

77

"""

78

Open file for reading or writing.

79

80

Parameters:

81

- filename: file path

82

- mode: file open mode ('r', 'w', 'a', 'rb', 'wb', etc.)

83

84

Returns:

85

- File object

86

"""

87

88

def mkstemp(self, suffix='', prefix='', dir=None, mode='wb'):

89

"""

90

Create temporary file.

91

92

Parameters:

93

- suffix: filename suffix

94

- prefix: filename prefix

95

- dir: directory for temp file (None = current directory)

96

- mode: file open mode

97

98

Returns:

99

- (fd, path) tuple of file descriptor and path

100

"""

101

102

def remove(self, path):

103

"""

104

Delete file.

105

106

Parameters:

107

- path: file path to delete

108

"""

109

110

def rename(self, src, dst):

111

"""

112

Rename/move file or directory.

113

114

Parameters:

115

- src: source path

116

- dst: destination path

117

"""

118

119

def chmod(self, path, mode):

120

"""

121

Change file/directory permissions.

122

123

Parameters:

124

- path: file/directory path

125

- mode: permission mode (octal integer)

126

"""

127

128

def stat(self, path):

129

"""

130

Get file/directory status information.

131

132

Parameters:

133

- path: file/directory path

134

135

Returns:

136

- os.stat_result object

137

"""

138

139

def lstat(self, path):

140

"""

141

Get file/directory status (don't follow symlinks).

142

143

Parameters:

144

- path: file/directory path

145

146

Returns:

147

- os.stat_result object

148

"""

149

150

def utime(self, path, timeval):

151

"""

152

Set file access and modification times.

153

154

Parameters:

155

- path: file path

156

- timeval: (atime, mtime) tuple or None for current time

157

"""

158

159

def readlink(self, path):

160

"""

161

Read symbolic link target.

162

163

Parameters:

164

- path: symlink path

165

166

Returns:

167

- Target path string

168

"""

169

170

# Directory operations

171

def chdir(self, path):

172

"""

173

Change current working directory.

174

175

Parameters:

176

- path: directory path (relative to root)

177

"""

178

179

def mkdir(self, path):

180

"""

181

Create directory.

182

183

Parameters:

184

- path: directory path to create

185

"""

186

187

def rmdir(self, path):

188

"""

189

Remove empty directory.

190

191

Parameters:

192

- path: directory path to remove

193

"""

194

195

def listdir(self, path):

196

"""

197

List directory contents.

198

199

Parameters:

200

- path: directory path

201

202

Returns:

203

- List of filenames

204

"""

205

206

def listdirinfo(self, path):

207

"""

208

List directory with file information.

209

210

Parameters:

211

- path: directory path

212

213

Returns:

214

- List of (filename, stat_result) tuples

215

"""

216

217

# File system queries

218

def isfile(self, path):

219

"""Check if path is a regular file."""

220

221

def isdir(self, path):

222

"""Check if path is a directory."""

223

224

def islink(self, path):

225

"""Check if path is a symbolic link."""

226

227

def getsize(self, path):

228

"""Get file size in bytes."""

229

230

def getmtime(self, path):

231

"""Get file modification time as timestamp."""

232

233

def realpath(self, path):

234

"""Get canonical path resolving all symlinks."""

235

236

def lexists(self, path):

237

"""Check if path exists (don't follow symlinks)."""

238

239

# User/group resolution

240

def get_user_by_uid(self, uid):

241

"""

242

Get username from UID.

243

244

Parameters:

245

- uid: user ID number

246

247

Returns:

248

- Username string or UID if not found

249

"""

250

251

def get_group_by_gid(self, gid):

252

"""

253

Get group name from GID.

254

255

Parameters:

256

- gid: group ID number

257

258

Returns:

259

- Group name string or GID if not found

260

"""

261

262

# Directory listing formatters

263

def format_list(self, basedir, listing, ignore_err=True):

264

"""

265

Format directory listing in Unix ls -l style.

266

267

Parameters:

268

- basedir: directory being listed

269

- listing: list of (filename, stat_result) tuples

270

- ignore_err: ignore files that cause stat errors

271

272

Returns:

273

- Iterator of formatted listing lines

274

"""

275

276

def format_mlsx(self, basedir, listing, perms, facts, ignore_err=True):

277

"""

278

Format directory listing in machine-readable MLSD format.

279

280

Parameters:

281

- basedir: directory being listed

282

- listing: list of (filename, stat_result) tuples

283

- perms: permission string for current user

284

- facts: requested fact names

285

- ignore_err: ignore files that cause stat errors

286

287

Returns:

288

- Iterator of formatted MLSD lines

289

"""

290

```

291

292

### Unix File System

293

294

Direct filesystem access without chroot restrictions, suitable for system-level FTP services on POSIX systems.

295

296

```python { .api }

297

class UnixFilesystem(AbstractedFS): # POSIX only

298

def __init__(self, root, cmd_channel):

299

"""

300

Initialize Unix filesystem with direct access.

301

302

Parameters:

303

- root: root directory (not enforced as chroot)

304

- cmd_channel: associated FTPHandler instance

305

"""

306

307

def ftp2fs(self, ftppath):

308

"""

309

Convert FTP path directly to filesystem path.

310

No chroot restrictions applied.

311

"""

312

313

def fs2ftp(self, fspath):

314

"""Convert filesystem path directly to FTP path."""

315

316

def validpath(self, path):

317

"""Always returns True - no path restrictions."""

318

```

319

320

## Exception Classes

321

322

```python { .api }

323

class FilesystemError(Exception):

324

"""Custom exception for filesystem-related errors."""

325

```

326

327

## Utility Functions

328

329

```python { .api }

330

def _memoize(fun):

331

"""

332

Memoization decorator for expensive operations like user/group lookups.

333

Caches function results to improve performance.

334

"""

335

```

336

337

## Usage Examples

338

339

### Basic Virtual Filesystem

340

341

```python

342

from pyftpdlib.filesystems import AbstractedFS

343

344

# Create filesystem rooted at user's home directory

345

fs = AbstractedFS("/home/user", cmd_channel)

346

347

# Path operations

348

print(fs.cwd) # Current directory relative to root

349

fs.chdir("documents") # Change to documents subdirectory

350

real_path = fs.ftp2fs("file.txt") # Convert to actual filesystem path

351

352

# File operations

353

with fs.open("readme.txt", "r") as f:

354

content = f.read()

355

356

fs.mkdir("new_folder")

357

fs.remove("old_file.txt")

358

fs.rename("old_name.txt", "new_name.txt")

359

```

360

361

### Directory Listing

362

363

```python

364

# Get directory contents

365

files = fs.listdir(".")

366

print(files) # ['file1.txt', 'file2.txt', 'subfolder']

367

368

# Get detailed file information

369

detailed = fs.listdirinfo(".")

370

for filename, stat_info in detailed:

371

print(f"{filename}: {stat_info.st_size} bytes")

372

373

# Format as Unix ls -l listing

374

listing = fs.format_list(".", detailed)

375

for line in listing:

376

print(line)

377

# Output: -rw-r--r-- 1 user group 1024 Jan 01 12:00 file1.txt

378

```

379

380

### File Information

381

382

```python

383

# Check file types

384

if fs.isfile("document.pdf"):

385

size = fs.getsize("document.pdf")

386

mtime = fs.getmtime("document.pdf")

387

print(f"File size: {size} bytes, modified: {mtime}")

388

389

if fs.isdir("folder"):

390

print("It's a directory")

391

392

if fs.islink("symlink"):

393

target = fs.readlink("symlink")

394

print(f"Symlink points to: {target}")

395

```

396

397

### Custom Filesystem

398

399

```python

400

class RestrictedFS(AbstractedFS):

401

def validpath(self, path):

402

"""Block access to hidden files and system directories."""

403

if not super().validpath(path):

404

return False

405

406

# Block hidden files

407

if "/.'" in path or path.startswith("."):

408

return False

409

410

# Block system directories

411

restricted = ["/etc", "/proc", "/sys", "/dev"]

412

for restricted_path in restricted:

413

if path.startswith(restricted_path):

414

return False

415

416

return True

417

418

def listdir(self, path):

419

"""Filter out hidden files from listings."""

420

files = super().listdir(path)

421

return [f for f in files if not f.startswith(".")]

422

423

# Use custom filesystem

424

class CustomFTPHandler(FTPHandler):

425

abstracted_fs = RestrictedFS

426

427

handler = CustomFTPHandler

428

handler.authorizer = authorizer

429

```

430

431

### Unix Direct Access

432

433

```python

434

from pyftpdlib.filesystems import UnixFilesystem

435

436

# Create filesystem with direct access (no chroot)

437

class SystemFTPHandler(FTPHandler):

438

abstracted_fs = UnixFilesystem

439

440

# WARNING: This allows access to entire filesystem

441

# Only use with trusted users and proper authorizer restrictions

442

handler = SystemFTPHandler

443

handler.authorizer = unix_authorizer # Should use UnixAuthorizer

444

```

445

446

### Integration with FTP Handler

447

448

```python

449

from pyftpdlib.handlers import FTPHandler

450

451

class CustomFTPHandler(FTPHandler):

452

# Use custom filesystem

453

abstracted_fs = RestrictedFS

454

455

def run_as_current_user(self, function, *args, **kwargs):

456

"""Execute filesystem operations with proper user context."""

457

return function(*args, **kwargs)

458

459

# Configure handler

460

handler = CustomFTPHandler

461

handler.authorizer = authorizer

462

```

463

464

### Permission Management

465

466

```python

467

# Set file permissions (Unix/Linux)

468

fs.chmod("script.sh", 0o755) # rwxr-xr-x

469

470

# Set file modification time

471

import time

472

current_time = time.time()

473

fs.utime("file.txt", (current_time, current_time))

474

475

# User/group lookup

476

uid = 1000

477

username = fs.get_user_by_uid(uid)

478

print(f"UID {uid} belongs to user: {username}")

479

```

480

481

## Security Considerations

482

483

- **AbstractedFS**: Provides chroot-like security by restricting access to files outside the root directory

484

- **UnixFilesystem**: Allows full filesystem access - use only with proper authentication and authorization

485

- **Path Validation**: Always validate paths with `validpath()` before file operations

486

- **Symbolic Links**: Be careful with symlinks that might point outside the chroot area

487

488

## Platform Support

489

490

- **AbstractedFS**: Cross-platform (Windows, Linux, macOS, etc.)

491

- **UnixFilesystem**: POSIX systems only (Linux, macOS, BSD, etc.)

492

- **Symlink Support**: Available on platforms that support symbolic links