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