This source file includes following definitions.
- UMSDOS_dir_read
- umsdos_readdir_x
- UMSDOS_readdir
- umsdos_lookup_patch
- umsdos_inode2entry
- umsdos_locate_ancestor
- umsdos_locate_path
- umsdos_is_pseudodos
- umsdos_lookup_x
- UMSDOS_lookup
- umsdos_hlink2inode
1
2
3
4
5
6
7
8
9
10 #include <asm/segment.h>
11
12 #include <linux/sched.h>
13 #include <linux/string.h>
14 #include <linux/fs.h>
15 #include <linux/msdos_fs.h>
16 #include <linux/errno.h>
17 #include <linux/stat.h>
18 #include <linux/limits.h>
19 #include <linux/umsdos_fs.h>
20 #include <linux/malloc.h>
21
22 #define PRINTK(x)
23 #define Printk(x) printk x
24
25 #define UMSDOS_SPECIAL_DIRFPOS 3
26 extern struct inode *pseudo_root;
27
28
29
30 int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
31 int count)
32 {
33 return -EISDIR;
34 }
35 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
36 #define ROUND_UP(x) (((x)+3) & ~3)
37
38
39
40
41
42
43
44
45
46
47
48 static int umsdos_readdir_x(
49 struct inode *dir,
50 struct file *filp,
51 struct dirent *dirent,
52 int dirent_in_fs,
53 int count,
54 struct umsdos_dirent *u_entry,
55 int follow_hlink,
56 off_t *pt_f_pos)
57 {
58 int ret = 0;
59
60 umsdos_startlookup(dir);
61 if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
62 && dir == pseudo_root
63 && dirent_in_fs){
64
65
66
67
68
69
70
71
72
73
74 put_fs_long(dir->i_sb->s_mounted->i_ino,&dirent->d_ino);
75 memcpy_tofs (dirent->d_name,"DOS",3);
76 put_fs_byte(0,dirent->d_name+3);
77 put_fs_word (3,&dirent->d_reclen);
78 if (u_entry != NULL) u_entry->flags = 0;
79 ret = ROUND_UP(NAME_OFFSET(dirent) + 3 + 1);
80 filp->f_pos++;
81 }else if (filp->f_pos < 2
82 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 ret = msdos_readdir(dir,filp,dirent,count);
117 if (filp->f_pos == 64) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
118 if (u_entry != NULL) u_entry->flags = 0;
119 }else{
120 struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
121 if (emd_dir != NULL){
122 if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
123 PRINTK (("f_pos %ld i_size %d\n",filp->f_pos,emd_dir->i_size));
124 ret = 0;
125 while (filp->f_pos < emd_dir->i_size){
126 struct umsdos_dirent entry;
127 off_t cur_f_pos = filp->f_pos;
128 if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
129 ret = -EIO;
130 break;
131 }else if (entry.name_len != 0){
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 struct umsdos_info info;
151 struct inode *inode;
152 int lret;
153 umsdos_parse (entry.name,entry.name_len,&info);
154 info.f_pos = cur_f_pos;
155 *pt_f_pos = cur_f_pos;
156 umsdos_manglename (&info);
157 lret = umsdos_real_lookup (dir,info.fake.fname
158 ,info.fake.len,&inode);
159 PRINTK (("Cherche inode de %s lret %d flags %d\n"
160 ,info.fake.fname,lret,entry.flags));
161 if (lret == 0
162 && (entry.flags & UMSDOS_HLINK)
163 && follow_hlink){
164 struct inode *rinode;
165 lret = umsdos_hlink2inode (inode,&rinode);
166 inode = rinode;
167 }
168 if (lret == 0){
169
170
171
172
173
174
175
176 if (inode != pseudo_root){
177 PRINTK (("Trouve ino %d ",inode->i_ino));
178 if (dirent_in_fs){
179 put_fs_long(inode->i_ino,&dirent->d_ino);
180 memcpy_tofs (dirent->d_name,entry.name
181 ,entry.name_len);
182 put_fs_byte(0,dirent->d_name+entry.name_len);
183 put_fs_word (entry.name_len
184 ,&dirent->d_reclen);
185
186
187 if (u_entry != NULL){
188 u_entry->flags = entry.flags;
189 }
190 }else{
191 dirent->d_ino = inode->i_ino;
192 memcpy (dirent->d_name,entry.name
193 ,entry.name_len);
194 dirent->d_name[entry.name_len] = '\0';
195 dirent->d_reclen = entry.name_len;
196 if (u_entry != NULL) *u_entry = entry;
197 }
198 ret = ROUND_UP(NAME_OFFSET(dirent) + entry.name_len + 1);
199 iput (inode);
200 break;
201 }
202 iput (inode);
203 }else{
204
205
206
207
208
209 ret = umsdos_writeentry (dir,emd_dir,&info,1);
210 if (ret != 0){
211 break;
212 }
213 }
214 }
215 }
216 iput(emd_dir);
217 }
218 }
219 umsdos_endlookup(dir);
220 PRINTK (("read dir %p pos %d ret %d\n",dir,filp->f_pos,ret));
221 return ret;
222 }
223
224
225
226
227
228 static int UMSDOS_readdir(
229 struct inode *dir,
230 struct file *filp,
231 struct dirent *dirent,
232 int count)
233 {
234 int ret = -ENOENT;
235 while (1){
236 struct umsdos_dirent entry;
237 off_t f_pos;
238 ret = umsdos_readdir_x (dir,filp,dirent,1,count,&entry,1,&f_pos);
239 if (ret <= 0 || !(entry.flags & UMSDOS_HIDDEN)) break;
240 }
241 return ret;
242 }
243
244
245
246 void umsdos_lookup_patch (
247 struct inode *dir,
248 struct inode *inode,
249 struct umsdos_dirent *entry,
250 off_t emd_pos)
251 {
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
282 if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
283 if (!umsdos_isinit(inode)){
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
302 inode->i_mode = entry->mode;
303 inode->i_rdev = entry->rdev;
304 inode->i_atime = entry->atime;
305 inode->i_ctime = entry->ctime;
306 inode->i_mtime = entry->mtime;
307 inode->i_uid = entry->uid;
308 inode->i_gid = entry->gid;
309
310
311
312
313
314
315
316
317 if (!S_ISDIR(entry->mode)){
318 if (entry->nlink > 0){
319 inode->i_nlink = entry->nlink;
320 }else{
321 printk ("UMSDOS: lookup_patch entry->nlink < 1 ???\n");
322 }
323 }
324 umsdos_patch_inode(inode,dir,emd_pos);
325 }
326 if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
327 if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
328 }
329 }
330
331
332
333
334
335
336
337 int umsdos_inode2entry (
338 struct inode *dir,
339 struct inode *inode,
340 struct umsdos_dirent *entry)
341 {
342 int ret = -ENOENT;
343 if (inode == pseudo_root){
344
345
346
347
348 memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
349 entry->name_len = UMSDOS_PSDROOT_LEN;
350 ret = 0;
351 }else{
352 struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
353 iput (emddir);
354 if (emddir == NULL){
355
356 struct file filp;
357 filp.f_reada = 1;
358 filp.f_pos = 0;
359 while (1){
360 struct dirent dirent;
361 if (umsdos_readdir_kmem (dir,&filp,&dirent,1) <= 0){
362 printk ("UMSDOS: can't locate inode %ld in DOS directory???\n"
363 ,inode->i_ino);
364 }else if (dirent.d_ino == inode->i_ino){
365 ret = 0;
366 memcpy (entry->name,dirent.d_name,dirent.d_reclen);
367 entry->name[dirent.d_reclen] = '\0';
368 entry->name_len = dirent.d_reclen;
369 inode->u.umsdos_i.i_dir_owner = dir->i_ino;
370 inode->u.umsdos_i.i_emd_owner = 0;
371 umsdos_setup_dir_inode(inode);
372 break;
373 }
374 }
375 }else{
376
377 struct file filp;
378 filp.f_reada = 1;
379 filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
380 while (1){
381 struct dirent dirent;
382 off_t f_pos;
383 if (umsdos_readdir_x(dir,&filp,&dirent
384 ,0,1,entry,0,&f_pos) <= 0){
385 printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
386 ,inode->i_ino);
387 break;
388 }else if (dirent.d_ino == inode->i_ino){
389 ret = 0;
390 umsdos_lookup_patch (dir,inode,entry,f_pos);
391 break;
392 }
393 }
394 }
395 }
396 return ret;
397 }
398
399
400
401
402 static int umsdos_locate_ancestor (
403 struct inode *dir,
404 struct inode **result,
405 struct umsdos_dirent *entry)
406 {
407 int ret;
408 umsdos_patch_inode (dir,NULL,0);
409 ret = umsdos_real_lookup (dir,"..",2,result);
410 PRINTK (("result %d %x ",ret,*result));
411 if (ret == 0){
412 struct inode *adir = *result;
413 ret = umsdos_inode2entry (adir,dir,entry);
414 }
415 PRINTK (("\n"));
416 return ret;
417 }
418
419
420
421
422
423
424 int umsdos_locate_path (
425 struct inode *inode,
426 char *path)
427 {
428 int ret = 0;
429 struct inode *dir = inode;
430 char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
431 if (bpath == NULL){
432 ret = -ENOMEM;
433 }else{
434 struct umsdos_dirent entry;
435 char *ptbpath = bpath+PATH_MAX-1;
436 *ptbpath = '\0';
437 PRINTK (("locate_path mode %x ",inode->i_mode));
438 if (!S_ISDIR(inode->i_mode)){
439 ret = umsdos_get_dirowner (inode,&dir);
440 PRINTK (("locate_path ret %d ",ret));
441 if (ret == 0){
442 ret = umsdos_inode2entry (dir,inode,&entry);
443 if (ret == 0){
444 ptbpath -= entry.name_len;
445 memcpy (ptbpath,entry.name,entry.name_len);
446 PRINTK (("ptbpath :%s: ",ptbpath));
447 }
448 }
449 }else{
450 dir->i_count++;
451 }
452 if (ret == 0){
453 while (dir != dir->i_sb->s_mounted){
454 struct inode *adir;
455 ret = umsdos_locate_ancestor (dir,&adir,&entry);
456 iput (dir);
457 dir = NULL;
458 PRINTK (("ancestor %d ",ret));
459 if (ret == 0){
460 *--ptbpath = '/';
461 ptbpath -= entry.name_len;
462 memcpy (ptbpath,entry.name,entry.name_len);
463 dir = adir;
464 PRINTK (("ptbpath :%s: ",ptbpath));
465 }else{
466 break;
467 }
468 }
469 }
470 strcpy (path,ptbpath);
471 kfree (bpath);
472 }
473 PRINTK (("\n"));
474 iput (dir);
475 return ret;
476 }
477
478
479
480
481 int umsdos_is_pseudodos (
482 struct inode *dir,
483 const char *name,
484 int len)
485 {
486
487
488
489
490
491
492
493 return dir == pseudo_root
494 && len == 3
495 && name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
496 }
497
498
499
500
501 static int umsdos_lookup_x (
502 struct inode *dir,
503 const char *name,
504 int len,
505 struct inode **result,
506 int nopseudo)
507 {
508 int ret = -ENOENT;
509 *result = NULL;
510 umsdos_startlookup(dir);
511 if (len == 1 && name[0] == '.'){
512 *result = dir;
513 dir->i_count++;
514 ret = 0;
515 }else if (len == 2 && name[0] == '.' && name[1] == '.'){
516 if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
517
518
519
520
521
522 ret = 0;
523 *result = pseudo_root;
524 pseudo_root->i_count++;
525 }else{
526
527
528
529
530
531
532
533
534
535
536 ret = umsdos_real_lookup (dir,"..",2,result);
537 PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
538 if (ret == 0
539 && *result != dir->i_sb->s_mounted
540 && *result != pseudo_root){
541 struct inode *aadir;
542 struct umsdos_dirent entry;
543 ret = umsdos_locate_ancestor (*result,&aadir,&entry);
544 iput (aadir);
545 }
546 }
547 }else if (umsdos_is_pseudodos(dir,name,len)){
548
549
550
551
552 *result = dir->i_sb->s_mounted;
553 (*result)->i_count++;
554 ret = 0;
555 }else{
556 struct umsdos_info info;
557 ret = umsdos_parse (name,len,&info);
558 if (ret == 0) ret = umsdos_findentry (dir,&info,0);
559 PRINTK (("lookup %s pos %d ret %d len %d ",info.fake.fname,info.f_pos,ret
560 ,info.fake.len));
561 if (ret == 0){
562
563
564
565
566
567
568
569
570
571 struct inode *inode;
572 ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
573 inode = *result;
574 if (inode == NULL){
575 printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
576 ,info.fake.fname);
577 umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
578 }else{
579 umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
580 PRINTK (("lookup ino %d flags %d\n",inode->i_ino
581 ,info.entry.flags));
582 if (info.entry.flags & UMSDOS_HLINK){
583 ret = umsdos_hlink2inode (inode,result);
584 }
585 if (*result == pseudo_root && !nopseudo){
586
587
588
589
590
591
592
593
594
595 iput (pseudo_root);
596 *result = NULL;
597 ret = -ENOENT;
598 }
599 }
600 }
601 }
602 umsdos_endlookup(dir);
603 iput (dir);
604 return ret;
605 }
606
607
608
609
610 int UMSDOS_lookup (
611 struct inode *dir,
612 const char *name,
613 int len,
614 struct inode **result)
615 {
616 return umsdos_lookup_x(dir,name,len,result,0);
617 }
618
619
620
621
622 int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
623 {
624 int ret = -EIO;
625 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
626 *result = NULL;
627 if (path == NULL){
628 ret = -ENOMEM;
629 iput (hlink);
630 }else{
631 struct file filp;
632 filp.f_reada = 1;
633 filp.f_pos = 0;
634 PRINTK (("hlink2inode "));
635 if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size)
636 ==hlink->i_size){
637 struct inode *dir;
638 char *pt = path;
639 dir = hlink->i_sb->s_mounted;
640 path[hlink->i_size] = '\0';
641 iput (hlink);
642 dir->i_count++;
643 while (1){
644 char *start = pt;
645 int len;
646 while (*pt != '\0' && *pt != '/') pt++;
647 len = (int)(pt - start);
648 if (*pt == '/') *pt++ = '\0';
649 if (dir->u.umsdos_i.i_emd_dir == 0){
650
651 ret = msdos_lookup(dir,start,len,result);
652 }else{
653 ret = umsdos_lookup_x(dir,start,len,result,1);
654 }
655 PRINTK (("h2n lookup :%s: -> %d ",start,ret));
656 if (ret == 0 && *pt != '\0'){
657 dir = *result;
658 }else{
659 break;
660 }
661 }
662 }else{
663 iput (hlink);
664 }
665 PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
666 kfree (path);
667 }
668 return ret;
669 }
670
671 static struct file_operations umsdos_dir_operations = {
672 NULL,
673 UMSDOS_dir_read,
674 NULL,
675 UMSDOS_readdir,
676 NULL,
677 UMSDOS_ioctl_dir,
678 NULL,
679 NULL,
680 NULL,
681 NULL
682 };
683
684 struct inode_operations umsdos_dir_inode_operations = {
685 &umsdos_dir_operations,
686 UMSDOS_create,
687 UMSDOS_lookup,
688 UMSDOS_link,
689 UMSDOS_unlink,
690 UMSDOS_symlink,
691 UMSDOS_mkdir,
692 UMSDOS_rmdir,
693 UMSDOS_mknod,
694 UMSDOS_rename,
695 NULL,
696 NULL,
697 NULL,
698 NULL,
699 NULL
700 };
701
702
703
704
705
706
707
708
709
710