1 /*
2 * linux/fs/umsdos/dir.c
3 *
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... : Werner Almesberger
6 *
7 * Extended MS-DOS directory handling functions
8 */
9
10 #include <linux/sched.h>
11 #include <linux/string.h>
12 #include <linux/fs.h>
13 #include <linux/msdos_fs.h>
14 #include <linux/errno.h>
15 #include <linux/stat.h>
16 #include <linux/limits.h>
17 #include <linux/umsdos_fs.h>
18 #include <linux/malloc.h>
19
20 #include <asm/segment.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 So grep * doesn't complain in the presence of directories.
29 */
30 int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
31 int count)
32 {
33 return -EISDIR;
34 }
35
36 struct UMSDOS_DIR_ONCE {
37 void *dirbuf;
38 filldir_t filldir;
39 int count;
40 int stop;
41 };
42
43 /*
44 Record a single entry the first call.
45 Return -EINVAL the next one.
46 */
47 static int umsdos_dir_once(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
48 void * buf,
49 const char * name,
50 int name_len,
51 off_t offset,
52 ino_t ino)
53 {
54 int ret = -EINVAL;
55 struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
56 if (d->count == 0){
57 #if 0
58 char zname[100];
59 memcpy (zname,name,name_len);
60 zname[name_len] = '\0';
61 Printk (("dir_once :%s: offset %Ld\n",zname,offset));
62 #endif
63 ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
64 d->stop = ret < 0;
65 d->count = 1;
66 }
67 return ret;
68 }
69
70 /*
71 Read count directory entries from directory filp
72 Return a negative value from linux/errno.h.
73 Return > 0 if success (The amount of byte written by filldir).
74
75 This function is used by the normal readdir VFS entry point and by
76 some function who try to find out info on a file from a pure MSDOS
77 inode. See umsdos_locate_ancestor() below.
78 */
79 static int umsdos_readdir_x(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
80 struct inode *dir, /* Point to a description of the super block */
81 struct file *filp, /* Point to a directory which is read */
82 void *dirbuf, /* Will hold count directory entry */
83 /* but filled by the filldir function */
84 int internal_read, /* Called for internal purpose */
85 struct umsdos_dirent *u_entry, /* Optional umsdos entry */
86 int follow_hlink,
87 filldir_t filldir)
88 {
89 int ret = 0;
90
91 umsdos_startlookup(dir);
92 if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
93 && dir == pseudo_root
94 && !internal_read){
95 /*
96 We don't need to simulate this pseudo directory
97 when umsdos_readdir_x is called for internal operation
98 of umsdos. This is why dirent_in_fs is tested
99 */
100 /* #Specification: pseudo root / directory /DOS
101 When umsdos operates in pseudo root mode (C:\linux is the
102 linux root), it simulate a directory /DOS which points to
103 the real root of the file system.
104 */
105 if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS
106 ,dir->i_sb->s_mounted->i_ino) == 0){
107 filp->f_pos++;
108 }
109 }else if (filp->f_pos < 2
110 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
111 /* #Specification: readdir / . and ..
112 The msdos filesystem manage the . and .. entry properly
113 so the EMD file won't hold any info about it.
114
115 In readdir, we assume that for the root directory
116 the read position will be 0 for ".", 1 for "..". For
117 a non root directory, the read position will be 0 for "."
118 and 32 for "..".
119 */
120 /*
121 This is a trick used by the msdos file system (fs/msdos/dir.c)
122 to manage . and .. for the root directory of a file system.
123 Since there is no such entry in the root, fs/msdos/dir.c
124 use the following:
125
126 if f_pos == 0, return ".".
127 if f_pos == 1, return "..".
128
129 So let msdos handle it
130
131 Since umsdos entries are much larger, we share the same f_pos.
132 if f_pos is 0 or 1 or 32, we are clearly looking at . and
133 ..
134
135 As soon as we get f_pos == 2 or f_pos == 64, then back to
136 0, but this time we are reading the EMD file.
137
138 Well, not so true. The problem, is that UMSDOS_REC_SIZE is
139 also 64, so as soon as we read the first record in the
140 EMD, we are back at offset 64. So we set the offset
141 to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
142 .. entry from msdos.
143
144 Now (linux 1.3), umsdos_readdir can read more than one
145 entry even if we limit (umsdos_dir_once) to only one:
146 It skips over hidden file. So we switch to
147 UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
148 the .. entry.
149 */
150 int last_f_pos = filp->f_pos;
151 struct UMSDOS_DIR_ONCE bufk;
152 bufk.dirbuf = dirbuf;
153 bufk.filldir = filldir;
154 bufk.count = 0;
155 ret = msdos_readdir(dir,filp,&bufk,umsdos_dir_once);
156 if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
157 if (u_entry != NULL) u_entry->flags = 0;
158 }else{
159 struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
160 if (emd_dir != NULL){
161 off_t start_fpos = filp->f_pos;
162 if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
163 PRINTK (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size));
164 ret = 0;
165 while (filp->f_pos < emd_dir->i_size){
166 struct umsdos_dirent entry;
167 off_t cur_f_pos = filp->f_pos;
168 if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
169 ret = -EIO;
170 break;
171 }else if (entry.name_len != 0){
172 /* #Specification: umsdos / readdir
173 umsdos_readdir() should fill a struct dirent with
174 an inode number. The cheap way to get it is to
175 do a lookup in the MSDOS directory for each
176 entry processed by the readdir() function.
177 This is not very efficient, but very simple. The
178 other way around is to maintain a copy of the inode
179 number in the EMD file. This is a problem because
180 this has to be maintained in sync using tricks.
181 Remember that MSDOS (the OS) does not update the
182 modification time (mtime) of a directory. There is
183 no easy way to tell that a directory was modified
184 during a DOS session and synchronise the EMD file.
185
186 Suggestion welcome.
187
188 So the easy way is used!
189 */
190 struct umsdos_info info;
191 struct inode *inode;
192 int lret;
193 umsdos_parse (entry.name,entry.name_len,&info);
194 info.f_pos = cur_f_pos;
195 umsdos_manglename (&info);
196 lret = umsdos_real_lookup (dir,info.fake.fname
197 ,info.fake.len,&inode);
198 PRINTK (("Cherche inode de %s lret %d flags %d\n"
199 ,info.fake.fname,lret,entry.flags));
200 if (lret == 0
201 && (entry.flags & UMSDOS_HLINK)
202 && follow_hlink){
203 struct inode *rinode;
204 lret = umsdos_hlink2inode (inode,&rinode);
205 inode = rinode;
206 }
207 if (lret == 0){
208 /* #Specification: pseudo root / reading real root
209 The pseudo root (/linux) is logically
210 erased from the real root. This mean that
211 ls /DOS, won't show "linux". This avoids
212 infinite recursion /DOS/linux/DOS/linux while
213 walking the file system.
214 */
215 if (inode != pseudo_root
216 && (internal_read
217 || !(entry.flags & UMSDOS_HIDDEN))){
218 if (filldir (dirbuf
219 ,entry.name,entry.name_len
220 ,cur_f_pos, inode->i_ino) < 0){
221 filp->f_pos = cur_f_pos;
222 }
223 PRINTK (("Trouve ino %ld ",inode->i_ino));
224 if (u_entry != NULL) *u_entry = entry;
225 iput (inode);
226 break;
227 }
228 iput (inode);
229 }else{
230 /* #Specification: umsdos / readdir / not in MSDOS
231 During a readdir operation, if the file is not
232 in the MSDOS directory anymore, the entry is
233 removed from the EMD file silently.
234 */
235 ret = umsdos_writeentry (dir,emd_dir,&info,1);
236 if (ret != 0){
237 break;
238 }
239 }
240 }
241 }
242 /*
243 If the fillbuf has failed, f_pos is back to 0.
244 To avoid getting back into the . and .. state
245 (see comments at the beginning), we put back
246 the special offset.
247 */
248 if (filp->f_pos == 0) filp->f_pos = start_fpos;
249 iput(emd_dir);
250 }
251 }
252 umsdos_endlookup(dir);
253 PRINTK (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret));
254 return ret;
255 }
256 /*
257 Read count directory entries from directory filp
258 Return a negative value from linux/errno.h.
259 Return 0 or positive if successful
260 */
261 static int UMSDOS_readdir(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
262 struct inode *dir, /* Point to a description of the super block */
263 struct file *filp, /* Point to a directory which is read */
264 void *dirbuf, /* Will hold directory entries */
265 filldir_t filldir)
266 {
267 int ret = 0;
268 int count = 0;
269 struct UMSDOS_DIR_ONCE bufk;
270 bufk.dirbuf = dirbuf;
271 bufk.filldir = filldir;
272 bufk.stop = 0;
273 PRINTK (("UMSDOS_readdir in\n"));
274 while (ret == 0 && bufk.stop == 0){
275 struct umsdos_dirent entry;
276 bufk.count = 0;
277 ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once);
278 if (bufk.count == 0) break;
279 count += bufk.count;
280 }
281 PRINTK (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count
282 ,filp->f_pos));
283 return count?:ret;
284 }
285 /*
286 Complete the inode content with info from the EMD file
287 */
288 void umsdos_lookup_patch (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
289 struct inode *dir,
290 struct inode *inode,
291 struct umsdos_dirent *entry,
292 off_t emd_pos)
293 {
294 /*
295 This function modify the state of a dir inode. It decides
296 if the dir is a umsdos dir or a dos dir. This is done
297 deeper in umsdos_patch_inode() called at the end of this function.
298
299 umsdos_patch_inode() may block because it is doing disk access.
300 At the same time, another process may get here to initialise
301 the same dir inode. There is 3 cases.
302
303 1-The inode is already initialised. We do nothing.
304 2-The inode is not initialised. We lock access and do it.
305 3-Like 2 but another process has lock the inode, so we try
306 to lock it and right after check if initialisation is still
307 needed.
308
309
310 Thanks to the mem option of the kernel command line, it was
311 possible to consistently reproduce this problem by limiting
312 my mem to 4 meg and running X.
313 */
314 /*
315 Do this only if the inode is freshly read, because we will lose
316 the current (updated) content.
317 */
318 /*
319 A lookup of a mount point directory yield the inode into
320 the other fs, so we don't care about initialising it. iget()
321 does this automatically.
322 */
323 if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
324 if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
325 if (!umsdos_isinit(inode)){
326 /* #Specification: umsdos / lookup / inode info
327 After successfully reading an inode from the MSDOS
328 filesystem, we use the EMD file to complete it.
329 We update the following field.
330
331 uid, gid, atime, ctime, mtime, mode.
332
333 We rely on MSDOS for mtime. If the file
334 was modified during an MSDOS session, at least
335 mtime will be meaningful. We do this only for regular
336 file.
337
338 We don't rely on MSDOS for mtime for directory because
339 the MSDOS directory date is creation time (strange
340 MSDOS behavior) which fit nowhere in the three UNIX
341 time stamp.
342 */
343 if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
344 inode->i_mode = entry->mode;
345 inode->i_rdev = to_kdev_t(entry->rdev);
346 inode->i_atime = entry->atime;
347 inode->i_ctime = entry->ctime;
348 inode->i_mtime = entry->mtime;
349 inode->i_uid = entry->uid;
350 inode->i_gid = entry->gid;
351 /* #Specification: umsdos / conversion mode
352 The msdos fs can do some inline conversion
353 of the data of a file. It can translate
354 silently from MsDOS text file format to Unix
355 one (crlf -> lf) while reading, and the reverse
356 while writting. This is activated using the mount
357 option conv=....
358
359 This is not useful for Linux file in promoted
360 directory. It can even be harmful. For this
361 reason, the binary (no conversion) mode is
362 always activated.
363 */
364 /* #Specification: umsdos / conversion mode / todo
365 A flag could be added to file and directories
366 forcing an automatic conversion mode (as
367 done with the msdos fs).
368
369 This flag could be setup on a directory basis
370 (instead of file) and all file in it would
371 logically inherited. If the conversion mode
372 is active (conv=) then the i_binary flag would
373 be left untouched in those directories.
374
375 It was proposed that the sticky bit was used
376 to set this. The problem is that new file would
377 be written incorrectly. The other problem is that
378 the sticky bit has a meaning for directories. So
379 another bit should be used (there is some space
380 in the EMD file for it) and a special utilities
381 would be used to assign the flag to a directory).
382 I don't think it is useful to assign this flag
383 on a single file.
384 */
385
386 MSDOS_I(inode)->i_binary = 1;
387 /* #Specification: umsdos / i_nlink
388 The nlink field of an inode is maintain by the MSDOS file system
389 for directory and by UMSDOS for other file. The logic is that
390 MSDOS is already figuring out what to do for directories and
391 does nothing for other files. For MSDOS, there are no hard link
392 so all file carry nlink==1. UMSDOS use some info in the
393 EMD file to plug the correct value.
394 */
395 if (!S_ISDIR(entry->mode)){
396 if (entry->nlink > 0){
397 inode->i_nlink = entry->nlink;
398 }else{
399 printk ("UMSDOS: lookup_patch entry->nlink < 1 ???\n");
400 }
401 }
402 umsdos_patch_inode(inode,dir,emd_pos);
403 }
404 if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
405 if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
406 }
407 }
408 struct UMSDOS_DIRENT_K{
409 off_t f_pos; /* will hold the offset of the entry in EMD */
410 ino_t ino;
411 };
412
413 /*
414 Just to record the offset of one entry.
415 */
416 static int umsdos_filldir_k(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
417 void * buf,
418 const char * name,
419 int name_len,
420 off_t offset,
421 ino_t ino)
422 {
423 struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf;
424 d->f_pos = offset;
425 d->ino = ino;
426 return 0;
427 }
428
429 struct UMSDOS_DIR_SEARCH{
430 struct umsdos_dirent *entry;
431 int found;
432 ino_t search_ino;
433 };
434
435 static int umsdos_dir_search (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
436 void * buf,
437 const char * name,
438 int name_len,
439 off_t offset,
440 ino_t ino)
441 {
442 int ret = 0;
443 struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf;
444 if (d->search_ino == ino){
445 d->found = 1;
446 memcpy (d->entry->name,name,name_len);
447 d->entry->name[name_len] = '\0';
448 d->entry->name_len = name_len;
449 ret = 1; /* So msdos_readdir will terminate */
450 }
451 return ret;
452 }
453
454
455 /*
456 Locate entry of an inode in a directory.
457 Return 0 or a negative error code.
458
459 Normally, this function must succeed. It means a strange corruption
460 in the file system if not.
461 */
462 int umsdos_inode2entry (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
463 struct inode *dir,
464 struct inode *inode,
465 struct umsdos_dirent *entry) /* Will hold the entry */
466 {
467 int ret = -ENOENT;
468 if (inode == pseudo_root){
469 /*
470 Quick way to find the name.
471 Also umsdos_readdir_x won't show /linux anyway
472 */
473 memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
474 entry->name_len = UMSDOS_PSDROOT_LEN;
475 ret = 0;
476 }else{
477 struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
478 iput (emddir);
479 if (emddir == NULL){
480 /* This is a DOS directory */
481 struct UMSDOS_DIR_SEARCH bufk;
482 struct file filp;
483 filp.f_reada = 1;
484 filp.f_pos = 0;
485 bufk.entry = entry;
486 bufk.search_ino = inode->i_ino;
487 msdos_readdir (dir,&filp,&bufk,umsdos_dir_search);
488 if (bufk.found){
489 ret = 0;
490 inode->u.umsdos_i.i_dir_owner = dir->i_ino;
491 inode->u.umsdos_i.i_emd_owner = 0;
492 umsdos_setup_dir_inode(inode);
493 }
494 }else{
495 /* skip . and .. see umsdos_readdir_x() */
496 struct file filp;
497 filp.f_reada = 1;
498 filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
499 while (1){
500 struct UMSDOS_DIRENT_K bufk;
501 if (umsdos_readdir_x(dir,&filp,&bufk
502 ,1,entry,0,umsdos_filldir_k) < 0){
503 printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
504 ,inode->i_ino);
505 break;
506 }else if (bufk.ino == inode->i_ino){
507 ret = 0;
508 umsdos_lookup_patch (dir,inode,entry,bufk.f_pos);
509 break;
510 }
511 }
512 }
513 }
514 return ret;
515 }
516 /*
517 Locate the parent of a directory and the info on that directory
518 Return 0 or a negative error code.
519 */
520 static int umsdos_locate_ancestor (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
521 struct inode *dir,
522 struct inode **result,
523 struct umsdos_dirent *entry)
524 {
525 int ret;
526 umsdos_patch_inode (dir,NULL,0);
527 ret = umsdos_real_lookup (dir,"..",2,result);
528 PRINTK (("result %d %p ",ret,*result));
529 if (ret == 0){
530 struct inode *adir = *result;
531 ret = umsdos_inode2entry (adir,dir,entry);
532 }
533 PRINTK (("\n"));
534 return ret;
535 }
536 /*
537 Build the path name of an inode (relative to the file system.
538 This function is need to set (pseudo) hard link.
539
540 It uses the same strategy as the standard getcwd().
541 */
542 int umsdos_locate_path (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
543 struct inode *inode,
544 char *path)
545 {
546 int ret = 0;
547 struct inode *dir = inode;
548 char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
549 if (bpath == NULL){
550 ret = -ENOMEM;
551 }else{
552 struct umsdos_dirent entry;
553 char *ptbpath = bpath+PATH_MAX-1;
554 *ptbpath = '\0';
555 PRINTK (("locate_path mode %x ",inode->i_mode));
556 if (!S_ISDIR(inode->i_mode)){
557 ret = umsdos_get_dirowner (inode,&dir);
558 PRINTK (("locate_path ret %d ",ret));
559 if (ret == 0){
560 ret = umsdos_inode2entry (dir,inode,&entry);
561 if (ret == 0){
562 ptbpath -= entry.name_len;
563 memcpy (ptbpath,entry.name,entry.name_len);
564 PRINTK (("ptbpath :%s: ",ptbpath));
565 }
566 }
567 }else{
568 dir->i_count++;
569 }
570 if (ret == 0){
571 while (dir != dir->i_sb->s_mounted){
572 struct inode *adir;
573 ret = umsdos_locate_ancestor (dir,&adir,&entry);
574 iput (dir);
575 dir = NULL;
576 PRINTK (("ancestor %d ",ret));
577 if (ret == 0){
578 *--ptbpath = '/';
579 ptbpath -= entry.name_len;
580 memcpy (ptbpath,entry.name,entry.name_len);
581 dir = adir;
582 PRINTK (("ptbpath :%s: ",ptbpath));
583 }else{
584 break;
585 }
586 }
587 }
588 strcpy (path,ptbpath);
589 kfree (bpath);
590 }
591 PRINTK (("\n"));
592 iput (dir);
593 return ret;
594 }
595
596 /*
597 Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
598 */
599 int umsdos_is_pseudodos (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
600 struct inode *dir,
601 const char *name,
602 int len)
603 {
604 /* #Specification: pseudo root / DOS hard coded
605 The pseudo sub-directory DOS in the pseudo root is hard coded.
606 The name is DOS. This is done this way to help standardised
607 the umsdos layout. The idea is that from now on /DOS is
608 a reserved path and nobody will think of using such a path
609 for a package.
610 */
611 return dir == pseudo_root
612 && len == 3
613 && name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
614 }
615 /*
616 Check if a file exist in the current directory.
617 Return 0 if ok, negative error code if not (ex: -ENOENT).
618 */
619 static int umsdos_lookup_x (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
620 struct inode *dir,
621 const char *name,
622 int len,
623 struct inode **result, /* Will hold inode of the file, if successful */
624 int nopseudo) /* Don't care about pseudo root mode */
625 {
626 int ret = -ENOENT;
627 *result = NULL;
628 umsdos_startlookup(dir);
629 if (len == 1 && name[0] == '.'){
630 *result = dir;
631 dir->i_count++;
632 ret = 0;
633 }else if (len == 2 && name[0] == '.' && name[1] == '.'){
634 if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
635 /* #Specification: pseudo root / .. in real root
636 Whenever a lookup is those in the real root for
637 the directory .., and pseudo root is active, the
638 pseudo root is returned.
639 */
640 ret = 0;
641 *result = pseudo_root;
642 pseudo_root->i_count++;
643 }else{
644 /* #Specification: locating .. / strategy
645 We use the msdos filesystem to locate the parent directory.
646 But it is more complicated than that.
647
648 We have to step back even further to
649 get the parent of the parent, so we can get the EMD
650 of the parent of the parent. Using the EMD file, we can
651 locate all the info on the parent, such a permissions
652 and owner.
653 */
654 ret = umsdos_real_lookup (dir,"..",2,result);
655 PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
656 if (ret == 0
657 && *result != dir->i_sb->s_mounted
658 && *result != pseudo_root){
659 struct inode *aadir;
660 struct umsdos_dirent entry;
661 ret = umsdos_locate_ancestor (*result,&aadir,&entry);
662 iput (aadir);
663 }
664 }
665 }else if (umsdos_is_pseudodos(dir,name,len)){
666 /* #Specification: pseudo root / lookup(DOS)
667 A lookup of DOS in the pseudo root will always succeed
668 and return the inode of the real root.
669 */
670 *result = dir->i_sb->s_mounted;
671 (*result)->i_count++;
672 ret = 0;
673 }else{
674 struct umsdos_info info;
675 ret = umsdos_parse (name,len,&info);
676 if (ret == 0) ret = umsdos_findentry (dir,&info,0);
677 PRINTK (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret
678 ,info.fake.len));
679 if (ret == 0){
680 /* #Specification: umsdos / lookup
681 A lookup for a file is done in two step. First, we locate
682 the file in the EMD file. If not present, we return
683 an error code (-ENOENT). If it is there, we repeat the
684 operation on the msdos file system. If this fails, it means
685 that the file system is not in sync with the emd file.
686 We silently remove this entry from the emd file,
687 and return ENOENT.
688 */
689 struct inode *inode;
690 ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
691 inode = *result;
692 if (inode == NULL){
693 printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
694 ,info.fake.fname);
695 umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
696 }else{
697 umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
698 PRINTK (("lookup ino %ld flags %d\n",inode->i_ino
699 ,info.entry.flags));
700 if (info.entry.flags & UMSDOS_HLINK){
701 ret = umsdos_hlink2inode (inode,result);
702 }
703 if (*result == pseudo_root && !nopseudo){
704 /* #Specification: pseudo root / dir lookup
705 For the same reason as readdir, a lookup in /DOS for
706 the pseudo root directory (linux) will fail.
707 */
708 /*
709 This has to be allowed for resolving hard link
710 which are recorded independently of the pseudo-root
711 mode.
712 */
713 iput (pseudo_root);
714 *result = NULL;
715 ret = -ENOENT;
716 }
717 }
718 }
719 }
720 umsdos_endlookup(dir);
721 iput (dir);
722 return ret;
723 }
724 /*
725 Check if a file exist in the current directory.
726 Return 0 if ok, negative error code if not (ex: -ENOENT).
727 */
728 int UMSDOS_lookup (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
729 struct inode *dir,
730 const char *name,
731 int len,
732 struct inode **result) /* Will hold inode of the file, if successful */
733 {
734 return umsdos_lookup_x(dir,name,len,result,0);
735 }
736 /*
737 Locate the inode pointed by a (pseudo) hard link
738 Return 0 if ok, a negative error code if not.
739 */
740 int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
741 {
742 int ret = -EIO;
743 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
744 *result = NULL;
745 if (path == NULL){
746 ret = -ENOMEM;
747 iput (hlink);
748 }else{
749 struct file filp;
750 filp.f_reada = 1;
751 filp.f_pos = 0;
752 PRINTK (("hlink2inode "));
753 if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size)
754 ==hlink->i_size){
755 struct inode *dir;
756 char *pt = path;
757 dir = hlink->i_sb->s_mounted;
758 path[hlink->i_size] = '\0';
759 iput (hlink);
760 dir->i_count++;
761 while (1){
762 char *start = pt;
763 int len;
764 while (*pt != '\0' && *pt != '/') pt++;
765 len = (int)(pt - start);
766 if (*pt == '/') *pt++ = '\0';
767 if (dir->u.umsdos_i.i_emd_dir == 0){
768 /* This is a DOS directory */
769 ret = umsdos_rlookup_x(dir,start,len,result,1);
770 }else{
771 ret = umsdos_lookup_x(dir,start,len,result,1);
772 }
773 PRINTK (("h2n lookup :%s: -> %d ",start,ret));
774 if (ret == 0 && *pt != '\0'){
775 dir = *result;
776 }else{
777 break;
778 }
779 }
780 }else{
781 iput (hlink);
782 }
783 PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
784 kfree (path);
785 }
786 return ret;
787 }
788
789 static struct file_operations umsdos_dir_operations = {
790 NULL, /* lseek - default */
791 UMSDOS_dir_read, /* read */
792 NULL, /* write - bad */
793 UMSDOS_readdir, /* readdir */
794 NULL, /* select - default */
795 UMSDOS_ioctl_dir, /* ioctl - default */
796 NULL, /* mmap */
797 NULL, /* no special open code */
798 NULL, /* no special release code */
799 NULL /* fsync */
800 };
801
802 struct inode_operations umsdos_dir_inode_operations = {
803 &umsdos_dir_operations, /* default directory file-ops */
804 UMSDOS_create, /* create */
805 UMSDOS_lookup, /* lookup */
806 UMSDOS_link, /* link */
807 UMSDOS_unlink, /* unlink */
808 UMSDOS_symlink, /* symlink */
809 UMSDOS_mkdir, /* mkdir */
810 UMSDOS_rmdir, /* rmdir */
811 UMSDOS_mknod, /* mknod */
812 UMSDOS_rename, /* rename */
813 NULL, /* readlink */
814 NULL, /* follow_link */
815 NULL, /* bmap */
816 NULL, /* truncate */
817 NULL /* permission */
818 };
819
820
821
822
823
824
825
826
827
828