embox

Форк
0
660 строк · 13.7 Кб
1
/**
2
 * @file
3
 * @brief
4
 *
5
 * @date 20.08.2012
6
 * @author Andrey Gazukin
7
 */
8

9
#include <errno.h>
10
#include <sys/stat.h>
11
#include <arpa/inet.h>
12
#include <ctype.h>
13
#include <string.h>
14

15
#include <util/math.h>
16

17
#include <fs/inode.h>
18
#include <fs/super_block.h>
19

20
#include <fs/iso9660.h>
21

22
#include <drivers/block_dev.h>
23
#include <mem/sysmalloc.h>
24

25
#include <framework/mod/options.h>
26

27
int cdfs_isonum_711(unsigned char *p) {
28
  return p[0];
29
}
30

31
static int cdfs_isonum_731(unsigned char *p) {
32
  return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
33
}
34

35
int cdfs_isonum_733(unsigned char *p) {
36
  return cdfs_isonum_731(p);
37
}
38

39
static int cdfs_fnmatch(struct cdfs_fs_info *cdfs, char *fn1, int len1, char *fn2, int len2) {
40
	wchar_t *wfn2;
41
	int wlen2;
42

43
	if (cdfs->joliet) {
44
		wfn2 = (wchar_t *) fn2;
45
		wlen2 = len2 / 2;
46
		if (wlen2 > 1 && ntohs(wfn2[wlen2 - 2]) == ';') {
47
			wlen2 -= 2;
48
		}
49
		if (wlen2 > 0 && ntohs(wfn2[wlen2 - 1]) == '.') {
50
			wlen2 -= 1;
51
		}
52
		if (len1 != wlen2) {
53
			return 0;
54
		}
55
		while (len1--) {
56
			if (*fn1++ != ntohs(*wfn2++)) {
57
				return 0;
58
			}
59
		}
60
		return 1;
61
	}
62
	else {
63
		if (len2 > 1 && fn2[len2 - 2] == ';') {
64
			len2 -= 2;
65
		}
66
		if (len2 > 0 && fn2[len2 - 1] == '.') {
67
			len2 -= 1;
68
		}
69
		if (len1 != len2) {
70
			return 0;
71
		}
72
		while (len1--) {
73
			if (toupper(*fn1++) != toupper(*fn2++)) {
74
				return 0;
75
			}
76
		}
77
		return 1;
78
	}
79
}
80

81
int cdfs_read_path_table(struct cdfs_fs_info *cdfs, iso_volume_descriptor_t *vd) {
82
	struct block_dev_cache *cache;
83
	unsigned char *pt;
84
	int ptblk;
85
	int ptlen;
86
	int ptpos;
87
	int n;
88
	iso_pathtable_record_t *pathrec;
89
	int namelen;
90
	int reclen;
91
	char name[128];
92

93
	/* Determine size and location of path table and allocate buffer */
94
	ptlen = cdfs_isonum_733(vd->path_table_size);
95
	ptblk = cdfs_isonum_731(vd->type_l_path_table);
96
	cdfs->path_table_buffer = sysmalloc(ptlen);
97
	if (!cdfs->path_table_buffer) {
98
		return -ENOMEM;
99
	}
100

101
	/* Read L path table into buffer */
102
	ptpos = 0;
103
	while (ptpos < ptlen) {
104
		cache = block_dev_cached_read(cdfs->bdev, ptblk++);
105
		if (!cache) {
106
			return -EIO;
107
		}
108

109
		if (ptlen - ptpos > CDFS_BLOCKSIZE) {
110
			memcpy(cdfs->path_table_buffer + ptpos, cache->data, CDFS_BLOCKSIZE);
111
			ptpos += CDFS_BLOCKSIZE;
112
		}
113
		else {
114
			memcpy(cdfs->path_table_buffer + ptpos, cache->data, ptlen - ptpos);
115
			ptpos = ptlen;
116
		}
117
	}
118

119
	/*
120
	 * Determine number of records in pathtable
121
	 * Path table records are indexed from 1 (first entry not used)
122
	 */
123
	pt = cdfs->path_table_buffer;
124
	n = 1;
125
	while (pt < cdfs->path_table_buffer + ptlen) {
126
		pathrec = (iso_pathtable_record_t *) pt;
127
		namelen = pathrec->length;
128
		reclen = sizeof(iso_pathtable_record_t) + namelen + (namelen & 1);
129

130
		n++;
131
		pt += reclen;
132
		memcpy(name, (char *)(pathrec + sizeof(iso_pathtable_record_t)), namelen);
133
	}
134
	if((0 == name[0]) && (0 == name[1])) {
135
		name[0] = 33;
136
	}
137

138
	cdfs->path_table_records = n;
139

140
	/* Allocate path table */
141
	cdfs->path_table = (iso_pathtable_record_t **)
142
							sysmalloc(cdfs->path_table_records *
143
							sizeof(iso_pathtable_record_t **));
144
	if (!cdfs->path_table) {
145
		return -ENOMEM;
146
	}
147
	cdfs->path_table[0] = NULL;
148

149
	/* Setup pointers into path table buffer */
150
	pt = cdfs->path_table_buffer;
151
	for (n = 1; n < cdfs->path_table_records; n++) {
152
		pathrec = (iso_pathtable_record_t *) pt;
153
		namelen = pathrec->length;
154
		reclen = sizeof(iso_pathtable_record_t) + namelen + (namelen & 1);
155

156
		cdfs->path_table[n] = pathrec;
157
		pt += reclen;
158
	}
159

160
	return 0;
161
}
162

163
int cdfs_find_dir(struct cdfs_fs_info *cdfs, char *name, int len) {
164
	char *p;
165
	int l;
166
	int dir = 2;
167
	int parent = 1;
168
	char upper_name[NAME_MAX];
169

170

171
	for(int i = 0; name[i]; i++){
172
		upper_name[i] = toupper(name[i]);
173
	}
174

175
	name = upper_name;
176

177
	while (1) {
178
		/* Skip path separator */
179
		if (*name == PS1 || *name == PS2) {
180
			name++;
181
			len--;
182
		}
183
		if (len == 0) {
184
			return parent;
185
		}
186

187
		/* Find next part of name */
188
		p = name;
189
		l = 0;
190
		while (l < len && *p != PS1 && *p != PS2) {
191
			l++;
192
			p++;
193
		}
194

195
		/* Find directory for next name part */
196
		while (dir < cdfs->path_table_records) {
197
			if (cdfs->path_table[dir]->parent != parent) {
198
				return -ENOENT;
199
			}
200
			if (cdfs_fnmatch(cdfs, name, l,
201
				cdfs->path_table[dir]->name, cdfs->path_table[dir]->length)) {
202
				break;
203
			}
204
			dir++;
205
		}
206

207
		/* If we reached the end of the path table the directory does not exist */
208
		if (dir == cdfs->path_table_records) {
209
			return -ENOENT;
210
		}
211

212
		/* If we have parsed the whole name return the directory number */
213
		if (l == len) {
214
			return dir;
215
		}
216

217
		/* Go forward in path table until first entry for directory found */
218
		parent = dir;
219
		while (dir < cdfs->path_table_records) {
220
			if (cdfs->path_table[dir]->parent == parent) {
221
				break;
222
			}
223
			dir++;
224
		}
225

226
		/* Prepare for next name part */
227
		name = p;
228
		len -= l;
229
	}
230
	return -ENOENT;
231
}
232

233
int cdfs_find_in_dir(struct cdfs_fs_info *cdfs, int dir, char *name, int len, iso_directory_record_t **dirrec) {
234
	struct block_dev_cache *cache;
235
	char *p;
236
	iso_directory_record_t *rec;
237
	int blk;
238
	int left;
239
	int reclen;
240
	int namelen;
241

242
	/* The first two directory records are . (current) and .. (parent) */
243
	blk = cdfs->path_table[dir]->extent;
244
	cache = block_dev_cached_read(cdfs->bdev, blk++);
245
	if (!cache) {
246
		return -EIO;
247
	}
248

249
	/* Get length of directory from the first record */
250
	p = cache->data;
251
	rec = (iso_directory_record_t *) p;
252
	left = cdfs_isonum_733(rec->size);
253

254
	/* Find named entry in directory */
255
	while (left > 0) {
256
		/*
257
		 * Read next block if all records in current block has been read
258
		 * Directory records never cross block boundaries
259
		 */
260
		if (p >= cache->data + CDFS_BLOCKSIZE) {
261
			if (p > cache->data + CDFS_BLOCKSIZE) {
262
				return -EIO;
263
			}
264
			cache = block_dev_cached_read(cdfs->bdev, blk++);
265
			if (!cache) {
266
				return -EIO;
267
			}
268
			p = cache->data;
269
		}
270

271
		/* Check for match */
272
		rec = (iso_directory_record_t *) p;
273
		reclen = cdfs_isonum_711(rec->length);
274
		namelen = cdfs_isonum_711(rec->name_len);
275

276
		if (reclen > 0) {
277
			if (cdfs_fnmatch(cdfs, name, len, (char *) rec->name, namelen)) {
278
				*dirrec = rec;
279
				return 0;
280
			}
281

282
			/* Skip to next record */
283
			p += reclen;
284
			left -= reclen;
285
		}
286
		else {
287
			/* Skip to next block */
288
			left -= (cache->data + CDFS_BLOCKSIZE) - p;
289
			p = cache->data + CDFS_BLOCKSIZE;
290
		}
291
	}
292

293
	return -ENOENT;
294
}
295

296
int cdfs_find_file(struct cdfs_fs_info *cdfs, char *name, int len, iso_directory_record_t **rec) {
297
	int dir;
298
	int split;
299
	int n;
300
	struct block_dev_cache *cache;
301
	iso_volume_descriptor_t *vd;
302

303
	/* If root get directory record from volume descriptor */
304
	if (len == 0 || (0 == strcmp(name, "/"))) {
305
		cache = block_dev_cached_read(cdfs->bdev, cdfs->vdblk);
306
		if (!cache) {
307
			return -EIO;
308
		}
309
		vd = (iso_volume_descriptor_t *) (cache)->data;
310
		*rec = (iso_directory_record_t *) vd->root_directory_record;
311
		return 1;
312
	}
313

314
	/* Split path into directory part and file name part */
315
	split = -1;
316
	for (n = 0; n < len; n++) {
317
		if (name[n] == PS1 || name[n] == PS2) {
318
			split = n;
319
		}
320
	}
321

322
	/* Find directly if file located in root directory */
323
	if (split == -1) {
324
		return cdfs_find_in_dir(cdfs, 1, name, len, rec);
325
	}
326

327
	/* Locate directory */
328
	dir = cdfs_find_dir(cdfs, name, split + 1);
329
	if (dir < 0) {
330
		return dir;
331
	}
332

333
	/* Find filename in directory */
334
	return cdfs_find_in_dir(cdfs, dir, name + split + 1,
335
								  len - split - 1, rec);
336
}
337

338
time_t cdfs_isodate(unsigned char *date)
339
{
340
	static struct tm tm;
341

342
	memset(&tm, 0, sizeof tm);
343
	tm.tm_year = date[0];
344
	tm.tm_mon = date[1] - 1;
345
	tm.tm_mday = date[2];
346
	tm.tm_hour = date[3];
347
	tm.tm_min = date[4];
348
	tm.tm_sec = date[5];
349
	tm.tm_min += (*(char *) &date[6]) * 15;
350

351
	return (time_t) &tm; /*mktime(&tm); */
352
}
353

354
int iso9660_fsi_init(struct inode *root_node)
355
{
356
	int rc;
357
	int blk;
358
	struct block_dev_cache *cache;
359
	iso_volume_descriptor_t *vd;
360
	int type;
361
	unsigned char *esc;
362
	struct cdfs_fs_info *fsi;
363

364
	fsi = root_node->i_sb->sb_data;
365

366
	/* Check block size */
367
	if (CDFS_BLOCKSIZE != block_dev_block_size(root_node->i_sb->bdev)) {
368
		return -ENXIO;
369
	}
370

371
	/* Allocate file system */
372
	fsi->bdev = root_node->i_sb->bdev;
373
	fsi->blks = block_dev_size(root_node->i_sb->bdev);
374
	if (fsi->blks < 0) {
375
		return fsi->blks;
376
	}
377

378
	/* Read volume descriptors */
379
	fsi->vdblk = 0;
380
	blk = 0x8000/CDFS_BLOCKSIZE;
381
	while (1) {
382
		cache  = block_dev_cached_read(root_node->i_sb->bdev, blk);
383
		if (!cache) {
384
			return -EIO;
385
		}
386
		vd = (iso_volume_descriptor_t *) cache->data;
387

388
		type = cdfs_isonum_711(vd->type);
389
		esc = vd->escape_sequences;
390

391
		if (memcmp(vd->id, "CD001", 5) != 0) {
392
			return -EIO;
393
		}
394

395
		if (fsi->vdblk == 0 && type == ISO_VD_PRIMARY) {
396
			fsi->vdblk = blk;
397
		}
398
		else if (type == ISO_VD_SUPPLEMENTAL &&
399
				 esc[0] == 0x25 && esc[1] == 0x2F &&
400
				 (esc[2] == 0x40 || esc[2] == 0x43 || esc[2] == 0x45)) {
401
			fsi->vdblk = blk;
402
			fsi->joliet = 1;
403
		}
404

405
		if (type == ISO_VD_END) {
406
			break;
407
		}
408
		blk++;
409
	}
410
	if (fsi->vdblk == 0) {
411
		return -EIO;
412
	}
413

414
	/* Initialize filesystem from selected volume descriptor and read path table */
415
	cache  = block_dev_cached_read(root_node->i_sb->bdev, fsi->vdblk);
416
	if (!cache) {
417
		return -EIO;
418
	}
419
	vd = (iso_volume_descriptor_t *) cache->data;
420

421
	fsi->volblks = cdfs_isonum_733(vd->volume_space_size);
422

423
	rc = cdfs_read_path_table(fsi, vd);
424
	if (rc < 0) {
425
		return rc;
426
	}
427

428
	return 0;
429
}
430

431
/* int cdfs_statfs(struct cdfs_fs_info *fsi, statfs_t *cache) { */
432
/* 	struct cdfs *cdfs = (struct cdfs *) fsi->data; */
433

434
/* 	cache->bsize = CDFS_BLOCKSIZE; */
435
/* 	cache->iosize = CDFS_BLOCKSIZE; */
436
/* 	cache->blocks = cdfs->volblks; */
437
/* 	cache->bfree = 0; */
438
/* 	cache->files = -1; */
439
/* 	cache->ffree = 0; */
440
/* 	/\*cache->cachesize = cdfs->cache->poolsize * CDFS_BLOCKSIZE; *\/ */
441

442
/* 	return 0; */
443
/* } */
444

445

446

447
/*
448
static int cdfs_opendir(struct inode *dir_node, char *name) {
449
	struct cdfs *cdfs;
450
	iso_directory_record_t *rec;
451
	cdfs_file_t *cdfile;
452
	time_t date;
453
	int size;
454
	int extent;
455
	int flags;
456
	int rc;
457
	struct cdfs_file_info *fi;
458

459
	fi = inode_priv(dir->node);
460
	cdfs = (struct cdfs *) dir_node->i_sb->data;
461

462
	// Locate directory
463
	rc = cdfs_find_file(cdfs, name, strlen(name), &rec);
464
	if (rc < 0) {
465
		return rc;
466
	}
467

468
	flags = cdfs_isonum_711(rec->flags);
469
	extent = cdfs_isonum_733(rec->extent);
470
	date = cdfs_isodate(rec->date);
471
	size = cdfs_isonum_733(rec->size);
472

473
	if (!(flags & 2)) {
474
		return -ENOTDIR;
475
	}
476

477
	// Allocate and initialize file block
478
	cdfile = (cdfs_file_t *) sysmalloc(sizeof(cdfs_file_t));
479
	if (!cdfile) {
480
		return -ENOMEM;
481
	}
482
	cdfile->extent = extent;
483
	cdfile->date = date;
484
	cdfile->size = size;
485

486
	fi->data = cdfile;
487
	fi->mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP |
488
				 S_IXGRP | S_IROTH | S_IXOTH;
489
	return 0;
490
}
491

492
static int cdfs_readdir(struct inode *node, direntry_t *dirp, int count) {
493
	cdfs_file_t *cdfile;
494
	struct cdfs *cdfs;
495
	iso_directory_record_t *rec;
496
	struct block_dev_cache *cache;
497
	int namelen;
498
	int reclen;
499
	int blkleft;
500
	char *name;
501
	wchar_t *wname;
502
	struct cdfs_file_info *fi;
503

504
	fi = inode_priv(node);
505
	cdfile = (cdfs_file_t *) fi->data;
506
	cdfs = (struct cdfs *) node->i_sb->data;
507

508
  blkagain:
509
	if (count != 1) {
510
		return -EINVAL;
511
	}
512
	if (fi->pos >= cdfile->size) {
513
		return 0;
514
	}
515

516
	// Get directory block
517
	cache = block_dev_cached_read(cdfs->bdev, cdfile->extent +
518
			(int) fi->pos / CDFS_BLOCKSIZE);
519
	if (!cache) {
520
		return -EIO;
521
	}
522

523
	// Locate directory record
524
  recagain:
525
	rec = (iso_directory_record_t *) (cache->data +
526
			(int) fi->pos % CDFS_BLOCKSIZE);
527
	reclen = cdfs_isonum_711(rec->length);
528
	namelen = cdfs_isonum_711(rec->name_len);
529

530
	// Check for no more records in block
531
	if (reclen == 0) {
532
		blkleft = CDFS_BLOCKSIZE - ((int) fi->pos % CDFS_BLOCKSIZE);
533
		fi->pos += blkleft;
534
		goto blkagain;
535
	}
536

537
	 // Check for . and .. entries /
538
	if (namelen == 1 && (rec->name[0] == 0 || rec->name[0] == 1)) {
539
		fi->pos += reclen;
540
		goto recagain;
541
	}
542

543
	// Get info from directory record /
544
	dirp->ino = cdfs_isonum_733(rec->extent);
545
	dirp->reclen = sizeof(direntry_t) - PATH_MAX + namelen + 1;
546
	if (cdfs->joliet) {
547
		namelen /= 2;
548
		wname = (wchar_t *) rec->name;
549
		if (namelen > 1 && ntohs(wname[namelen - 2]) == ';') {
550
			namelen -= 2;
551
		}
552
		if (namelen > 0 && ntohs(wname[namelen - 1]) == '.') {
553
			namelen -= 1;
554
		}
555

556
		dirp->namelen = namelen;
557
		for (int n = 0; n < namelen; n++) {
558
			dirp->name[n] = (char) ntohs(wname[n]);
559
		}
560
		dirp->name[namelen] = 0;
561
	}
562
	else {
563
		name = (char *) rec->name;
564
		if (namelen > 1 && name[namelen - 2] == ';') namelen -= 2;
565
		if (namelen > 0 && name[namelen - 1] == '.') namelen -= 1;
566

567
		dirp->namelen = namelen;
568
		memcpy(dirp->name, name, namelen);
569
		dirp->name[namelen] = 0;
570
	}
571

572
	fi->pos += reclen;
573
	return 1;
574
}
575

576
void cdfs_init(void) {
577

578
	return;
579
}
580
*/
581

582
int cdfs_alloc_inode_priv(struct inode* node) {
583
	struct cdfs_file_info *fi;
584

585
	fi = inode_priv(node);
586
	if (fi) {
587
		return 0;
588
	}
589

590
	fi = iso9660_fi_alloc();
591
	if (!fi) {
592
		return -ENOMEM;
593
	}
594

595
	memset(fi, 0, sizeof(struct cdfs_file_info));
596

597
	inode_priv_set(node, fi);
598

599
	return 0;
600
}
601

602
int cdfs_fill_node(struct inode* node, char *name, struct cdfs_fs_info *cdfs, iso_directory_record_t *rec) {
603
	int flags;
604
	int namelen;
605
	struct cdfs_file_info *fi;
606

607
	fi = inode_priv(node);
608
	assert(fi);
609

610
	namelen = cdfs_isonum_711(rec->name_len);
611
	flags = cdfs_isonum_711(rec->flags);
612

613
	if (cdfs->joliet) {
614
		wchar_t *wname;
615

616
		namelen /= 2;
617
		namelen = min(NAME_MAX, namelen);
618

619
		wname = (wchar_t *) rec->name;
620
		if (namelen > 1 && ntohs(wname[namelen - 2]) == ';') {
621
			namelen -= 2;
622
		}
623
		if (namelen > 0 && ntohs(wname[namelen - 1]) == '.') {
624
			namelen -= 1;
625
		}
626

627
		for (int n = 0; n < namelen; n++) {
628
			name[n] = (char) ntohs(wname[n]);
629
		}
630
	} else {
631
		namelen = min(NAME_MAX, namelen);
632
		if (namelen > 1 && rec->name[namelen - 2] == ';') {
633
			namelen -= 2;
634
		}
635
		if (namelen > 0 && rec->name[namelen - 1] == '.') {
636
			namelen -= 1;
637
		}
638
		memcpy(name, rec->name, namelen);
639
	}
640
	name[namelen] = 0;
641

642
	for(int i = 0; name[i]; i++){
643
		name[i] = tolower(name[i]);
644
	}
645

646
	/* if directory then not create node */
647
	if (flags & 2) {
648
		node->i_mode = S_IFDIR;
649
	} else {
650
		node->i_mode = S_IFREG;
651
	}
652

653
	fi->size = cdfs_isonum_733(rec->size);
654
	fi->extent = cdfs_isonum_733(rec->extent);
655
	fi->date = cdfs_isodate(rec->date);
656

657
	inode_size_set(node, fi->size);
658

659
	return 0;
660
}
661

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.