|
|
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.