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