|
|
1.1 root 1: /*
2: * linux/fs/msdos/misc.c
3: *
4: * Written 1992 by Werner Almesberger
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" /* program code */
16: "ARCZIPLHALZHZOOTARZ ARJTZ " /* common archivers */
17: "GIFBMPTIFGL JPGPCX" /* graphics */
18: "TFMVF GF PK PXLDVI"; /* TeX */
19:
20:
21: /* Select binary/text conversion */
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; /* works best if one FS is being used */
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; /* to keep GCC happy */
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: /* Linear day numbers of the respective 1sts in non-leap years. */
161:
162: static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
163: /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
164:
165:
166: /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
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: /* days since 1.1.70 plus 80's leap day */
178: }
179:
180:
181: /* Convert linear UNIX date to a MS-DOS time/date pair. */
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: /* Returns the inode number of the directory entry at offset pos. If bh is
208: non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
209: returned in bh. */
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; /* FAT error ... */
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: /* Scans a directory for a given file (name points to its formatted name) or
237: for an empty directory slot (name is NULL). Returns the inode number. */
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: /* skip deleted files that haven't been closed yet */
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: /* Now an ugly part: this set of directory scan routines works on clusters
276: rather than on inodes and sectors. They are necessary to locate the '..'
277: directory "inode". */
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(); /* prevent renames */
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.