or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

directory-operations.mdfile-descriptors.mdfile-operations.mdfile-watching.mdindex.mdstats-permissions.mdstreams.mdsymbolic-links.md

stats-permissions.mddocs/

0

# Stats and Permissions

1

2

File statistics, permission checking, and metadata operations with full compatibility for Node.js Stats objects. Provides comprehensive file system metadata access and permission management.

3

4

## Capabilities

5

6

### File Statistics

7

8

Get detailed information about files and directories including size, permissions, and timestamps.

9

10

```javascript { .api }

11

/**

12

* Synchronously get file statistics (follows symbolic links)

13

* @param path - File or directory path

14

* @returns Stats object with file information

15

*/

16

statSync(path: string | Buffer): Stats;

17

18

/**

19

* Synchronously get file statistics (does not follow symbolic links)

20

* @param path - File or directory path

21

* @returns Stats object (for symlinks, returns symlink stats not target stats)

22

*/

23

lstatSync(path: string | Buffer): Stats;

24

25

/**

26

* Asynchronously get file statistics (follows symbolic links)

27

* @param path - File or directory path

28

* @param callback - Completion callback with stats

29

*/

30

stat(path: string | Buffer, callback: (err?: Error, stats?: Stats) => void): void;

31

32

/**

33

* Asynchronously get file statistics (does not follow symbolic links)

34

* @param path - File or directory path

35

* @param callback - Completion callback with stats

36

*/

37

lstat(path: string | Buffer, callback: (err?: Error, stats?: Stats) => void): void;

38

39

interface Stats {

40

/** File size in bytes */

41

size: number;

42

/** File mode (permissions and type) */

43

mode: number;

44

/** User ID of file owner */

45

uid: number;

46

/** Group ID of file owner */

47

gid: number;

48

/** Device ID */

49

dev: number;

50

/** Inode number */

51

ino: number;

52

/** Number of hard links */

53

nlink: number;

54

/** Device ID (for special files) */

55

rdev: number;

56

/** Block size for I/O operations */

57

blksize: number;

58

/** Number of 512-byte blocks allocated */

59

blocks: number;

60

61

// Timestamps

62

/** Access time in milliseconds */

63

atimeMs: number;

64

/** Modification time in milliseconds */

65

mtimeMs: number;

66

/** Status change time in milliseconds */

67

ctimeMs: number;

68

/** Birth time in milliseconds */

69

birthtimeMs: number;

70

71

/** Access time as Date object */

72

atime: Date;

73

/** Modification time as Date object */

74

mtime: Date;

75

/** Status change time as Date object */

76

ctime: Date;

77

/** Birth time as Date object */

78

birthtime: Date;

79

80

// Type checking methods

81

/** Check if this is a regular file */

82

isFile(): boolean;

83

/** Check if this is a directory */

84

isDirectory(): boolean;

85

/** Check if this is a symbolic link (lstat only) */

86

isSymbolicLink(): boolean;

87

/** Check if this is a block device */

88

isBlockDevice(): boolean;

89

/** Check if this is a character device */

90

isCharacterDevice(): boolean;

91

/** Check if this is a FIFO pipe */

92

isFIFO(): boolean;

93

/** Check if this is a socket */

94

isSocket(): boolean;

95

}

96

```

97

98

**Usage Examples:**

99

100

```javascript

101

// Get file statistics

102

const stats = fs.statSync('/document.txt');

103

console.log('File size:', stats.size, 'bytes');

104

console.log('Is file:', stats.isFile());

105

console.log('Is directory:', stats.isDirectory());

106

console.log('Last modified:', stats.mtime);

107

console.log('File mode:', stats.mode.toString(8)); // Octal representation

108

109

// Check file type

110

if (stats.isFile()) {

111

console.log('This is a regular file');

112

} else if (stats.isDirectory()) {

113

console.log('This is a directory');

114

}

115

116

// Compare stat vs lstat for symlinks

117

fs.symlinkSync('/target.txt', '/link.txt');

118

const fileStats = fs.statSync('/link.txt'); // Stats of target file

119

const linkStats = fs.lstatSync('/link.txt'); // Stats of symlink itself

120

121

console.log('Target file size:', fileStats.size);

122

console.log('Link target path length:', linkStats.size);

123

console.log('Is target file:', fileStats.isFile()); // true

124

console.log('Is link symbolic:', linkStats.isSymbolicLink()); // true

125

126

// Async stats

127

fs.stat('/async-file.txt', (err, stats) => {

128

if (!err) {

129

console.log('File info:', {

130

size: stats.size,

131

modified: stats.mtime,

132

isFile: stats.isFile()

133

});

134

}

135

});

136

137

// Promise-based stats

138

const stats = await fs.promises.stat('/promise-file.txt');

139

console.log('File size:', stats.size);

140

```

141

142

### Permission Management

143

144

Change file and directory permissions with support for both numeric and symbolic modes.

145

146

```javascript { .api }

147

/**

148

* Synchronously change file permissions (follows symbolic links)

149

* @param path - File or directory path

150

* @param mode - New file mode (permissions)

151

*/

152

chmodSync(path: string | Buffer, mode: number | string): void;

153

154

/**

155

* Synchronously change file permissions (does not follow symbolic links)

156

* @param path - File or directory path

157

* @param mode - New file mode (permissions)

158

*/

159

lchmodSync(path: string | Buffer, mode: number | string): void;

160

161

/**

162

* Asynchronously change file permissions (follows symbolic links)

163

* @param path - File or directory path

164

* @param mode - New file mode (permissions)

165

* @param callback - Completion callback

166

*/

167

chmod(path: string | Buffer, mode: number | string, callback?: (err?: Error) => void): void;

168

169

/**

170

* Asynchronously change file permissions (does not follow symbolic links)

171

* @param path - File or directory path

172

* @param mode - New file mode (permissions)

173

* @param callback - Completion callback

174

*/

175

lchmod(path: string | Buffer, mode: number | string, callback?: (err?: Error) => void): void;

176

```

177

178

**Permission Modes:**

179

- Numeric: `0o755`, `0o644`, `0o600` (octal notation)

180

- String: `"755"`, `"644"`, `"600"` (octal string)

181

- Common patterns:

182

- `0o755` - rwxr-xr-x (executable file)

183

- `0o644` - rw-r--r-- (regular file)

184

- `0o600` - rw------- (private file)

185

- `0o777` - rwxrwxrwx (fully accessible)

186

187

**Usage Examples:**

188

189

```javascript

190

// Set file permissions using numeric mode

191

fs.chmodSync('/script.sh', 0o755); // Make executable

192

fs.chmodSync('/config.json', 0o644); // Read-write for owner, read-only for others

193

fs.chmodSync('/private.key', 0o600); // Owner only

194

195

// Set permissions using string mode

196

fs.chmodSync('/public.txt', '644');

197

fs.chmodSync('/secure.txt', '600');

198

199

// Change directory permissions

200

fs.chmodSync('/uploads', 0o755); // Directory with execute permission

201

202

// Use lchmod for symbolic links (change link permissions, not target)

203

fs.symlinkSync('/target.txt', '/link.txt');

204

fs.lchmodSync('/link.txt', 0o644); // Change link permissions only

205

206

// Async permission changes

207

fs.chmod('/async-file.txt', 0o755, (err) => {

208

if (!err) {

209

console.log('Permissions changed successfully');

210

}

211

});

212

213

// Promise-based permission changes

214

await fs.promises.chmod('/promise-file.txt', 0o644);

215

216

// Check permissions after changing

217

const stats = fs.statSync('/script.sh');

218

console.log('File mode:', (stats.mode & 0o777).toString(8)); // Get permission bits

219

```

220

221

### File Renaming and Moving

222

223

Rename or move files and directories within the filesystem.

224

225

```javascript { .api }

226

/**

227

* Synchronously rename/move a file or directory

228

* @param oldPath - Current path

229

* @param newPath - New path

230

*/

231

renameSync(oldPath: string | Buffer, newPath: string | Buffer): void;

232

233

/**

234

* Asynchronously rename/move a file or directory

235

* @param oldPath - Current path

236

* @param newPath - New path

237

* @param callback - Completion callback

238

*/

239

rename(oldPath: string | Buffer, newPath: string | Buffer, callback?: (err?: Error) => void): void;

240

```

241

242

**Usage Examples:**

243

244

```javascript

245

// Rename a file

246

fs.writeFileSync('/old-name.txt', 'content');

247

fs.renameSync('/old-name.txt', '/new-name.txt');

248

249

// Move file to different directory

250

fs.mkdirSync('/archive');

251

fs.renameSync('/document.txt', '/archive/document.txt');

252

253

// Rename directory

254

fs.mkdirSync('/old-folder');

255

fs.renameSync('/old-folder', '/new-folder');

256

257

// Move and rename simultaneously

258

fs.renameSync('/src/temp.js', '/build/compiled.js');

259

260

// Async rename

261

fs.rename('/temp.txt', '/permanent.txt', (err) => {

262

if (!err) {

263

console.log('File renamed successfully');

264

}

265

});

266

267

// Promise-based rename

268

await fs.promises.rename('/source.txt', '/destination.txt');

269

270

// Safe rename with existence check

271

function safeRename(oldPath, newPath) {

272

if (!fs.existsSync(oldPath)) {

273

throw new Error(`Source file does not exist: ${oldPath}`);

274

}

275

276

if (fs.existsSync(newPath)) {

277

throw new Error(`Destination already exists: ${newPath}`);

278

}

279

280

fs.renameSync(oldPath, newPath);

281

}

282

```

283

284

### Permission Constants and Checking

285

286

Work with file permission constants and check specific permissions.

287

288

```javascript { .api }

289

// File mode constants (available via fs.constants)

290

interface FileConstants {

291

// File type constants

292

S_IFMT: number; // File type mask

293

S_IFREG: number; // Regular file

294

S_IFDIR: number; // Directory

295

S_IFLNK: number; // Symbolic link

296

S_IFCHR: number; // Character device

297

S_IFBLK: number; // Block device

298

S_IFIFO: number; // FIFO pipe

299

S_IFSOCK: number; // Socket

300

301

// Permission constants

302

S_IRWXU: number; // User read, write, execute (0o700)

303

S_IRUSR: number; // User read (0o400)

304

S_IWUSR: number; // User write (0o200)

305

S_IXUSR: number; // User execute (0o100)

306

307

S_IRWXG: number; // Group read, write, execute (0o070)

308

S_IRGRP: number; // Group read (0o040)

309

S_IWGRP: number; // Group write (0o020)

310

S_IXGRP: number; // Group execute (0o010)

311

312

S_IRWXO: number; // Other read, write, execute (0o007)

313

S_IROTH: number; // Other read (0o004)

314

S_IWOTH: number; // Other write (0o002)

315

S_IXOTH: number; // Other execute (0o001)

316

}

317

```

318

319

**Usage Examples:**

320

321

```javascript

322

// Check specific permissions using constants

323

const stats = fs.statSync('/file.txt');

324

const mode = stats.mode;

325

326

// Check if user can read

327

if (mode & fs.constants.S_IRUSR) {

328

console.log('User can read');

329

}

330

331

// Check if group can write

332

if (mode & fs.constants.S_IWGRP) {

333

console.log('Group can write');

334

}

335

336

// Check if others can execute

337

if (mode & fs.constants.S_IXOTH) {

338

console.log('Others can execute');

339

}

340

341

// Extract permission bits

342

const permissions = mode & 0o777;

343

console.log('Permissions:', permissions.toString(8));

344

345

// Check file type using constants

346

const fileType = mode & fs.constants.S_IFMT;

347

if (fileType === fs.constants.S_IFREG) {

348

console.log('Regular file');

349

} else if (fileType === fs.constants.S_IFDIR) {

350

console.log('Directory');

351

} else if (fileType === fs.constants.S_IFLNK) {

352

console.log('Symbolic link');

353

}

354

355

// Permission checker utility

356

function checkPermissions(path) {

357

const stats = fs.statSync(path);

358

const mode = stats.mode;

359

360

return {

361

isReadable: !!(mode & fs.constants.S_IRUSR),

362

isWritable: !!(mode & fs.constants.S_IWUSR),

363

isExecutable: !!(mode & fs.constants.S_IXUSR),

364

permissions: (mode & 0o777).toString(8),

365

type: stats.isFile() ? 'file' :

366

stats.isDirectory() ? 'directory' :

367

stats.isSymbolicLink() ? 'symlink' : 'other'

368

};

369

}

370

371

const info = checkPermissions('/script.sh');

372

console.log('File info:', info);

373

```

374

375

### Advanced Statistics Operations

376

377

Advanced patterns for working with file statistics and metadata.

378

379

```javascript

380

// Compare file timestamps

381

function compareFiles(path1, path2) {

382

const stats1 = fs.statSync(path1);

383

const stats2 = fs.statSync(path2);

384

385

return {

386

newerFile: stats1.mtime > stats2.mtime ? path1 : path2,

387

sizeDifference: stats1.size - stats2.size,

388

sameSize: stats1.size === stats2.size,

389

sameMtime: stats1.mtime.getTime() === stats2.mtime.getTime()

390

};

391

}

392

393

// Find files by size

394

function findFilesBySize(directory, minSize, maxSize) {

395

const files = [];

396

const entries = fs.readdirSync(directory, { withFileTypes: true });

397

398

for (const entry of entries) {

399

const fullPath = `${directory}/${entry.name}`;

400

401

if (entry.isFile()) {

402

const stats = fs.statSync(fullPath);

403

if (stats.size >= minSize && stats.size <= maxSize) {

404

files.push({

405

path: fullPath,

406

size: stats.size

407

});

408

}

409

} else if (entry.isDirectory()) {

410

files.push(...findFilesBySize(fullPath, minSize, maxSize));

411

}

412

}

413

414

return files;

415

}

416

417

// Get directory size recursively

418

function getDirectorySize(dirPath) {

419

let totalSize = 0;

420

const entries = fs.readdirSync(dirPath, { withFileTypes: true });

421

422

for (const entry of entries) {

423

const fullPath = `${dirPath}/${entry.name}`;

424

425

if (entry.isFile()) {

426

const stats = fs.statSync(fullPath);

427

totalSize += stats.size;

428

} else if (entry.isDirectory()) {

429

totalSize += getDirectorySize(fullPath);

430

}

431

}

432

433

return totalSize;

434

}

435

436

// File age utilities

437

function getFileAge(path) {

438

const stats = fs.statSync(path);

439

const now = new Date();

440

const ageMs = now.getTime() - stats.mtime.getTime();

441

442

return {

443

milliseconds: ageMs,

444

seconds: Math.floor(ageMs / 1000),

445

minutes: Math.floor(ageMs / (1000 * 60)),

446

hours: Math.floor(ageMs / (1000 * 60 * 60)),

447

days: Math.floor(ageMs / (1000 * 60 * 60 * 24))

448

};

449

}

450

451

// Find old files

452

function findOldFiles(directory, daysOld) {

453

const oldFiles = [];

454

const cutoffTime = Date.now() - (daysOld * 24 * 60 * 60 * 1000);

455

456

function scanDirectory(dir) {

457

const entries = fs.readdirSync(dir, { withFileTypes: true });

458

459

for (const entry of entries) {

460

const fullPath = `${dir}/${entry.name}`;

461

462

if (entry.isFile()) {

463

const stats = fs.statSync(fullPath);

464

if (stats.mtime.getTime() < cutoffTime) {

465

oldFiles.push({

466

path: fullPath,

467

age: getFileAge(fullPath),

468

size: stats.size

469

});

470

}

471

} else if (entry.isDirectory()) {

472

scanDirectory(fullPath);

473

}

474

}

475

}

476

477

scanDirectory(directory);

478

return oldFiles;

479

}

480

```

481

482

### Permission Management Utilities

483

484

Advanced permission management and security utilities.

485

486

```javascript

487

// Set secure permissions for different file types

488

function setSecurePermissions(path) {

489

const stats = fs.statSync(path);

490

491

if (stats.isDirectory()) {

492

fs.chmodSync(path, 0o755); // rwxr-xr-x for directories

493

} else if (stats.isFile()) {

494

// Check if file should be executable

495

const content = fs.readFileSync(path, 'utf8');

496

if (content.startsWith('#!') || path.endsWith('.sh')) {

497

fs.chmodSync(path, 0o755); // rwxr-xr-x for scripts

498

} else {

499

fs.chmodSync(path, 0o644); // rw-r--r-- for regular files

500

}

501

}

502

}

503

504

// Mass permission update

505

function updatePermissionsRecursively(directory, fileMode, dirMode) {

506

const entries = fs.readdirSync(directory, { withFileTypes: true });

507

508

for (const entry of entries) {

509

const fullPath = `${directory}/${entry.name}`;

510

511

if (entry.isFile()) {

512

fs.chmodSync(fullPath, fileMode);

513

} else if (entry.isDirectory()) {

514

fs.chmodSync(fullPath, dirMode);

515

updatePermissionsRecursively(fullPath, fileMode, dirMode);

516

}

517

}

518

}

519

520

// Permission validator

521

function validatePermissions(path, expectedMode) {

522

const stats = fs.statSync(path);

523

const actualMode = stats.mode & 0o777;

524

const expected = typeof expectedMode === 'string' ?

525

parseInt(expectedMode, 8) : expectedMode;

526

527

return {

528

isValid: actualMode === expected,

529

actual: actualMode.toString(8),

530

expected: expected.toString(8),

531

needsUpdate: actualMode !== expected

532

};

533

}

534

535

// Usage examples

536

const validation = validatePermissions('/script.sh', 0o755);

537

if (!validation.isValid) {

538

console.log(`Permission mismatch: expected ${validation.expected}, got ${validation.actual}`);

539

fs.chmodSync('/script.sh', 0o755);

540

}

541

```

542

543

## Error Handling

544

545

Common statistics and permissions errors:

546

547

- `ENOENT` - File or directory doesn't exist

548

- `EPERM` - Operation not permitted (insufficient permissions)

549

- `EACCES` - Access denied

550

- `EISDIR` - Is a directory (when file expected)

551

- `ENOTDIR` - Not a directory (when directory expected)

552

553

```javascript

554

// Safe stat operation

555

function safeStat(path) {

556

try {

557

return fs.statSync(path);

558

} catch (err) {

559

if (err.code === 'ENOENT') {

560

return null; // File doesn't exist

561

}

562

throw err; // Re-throw other errors

563

}

564

}

565

566

// Safe permission change

567

function safeChmod(path, mode) {

568

try {

569

fs.chmodSync(path, mode);

570

return true;

571

} catch (err) {

572

if (err.code === 'EPERM') {

573

console.warn(`Permission denied changing mode for ${path}`);

574

return false;

575

}

576

throw err;

577

}

578

}

579

```