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 #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 So grep * doesn't complain in the presence of directories.
33 */
34 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)
*/
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 Read count directory entries from directory filp
44 Return a negative value from linux/errno.h.
45 Return > 0 if success (The amount of byte written in
46 dirent round_up to a word size (32 bits).
47
48 This function is used by the normal readdir VFS entry point and by
49 some function who try to find out info on a file from a pure MSDOS
50 inode. See umsdos_locate_ancestor() below.
51 */
52 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)
*/
53 struct inode *dir, /* Point to a description of the super block */
54 struct file *filp, /* Point to a directory which is read */
55 struct dirent *dirent, /* Will hold count directory entry */
56 int dirent_in_fs, /* dirent point in user's space ? */
57 int count,
58 struct umsdos_dirent *u_entry, /* Optional umsdos entry */
59 int follow_hlink,
60 off_t *pt_f_pos) /* will hold the offset of the entry in EMD */
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 We don't need to simulate this pseudo directory
70 when umsdos_readdir_x is called for internal operation
71 of umsdos. This is why dirent_in_fs is tested
72 */
73 /* #Specification: pseudo root / directory /DOS
74 When umsdos operates in pseudo root mode (C:\linux is the
75 linux root), it simulate a directory /DOS which points to
76 the real root of the file system.
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 /* #Specification: readdir / . and ..
88 The msdos filesystem manage the . and .. entry properly
89 so the EMD file won't hold any info about it.
90
91 In readdir, we assume that for the root directory
92 the read position will be 0 for ".", 1 for "..". For
93 a non root directory, the read position will be 0 for "."
94 and 32 for "..".
95 */
96 /*
97 This is a trick used by the msdos file system (fs/msdos/dir.c)
98 to manage . and .. for the root directory of a file system.
99 Since there is no such entry in the root, fs/msdos/dir.c
100 use the following:
101
102 if f_pos == 0, return ".".
103 if f_pos == 1, return "..".
104
105 So let msdos handle it
106
107 Since umsdos entries are much larger, we share the same f_pos.
108 if f_pos is 0 or 1 or 32, we are clearly looking at . and
109 ..
110
111 As soon as we get f_pos == 2 or f_pos == 64, then back to
112 0, but this time we are reading the EMD file.
113
114 Well, not so true. The problem, is that UMSDOS_REC_SIZE is
115 also 64, so as soon as we read the first record in the
116 EMD, we are back at offset 64. So we set the offset
117 to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
118 .. entry from msdos.
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 /* #Specification: umsdos / readdir
137 umsdos_readdir() should fill a struct dirent with
138 an inode number. The cheap way to get it is to
139 do a lookup in the MSDOS directory for each
140 entry processed by the readdir() function.
141 This is not very efficient, but very simple. The
142 other way around is to maintain a copy of the inode
143 number in the EMD file. This is a problem because
144 this has to be maintained in sync using tricks.
145 Remember that MSDOS (the OS) does not update the
146 modification time (mtime) of a directory. There is
147 no easy way to tell that a directory was modified
148 during a DOS session and synchronise the EMD file.
149
150 Suggestion welcome.
151
152 So the easy way is used!
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 /* #Specification: pseudo root / reading real root
174 The pseudo root (/linux) is logically
175 erased from the real root. This mean that
176 ls /DOS, won't show "linux". This avoids
177 infinite recursion /DOS/linux/DOS/linux while
178 walking the file system.
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 /* In this case, the caller only needs */
190 /* flags */
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 /* #Specification: umsdos / readdir / not in MSDOS
209 During a readdir operation, if the file is not
210 in the MSDOS directory anymore, the entry is
211 removed from the EMD file silently.
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 Read count directory entries from directory filp
229 Return a negative value from linux/errno.h.
230 Return > 0 if success (the amount of byte written to dirent)
231 */
232 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)
*/
233 struct inode *dir, /* Point to a description of the super block */
234 struct file *filp, /* Point to a directory which is read */
235 struct dirent *dirent, /* Will hold count directory entry */
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 Complete the inode content with info from the EMD file
249 */
250 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)
*/
251 struct inode *dir,
252 struct inode *inode,
253 struct umsdos_dirent *entry,
254 off_t emd_pos)
255 {
256 /*
257 This function modify the state of a dir inode. It decides
258 if the dir is a umsdos dir or a dos dir. This is done
259 deeper in umsdos_patch_inode() called at the end of this function.
260
261 umsdos_patch_inode() may block because it is doing disk access.
262 At the same time, another process may get here to initialise
263 the same dir inode. There is 3 cases.
264
265 1-The inode is already initialised. We do nothing.
266 2-The inode is not initialised. We lock access and do it.
267 3-Like 2 but another process has lock the inode, so we try
268 to lock it and right after check if initialisation is still
269 needed.
270
271
272 Thanks to the mem option of the kernel command line, it was
273 possible to consistently reproduce this problem by limiting
274 my mem to 4 meg and running X.
275 */
276 /*
277 Do this only if the inode is freshly read, because we will lose
278 the current (updated) content.
279 */
280 /*
281 A lookup of a mount point directory yield the inode into
282 the other fs, so we don't care about initialising it. iget()
283 does this automatically.
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 /* #Specification: umsdos / lookup / inode info
289 After successfully reading an inode from the MSDOS
290 filesystem, we use the EMD file to complete it.
291 We update the following field.
292
293 uid, gid, atime, ctime, mtime, mode.
294
295 We rely on MSDOS for mtime. If the file
296 was modified during an MSDOS session, at least
297 mtime will be meaningful. We do this only for regular
298 file.
299
300 We don't rely on MSDOS for mtime for directory because
301 the MSDOS directory date is creation time (strange
302 MSDOS behavior) which fit nowhere in the three UNIX
303 time stamp.
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 /* #Specification: umsdos / i_nlink
314 The nlink field of an inode is maintain by the MSDOS file system
315 for directory and by UMSDOS for other file. The logic is that
316 MSDOS is already figuring out what to do for directories and
317 does nothing for other files. For MSDOS, there are no hard link
318 so all file carry nlink==1. UMSDOS use some info in the
319 EMD file to plug the correct value.
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 Locate entry of an inode in a directory.
336 Return 0 or a negative error code.
337
338 Normally, this function must succeed. It means a strange corruption
339 in the file system if not.
340 */
341 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)
*/
342 struct inode *dir,
343 struct inode *inode,
344 struct umsdos_dirent *entry) /* Will hold the entry */
345 {
346 int ret = -ENOENT;
347 if (inode == pseudo_root){
348 /*
349 Quick way to find the name.
350 Also umsdos_readdir_x won't show /linux anyway
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 /* This is a DOS directory */
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 /* skip . and .. see umsdos_readdir_x() */
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 Locate the parent of a directory and the info on that directory
404 Return 0 or a negative error code.
405 */
406 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)
*/
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 Build the path name of an inode (relative to the file system.
424 This function is need to set (pseudo) hard link.
425
426 It uses the same strategy as the standard getcwd().
427 */
428 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)
*/
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 Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
484 */
485 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)
*/
486 struct inode *dir,
487 const char *name,
488 int len)
489 {
490 /* #Specification: pseudo root / DOS hard coded
491 The pseudo sub-directory DOS in the pseudo root is hard coded.
492 The name is DOS. This is done this way to help standardised
493 the umsdos layout. The idea is that from now on /DOS is
494 a reserved path and nobody will think of using such a path
495 for a package.
496 */
497 return dir == pseudo_root
498 && len == 3
499 && name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
500 }
501 /*
502 Check if a file exist in the current directory.
503 Return 0 if ok, negative error code if not (ex: -ENOENT).
504 */
505 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)
*/
506 struct inode *dir,
507 const char *name,
508 int len,
509 struct inode **result, /* Will hold inode of the file, if successful */
510 int nopseudo) /* Don't care about pseudo root mode */
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 /* #Specification: pseudo root / .. in real root
522 Whenever a lookup is those in the real root for
523 the directory .., and pseudo root is active, the
524 pseudo root is returned.
525 */
526 ret = 0;
527 *result = pseudo_root;
528 pseudo_root->i_count++;
529 }else{
530 /* #Specification: locating .. / strategy
531 We use the msdos filesystem to locate the parent directory.
532 But it is more complicated than that.
533
534 We have to step back even further to
535 get the parent of the parent, so we can get the EMD
536 of the parent of the parent. Using the EMD file, we can
537 locate all the info on the parent, such a permissions
538 and owner.
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 /* #Specification: pseudo root / lookup(DOS)
553 A lookup of DOS in the pseudo root will always succeed
554 and return the inode of the real root.
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 /* #Specification: umsdos / lookup
567 A lookup for a file is done in two step. First, we locate
568 the file in the EMD file. If not present, we return
569 an error code (-ENOENT). If it is there, we repeat the
570 operation on the msdos file system. If this fails, it means
571 that the file system is not in sync with the emd file.
572 We silently remove this entry from the emd file,
573 and return ENOENT.
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 /* #Specification: pseudo root / dir lookup
591 For the same reason as readdir, a lookup in /DOS for
592 the pseudo root directory (linux) will fail.
593 */
594 /*
595 This has to be allowed for resolving hard link
596 which are recorded independently of the pseudo-root
597 mode.
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 Check if a file exist in the current directory.
612 Return 0 if ok, negative error code if not (ex: -ENOENT).
613 */
614 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)
*/
615 struct inode *dir,
616 const char *name,
617 int len,
618 struct inode **result) /* Will hold inode of the file, if successful */
619 {
620 return umsdos_lookup_x(dir,name,len,result,0);
621 }
622 /*
623 Locate the inode pointed by a (pseudo) hard link
624 Return 0 if ok, a negative error code if not.
625 */
626 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)
*/
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 /* This is a DOS directory */
655 ret = umsdos_rlookup_x(dir,start,len,result,1);
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, /* lseek - default */
677 UMSDOS_dir_read, /* read */
678 NULL, /* write - bad */
679 UMSDOS_readdir, /* readdir */
680 NULL, /* select - default */
681 UMSDOS_ioctl_dir, /* ioctl - default */
682 NULL, /* mmap */
683 NULL, /* no special open code */
684 NULL, /* no special release code */
685 NULL /* fsync */
686 };
687
688 struct inode_operations umsdos_dir_inode_operations = {
689 &umsdos_dir_operations, /* default directory file-ops */
690 UMSDOS_create, /* create */
691 UMSDOS_lookup, /* lookup */
692 UMSDOS_link, /* link */
693 UMSDOS_unlink, /* unlink */
694 UMSDOS_symlink, /* symlink */
695 UMSDOS_mkdir, /* mkdir */
696 UMSDOS_rmdir, /* rmdir */
697 UMSDOS_mknod, /* mknod */
698 UMSDOS_rename, /* rename */
699 NULL, /* readlink */
700 NULL, /* follow_link */
701 NULL, /* bmap */
702 NULL, /* truncate */
703 NULL /* permission */
704 };
705
706
707
708
709
710
711
712
713
714