This source file includes following definitions.
- is_binary
- lock_creation
- unlock_creation
- msdos_add_cluster
- date_dos2unix
- date_unix2dos
- msdos_get_entry
- msdos_scan
- raw_found
- raw_scan_root
- raw_scan_nonroot
- raw_scan
- msdos_parent_ino
1
2
3
4
5
6
7 #include <linux/msdos_fs.h>
8 #include <linux/sched.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/string.h>
12 #include <linux/stat.h>
13
14 static char bin_extensions[] =
15 "EXECOMAPPSYSOVLOBJLIB"
16 "ARCZIPLHALZHZOOTARZ ARJTZ "
17 "GIFBMPTIFGL JPGPCX"
18 "TFMVF GF PK PXLDVI";
19
20
21
22
23 int is_binary(char conversion,char *extension)
24 {
25 char *walk;
26
27 switch (conversion) {
28 case 'b':
29 return 1;
30 case 't':
31 return 0;
32 case 'a':
33 for (walk = bin_extensions; *walk; walk += 3)
34 if (!strncmp(extension,walk,3)) return 1;
35 return 0;
36 default:
37 panic("Invalid conversion mode");
38 }
39 }
40
41
42 static struct wait_queue *creation_wait = NULL;
43 static creation_lock = 0;
44
45
46 void lock_creation(void)
47 {
48 while (creation_lock) sleep_on(&creation_wait);
49 creation_lock = 1;
50 }
51
52
53 void unlock_creation(void)
54 {
55 creation_lock = 0;
56 wake_up(&creation_wait);
57 }
58
59
60 int msdos_add_cluster(struct inode *inode)
61 {
62 static struct wait_queue *wait = NULL;
63 static int lock = 0;
64 static int previous = 0;
65 int count,this,limit,last,current,sector;
66 void *data;
67 struct buffer_head *bh;
68
69 if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
70 while (lock) sleep_on(&wait);
71 lock = 1;
72 limit = MSDOS_SB(inode->i_sb)->clusters;
73 this = limit;
74 for (count = 0; count < limit; count++) {
75 this = ((count+previous) % limit)+2;
76 if (fat_access(inode->i_sb,this,-1) == 0) break;
77 }
78 #ifdef DEBUG
79 printk("free cluster: %d\r\n",this);
80 #endif
81 previous = (count+previous+1) % limit;
82 if (count >= limit) {
83 lock = 0;
84 wake_up(&wait);
85 return -ENOSPC;
86 }
87 fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
88 0xff8 : 0xfff8);
89 lock = 0;
90 wake_up(&wait);
91 #ifdef DEBUG
92 printk("set to %x\r\n",fat_access(inode->i_sb,this,-1));
93 #endif
94 if (!S_ISDIR(inode->i_mode)) {
95 last = inode->i_size ? get_cluster(inode,(inode->i_size-1)/
96 SECTOR_SIZE/MSDOS_SB(inode->i_sb)->cluster_size) : 0;
97 }
98 else {
99 last = 0;
100 if (current = inode->i_data[D_START]) {
101 cache_lookup(inode,0x7fffffff,&last,¤t);
102 while (current && current != -1)
103 if (!(current = fat_access(inode->i_sb,
104 last = current,-1)))
105 panic("File without EOF");
106 }
107 }
108 #ifdef DEBUG
109 printk("last = %d\r\n",last);
110 #endif
111 if (last) fat_access(inode->i_sb,last,this);
112 else {
113 inode->i_data[D_START] = this;
114 inode->i_dirt = 1;
115 }
116 #ifdef DEBUG
117 if (last) printk("next set to %d\r\n",fat_access(inode->i_sb,last,-1));
118 #endif
119 for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
120 current++) {
121 sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)*
122 MSDOS_SB(inode->i_sb)->cluster_size+current;
123 #ifdef DEBUG
124 printk("zeroing sector %d\r\n",sector);
125 #endif
126 if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
127 !(sector & 1)) {
128 if (!(bh = getblk(inode->i_dev,sector >> 1, BLOCK_SIZE)))
129 printk("getblk failed\r\n");
130 else {
131 memset(bh->b_data,0,BLOCK_SIZE);
132 bh->b_uptodate = 1;
133 }
134 current++;
135 }
136 else {
137 if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
138 printk("msdos_sread failed\r\n");
139 else memset(data,0,SECTOR_SIZE);
140 }
141 if (bh) {
142 bh->b_dirt = 1;
143 brelse(bh);
144 }
145 }
146 if (S_ISDIR(inode->i_mode)) {
147 if (inode->i_size & (SECTOR_SIZE-1))
148 panic("Odd directory size");
149 inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
150 cluster_size;
151 #ifdef DEBUG
152 printk("size is %d now (%x)\r\n",inode->i_size,inode);
153 #endif
154 inode->i_dirt = 1;
155 }
156 return 0;
157 }
158
159
160
161
162 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
163
164
165
166
167
168 int date_dos2unix(unsigned short time,unsigned short date)
169 {
170 int month,year;
171
172 month = ((date >> 5) & 15)-1;
173 year = date >> 9;
174 return (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
175 ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
176 month < 2 ? 1 : 0)+3653);
177
178 }
179
180
181
182
183 void date_unix2dos(int unix_date,unsigned short *time,
184 unsigned short *date)
185 {
186 int day,year,nl_day,month;
187
188 *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
189 (((unix_date/3600) % 24) << 11);
190 day = unix_date/86400-3652;
191 year = day/365;
192 if ((year+3)/4+365*year > day) year--;
193 day -= (year+3)/4+365*year;
194 if (day == 59 && !(year & 3)) {
195 nl_day = day;
196 month = 2;
197 }
198 else {
199 nl_day = (year & 3) || day <= 59 ? day : day-1;
200 for (month = 0; month < 12; month++)
201 if (day_n[month] > nl_day) break;
202 }
203 *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
204 }
205
206
207
208
209
210
211 int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
212 struct msdos_dir_entry **de)
213 {
214 int sector,offset;
215 void *data;
216
217 while (1) {
218 offset = *pos;
219 if ((sector = msdos_smap(dir,*pos >> SECTOR_BITS)) == -1)
220 return -1;
221 if (!sector)
222 return -1;
223 *pos += sizeof(struct msdos_dir_entry);
224 if (*bh)
225 brelse(*bh);
226 if (!(*bh = msdos_sread(dir->i_dev,sector,&data)))
227 continue;
228 *de = (struct msdos_dir_entry *) (data+(offset &
229 (SECTOR_SIZE-1)));
230 return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
231 MSDOS_DIR_BITS);
232 }
233 }
234
235
236
237
238
239 int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
240 struct msdos_dir_entry **res_de,int *ino)
241 {
242 int pos;
243 struct msdos_dir_entry *de;
244 struct inode *inode;
245
246 pos = 0;
247 *res_bh = NULL;
248 while ((*ino = msdos_get_entry(dir,&pos,res_bh,&de)) > -1) {
249 if (name) {
250 if (de->name[0] && ((unsigned char *) (de->name))[0]
251 != DELETED_FLAG && !(de->attr & ATTR_VOLUME) &&
252 !strncmp(de->name,name,MSDOS_NAME)) break;
253 }
254 else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
255 DELETED_FLAG) {
256 if (!(inode = iget(dir->i_dev,*ino))) break;
257 if (!inode->i_data[D_BUSY]) {
258 iput(inode);
259 break;
260 }
261
262 iput(inode);
263 }
264 }
265 if (*ino == -1) {
266 if (*res_bh) brelse(*res_bh);
267 *res_bh = NULL;
268 return name ? -ENOENT : -ENOSPC;
269 }
270 *res_de = de;
271 return 0;
272 }
273
274
275
276
277
278
279
280 static int raw_found(struct super_block *sb,int sector,char *name,int number,
281 int *ino)
282 {
283 struct buffer_head *bh;
284 struct msdos_dir_entry *data;
285 int entry,start;
286
287 if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
288 for (entry = 0; entry < MSDOS_DPS; entry++)
289 if (name ? !strncmp(data[entry].name,name,MSDOS_NAME) :
290 *(unsigned char *) data[entry].name != DELETED_FLAG &&
291 data[entry].start == number) {
292 if (ino) *ino = sector*MSDOS_DPS+entry;
293 start = data[entry].start;
294 brelse(bh);
295 return start;
296 }
297 brelse(bh);
298 return -1;
299 }
300
301
302 static int raw_scan_root(struct super_block *sb,char *name,int number,int *ino)
303 {
304 int count,cluster;
305
306 for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
307 if ((cluster = raw_found(sb,MSDOS_SB(sb)->dir_start+count,name,
308 number,ino)) >= 0) return cluster;
309 }
310 return -ENOENT;
311 }
312
313
314 static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
315 int number,int *ino)
316 {
317 int count,cluster;
318
319 do {
320 for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
321 if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)->
322 cluster_size+MSDOS_SB(sb)->data_start+count,name,
323 number,ino)) >= 0) return cluster;
324 }
325 if (!(start = fat_access(sb,start,-1))) panic("FAT error");
326 }
327 while (start != -1);
328 return -ENOENT;
329 }
330
331
332 static int raw_scan(struct super_block *sb,int start,char *name,int number,
333 int *ino)
334 {
335 if (start) return raw_scan_nonroot(sb,start,name,number,ino);
336 else return raw_scan_root(sb,name,number,ino);
337 }
338
339
340 int msdos_parent_ino(struct inode *dir,int locked)
341 {
342 int error,current,prev,this;
343
344 if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
345 if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
346 if (!locked) lock_creation();
347 if ((current = raw_scan(dir->i_sb,dir->i_data[D_START],MSDOS_DOTDOT,0,
348 NULL)) < 0) {
349 if (!locked) unlock_creation();
350 return current;
351 }
352 if (!current) this = MSDOS_ROOT_INO;
353 else {
354 if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,0,NULL)) <
355 0) {
356 if (!locked) unlock_creation();
357 return prev;
358 }
359 if ((error = raw_scan(dir->i_sb,prev,NULL,current,&this)) < 0) {
360 if (!locked) unlock_creation();
361 return error;
362 }
363 }
364 if (!locked) unlock_creation();
365 return this;
366 }