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_fs_byte(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 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 char *start,*to,ch;
277 struct buffer_head *bh;
278 int binary_mode = MSDOS_I(inode)->i_binary;
279
280 if (!inode) {
281 printk("msdos_file_write: inode = NULL\n");
282 return -EINVAL;
283 }
284 /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
285 if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
286 printk("msdos_file_write: mode = %07o\n",inode->i_mode);
287 return -EINVAL;
288 }
289 /*
290 * ok, append may not work when many processes are writing at the same time
291 * but so what. That way leads to madness anyway.
292 */
293 if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
294 if (count <= 0) return 0;
295 error = carry = 0;
296 for (start = buf; count || carry; count -= size) {
297 while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
298 if ((error = msdos_add_cluster(inode)) < 0) break;
299 if (error) {
300 msdos_truncate(inode);
301 break;
302 }
303 offset = filp->f_pos & (SECTOR_SIZE-1);
304 size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
305 if (binary_mode
306 && offset == 0
307 && (size == SECTOR_SIZE
308 || filp->f_pos + size >= inode->i_size)){
309 /* No need to read the block first since we will */
310 /* completely overwrite it */
311 /* or at least write past the end of file */
312 if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
313 error = -EIO;
314 break;
315 }
316 }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) {
317 error = -EIO;
318 break;
319 }
320 if (binary_mode) {
321 memcpy_fromfs(bh->b_data+offset,buf,written = size);
322 buf += size;
323 }
324 else {
325 written = left = SECTOR_SIZE-offset;
326 to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
327 if (carry) {
328 *to++ = '\n';
329 left--;
330 carry = 0;
331 }
332 for (size = 0; size < count && left; size++) {
333 if ((ch = get_fs_byte(buf++)) == '\n') {
334 *to++ = '\r';
335 left--;
336 }
337 if (!left) carry = 1;
338 else {
339 *to++ = ch;
340 left--;
341 }
342 }
343 written -= left;
344 }
345 filp->f_pos += written;
346 if (filp->f_pos > inode->i_size) {
347 inode->i_size = filp->f_pos;
348 inode->i_dirt = 1;
349 }
350 msdos_set_uptodate(sb,bh,1);
351 mark_buffer_dirty(bh, 0);
352 brelse(bh);
353 }
354 if (start == buf)
355 return error;
356 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
357 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
358 inode->i_dirt = 1;
359 return buf-start;
360 }
361
362 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)
*/
363 {
364 int cluster;
365
366 cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
367 (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
368 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
369 inode->i_dirt = 1;
370 }