|
|
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:
1.1.1.2 ! root 37: printk("Invalid conversion mode - defaulting to "
! 38: "binary.\n");
! 39: return 1;
1.1 root 40: }
41: }
42:
43:
1.1.1.2 ! root 44: /* File creation lock. This is system-wide to avoid deadlocks in rename. */
! 45: /* (rename might deadlock before detecting cross-FS moves.) */
! 46:
1.1 root 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:
1.1.1.2 ! root 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:
1.1 root 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; /* works best if one FS is being used */
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;
1.1.1.2 ! root 89: if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
1.1 root 90: while (lock) sleep_on(&wait);
91: lock = 1;
1.1.1.2 ! root 92: lock_fat(inode->i_sb);
1.1 root 93: limit = MSDOS_SB(inode->i_sb)->clusters;
94: this = limit; /* to keep GCC happy */
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
1.1.1.2 ! root 100: printk("free cluster: %d\n",this);
1.1 root 101: #endif
102: previous = (count+previous+1) % limit;
103: if (count >= limit) {
1.1.1.2 ! root 104: MSDOS_SB(inode->i_sb)->free_clusters = 0;
! 105: unlock_fat(inode->i_sb);
1.1 root 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);
1.1.1.2 ! root 112: if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
! 113: MSDOS_SB(inode->i_sb)->free_clusters--;
! 114: unlock_fat(inode->i_sb);
1.1 root 115: lock = 0;
116: wake_up(&wait);
117: #ifdef DEBUG
1.1.1.2 ! root 118: printk("set to %x\n",fat_access(inode->i_sb,this,-1));
1.1 root 119: #endif
1.1.1.2 ! root 120: last = 0;
! 121: if (current = MSDOS_I(inode)->i_start) {
! 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");
1.1 root 127: }
128: #ifdef DEBUG
1.1.1.2 ! root 129: printk("last = %d\n",last);
1.1 root 130: #endif
131: if (last) fat_access(inode->i_sb,last,this);
132: else {
1.1.1.2 ! root 133: MSDOS_I(inode)->i_start = this;
1.1 root 134: inode->i_dirt = 1;
135: }
136: #ifdef DEBUG
1.1.1.2 ! root 137: if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
1.1 root 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
1.1.1.2 ! root 144: printk("zeroing sector %d\n",sector);
1.1 root 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)))
1.1.1.2 ! root 149: printk("getblk failed\n");
1.1 root 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)))
1.1.1.2 ! root 158: printk("msdos_sread failed\n");
1.1 root 159: else memset(data,0,SECTOR_SIZE);
160: }
161: if (bh) {
162: bh->b_dirt = 1;
163: brelse(bh);
164: }
165: }
1.1.1.2 ! root 166: inode->i_blocks++;
1.1 root 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
1.1.1.2 ! root 173: printk("size is %d now (%x)\n",inode->i_size,inode);
1.1 root 174: #endif
175: inode->i_dirt = 1;
176: }
177: return 0;
178: }
179:
180:
181: /* Linear day numbers of the respective 1sts in non-leap years. */
182:
183: static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
184: /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
185:
186:
1.1.1.2 ! root 187: extern struct timezone sys_tz;
! 188:
! 189:
1.1 root 190: /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
191:
192: int date_dos2unix(unsigned short time,unsigned short date)
193: {
1.1.1.2 ! root 194: int month,year,secs;
1.1 root 195:
196: month = ((date >> 5) & 15)-1;
197: year = date >> 9;
1.1.1.2 ! root 198: secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
1.1 root 199: ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
200: month < 2 ? 1 : 0)+3653);
201: /* days since 1.1.70 plus 80's leap day */
1.1.1.2 ! root 202: secs += sys_tz.tz_minuteswest*60;
! 203: return secs;
1.1 root 204: }
205:
206:
207: /* Convert linear UNIX date to a MS-DOS time/date pair. */
208:
209: void date_unix2dos(int unix_date,unsigned short *time,
210: unsigned short *date)
211: {
212: int day,year,nl_day,month;
213:
1.1.1.2 ! root 214: unix_date -= sys_tz.tz_minuteswest*60;
1.1 root 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: /* Returns the inode number of the directory entry at offset pos. If bh is
235: non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
236: returned in bh. */
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;
1.1.1.2 ! root 246: if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
1.1 root 247: return -1;
248: if (!sector)
249: return -1; /* FAT error ... */
250: *pos += sizeof(struct msdos_dir_entry);
251: if (*bh)
252: brelse(*bh);
1.1.1.2 ! root 253: if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
! 254: printk("Directory sread (sector %d) failed\n",sector);
1.1 root 255: continue;
1.1.1.2 ! root 256: }
1.1 root 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: /* Scans a directory for a given file (name points to its formatted name) or
266: for an empty directory slot (name is NULL). Returns the inode number. */
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_dev,*ino))) break;
1.1.1.2 ! root 286: if (!MSDOS_I(inode)->i_busy) {
1.1 root 287: iput(inode);
288: break;
289: }
290: /* skip deleted files that haven't been closed yet */
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: /* Now an ugly part: this set of directory scan routines works on clusters
305: rather than on inodes and sectors. They are necessary to locate the '..'
1.1.1.2 ! root 306: directory "inode". raw_found operates in three modes: if name is non-NULL,
! 307: the directory is scanned for an entry with that name. If ino is non-NULL,
! 308: the directory is scanned for an entry whose data starts at *number. If name
! 309: and ino are NULL, the directory entries are counted in *number. */
1.1 root 310:
311:
1.1.1.2 ! root 312: static int raw_found(struct super_block *sb,int sector,char *name,int *number,
1.1 root 313: int *ino)
314: {
315: struct buffer_head *bh;
316: struct msdos_dir_entry *data;
1.1.1.2 ! root 317: int entry,start,done;
1.1 root 318:
319: if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
1.1.1.2 ! root 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) {
1.1 root 335: if (ino) *ino = sector*MSDOS_DPS+entry;
336: start = data[entry].start;
337: brelse(bh);
338: return start;
339: }
1.1.1.2 ! root 340: }
1.1 root 341: brelse(bh);
342: return -1;
343: }
344:
345:
1.1.1.2 ! root 346: static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino)
1.1 root 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,
1.1.1.2 ! root 359: int *number,int *ino)
1.1 root 360: {
361: int count,cluster;
362:
1.1.1.2 ! root 363: #ifdef DEBUG
! 364: printk("raw_scan_nonroot: start=%d\n",start);
! 365: #endif
1.1 root 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");
1.1.1.2 ! root 373: #ifdef DEBUG
! 374: printk("next start: %d\n",start);
! 375: #endif
1.1 root 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: {
1.1.1.2 ! root 385: if (start) return raw_scan_nonroot(sb,start,name,&number,ino);
! 386: else return raw_scan_root(sb,name,&number,ino);
1.1 root 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(); /* prevent renames */
1.1.1.2 ! root 397: if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,0,
1.1 root 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: }
1.1.1.2 ! root 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; /* in mkdir */
! 428: else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
! 429: NULL,&count,NULL);
! 430: }
! 431: return count;
! 432: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.