1 /*
2 * linux/fs/umsdos/inode.c
3 *
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... by Werner Almesberger
6 *
7 */
8
9 #include <stdlib.h>
10 #include <linux/fs.h>
11 #include <linux/msdos_fs.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/errno.h>
15 #include <asm/segment.h>
16 #include <linux/string.h>
17 #include <linux/ctype.h>
18 #include <linux/stat.h>
19 #include <linux/umsdos_fs.h>
20
21 #ifdef MODULE
22 #include <linux/module.h>
23 #include "../../tools/version.h"
24 #endif
25
26 struct inode *pseudo_root=NULL; /* Useful to simulate the pseudo DOS */
27 /* directory. See UMSDOS_readdir_x() */
28
29 /* #Specification: convention / PRINTK Printk and printk
30 Here is the convention for the use of printk inside fs/umsdos
31
32 printk carry important message (error or status).
33 Printk is for debugging (it is a macro defined at the beginning of
34 most source.
35 PRINTK is a nulled Printk macro.
36
37 This convention makes the source easier to read, and Printk easier
38 to shut off.
39 */
40 #define PRINTK(x)
41 #define Printk(x) printk x
42
43
44 void UMSDOS_put_inode(struct inode *inode)
/* ![[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)
*/
45 {
46 PRINTK (("put inode %x owner %x pos %d dir %x\n",inode
47 ,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
48 ,inode->u.umsdos_i.i_emd_dir));
49 msdos_put_inode(inode);
50 }
51
52
53 void UMSDOS_put_super(struct super_block *sb)
/* ![[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)
*/
54 {
55 msdos_put_super(sb);
56 #ifdef MODULE
57 MOD_DEC_USE_COUNT;
58 #endif
59 }
60
61
62 void UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
/* ![[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)
*/
63 {
64 msdos_statfs(sb,buf);
65 }
66
67
68 /*
69 Call msdos_lookup, but set back the original msdos function table.
70 Return 0 if ok, or a negative error code if not.
71 */
72 int umsdos_real_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)
*/
73 struct inode *dir,
74 const char *name,
75 int len,
76 struct inode **result) /* Will hold inode of the file, if successful */
77 {
78 int ret;
79 dir->i_count++;
80 ret = msdos_lookup (dir,name,len,result);
81 return ret;
82 }
83 /*
84 Complete the setup of an directory inode.
85 First, it completes the function pointers, then
86 it locates the EMD file. If the EMD is there, then plug the
87 umsdos function table. If not, use the msdos one.
88 */
89 void umsdos_setup_dir_inode (struct inode *inode)
/* ![[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)
*/
90 {
91 inode->u.umsdos_i.i_emd_dir = 0;
92 {
93 struct inode *emd_dir = umsdos_emd_dir_lookup (inode,0);
94 extern struct inode_operations umsdos_rdir_inode_operations;
95 inode->i_op = emd_dir != NULL
96 ? &umsdos_dir_inode_operations
97 : &umsdos_rdir_inode_operations;
98 iput (emd_dir);
99 }
100 }
101 /*
102 Add some info into an inode so it can find its owner quickly
103 */
104 void umsdos_set_dirinfo(
/* ![[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)
*/
105 struct inode *inode,
106 struct inode *dir,
107 off_t f_pos)
108 {
109 struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
110 inode->u.umsdos_i.i_dir_owner = dir->i_ino;
111 inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
112 iput (emd_owner);
113 inode->u.umsdos_i.pos = f_pos;
114 }
115 /*
116 Tells if an Umsdos inode has been "patched" once.
117 Return != 0 if so.
118 */
119 int umsdos_isinit (struct inode *inode)
/* ![[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)
*/
120 {
121 #if 1
122 return inode->u.umsdos_i.i_emd_owner != 0;
123 #elif 0
124 return inode->i_atime != 0;
125 #else
126 return inode->i_count > 1;
127 #endif
128 }
129 /*
130 Connect the proper tables in the inode and add some info.
131 */
132 void umsdos_patch_inode (
/* ![[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)
*/
133 struct inode *inode,
134 struct inode *dir, /* May be NULL */
135 off_t f_pos)
136 {
137 /*
138 This function is called very early to setup the inode, somewhat
139 too early (called by UMSDOS_read_inode). At this point, we can't
140 do to much, such as lookup up EMD files and so on. This causes
141 confusion in the kernel. This is why some initialisation
142 will be done when dir != NULL only.
143
144 UMSDOS do run piggy back on top of msdos fs. It looks like something
145 is missing in the VFS to accommodate stacked fs. Still unclear what
146 (quite honestly).
147
148 Well, maybe one! A new entry "may_unmount" which would allow
149 the stacked fs to allocate some inode permanently and release
150 them at the end. Doing that now introduce a problem. unmount
151 always fail because some inodes are in use.
152 */
153 if (!umsdos_isinit(inode)){
154 inode->u.umsdos_i.i_emd_dir = 0;
155 if (S_ISREG(inode->i_mode)){
156 static char is_init = 0;
157 if (!is_init){
158 /*
159 I don't want to change the msdos file system code
160 so I get the address of some subroutine dynamically
161 once.
162 */
163 umsdos_file_inode_operations.bmap = inode->i_op->bmap;
164 inode->i_op = &umsdos_file_inode_operations;
165 is_init = 1;
166 }
167 inode->i_op = &umsdos_file_inode_operations;
168 }else if (S_ISDIR(inode->i_mode)){
169 if (dir != NULL){
170 umsdos_setup_dir_inode(inode);
171 }
172 }else if (S_ISLNK(inode->i_mode)){
173 inode->i_op = &umsdos_symlink_inode_operations;
174 }else if (S_ISCHR(inode->i_mode)){
175 inode->i_op = &chrdev_inode_operations;
176 }else if (S_ISBLK(inode->i_mode)){
177 inode->i_op = &blkdev_inode_operations;
178 }else if (S_ISFIFO(inode->i_mode)){
179 init_fifo(inode);
180 }
181 if (dir != NULL){
182 /* #Specification: inode / umsdos info
183 The first time an inode is seen (inode->i_count == 1),
184 the inode number of the EMD file which control this inode
185 is tagged to this inode. It allows operation such
186 as notify_change to be handled.
187 */
188 /*
189 This is done last because it also control the
190 status of umsdos_isinit()
191 */
192 umsdos_set_dirinfo (inode,dir,f_pos);
193 }
194 }else if (dir != NULL){
195 /*
196 Test to see if the info is maintained.
197 This should be removed when the file system will be proven.
198 */
199 struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
200 iput (emd_owner);
201 if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
202 printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
203 ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
204 }
205 }
206 }
207 /*
208 Get the inode of the directory which owns this inode.
209 Return 0 if ok, -EIO if error.
210 */
211 int umsdos_get_dirowner(
/* ![[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)
*/
212 struct inode *inode,
213 struct inode **result) /* Hold NULL if any error */
214 /* else, the inode of the directory */
215 {
216 int ret = -EIO;
217 unsigned long ino = inode->u.umsdos_i.i_dir_owner;
218 *result = NULL;
219 if (ino == 0){
220 printk ("UMSDOS: umsdos_get_dirowner ino == 0\n");
221 }else{
222 struct inode *dir = *result = iget(inode->i_sb,ino);
223 if (dir != NULL){
224 umsdos_patch_inode (dir,NULL,0);
225 ret = 0;
226 }
227 }
228 return ret;
229 }
230 /*
231 Load an inode from disk.
232 */
233 void UMSDOS_read_inode(struct inode *inode)
/* ![[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)
*/
234 {
235 PRINTK (("read inode %x ino = %d ",inode,inode->i_ino));
236 msdos_read_inode(inode);
237 PRINTK (("ino = %d %d\n",inode->i_ino,inode->i_count));
238 if (S_ISDIR(inode->i_mode)
239 && (inode->u.umsdos_i.u.dir_info.creating != 0
240 || inode->u.umsdos_i.u.dir_info.looking != 0
241 || inode->u.umsdos_i.u.dir_info.p != NULL)){
242 Printk (("read inode %d %d %p\n"
243 ,inode->u.umsdos_i.u.dir_info.creating
244 ,inode->u.umsdos_i.u.dir_info.looking
245 ,inode->u.umsdos_i.u.dir_info.p));
246 }
247 /* #Specification: Inode / post initialisation
248 To completely initialise an inode, we need access to the owner
249 directory, so we can locate more info in the EMD file. This is
250 not available the first time the inode is access, we use
251 a value in the inode to tell if it has been finally initialised.
252
253 At first, we have tried testing i_count but it was causing
254 problem. It is possible that two or more process use the
255 newly accessed inode. While the first one block during
256 the initialisation (probably while reading the EMD file), the
257 others believe all is well because i_count > 1. They go banana
258 with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.
259 */
260 umsdos_patch_inode(inode,NULL,0);
261 }
262
263 /*
264 Update the disk with the inode content
265 */
266 void UMSDOS_write_inode(struct inode *inode)
/* ![[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)
*/
267 {
268 struct iattr newattrs;
269
270 PRINTK (("UMSDOS_write_inode emd %d\n",inode->u.umsdos_i.i_emd_owner));
271 msdos_write_inode(inode);
272 newattrs.ia_mtime = inode->i_mtime;
273 newattrs.ia_atime = inode->i_atime;
274 newattrs.ia_ctime = inode->i_ctime;
275 newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
276 /*
277 UMSDOS_notify_change is convenient to call here
278 to update the EMD entry associated with this inode.
279 But it has the side effect to re"dirt" the inode.
280 */
281 UMSDOS_notify_change (inode, &newattrs);
282 inode->i_dirt = 0;
283 }
284
285 int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
/* ![[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)
*/
286 {
287 int ret = 0;
288
289 if ((ret = inode_change_ok(inode, attr)) != 0)
290 return ret;
291
292 if (inode->i_nlink > 0){
293 /* #Specification: notify_change / i_nlink > 0
294 notify change is only done for inode with nlink > 0. An inode
295 with nlink == 0 is no longer associated with any entry in
296 the EMD file, so there is nothing to update.
297 */
298 unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
299 if (inode == inode->i_sb->s_mounted){
300 /* #Specification: root inode / attributes
301 I don't know yet how this should work. Normally
302 the attributes (permissions bits, owner, times) of
303 a directory are stored in the EMD file of its parent.
304
305 One thing we could do is store the attributes of the root
306 inode in its own EMD file. A simple entry named "." could
307 be used for this special case. It would be read once
308 when the file system is mounted and update in
309 UMSDOS_notify_change() (right here).
310
311 I am not sure of the behavior of the root inode for
312 a real UNIX file system. For now, this is a nop.
313 */
314 }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){
315 /* This inode is not a EMD file nor an inode used internally
316 by MSDOS, so we can update its status.
317 See emd.c
318 */
319 struct inode *emd_owner = iget (inode->i_sb,i_emd_owner);
320 PRINTK (("notify change %p ",inode));
321 if (emd_owner == NULL){
322 printk ("UMSDOS: emd_owner = NULL ???");
323 ret = -EPERM;
324 }else{
325 struct file filp;
326 struct umsdos_dirent entry;
327 filp.f_pos = inode->u.umsdos_i.pos;
328 filp.f_reada = 0;
329 PRINTK (("pos = %d ",filp.f_pos));
330 /* Read only the start of the entry since we don't touch */
331 /* the name */
332 ret = umsdos_emd_dir_read (emd_owner,&filp,(char*)&entry
333 ,UMSDOS_REC_SIZE);
334 if (ret == 0){
335 if (attr->ia_valid & ATTR_UID)
336 entry.uid = attr->ia_uid;
337 if (attr->ia_valid & ATTR_GID)
338 entry.gid = attr->ia_gid;
339 if (attr->ia_valid & ATTR_MODE)
340 entry.mode = attr->ia_mode;
341 if (attr->ia_valid & ATTR_ATIME)
342 entry.atime = attr->ia_atime;
343 if (attr->ia_valid & ATTR_MTIME)
344 entry.mtime = attr->ia_mtime;
345 if (attr->ia_valid & ATTR_CTIME)
346 entry.ctime = attr->ia_ctime;
347
348 entry.nlink = inode->i_nlink;
349 filp.f_pos = inode->u.umsdos_i.pos;
350 ret = umsdos_emd_dir_write (emd_owner,&filp,(char*)&entry
351 ,UMSDOS_REC_SIZE);
352
353 PRINTK (("notify pos %d ret %d nlink %d "
354 ,inode->u.umsdos_i.pos
355 ,ret,entry.nlink));
356 /* #Specification: notify_change / msdos fs
357 notify_change operation are done only on the
358 EMD file. The msdos fs is not even called.
359 */
360 }
361 iput (emd_owner);
362 }
363 PRINTK (("\n"));
364 }
365 }
366 if (ret == 0)
367 inode_setattr(inode, attr);
368 return ret;
369 }
370
371 /* #Specification: function name / convention
372 A simple convention for function name has been used in
373 the UMSDOS file system. First all function use the prefix
374 umsdos_ to avoid name clash with other part of the kernel.
375
376 And standard VFS entry point use the prefix UMSDOS (upper case)
377 so it's easier to tell them apart.
378 */
379
380 static struct super_operations umsdos_sops = {
381 UMSDOS_read_inode,
382 UMSDOS_notify_change,
383 UMSDOS_write_inode,
384 UMSDOS_put_inode,
385 UMSDOS_put_super,
386 NULL, /* added in 0.96c */
387 UMSDOS_statfs,
388 NULL
389 };
390
391 /*
392 Read the super block of an Extended MS-DOS FS.
393 */
394 struct super_block *UMSDOS_read_super(
/* ![[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)
*/
395 struct super_block *s,
396 void *data,
397 int silent)
398 {
399 /* #Specification: mount / options
400 Umsdos run on top of msdos. Currently, it supports no
401 mount option, but happily pass all option received to
402 the msdos driver. I am not sure if all msdos mount option
403 make sense with Umsdos. Here are at least those who
404 are useful.
405 uid=
406 gid=
407
408 These options affect the operation of umsdos in directories
409 which do not have an EMD file. They behave like normal
410 msdos directory, with all limitation of msdos.
411 */
412 struct super_block *sb = msdos_read_super(s,data,silent);
413 printk ("UMSDOS Alpha 0.5 (compatibility level %d.%d, fast msdos)\n"
414 ,UMSDOS_VERSION,UMSDOS_RELEASE);
415 if (sb != NULL){
416 sb->s_op = &umsdos_sops;
417 PRINTK (("umsdos_read_super %p\n",sb->s_mounted));
418 umsdos_setup_dir_inode (sb->s_mounted);
419 PRINTK (("End umsdos_read_super\n"));
420 if (s == super_blocks){
421 /* #Specification: pseudo root / mount
422 When a umsdos fs is mounted, a special handling is done
423 if it is the root partition. We check for the presence
424 of the file /linux/etc/init or /linux/etc/rc.
425 If one is there, we do a chroot("/linux").
426
427 We check both because (see init/main.c) the kernel
428 try to exec init at different place and if it fails
429 it tries /bin/sh /etc/rc. To be consistent with
430 init/main.c, many more test would have to be done
431 to locate init. Any complain ?
432
433 The chroot is done manually in init/main.c but the
434 info (the inode) is located at mount time and store
435 in a global variable (pseudo_root) which is used at
436 different place in the umsdos driver. There is no
437 need to store this variable elsewhere because it
438 will always be one, not one per mount.
439
440 This feature allows the installation
441 of a linux system within a DOS system in a subdirectory.
442
443 A user may install its linux stuff in c:\linux
444 avoiding any clash with existing DOS file and subdirectory.
445 When linux boots, it hides this fact, showing a normal
446 root directory with /etc /bin /tmp ...
447
448 The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
449 in the macro UMSDOS_PSDROOT_NAME.
450 */
451
452 struct inode *pseudo;
453 Printk (("Mounting root\n"));
454 if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME
455 ,UMSDOS_PSDROOT_LEN,&pseudo)==0
456 && S_ISDIR(pseudo->i_mode)){
457 struct inode *etc = NULL;
458 struct inode *rc = NULL;
459 Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
460 if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0
461 && S_ISDIR(etc->i_mode)){
462 struct inode *init;
463 Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
464 if ((umsdos_real_lookup (etc,"init",4,&init)==0
465 && S_ISREG(init->i_mode))
466 || (umsdos_real_lookup (etc,"rc",2,&rc)==0
467 && S_ISREG(rc->i_mode))){
468 umsdos_setup_dir_inode (pseudo);
469 Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
470 pseudo_root = pseudo;
471 pseudo->i_count++;
472 pseudo = NULL;
473 }
474 iput (init);
475 iput (rc);
476 }
477 iput (etc);
478 }
479 iput (pseudo);
480 }
481 #ifdef MODULE
482 MOD_INC_USE_COUNT;
483 #endif
484 }
485 return sb;
486 }
487
488
489 #ifdef MODULE
490
491 char kernel_version[] = UTS_RELEASE;
492
493 static struct file_system_type umsdos_fs_type = {
494 UMSDOS_read_super, "umsdos", 1, NULL
495 };
496
497 int init_module(void)
/* ![[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)
*/
498 {
499 register_filesystem(&umsdos_fs_type);
500 return 0;
501 }
502
503 void cleanup_module(void)
/* ![[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)
*/
504 {
505 if (MOD_IN_USE)
506 printk("Umsdos: file system in use, remove delayed\n");
507 else
508 {
509 unregister_filesystem(&umsdos_fs_type);
510 }
511 }
512
513 #endif
514