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