This source file includes following definitions.
- fs_panic
 
- is_binary
 
- lock_creation
 
- unlock_creation
 
- lock_fat
 
- unlock_fat
 
- msdos_add_cluster
 
- date_dos2unix
 
- date_unix2dos
 
- msdos_get_entry
 
- raw_scan_sector
 
- raw_scan_root
 
- raw_scan_nonroot
 
- raw_scan
 
- msdos_parent_ino
 
- msdos_subdirs
 
- msdos_scan
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 #include <linux/fs.h>
   8 #include <linux/msdos_fs.h>
   9 #include <linux/sched.h>
  10 #include <linux/kernel.h>
  11 #include <linux/errno.h>
  12 #include <linux/string.h>
  13 #include <linux/stat.h>
  14 
  15 
  16 
  17 static char bin_extensions[] =
  18   "EXECOMBINAPPSYSDRVOVLOVROBJLIBDLLPIF"        
  19   "ARCZIPLHALZHZOOTARZ  ARJ"    
  20   "TZ TAZTZPTPZ"                
  21   "GZ TGZDEB"                   
  22   "GIFBMPTIFGL JPGPCX"          
  23   "TFMVF GF PK PXLDVI";         
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 void fs_panic(struct super_block *s,char *msg)
     
  32 {
  33         int not_ro;
  34 
  35         not_ro = !(s->s_flags & MS_RDONLY);
  36         if (not_ro) s->s_flags |= MS_RDONLY;
  37         printk("Filesystem panic (dev 0x%04X, mounted on 0x%04X:%ld)\n  %s\n",
  38             s->s_dev,s->s_covered->i_dev,s->s_covered->i_ino,msg);
  39         if (not_ro)
  40                 printk("  File system has been set read-only\n");
  41 }
  42 
  43 
  44 
  45 
  46 
  47 
  48 
  49 int is_binary(char conversion,char *extension)
     
  50 {
  51         char *walk;
  52 
  53         switch (conversion) {
  54                 case 'b':
  55                         return 1;
  56                 case 't':
  57                         return 0;
  58                 case 'a':
  59                         for (walk = bin_extensions; *walk; walk += 3)
  60                                 if (!strncmp(extension,walk,3)) return 1;
  61                         return 0;
  62                 default:
  63                         printk("Invalid conversion mode - defaulting to "
  64                             "binary.\n");
  65                         return 1;
  66         }
  67 }
  68 
  69 
  70 
  71 
  72 
  73 static struct wait_queue *creation_wait = NULL;
  74 static creation_lock = 0;
  75 
  76 
  77 void lock_creation(void)
     
  78 {
  79         while (creation_lock) sleep_on(&creation_wait);
  80         creation_lock = 1;
  81 }
  82 
  83 
  84 void unlock_creation(void)
     
  85 {
  86         creation_lock = 0;
  87         wake_up(&creation_wait);
  88 }
  89 
  90 
  91 void lock_fat(struct super_block *sb)
     
  92 {
  93         while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
  94         MSDOS_SB(sb)->fat_lock = 1;
  95 }
  96 
  97 
  98 void unlock_fat(struct super_block *sb)
     
  99 {
 100         MSDOS_SB(sb)->fat_lock = 0;
 101         wake_up(&MSDOS_SB(sb)->fat_wait);
 102 }
 103 
 104 
 105 
 106 
 107 
 108 
 109 
 110 int msdos_add_cluster(struct inode *inode)
     
 111 {
 112         int count,nr,limit,last,current,sector;
 113         void *data;
 114         struct buffer_head *bh;
 115 
 116         if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
 117         if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
 118         lock_fat(inode->i_sb);
 119         limit = MSDOS_SB(inode->i_sb)->clusters;
 120         nr = limit; 
 121         for (count = 0; count < limit; count++) {
 122                 nr = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
 123                 if (fat_access(inode->i_sb,nr,-1) == 0) break;
 124         }
 125 #ifdef DEBUG
 126 printk("free cluster: %d\n",nr);
 127 #endif
 128         MSDOS_SB(inode->i_sb)->prev_free = (count+MSDOS_SB(inode->i_sb)->
 129             prev_free+1) % limit;
 130         if (count >= limit) {
 131                 MSDOS_SB(inode->i_sb)->free_clusters = 0;
 132                 unlock_fat(inode->i_sb);
 133                 return -ENOSPC;
 134         }
 135         fat_access(inode->i_sb,nr,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
 136             0xff8 : 0xfff8);
 137         if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
 138                 MSDOS_SB(inode->i_sb)->free_clusters--;
 139         unlock_fat(inode->i_sb);
 140 #ifdef DEBUG
 141 printk("set to %x\n",fat_access(inode->i_sb,nr,-1));
 142 #endif
 143         last = 0;
 144         if ((current = MSDOS_I(inode)->i_start) != 0) {
 145                 cache_lookup(inode,INT_MAX,&last,¤t);
 146                 while (current && current != -1)
 147                         if (!(current = fat_access(inode->i_sb,
 148                             last = current,-1))) {
 149                                 fs_panic(inode->i_sb,"File without EOF");
 150                                 return -ENOSPC;
 151                         }
 152         }
 153 #ifdef DEBUG
 154 printk("last = %d\n",last);
 155 #endif
 156         if (last) fat_access(inode->i_sb,last,nr);
 157         else {
 158                 MSDOS_I(inode)->i_start = nr;
 159                 inode->i_dirt = 1;
 160         }
 161 #ifdef DEBUG
 162 if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
 163 #endif
 164         for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
 165             current++) {
 166                 sector = MSDOS_SB(inode->i_sb)->data_start+(nr-2)*
 167                     MSDOS_SB(inode->i_sb)->cluster_size+current;
 168 #ifdef DEBUG
 169 printk("zeroing sector %d\n",sector);
 170 #endif
 171                 if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
 172                     !(sector & 1)) {
 173                         if (!(bh = getblk(inode->i_dev,sector >> 1,
 174                             BLOCK_SIZE)))
 175                                 printk("getblk failed\n");
 176                         else {
 177                                 memset(bh->b_data,0,BLOCK_SIZE);
 178                                 bh->b_uptodate = 1;
 179                         }
 180                         current++;
 181                 }
 182                 else {
 183                         if (!(bh = msdos_sread(inode->i_dev,sector,
 184                             &data)))
 185                                 printk("msdos_sread failed\n");
 186                         else memset(data,0,SECTOR_SIZE);
 187                 }
 188                 if (bh) {
 189                         mark_buffer_dirty(bh, 1);
 190                         brelse(bh);
 191                 }
 192         }
 193         inode->i_blocks += MSDOS_SB(inode->i_sb)->cluster_size;
 194         if (S_ISDIR(inode->i_mode)) {
 195                 if (inode->i_size & (SECTOR_SIZE-1)) {
 196                         fs_panic(inode->i_sb,"Odd directory size");
 197                         inode->i_size = (inode->i_size+SECTOR_SIZE) &
 198                             ~(SECTOR_SIZE-1);
 199                 }
 200                 inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
 201                     cluster_size;
 202 #ifdef DEBUG
 203 printk("size is %d now (%x)\n",inode->i_size,inode);
 204 #endif
 205                 inode->i_dirt = 1;
 206         }
 207         return 0;
 208 }
 209 
 210 
 211 
 212 
 213 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
 214                   
 215 
 216 
 217 extern struct timezone sys_tz;
 218 
 219 
 220 
 221 
 222 int date_dos2unix(unsigned short time,unsigned short date)
     
 223 {
 224         int month,year,secs;
 225 
 226         month = ((date >> 5) & 15)-1;
 227         year = date >> 9;
 228         secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
 229             ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
 230             month < 2 ? 1 : 0)+3653);
 231                         
 232         secs += sys_tz.tz_minuteswest*60;
 233         return secs;
 234 }
 235 
 236 
 237 
 238 
 239 void date_unix2dos(int unix_date,unsigned short *time,
     
 240     unsigned short *date)
 241 {
 242         int day,year,nl_day,month;
 243 
 244         unix_date -= sys_tz.tz_minuteswest*60;
 245         *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
 246             (((unix_date/3600) % 24) << 11);
 247         day = unix_date/86400-3652;
 248         year = day/365;
 249         if ((year+3)/4+365*year > day) year--;
 250         day -= (year+3)/4+365*year;
 251         if (day == 59 && !(year & 3)) {
 252                 nl_day = day;
 253                 month = 2;
 254         }
 255         else {
 256                 nl_day = (year & 3) || day <= 59 ? day : day-1;
 257                 for (month = 0; month < 12; month++)
 258                         if (day_n[month] > nl_day) break;
 259         }
 260         *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
 261 }
 262 
 263 
 264 
 265 
 266 
 267 
 268 int msdos_get_entry(struct inode *dir, off_t *pos,struct buffer_head **bh,
     
 269     struct msdos_dir_entry **de)
 270 {
 271         int sector,offset;
 272         void *data;
 273 
 274         while (1) {
 275                 offset = *pos;
 276                 if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
 277                         return -1;
 278                 if (!sector)
 279                         return -1; 
 280                 *pos += sizeof(struct msdos_dir_entry);
 281                 if (*bh)
 282                         brelse(*bh);
 283                 if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
 284                         printk("Directory sread (sector %d) failed\n",sector);
 285                         continue;
 286                 }
 287                 *de = (struct msdos_dir_entry *) (data+(offset &
 288                     (SECTOR_SIZE-1)));
 289                 return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
 290                     MSDOS_DIR_BITS);
 291         }
 292 }
 293 
 294 
 295 
 296 
 297 
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 
 309 
 310 
 311 
 312 
 313 
 314 
 315 
 316 
 317 
 318 
 319 
 320 #define RSS_NAME  \
 321     done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
 322      !(data[entry].attr & ATTR_VOLUME);
 323 
 324 #define RSS_START  \
 325     done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number;
 326 
 327 #define RSS_FREE  \
 328     { \
 329         done = IS_FREE(data[entry].name); \
 330         if (done) { \
 331             inode = iget(sb,sector*MSDOS_DPS+entry); \
 332             if (inode) { \
 333              \
 334                 done = !MSDOS_I(inode)->i_busy; \
 335                 iput(inode); \
 336             } \
 337         } \
 338     }
 339 
 340 #define RSS_COUNT  \
 341     { \
 342         done = 0; \
 343         if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
 344             (*number)++; \
 345     }
 346 
 347 static int raw_scan_sector(struct super_block *sb,int sector,char *name,
     
 348     int *number,int *ino,struct buffer_head **res_bh,
 349     struct msdos_dir_entry **res_de)
 350 {
 351         struct buffer_head *bh;
 352         struct msdos_dir_entry *data;
 353         struct inode *inode;
 354         int entry,start,done;
 355 
 356         if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
 357         for (entry = 0; entry < MSDOS_DPS; entry++) {
 358                 if (name) RSS_NAME
 359                 else {
 360                         if (!ino) RSS_COUNT
 361                         else {
 362                                 if (number) RSS_START
 363                                 else RSS_FREE
 364                         }
 365                 }
 366                 if (done) {
 367                         if (ino) *ino = sector*MSDOS_DPS+entry;
 368                         start = CF_LE_W(data[entry].start);
 369                         if (!res_bh) brelse(bh);
 370                         else {
 371                                 *res_bh = bh;
 372                                 *res_de = &data[entry];
 373                         }
 374                         return start;
 375                 }
 376         }
 377         brelse(bh);
 378         return -ENOENT;
 379 }
 380 
 381 
 382 
 383 
 384 
 385 
 386 
 387 static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino,
     
 388     struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
 389 {
 390         int count,cluster;
 391 
 392         for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
 393                 if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
 394                     name,number,ino,res_bh,res_de)) >= 0) return cluster;
 395         }
 396         return -ENOENT;
 397 }
 398 
 399 
 400 
 401 
 402 
 403 
 404 
 405 static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
     
 406     int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
 407     **res_de)
 408 {
 409         int count,cluster;
 410 
 411 #ifdef DEBUG
 412         printk("raw_scan_nonroot: start=%d\n",start);
 413 #endif
 414         do {
 415                 for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
 416                         if ((cluster = raw_scan_sector(sb,(start-2)*
 417                             MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
 418                             count,name,number,ino,res_bh,res_de)) >= 0)
 419                                 return cluster;
 420                 }
 421                 if (!(start = fat_access(sb,start,-1))) {
 422                         fs_panic(sb,"FAT error");
 423                         break;
 424                 }
 425 #ifdef DEBUG
 426         printk("next start: %d\n",start);
 427 #endif
 428         }
 429         while (start != -1);
 430         return -ENOENT;
 431 }
 432 
 433 
 434 
 435 
 436 
 437 
 438 
 439 
 440 
 441 static int raw_scan(struct super_block *sb,int start,char *name,int *number,
     
 442     int *ino,struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
 443 {
 444         if (start)
 445                 return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de);
 446         else return raw_scan_root(sb,name,number,ino,res_bh,res_de);
 447 }
 448 
 449 
 450 
 451 
 452 
 453 
 454 
 455 
 456 int msdos_parent_ino(struct inode *dir,int locked)
     
 457 {
 458         static int zero = 0;
 459         int error,current,prev,nr;
 460 
 461         if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
 462         if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
 463         if (!locked) lock_creation(); 
 464         if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,
 465             &zero,NULL,NULL,NULL)) < 0) {
 466                 if (!locked) unlock_creation();
 467                 return current;
 468         }
 469         if (!current) nr = MSDOS_ROOT_INO;
 470         else {
 471                 if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,&zero,NULL,
 472                     NULL,NULL)) < 0) {
 473                         if (!locked) unlock_creation();
 474                         return prev;
 475                 }
 476                 if ((error = raw_scan(dir->i_sb,prev,NULL,¤t,&nr,NULL,
 477                     NULL)) < 0) {
 478                         if (!locked) unlock_creation();
 479                         return error;
 480                 }
 481         }
 482         if (!locked) unlock_creation();
 483         return nr;
 484 }
 485 
 486 
 487 
 488 
 489 
 490 
 491 
 492 int msdos_subdirs(struct inode *dir)
     
 493 {
 494         int count;
 495 
 496         count = 0;
 497         if (dir->i_ino == MSDOS_ROOT_INO)
 498                 (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
 499         else {
 500                 if (!MSDOS_I(dir)->i_start) return 0; 
 501                 else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
 502                     NULL,&count,NULL,NULL,NULL);
 503         }
 504         return count;
 505 }
 506 
 507 
 508 
 509 
 510 
 511 
 512 
 513 int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
     
 514     struct msdos_dir_entry **res_de,int *ino)
 515 {
 516         int res;
 517 
 518         if (name)
 519                 res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,name,NULL,ino,
 520                     res_bh,res_de);
 521         else res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,NULL,NULL,ino,
 522                     res_bh,res_de);
 523         return res < 0 ? res : 0;
 524 }