1 |
1275 |
phoenix |
/* #Specification: umsdos / readdir
|
2 |
|
|
* umsdos_readdir() should fill a struct dirent with
|
3 |
|
|
* an inode number. The cheap way to get it is to
|
4 |
|
|
* do a lookup in the MSDOS directory for each
|
5 |
|
|
* entry processed by the readdir() function.
|
6 |
|
|
* This is not very efficient, but very simple. The
|
7 |
|
|
* other way around is to maintain a copy of the inode
|
8 |
|
|
* number in the EMD file. This is a problem because
|
9 |
|
|
* this has to be maintained in sync using tricks.
|
10 |
|
|
* Remember that MSDOS (the OS) does not update the
|
11 |
|
|
* modification time (mtime) of a directory. There is
|
12 |
|
|
* no easy way to tell that a directory was modified
|
13 |
|
|
* during a DOS session and synchronise the EMD file.
|
14 |
|
|
*/
|
15 |
|
|
/* #Specification: readdir / . and ..
|
16 |
|
|
* The msdos filesystem manages the . and .. entry properly
|
17 |
|
|
* so the EMD file won't hold any info about it.
|
18 |
|
|
*
|
19 |
|
|
* In readdir, we assume that for the root directory
|
20 |
|
|
* the read position will be 0 for ".", 1 for "..". For
|
21 |
|
|
* a non root directory, the read position will be 0 for "."
|
22 |
|
|
* and 32 for "..".
|
23 |
|
|
*/
|
24 |
|
|
/*
|
25 |
|
|
* This is a trick used by the msdos file system (fs/msdos/dir.c)
|
26 |
|
|
* to manage . and .. for the root directory of a file system.
|
27 |
|
|
* Since there is no such entry in the root, fs/msdos/dir.c
|
28 |
|
|
* use the following:
|
29 |
|
|
*
|
30 |
|
|
* if f_pos == 0, return ".".
|
31 |
|
|
* if f_pos == 1, return "..".
|
32 |
|
|
*
|
33 |
|
|
* So let msdos handle it
|
34 |
|
|
*
|
35 |
|
|
* Since umsdos entries are much larger, we share the same f_pos.
|
36 |
|
|
* if f_pos is 0 or 1 or 32, we are clearly looking at . and
|
37 |
|
|
* ..
|
38 |
|
|
*
|
39 |
|
|
* As soon as we get f_pos == 2 or f_pos == 64, then back to
|
40 |
|
|
* 0, but this time we are reading the EMD file.
|
41 |
|
|
*
|
42 |
|
|
* Well, not so true. The problem, is that UMSDOS_REC_SIZE is
|
43 |
|
|
* also 64, so as soon as we read the first record in the
|
44 |
|
|
* EMD, we are back at offset 64. So we set the offset
|
45 |
|
|
* to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
|
46 |
|
|
* .. entry from msdos.
|
47 |
|
|
*
|
48 |
|
|
* Now (linux 1.3), umsdos_readdir can read more than one
|
49 |
|
|
* entry even if we limit (umsdos_dir_once) to only one:
|
50 |
|
|
* It skips over hidden file. So we switch to
|
51 |
|
|
* UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
|
52 |
|
|
* the .. entry.
|
53 |
|
|
*/
|
54 |
|
|
/* #Specification: umsdos / lookup / inode info
|
55 |
|
|
* After successfully reading an inode from the MSDOS
|
56 |
|
|
* filesystem, we use the EMD file to complete it.
|
57 |
|
|
* We update the following field.
|
58 |
|
|
*
|
59 |
|
|
* uid, gid, atime, ctime, mtime, mode.
|
60 |
|
|
*
|
61 |
|
|
* We rely on MSDOS for mtime. If the file
|
62 |
|
|
* was modified during an MSDOS session, at least
|
63 |
|
|
* mtime will be meaningful. We do this only for regular
|
64 |
|
|
* file.
|
65 |
|
|
*
|
66 |
|
|
* We don't rely on MS-DOS for mtime for directories
|
67 |
|
|
* because the MS-DOS date on a directory is its
|
68 |
|
|
* creation time (strange MSDOS behavior) which
|
69 |
|
|
* corresponds to none of the three Unix time stamps.
|
70 |
|
|
*/
|
71 |
|
|
/* #Specification: umsdos / conversion mode
|
72 |
|
|
* The msdos filesystem can do some inline conversion
|
73 |
|
|
* of the data of a file. It can translate silently
|
74 |
|
|
* from the MS-DOS text file format to the Unix one
|
75 |
|
|
* (CRLF -> LF) while reading, and the reverse
|
76 |
|
|
* while writing. This is activated using the mount
|
77 |
|
|
* option conv=....
|
78 |
|
|
*
|
79 |
|
|
* This is not useful for Linux files in a promoted
|
80 |
|
|
* directory. It can even be harmful. For this
|
81 |
|
|
* reason, the binary (no conversion) mode is
|
82 |
|
|
* always activated.
|
83 |
|
|
*/
|
84 |
|
|
/* #Specification: umsdos / conversion mode / todo
|
85 |
|
|
* A flag could be added to file and directories
|
86 |
|
|
* forcing an automatic conversion mode (as
|
87 |
|
|
* done with the msdos filesystem).
|
88 |
|
|
*
|
89 |
|
|
* This flag could be setup on a directory basis
|
90 |
|
|
* (instead of file) and all files in it would
|
91 |
|
|
* logically inherit it. If the conversion mode
|
92 |
|
|
* is active (conv=) then the i_binary flag would
|
93 |
|
|
* be left untouched in those directories.
|
94 |
|
|
*
|
95 |
|
|
* It was proposed that the sticky bit be used to set
|
96 |
|
|
* this. A problem with that is that new files would
|
97 |
|
|
* be written incorrectly. The other problem is that
|
98 |
|
|
* the sticky bit has a meaning for directories. So
|
99 |
|
|
* another bit should be used (there is some space
|
100 |
|
|
* in the EMD file for it) and a special utility
|
101 |
|
|
* would be used to assign the flag to a directory).
|
102 |
|
|
* I don't think it is useful to assign this flag
|
103 |
|
|
* on a single file.
|
104 |
|
|
*/
|
105 |
|
|
* #Specification: weakness / rename
|
106 |
|
|
* There is a case where UMSDOS rename has a different behavior
|
107 |
|
|
* than a normal Unix file system. Renaming an open file across
|
108 |
|
|
* directory boundary does not work. Renaming an open file within
|
109 |
|
|
* a directory does work, however.
|
110 |
|
|
*
|
111 |
|
|
* The problem may is in Linux VFS driver for msdos.
|
112 |
|
|
* I believe this is not a bug but a design feature, because
|
113 |
|
|
* an inode number represents some sort of directory address
|
114 |
|
|
* in the MSDOS directory structure, so moving the file into
|
115 |
|
|
* another directory does not preserve the inode number.
|
116 |
|
|
*/
|
117 |
|
|
/* #Specification: rename / new name exist
|
118 |
|
|
* If the destination name already exists, it will
|
119 |
|
|
* silently be removed. EXT2 does it this way
|
120 |
|
|
* and this is the spec of SunOS. So does UMSDOS.
|
121 |
|
|
*
|
122 |
|
|
* If the destination is an empty directory it will
|
123 |
|
|
* also be removed.
|
124 |
|
|
*/
|
125 |
|
|
/* #Specification: rename / new name exist / possible flaw
|
126 |
|
|
* The code to handle the deletion of the target (file
|
127 |
|
|
* and directory) use to be in umsdos_rename_f, surrounded
|
128 |
|
|
* by proper directory locking. This was ensuring that only
|
129 |
|
|
* one process could achieve a rename (modification) operation
|
130 |
|
|
* in the source and destination directory. This was also
|
131 |
|
|
* ensuring the operation was "atomic".
|
132 |
|
|
*
|
133 |
|
|
* This has been changed because this was creating a
|
134 |
|
|
* stack overflow (the stack is only 4 kB) in the kernel. To avoid
|
135 |
|
|
* the code doing the deletion of the target (if exist) has
|
136 |
|
|
* been moved to a upper layer. umsdos_rename_f is tried
|
137 |
|
|
* once and if it fails with EEXIST, the target is removed
|
138 |
|
|
* and umsdos_rename_f is done again.
|
139 |
|
|
*
|
140 |
|
|
* This makes the code cleaner and may solve a
|
141 |
|
|
* deadlock problem one tester was experiencing.
|
142 |
|
|
*
|
143 |
|
|
* The point is to mention that possibly, the semantic of
|
144 |
|
|
* "rename" may be wrong. Anyone dare to check that :-)
|
145 |
|
|
* Be aware that IF it is wrong, to produce the problem you
|
146 |
|
|
* will need two process trying to rename a file to the
|
147 |
|
|
* same target at the same time. Again, I am not sure it
|
148 |
|
|
* is a problem at all.
|
149 |
|
|
*/
|
150 |
|
|
|
151 |
|
|
/* #Specification: hard link / strategy
|
152 |
|
|
* Hard links are difficult to implement on top of an MS-DOS FAT file
|
153 |
|
|
* system. Unlike Unix file systems, there are no inodes. A directory
|
154 |
|
|
* entry holds the functionality of the inode and the entry.
|
155 |
|
|
*
|
156 |
|
|
* We will used the same strategy as a normal Unix file system
|
157 |
|
|
* (with inodes) except we will do it symbolically (using paths).
|
158 |
|
|
*
|
159 |
|
|
* Because anything can happen during a DOS session (defragment,
|
160 |
|
|
* directory sorting, etc.), we can't rely on an MS-DOS pseudo
|
161 |
|
|
* inode number to record the link. For this reason, the link
|
162 |
|
|
* will be done using hidden symbolic links. The following
|
163 |
|
|
* scenario illustrates how it works.
|
164 |
|
|
*
|
165 |
|
|
* Given a file /foo/file
|
166 |
|
|
*
|
167 |
|
|
* #
|
168 |
|
|
* ln /foo/file /tmp/file2
|
169 |
|
|
*
|
170 |
|
|
* become internally
|
171 |
|
|
*
|
172 |
|
|
* mv /foo/file /foo/-LINK1
|
173 |
|
|
* ln -s /foo/-LINK1 /foo/file
|
174 |
|
|
* ln -s /foo/-LINK1 /tmp/file2
|
175 |
|
|
* #
|
176 |
|
|
*
|
177 |
|
|
* Using this strategy, we can operate on /foo/file or /foo/file2.
|
178 |
|
|
* We can remove one and keep the other, like a normal Unix hard link.
|
179 |
|
|
* We can rename /foo/file or /tmp/file2 independently.
|
180 |
|
|
*
|
181 |
|
|
* The entry -LINK1 will be hidden. It will hold a link count.
|
182 |
|
|
* When all link are erased, the hidden file is erased too.
|
183 |
|
|
*/
|
184 |
|
|
|
185 |
|
|
/* #Specification: weakness / hard link
|
186 |
|
|
* The strategy for hard link introduces a side effect that
|
187 |
|
|
* may or may not be acceptable. Here is the sequence
|
188 |
|
|
*
|
189 |
|
|
* #
|
190 |
|
|
* mkdir subdir1
|
191 |
|
|
* touch subdir1/file
|
192 |
|
|
* mkdir subdir2
|
193 |
|
|
* ln subdir1/file subdir2/file
|
194 |
|
|
* rm subdir1/file
|
195 |
|
|
* rmdir subdir1
|
196 |
|
|
* rmdir: subdir1: Directory not empty
|
197 |
|
|
* #
|
198 |
|
|
*
|
199 |
|
|
* This happen because there is an invisible file (--link) in
|
200 |
|
|
* subdir1 which is referenced by subdir2/file.
|
201 |
|
|
*
|
202 |
|
|
* Any idea ?
|
203 |
|
|
*/
|
204 |
|
|
/* #Specification: weakness / hard link / rename directory
|
205 |
|
|
* Another weakness of hard link come from the fact that
|
206 |
|
|
* it is based on hidden symbolic links. Here is an example.
|
207 |
|
|
*
|
208 |
|
|
* #
|
209 |
|
|
* mkdir /subdir1
|
210 |
|
|
* touch /subdir1/file
|
211 |
|
|
* mkdir /subdir2
|
212 |
|
|
* ln /subdir1/file subdir2/file
|
213 |
|
|
* mv /subdir1 subdir3
|
214 |
|
|
* ls -l /subdir2/file
|
215 |
|
|
* #
|
216 |
|
|
*
|
217 |
|
|
* Since /subdir2/file is a hidden symbolic link
|
218 |
|
|
* to /subdir1/..hlinkNNN, accessing it will fail since
|
219 |
|
|
* /subdir1 does not exist anymore (has been renamed).
|
220 |
|
|
*/
|
221 |
|
|
/* #Specification: hard link / directory
|
222 |
|
|
* A hard link can't be made on a directory. EPERM is returned
|
223 |
|
|
* in this case.
|
224 |
|
|
*/
|
225 |
|
|
/* #Specification: hard link / first hard link
|
226 |
|
|
* The first time a hard link is done on a file, this
|
227 |
|
|
* file must be renamed and hidden. Then an internal
|
228 |
|
|
* symbolic link must be done on the hidden file.
|
229 |
|
|
*
|
230 |
|
|
* The second link is done after on this hidden file.
|
231 |
|
|
*
|
232 |
|
|
* It is expected that the Linux MSDOS file system
|
233 |
|
|
* keeps the same pseudo inode when a rename operation
|
234 |
|
|
* is done on a file in the same directory.
|
235 |
|
|
*/
|
236 |
|
|
/* #Specification: function name / convention
|
237 |
|
|
* A simple convention for function names has been used in
|
238 |
|
|
* the UMSDOS filesystem. First, all functions use the prefix
|
239 |
|
|
* umsdos_ to avoid name clashes with other parts of the kernel.
|
240 |
|
|
*
|
241 |
|
|
* Standard VFS entry points use the prefix UMSDOS (upper case)
|
242 |
|
|
* so it's easier to tell them apart.
|
243 |
|
|
* N.B. (FIXME) PTW, the order and contents of this struct changed.
|
244 |
|
|
*/
|
245 |
|
|
|
246 |
|
|
/* #Specification: mount / options
|
247 |
|
|
* Umsdos run on top of msdos. Currently, it supports no
|
248 |
|
|
* mount option, but happily pass all option received to
|
249 |
|
|
* the msdos driver. I am not sure if all msdos mount option
|
250 |
|
|
* make sense with Umsdos. Here are at least those who
|
251 |
|
|
* are useful.
|
252 |
|
|
* uid=
|
253 |
|
|
* gid=
|
254 |
|
|
*
|
255 |
|
|
* These options affect the operation of umsdos in directories
|
256 |
|
|
* which do not have an EMD file. They behave like normal
|
257 |
|
|
* msdos directory, with all limitation of msdos.
|
258 |
|
|
*/
|
259 |
|
|
|
260 |
|
|
/* #Specification: pseudo root / mount
|
261 |
|
|
* When a umsdos fs is mounted, a special handling is done
|
262 |
|
|
* if it is the root partition. We check for the presence
|
263 |
|
|
* of the file /linux/etc/init or /linux/etc/rc or
|
264 |
|
|
* /linux/sbin/init. If one is there, we do a chroot("/linux").
|
265 |
|
|
*
|
266 |
|
|
* We check both because (see init/main.c) the kernel
|
267 |
|
|
* try to exec init at different place and if it fails
|
268 |
|
|
* it tries /bin/sh /etc/rc. To be consistent with
|
269 |
|
|
* init/main.c, many more test would have to be done
|
270 |
|
|
* to locate init. Any complain ?
|
271 |
|
|
*
|
272 |
|
|
* The chroot is done manually in init/main.c but the
|
273 |
|
|
* info (the inode) is located at mount time and store
|
274 |
|
|
* in a global variable (pseudo_root) which is used at
|
275 |
|
|
* different place in the umsdos driver. There is no
|
276 |
|
|
* need to store this variable elsewhere because it
|
277 |
|
|
* will always be one, not one per mount.
|
278 |
|
|
*
|
279 |
|
|
* This feature allows the installation
|
280 |
|
|
* of a linux system within a DOS system in a subdirectory.
|
281 |
|
|
*
|
282 |
|
|
* A user may install its linux stuff in c:\linux
|
283 |
|
|
* avoiding any clash with existing DOS file and subdirectory.
|
284 |
|
|
* When linux boots, it hides this fact, showing a normal
|
285 |
|
|
* root directory with /etc /bin /tmp ...
|
286 |
|
|
*
|
287 |
|
|
* The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
|
288 |
|
|
* in the macro UMSDOS_PSDROOT_NAME.
|
289 |
|
|
*/
|