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 #include <asm/segment.h>
10 #include <asm/system.h>
11
12 #include <linux/sched.h>
13 #include <linux/fs.h>
14 #include <linux/msdos_fs.h>
15 #include <linux/errno.h>
16 #include <linux/fcntl.h>
17 #include <linux/stat.h>
18 #include <linux/string.h>
19
20 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
21 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
22
23 static struct file_operations msdos_file_operations = {
24 NULL, /* lseek - default */
25 msdos_file_read, /* read */
26 msdos_file_write, /* write */
27 NULL, /* readdir - bad */
28 NULL, /* select - default */
29 NULL, /* ioctl - default */
30 msdos_mmap, /* mmap */
31 NULL, /* no special open is needed */
32 NULL, /* release */
33 file_fsync /* fsync */
34 };
35
36 struct inode_operations msdos_file_inode_operations = {
37 &msdos_file_operations, /* default file operations */
38 NULL, /* create */
39 NULL, /* lookup */
40 NULL, /* link */
41 NULL, /* unlink */
42 NULL, /* symlink */
43 NULL, /* mkdir */
44 NULL, /* rmdir */
45 NULL, /* mknod */
46 NULL, /* rename */
47 NULL, /* readlink */
48 NULL, /* follow_link */
49 msdos_bmap, /* bmap */
50 msdos_truncate, /* truncate */
51 NULL, /* permission */
52 msdos_smap /* smap */
53 };
54
55 /* No bmap for MS-DOS FS' that don't align data at kByte boundaries. */
56
57 struct inode_operations msdos_file_inode_operations_no_bmap = {
58 &msdos_file_operations, /* default file operations */
59 NULL, /* create */
60 NULL, /* lookup */
61 NULL, /* link */
62 NULL, /* unlink */
63 NULL, /* symlink */
64 NULL, /* mkdir */
65 NULL, /* rmdir */
66 NULL, /* mknod */
67 NULL, /* rename */
68 NULL, /* readlink */
69 NULL, /* follow_link */
70 NULL, /* bmap */
71 msdos_truncate, /* truncate */
72 NULL, /* permission */
73 msdos_smap /* smap */
74 };
75
76
77 /*
78 Read a file into user space
79 */
80 int msdos_file_read(
/* ![[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)
*/
81 struct inode *inode,
82 struct file *filp,
83 char *buf,
84 int count)
85 {
86 char *start;
87 int left,offset,size,sector,cnt;
88 char ch;
89 struct buffer_head *bh;
90 void *data;
91
92 /* printk("msdos_file_read\n"); */
93 if (!inode) {
94 printk("msdos_file_read: inode = NULL\n");
95 return -EINVAL;
96 }
97 /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
98 if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
99 printk("msdos_file_read: mode = %07o\n",inode->i_mode);
100 return -EINVAL;
101 }
102 if (filp->f_pos >= inode->i_size || count <= 0) return 0;
103 start = buf;
104 while ((left = MIN(inode->i_size-filp->f_pos,count-(buf-start))) > 0){
105 if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
106 break;
107 offset = filp->f_pos & (SECTOR_SIZE-1);
108 if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break;
109 filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
110 if (MSDOS_I(inode)->i_binary) {
111 memcpy_tofs(buf,data+offset,size);
112 buf += size;
113 }
114 else for (cnt = size; cnt; cnt--) {
115 if ((ch = *((char *) data+offset++)) == '\r')
116 size--;
117 else {
118 if (ch != 26) put_fs_byte(ch,buf++);
119 else {
120 filp->f_pos = inode->i_size;
121 brelse(bh);
122 if (start != buf
123 && !IS_RDONLY(inode))
124 inode->i_atime
125 = CURRENT_TIME;
126 return buf-start;
127 }
128 }
129 }
130 brelse(bh);
131 }
132 if (start == buf) return -EIO;
133 if (!IS_RDONLY(inode))
134 inode->i_atime = CURRENT_TIME;
135 return buf-start;
136 }
137
138 /*
139 Write to a file either from user space
140 */
141 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)
*/
142 struct inode *inode,
143 struct file *filp,
144 char *buf,
145 int count)
146 {
147 int sector,offset,size,left,written;
148 int error,carry;
149 char *start,*to,ch;
150 struct buffer_head *bh;
151 void *data;
152
153 if (!inode) {
154 printk("msdos_file_write: inode = NULL\n");
155 return -EINVAL;
156 }
157 /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
158 if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
159 printk("msdos_file_write: mode = %07o\n",inode->i_mode);
160 return -EINVAL;
161 }
162 /*
163 * ok, append may not work when many processes are writing at the same time
164 * but so what. That way leads to madness anyway.
165 */
166 if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
167 if (count <= 0) return 0;
168 error = carry = 0;
169 for (start = buf; count || carry; count -= size) {
170 while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
171 if ((error = msdos_add_cluster(inode)) < 0) break;
172 if (error) {
173 msdos_truncate(inode);
174 break;
175 }
176 offset = filp->f_pos & (SECTOR_SIZE-1);
177 size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
178 if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
179 error = -EIO;
180 break;
181 }
182 if (MSDOS_I(inode)->i_binary) {
183 memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)),
184 buf,written = size);
185 buf += size;
186 }
187 else {
188 written = left = SECTOR_SIZE-offset;
189 to = (char *) data+(filp->f_pos & (SECTOR_SIZE-1));
190 if (carry) {
191 *to++ = '\n';
192 left--;
193 carry = 0;
194 }
195 for (size = 0; size < count && left; size++) {
196 if ((ch = get_fs_byte(buf++)) == '\n') {
197 *to++ = '\r';
198 left--;
199 }
200 if (!left) carry = 1;
201 else {
202 *to++ = ch;
203 left--;
204 }
205 }
206 written -= left;
207 }
208 filp->f_pos += written;
209 if (filp->f_pos > inode->i_size) {
210 inode->i_size = filp->f_pos;
211 inode->i_dirt = 1;
212 }
213 mark_buffer_dirty(bh, 0);
214 brelse(bh);
215 }
216 if (start == buf)
217 return error;
218 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
219 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
220 inode->i_dirt = 1;
221 return buf-start;
222 }
223
224 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)
*/
225 {
226 int cluster;
227
228 cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
229 (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
230 MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
231 inode->i_dirt = 1;
232 }