This source file includes following definitions.
- is_binary
- lock_creation
- unlock_creation
- lock_fat
- unlock_fat
- 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
- msdos_subdirs
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 printk("Invalid conversion mode - defaulting to "
38 "binary.\n");
39 return 1;
40 }
41 }
42
43
44
45
46
47 static struct wait_queue *creation_wait = NULL;
48 static creation_lock = 0;
49
50
51 void lock_creation(void)
52 {
53 while (creation_lock) sleep_on(&creation_wait);
54 creation_lock = 1;
55 }
56
57
58 void unlock_creation(void)
59 {
60 creation_lock = 0;
61 wake_up(&creation_wait);
62 }
63
64
65 void lock_fat(struct super_block *sb)
66 {
67 while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
68 MSDOS_SB(sb)->fat_lock = 1;
69 }
70
71
72 void unlock_fat(struct super_block *sb)
73 {
74 MSDOS_SB(sb)->fat_lock = 0;
75 wake_up(&MSDOS_SB(sb)->fat_wait);
76 }
77
78
79 int msdos_add_cluster(struct inode *inode)
80 {
81 static struct wait_queue *wait = NULL;
82 static int lock = 0;
83 static int previous = 0;
84 int count,this,limit,last,current,sector;
85 void *data;
86 struct buffer_head *bh;
87
88 if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
89 if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
90 while (lock) sleep_on(&wait);
91 lock = 1;
92 lock_fat(inode->i_sb);
93 limit = MSDOS_SB(inode->i_sb)->clusters;
94 this = limit;
95 for (count = 0; count < limit; count++) {
96 this = ((count+previous) % limit)+2;
97 if (fat_access(inode->i_sb,this,-1) == 0) break;
98 }
99 #ifdef DEBUG
100 printk("free cluster: %d\n",this);
101 #endif
102 previous = (count+previous+1) % limit;
103 if (count >= limit) {
104 MSDOS_SB(inode->i_sb)->free_clusters = 0;
105 unlock_fat(inode->i_sb);
106 lock = 0;
107 wake_up(&wait);
108 return -ENOSPC;
109 }
110 fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
111 0xff8 : 0xfff8);
112 if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
113 MSDOS_SB(inode->i_sb)->free_clusters--;
114 unlock_fat(inode->i_sb);
115 lock = 0;
116 wake_up(&wait);
117 #ifdef DEBUG
118 printk("set to %x\n",fat_access(inode->i_sb,this,-1));
119 #endif
120 last = 0;
121 if ((current = MSDOS_I(inode)->i_start) != 0) {
122 cache_lookup(inode,0x7fffffff,&last,¤t);
123 while (current && current != -1)
124 if (!(current = fat_access(inode->i_sb,
125 last = current,-1)))
126 panic("File without EOF");
127 }
128 #ifdef DEBUG
129 printk("last = %d\n",last);
130 #endif
131 if (last) fat_access(inode->i_sb,last,this);
132 else {
133 MSDOS_I(inode)->i_start = this;
134 inode->i_dirt = 1;
135 }
136 #ifdef DEBUG
137 if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
138 #endif
139 for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
140 current++) {
141 sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)*
142 MSDOS_SB(inode->i_sb)->cluster_size+current;
143 #ifdef DEBUG
144 printk("zeroing sector %d\n",sector);
145 #endif
146 if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
147 !(sector & 1)) {
148 if (!(bh = getblk(inode->i_dev,sector >> 1, BLOCK_SIZE)))
149 printk("getblk failed\n");
150 else {
151 memset(bh->b_data,0,BLOCK_SIZE);
152 bh->b_uptodate = 1;
153 }
154 current++;
155 }
156 else {
157 if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
158 printk("msdos_sread failed\n");
159 else memset(data,0,SECTOR_SIZE);
160 }
161 if (bh) {
162 bh->b_dirt = 1;
163 brelse(bh);
164 }
165 }
166 inode->i_blocks += MSDOS_SB(inode->i_sb)->cluster_size;
167 if (S_ISDIR(inode->i_mode)) {
168 if (inode->i_size & (SECTOR_SIZE-1))
169 panic("Odd directory size");
170 inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
171 cluster_size;
172 #ifdef DEBUG
173 printk("size is %d now (%x)\n",inode->i_size,inode);
174 #endif
175 inode->i_dirt = 1;
176 }
177 return 0;
178 }
179
180
181
182
183 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
184
185
186
187 extern struct timezone sys_tz;
188
189
190
191
192 int date_dos2unix(unsigned short time,unsigned short date)
193 {
194 int month,year,secs;
195
196 month = ((date >> 5) & 15)-1;
197 year = date >> 9;
198 secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
199 ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
200 month < 2 ? 1 : 0)+3653);
201
202 secs += sys_tz.tz_minuteswest*60;
203 return secs;
204 }
205
206
207
208
209 void date_unix2dos(int unix_date,unsigned short *time,
210 unsigned short *date)
211 {
212 int day,year,nl_day,month;
213
214 unix_date -= sys_tz.tz_minuteswest*60;
215 *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
216 (((unix_date/3600) % 24) << 11);
217 day = unix_date/86400-3652;
218 year = day/365;
219 if ((year+3)/4+365*year > day) year--;
220 day -= (year+3)/4+365*year;
221 if (day == 59 && !(year & 3)) {
222 nl_day = day;
223 month = 2;
224 }
225 else {
226 nl_day = (year & 3) || day <= 59 ? day : day-1;
227 for (month = 0; month < 12; month++)
228 if (day_n[month] > nl_day) break;
229 }
230 *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
231 }
232
233
234
235
236
237
238 int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
239 struct msdos_dir_entry **de)
240 {
241 int sector,offset;
242 void *data;
243
244 while (1) {
245 offset = *pos;
246 if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
247 return -1;
248 if (!sector)
249 return -1;
250 *pos += sizeof(struct msdos_dir_entry);
251 if (*bh)
252 brelse(*bh);
253 if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
254 printk("Directory sread (sector %d) failed\n",sector);
255 continue;
256 }
257 *de = (struct msdos_dir_entry *) (data+(offset &
258 (SECTOR_SIZE-1)));
259 return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
260 MSDOS_DIR_BITS);
261 }
262 }
263
264
265
266
267
268 int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
269 struct msdos_dir_entry **res_de,int *ino)
270 {
271 int pos;
272 struct msdos_dir_entry *de;
273 struct inode *inode;
274
275 pos = 0;
276 *res_bh = NULL;
277 while ((*ino = msdos_get_entry(dir,&pos,res_bh,&de)) > -1) {
278 if (name) {
279 if (de->name[0] && ((unsigned char *) (de->name))[0]
280 != DELETED_FLAG && !(de->attr & ATTR_VOLUME) &&
281 !strncmp(de->name,name,MSDOS_NAME)) break;
282 }
283 else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
284 DELETED_FLAG) {
285 if (!(inode = iget(dir->i_sb,*ino))) break;
286 if (!MSDOS_I(inode)->i_busy) {
287 iput(inode);
288 break;
289 }
290
291 iput(inode);
292 }
293 }
294 if (*ino == -1) {
295 if (*res_bh) brelse(*res_bh);
296 *res_bh = NULL;
297 return name ? -ENOENT : -ENOSPC;
298 }
299 *res_de = de;
300 return 0;
301 }
302
303
304
305
306
307
308
309
310
311
312 static int raw_found(struct super_block *sb,int sector,char *name,int *number,
313 int *ino)
314 {
315 struct buffer_head *bh;
316 struct msdos_dir_entry *data;
317 int entry,start,done;
318
319 if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
320 for (entry = 0; entry < MSDOS_DPS; entry++) {
321 if (name) done = !strncmp(data[entry].name,name,MSDOS_NAME);
322 else {
323 if (ino)
324 done = *(unsigned char *) data[entry].name !=
325 DELETED_FLAG && data[entry].start ==
326 *number;
327 else {
328 done = 0;
329 if (*data[entry].name && *(unsigned char *)
330 data[entry].name != DELETED_FLAG &&
331 (data[entry].attr & ATTR_DIR)) (*number)++;
332 }
333 }
334 if (done) {
335 if (ino) *ino = sector*MSDOS_DPS+entry;
336 start = data[entry].start;
337 brelse(bh);
338 return start;
339 }
340 }
341 brelse(bh);
342 return -1;
343 }
344
345
346 static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino)
347 {
348 int count,cluster;
349
350 for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
351 if ((cluster = raw_found(sb,MSDOS_SB(sb)->dir_start+count,name,
352 number,ino)) >= 0) return cluster;
353 }
354 return -ENOENT;
355 }
356
357
358 static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
359 int *number,int *ino)
360 {
361 int count,cluster;
362
363 #ifdef DEBUG
364 printk("raw_scan_nonroot: start=%d\n",start);
365 #endif
366 do {
367 for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
368 if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)->
369 cluster_size+MSDOS_SB(sb)->data_start+count,name,
370 number,ino)) >= 0) return cluster;
371 }
372 if (!(start = fat_access(sb,start,-1))) panic("FAT error");
373 #ifdef DEBUG
374 printk("next start: %d\n",start);
375 #endif
376 }
377 while (start != -1);
378 return -ENOENT;
379 }
380
381
382 static int raw_scan(struct super_block *sb,int start,char *name,int number,
383 int *ino)
384 {
385 if (start) return raw_scan_nonroot(sb,start,name,&number,ino);
386 else return raw_scan_root(sb,name,&number,ino);
387 }
388
389
390 int msdos_parent_ino(struct inode *dir,int locked)
391 {
392 int error,current,prev,this;
393
394 if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
395 if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
396 if (!locked) lock_creation();
397 if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,0,
398 NULL)) < 0) {
399 if (!locked) unlock_creation();
400 return current;
401 }
402 if (!current) this = MSDOS_ROOT_INO;
403 else {
404 if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,0,NULL)) <
405 0) {
406 if (!locked) unlock_creation();
407 return prev;
408 }
409 if ((error = raw_scan(dir->i_sb,prev,NULL,current,&this)) < 0) {
410 if (!locked) unlock_creation();
411 return error;
412 }
413 }
414 if (!locked) unlock_creation();
415 return this;
416 }
417
418
419 int msdos_subdirs(struct inode *dir)
420 {
421 int count;
422
423 count = 0;
424 if (dir->i_ino == MSDOS_ROOT_INO)
425 (void) raw_scan_root(dir->i_sb,NULL,&count,NULL);
426 else {
427 if (!MSDOS_I(dir)->i_start) return 0;
428 else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
429 NULL,&count,NULL);
430 }
431 return count;
432 }