1 /*
2 * linux/fs/msdos/file.c
3 *
4 * Written 1992,1993 by Werner Almesberger
5 *
6 * MS-DOS regular file handling primitives
7 */
8
9 #ifdef MODULE
10 #include <linux/module.h>
11 #endif
12
13 #include <asm/segment.h>
14 #include <asm/system.h>
15
16 #include <linux/sched.h>
17 #include <linux/locks.h>
18 #include <linux/fs.h>
19 #include <linux/msdos_fs.h>
20 #include <linux/errno.h>
21 #include <linux/fcntl.h>
22 #include <linux/stat.h>
23 #include <linux/string.h>
24
25 #include "msbuffer.h"
26
27 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
28 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
29
30 #define PRINTK(x)
31 #define Printk(x) printk x
32
33 static struct file_operations msdos_file_operations = {
34 NULL, /* lseek - default */
35 msdos_file_read, /* read */
36 msdos_file_write, /* write */
37 NULL, /* readdir - bad */
38 NULL, /* select - default */
39 NULL, /* ioctl - default */
40 generic_mmap, /* mmap */
41 NULL, /* no special open is needed */
42 NULL, /* release */
43 file_fsync /* fsync */
44 };
45
46 struct inode_operations msdos_file_inode_operations = {
47 &msdos_file_operations, /* default file operations */
48 NULL, /* create */
49 NULL, /* lookup */
50 NULL, /* link */
51 NULL, /* unlink */
52 NULL, /* symlink */
53 NULL, /* mkdir */
54 NULL, /* rmdir */
55 NULL, /* mknod */
56 NULL, /* rename */
57 NULL, /* readlink */
58 NULL, /* follow_link */
59 msdos_bmap, /* bmap */
60 msdos_truncate, /* truncate */
61 NULL, /* permission */
62 NULL /* smap */
63 };
64 /* #Specification: msdos / special devices / mmap
65 Mmapping does work because a special mmap is provide in that case.
66 Note that it is much less efficient than the generic_mmap normally
67 used since it allocate extra buffer. generic_mmap is used for
68 normal device (512 bytes hardware sectors).
69 */
70 static struct file_operations msdos_file_operations_1024 = {
71 NULL, /* lseek - default */
72 msdos_file_read, /* read */
73 msdos_file_write, /* write */
74 NULL, /* readdir - bad */
75 NULL, /* select - default */
76 NULL, /* ioctl - default */
77 msdos_mmap, /* mmap */
78 NULL, /* no special open is needed */
79 NULL, /* release */
80 file_fsync /* fsync */
81 };
82
83 /* #Specification: msdos / special devices / swap file
84 Swap file can't work on special devices with a large sector
85 size (1024 bytes hard sector). Those devices have a weird
86 MsDOS filesystem layout. Generally a single hardware sector
87 may contain 2 unrelated logical sector. This mean that there is
88 no easy way to do a mapping between disk sector of a file and virtual
89 memory. So swap file is difficult (not available right now)
90 on those devices. Off course, Ext2 does not have this problem.
91 */
92 struct inode_operations msdos_file_inode_operations_1024 = {
93 &msdos_file_operations_1024, /* default file operations */
94 NULL, /* create */
95 NULL, /* lookup */
96 NULL, /* link */
97 NULL, /* unlink */
98 NULL, /* symlink */
99 NULL, /* mkdir */
100 NULL, /* rmdir */
101 NULL, /* mknod */
102 NULL, /* rename */
103 NULL, /* readlink */
104 NULL, /* follow_link */
105 NULL, /* bmap */
106 msdos_truncate, /* truncate */
107 NULL, /* permission */
108 NULL /* smap */
109 };
110
111 #define MSDOS_PREFETCH 32
112 struct msdos_pre {
113 int file_sector;/* Next sector to read in the prefetch table */
114 /* This is relative to the file, not the disk */
115 struct buffer_head *bhlist[MSDOS_PREFETCH]; /* All buffers needed */
116 int nblist; /* Number of buffers in bhlist */
117 int nolist; /* index in bhlist */
118 };
119 /*
120 Order the prefetch of more sectors.
121 */
122 static void msdos_prefetch (
/* ![[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)
*/
123 struct inode *inode,
124 struct msdos_pre *pre,
125 int nb) /* How many must be prefetch at once */
126 {
127 struct super_block *sb = inode->i_sb;
128 struct buffer_head *bhreq[MSDOS_PREFETCH]; /* Buffers not */
129 /* already read */
130 int nbreq=0; /* Number of buffers in bhreq */
131 int i;
132 for (i=0; i<nb; i++){
133 int sector = msdos_smap(inode,pre->file_sector);
134 if (sector != 0){
135 struct buffer_head *bh;
136 PRINTK (("fsector2 %d -> %d\n",pre->file_sector-1,sector));
137 pre->file_sector++;
138 bh = getblk(inode->i_dev,sector,SECTOR_SIZE);
139 if (bh == NULL) break;
140 pre->bhlist[pre->nblist++] = bh;
141 if (!msdos_is_uptodate(sb,bh)) bhreq[nbreq++] = bh;
142 }else{
143 break;
144 }
145 }
146 if (nbreq > 0) msdos_ll_rw_block (sb,READ,nbreq,bhreq);
147 for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
148 }
149
150 /*
151 Read a file into user space
152 */
153 int msdos_file_read(
/* ![[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)
*/
154 struct inode *inode,
155 struct file *filp,
156 char *buf,
157 int count)
158 {
159 struct super_block *sb = inode->i_sb;
160 char *start = buf;
161 char *end = buf + count;
162 int i;
163 int left_in_file;
164 struct msdos_pre pre;
165
166
167 if (!inode) {
168 printk("msdos_file_read: inode = NULL\n");
169 return -EINVAL;
170 }
171 /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
172 if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
173 printk("msdos_file_read: mode = %07o\n",inode->i_mode);
174 return -EINVAL;
175 }
176 if (filp->f_pos >= inode->i_size || count <= 0) return 0;
177 /*
178 Tell the buffer cache which block we expect to read in advance
179 Since we are limited with the stack, we preread only MSDOS_PREFETCH
180 because we have to keep the result into the local
181 arrays pre.bhlist and bhreq.
182
183 Each time we process one block in bhlist, we replace
184 it by a new prefetch block if needed.
185 */
186 PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,filp->f_pos,inode->i_size,count));
187 {
188 /*
189 We must prefetch complete block, so we must
190 take in account the offset in the first block.
191 */
192 int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count;
193 int to_reada; /* How many block to read all at once */
194 pre.file_sector = filp->f_pos >> SECTOR_BITS;
195 to_reada = count_max / SECTOR_SIZE;
196 if (count_max & (SECTOR_SIZE-1)) to_reada++;
197 if (filp->f_reada || !MSDOS_I(inode)->i_binary){
198 /* Doing a read ahead on ascii file make sure we always */
199 /* pre read enough, since we don't know how many blocks */
200 /* we really need */
201 int ahead = read_ahead[MAJOR(inode->i_dev)];
202 PRINTK (("to_reada %d ahead %d\n",to_reada,ahead));
203 if (ahead == 0) ahead = 8;
204 to_reada += ahead;
205 }
206 if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
207 pre.nblist = 0;
208 msdos_prefetch (inode,&pre,to_reada);
209 }
210 pre.nolist = 0;
211 PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
212 while ((left_in_file = inode->i_size - filp->f_pos) > 0
213 && buf < end){
214 struct buffer_head *bh = pre.bhlist[pre.nolist];
215 char *data;
216 int size,offset;
217 if (bh == NULL) break;
218 pre.bhlist[pre.nolist] = NULL;
219 pre.nolist++;
220 if (pre.nolist == MSDOS_PREFETCH/2){
221 memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
222 ,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
223 pre.nblist -= MSDOS_PREFETCH/2;
224 msdos_prefetch (inode,&pre,MSDOS_PREFETCH/2);
225 pre.nolist = 0;
226 }
227 PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
228 wait_on_buffer(bh);
229 if (!msdos_is_uptodate(sb,bh)){
230 /* read error ? */
231 brelse (bh);
232 break;
233 }
234 offset = filp->f_pos & (SECTOR_SIZE-1);
235 data = bh->b_data + offset;
236 size = MIN(SECTOR_SIZE-offset,left_in_file);
237 if (MSDOS_I(inode)->i_binary) {
238 size = MIN(size,end-buf);
239 memcpy_tofs(buf,data,size);
240 buf += size;
241 filp->f_pos += size;
242 }else{
243 for (; size && buf < end; size--) {
244 char ch = *data++;
245 filp->f_pos++;
246 if (ch == 26){
247 filp->f_pos = inode->i_size;
248 break;
249 }else if (ch != '\r'){
250 put_user(ch,buf++);
251 }
252 }
253 }
254 brelse(bh);
255 }
256 PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
257 for (i=0; i<pre.nblist; i++) brelse (pre.bhlist[i]);
258 if (start == buf) return -EIO;
259 if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
260 filp->f_reada = 1; /* Will be reset if a lseek is done */
261 return buf-start;
262 }
263
264 /*
265 Write to a file either from user space
266 */
267 int msdos_file_write(
/* ![[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)
*/
268 struct inode *inode,
269 struct file *filp,
270 const char *buf,
271 int count)
272 {
273 struct super_block *sb = inode->i_sb;
274 int sector,offset,size,left,written;
275 int error,carry;
276 const char *start;
277 char *to,ch;
278 struct buffer_head *bh;
279 int binary_mode = MSDOS_I(inode)->i_binary;
280
281 if (!inode) {
282 printk("msdos_file_write: inode = NULL\n");
283 return -EINVAL;
284 }
285 /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
286 if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
287 printk("msdos_file_write: mode = %07o\n",inode->i_mode);
288 return -EINVAL;
289 }
290 /*
291 * ok, append may not work when many processes are writing at the same time
292 * but so what. That way leads to madness anyway.
293 */
294 if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
295 if (count <= 0) return 0;
296 error = carry = 0;
297 for (start = buf; count || carry; count -= size) {
298 while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
299 if ((error = msdos_add_cluster(inode)) < 0) break;
300 if (error) {
301 msdos_truncate(inode);
302 break;
303 }
304 offset = filp->f_pos & (SECTOR_SIZE-1);
305 size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
306 if (binary_mode
307 && offset == 0
308 && (size == SECTOR_SIZE
309 || filp->f_pos + size >= inode->i_size)){
310 /* No need to read the block first since we will */
311 /* completely overwrite it */
312 /* or at least write past the end of file */
313 if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
314 error = -EIO;
315 break;
316 }
317 }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) {
318 error = -EIO;
319 break;
320 }
321 if (binary_mode) {
322 memcpy_fromfs(bh->b_data+offset,buf,written = size);
323 buf += size;
324 }
325 else {
326 written = left = SECTOR_SIZE-offset;
327 to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
328 if (carry) {
329 *to++ = '\n';
330 left--;
331 carry = 0;
332 }
333 for (size = 0; size < count && left; size++) {
334 if ((ch = get_user(buf++)) == '\n') {
335 *to++ = '\r';
336 left--;
337 }
338 if (!left) carry = 1;
339 else {
340 *to++ = ch;
341 left--;
342 }
343 }
344 written -= left;
345 }
346 filp->f_pos += written;
347 if (filp->f_pos > inode->i_size) {
348 inode->i_size = filp->f_pos;
349 inode->i_dirt = 1;
350 }
351 msdos_set_uptodate(sb,bh,1);
352 mark_buffer_dirty(bh, 0);
353 brelse(bh);
354 }
355 if (start == buf)
356 return error;
357 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
358 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
359 inode->i_dirt = 1;
360 return buf-start;
361 }
362
363 void msdos_truncate(struct inode *inode)
/* ![[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)
*/
364 {
365 int cluster;
366
367 cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
368 (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
369 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
370 inode->i_dirt = 1;
371 }