root/fs/msdos/misc.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fs_panic
  2. is_binary
  3. lock_creation
  4. unlock_creation
  5. lock_fat
  6. unlock_fat
  7. msdos_add_cluster
  8. date_dos2unix
  9. date_unix2dos
  10. msdos_get_entry
  11. raw_scan_sector
  12. raw_scan_root
  13. raw_scan_nonroot
  14. raw_scan
  15. msdos_parent_ino
  16. msdos_subdirs
  17. msdos_scan

   1 /*
   2  *  linux/fs/msdos/misc.c
   3  *
   4  *  Written 1992,1993 by Werner Almesberger
   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 #include "msbuffer.h"
  16 
  17 #define PRINTK(x)
  18 #define Printk(x)       printk x
  19 
  20 /* Well-known binary file extensions - of course there are many more */
  21 
  22 static char bin_extensions[] =
  23   "EXE" "COM" "BIN" "APP" "SYS" "DRV" "OVL" "OVR" "OBJ" "LIB" "DLL" "PIF" /* program code */
  24   "ARC" "ZIP" "LHA" "LZH" "ZOO" "TAR" "Z  " "ARJ"       /* common archivers */
  25   "TZ " "TAZ" "TZP" "TPZ"               /* abbreviations of tar.Z and tar.zip */
  26   "GZ " "TGZ" "DEB"                     /* .gz, .tar.gz and Debian packages   */
  27   "GIF" "BMP" "TIF" "GL " "JPG" "PCX"   /* graphics */
  28   "TFM" "VF " "GF " "PK " "PXL" "DVI";  /* TeX */
  29 
  30 
  31 /*
  32  * fs_panic reports a severe file system problem and sets the file system
  33  * read-only. The file system can be made writable again by remounting it.
  34  */
  35 
  36 void fs_panic(struct super_block *s,const char *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38         int not_ro;
  39 
  40         not_ro = !(s->s_flags & MS_RDONLY);
  41         if (not_ro) s->s_flags |= MS_RDONLY;
  42         printk("Filesystem panic (dev %s, ", kdevname(s->s_dev));
  43         printk("mounted on %s:%ld)\n  %s\n", /* note: kdevname returns & static char[] */
  44                kdevname(s->s_covered->i_dev), s->s_covered->i_ino, msg);
  45         if (not_ro)
  46                 printk("  File system has been set read-only\n");
  47 }
  48 
  49 
  50 /*
  51  * is_binary selects optional text conversion based on the conversion mode and
  52  * the extension part of the file name.
  53  */
  54 
  55 int is_binary(char conversion,char *extension)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         char *walk;
  58 
  59         switch (conversion) {
  60                 case 'b':
  61                         return 1;
  62                 case 't':
  63                         return 0;
  64                 case 'a':
  65                         for (walk = bin_extensions; *walk; walk += 3)
  66                                 if (!strncmp(extension,walk,3)) return 1;
  67                         return 0;
  68                 default:
  69                         printk("Invalid conversion mode - defaulting to "
  70                             "binary.\n");
  71                         return 1;
  72         }
  73 }
  74 
  75 
  76 /* File creation lock. This is system-wide to avoid deadlocks in rename. */
  77 /* (rename might deadlock before detecting cross-FS moves.) */
  78 
  79 static struct wait_queue *creation_wait = NULL;
  80 static creation_lock = 0;
  81 
  82 
  83 void lock_creation(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85         while (creation_lock) sleep_on(&creation_wait);
  86         creation_lock = 1;
  87 }
  88 
  89 
  90 void unlock_creation(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         creation_lock = 0;
  93         wake_up(&creation_wait);
  94 }
  95 
  96 
  97 void lock_fat(struct super_block *sb)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99         while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
 100         MSDOS_SB(sb)->fat_lock = 1;
 101 }
 102 
 103 
 104 void unlock_fat(struct super_block *sb)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106         MSDOS_SB(sb)->fat_lock = 0;
 107         wake_up(&MSDOS_SB(sb)->fat_wait);
 108 }
 109 
 110 
 111 /*
 112  * msdos_add_cluster tries to allocate a new cluster and adds it to the file
 113  * represented by inode. The cluster is zero-initialized.
 114  */
 115 
 116 int msdos_add_cluster(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118         struct super_block *sb = inode->i_sb;
 119         int count,nr,limit,last,curr,sector,last_sector,file_cluster;
 120         struct buffer_head *bh;
 121         int cluster_size = MSDOS_SB(inode->i_sb)->cluster_size;
 122 
 123         if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
 124         if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
 125         lock_fat(inode->i_sb);
 126         limit = MSDOS_SB(inode->i_sb)->clusters;
 127         nr = limit; /* to keep GCC happy */
 128         for (count = 0; count < limit; count++) {
 129                 nr = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
 130                 if (fat_access(inode->i_sb,nr,-1) == 0) break;
 131         }
 132         PRINTK (("cnt = %d --",count));
 133 #ifdef DEBUG
 134 printk("free cluster: %d\n",nr);
 135 #endif
 136         MSDOS_SB(inode->i_sb)->prev_free = (count+MSDOS_SB(inode->i_sb)->
 137             prev_free+1) % limit;
 138         if (count >= limit) {
 139                 MSDOS_SB(inode->i_sb)->free_clusters = 0;
 140                 unlock_fat(inode->i_sb);
 141                 return -ENOSPC;
 142         }
 143         fat_access(inode->i_sb,nr,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
 144             0xff8 : 0xfff8);
 145         if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
 146                 MSDOS_SB(inode->i_sb)->free_clusters--;
 147         unlock_fat(inode->i_sb);
 148 #ifdef DEBUG
 149 printk("set to %x\n",fat_access(inode->i_sb,nr,-1));
 150 #endif
 151         last = 0;
 152         /* We must locate the last cluster of the file to add this
 153            new one (nr) to the end of the link list (the FAT).
 154            
 155            Here file_cluster will be the number of the last cluster of the
 156            file (before we add nr).
 157            
 158            last is the corresponding cluster number on the disk. We will
 159            use last to plug the nr cluster. We will use file_cluster to
 160            update the cache.
 161         */
 162         file_cluster = 0;
 163         if ((curr = MSDOS_I(inode)->i_start) != 0) {
 164                 cache_lookup(inode,INT_MAX,&last,&curr);
 165                 file_cluster = last;
 166                 while (curr && curr != -1){
 167                         PRINTK (("."));
 168                         file_cluster++;
 169                         if (!(curr = fat_access(inode->i_sb,
 170                             last = curr,-1))) {
 171                                 fs_panic(inode->i_sb,"File without EOF");
 172                                 return -ENOSPC;
 173                         }
 174                 }
 175                 PRINTK ((" --  "));
 176         }
 177 #ifdef DEBUG
 178 printk("last = %d\n",last);
 179 #endif
 180         if (last) fat_access(inode->i_sb,last,nr);
 181         else {
 182                 MSDOS_I(inode)->i_start = nr;
 183                 inode->i_dirt = 1;
 184         }
 185 #ifdef DEBUG
 186 if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
 187 #endif
 188         sector = MSDOS_SB(inode->i_sb)->data_start+(nr-2)*cluster_size;
 189         last_sector = sector + cluster_size;
 190         for ( ; sector < last_sector; sector++) {
 191                 #ifdef DEBUG
 192                         printk("zeroing sector %d\n",sector);
 193                 #endif
 194                 if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE)))
 195                         printk("getblk failed\n");
 196                 else {
 197                         memset(bh->b_data,0,SECTOR_SIZE);
 198                         msdos_set_uptodate(sb,bh,1);
 199                         mark_buffer_dirty(bh, 1);
 200                         brelse(bh);
 201                 }
 202         }
 203         if (file_cluster != inode->i_blocks/cluster_size){
 204                 printk ("file_cluster badly computed!!! %d <> %ld\n"
 205                         ,file_cluster,inode->i_blocks/cluster_size);
 206         }else{
 207                 cache_add(inode,file_cluster,nr);
 208         }
 209         inode->i_blocks += cluster_size;
 210         if (S_ISDIR(inode->i_mode)) {
 211                 if (inode->i_size & (SECTOR_SIZE-1)) {
 212                         fs_panic(inode->i_sb,"Odd directory size");
 213                         inode->i_size = (inode->i_size+SECTOR_SIZE) &
 214                             ~(SECTOR_SIZE-1);
 215                 }
 216                 inode->i_size += SECTOR_SIZE*cluster_size;
 217 #ifdef DEBUG
 218 printk("size is %d now (%x)\n",inode->i_size,inode);
 219 #endif
 220                 inode->i_dirt = 1;
 221         }
 222         return 0;
 223 }
 224 
 225 
 226 /* Linear day numbers of the respective 1sts in non-leap years. */
 227 
 228 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
 229                   /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
 230 
 231 
 232 extern struct timezone sys_tz;
 233 
 234 
 235 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 236 
 237 int date_dos2unix(unsigned short time,unsigned short date)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239         int month,year,secs;
 240 
 241         month = ((date >> 5) & 15)-1;
 242         year = date >> 9;
 243         secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
 244             ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
 245             month < 2 ? 1 : 0)+3653);
 246                         /* days since 1.1.70 plus 80's leap day */
 247         secs += sys_tz.tz_minuteswest*60;
 248         return secs;
 249 }
 250 
 251 
 252 /* Convert linear UNIX date to a MS-DOS time/date pair. */
 253 
 254 void date_unix2dos(int unix_date,unsigned short *time,
     /* [previous][next][first][last][top][bottom][index][help] */
 255     unsigned short *date)
 256 {
 257         int day,year,nl_day,month;
 258 
 259         unix_date -= sys_tz.tz_minuteswest*60;
 260         *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
 261             (((unix_date/3600) % 24) << 11);
 262         day = unix_date/86400-3652;
 263         year = day/365;
 264         if ((year+3)/4+365*year > day) year--;
 265         day -= (year+3)/4+365*year;
 266         if (day == 59 && !(year & 3)) {
 267                 nl_day = day;
 268                 month = 2;
 269         }
 270         else {
 271                 nl_day = (year & 3) || day <= 59 ? day : day-1;
 272                 for (month = 0; month < 12; month++)
 273                         if (day_n[month] > nl_day) break;
 274         }
 275         *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
 276 }
 277 
 278 
 279 /* Returns the inode number of the directory entry at offset pos. If bh is
 280    non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
 281    returned in bh. */
 282 
 283 int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
     /* [previous][next][first][last][top][bottom][index][help] */
 284     struct msdos_dir_entry **de)
 285 {
 286         struct super_block *sb = dir->i_sb;
 287         int sector,offset;
 288 
 289         while (1) {
 290                 offset = *pos;
 291                 PRINTK (("get_entry offset %d\n",offset));
 292                 if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
 293                         return -1;
 294                 PRINTK (("get_entry sector %d %p\n",sector,*bh));
 295                 if (!sector)
 296                         return -1; /* beyond EOF */
 297                 *pos += sizeof(struct msdos_dir_entry);
 298                 if (*bh)
 299                         brelse(*bh);
 300                 PRINTK (("get_entry sector apres brelse\n"));
 301                 if (!(*bh = bread(dir->i_dev,sector,SECTOR_SIZE))) {
 302                         printk("Directory sread (sector %d) failed\n",sector);
 303                         continue;
 304                 }
 305                 PRINTK (("get_entry apres sread\n"));
 306                 *de = (struct msdos_dir_entry *) ((*bh)->b_data+(offset &
 307                     (SECTOR_SIZE-1)));
 308                 return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
 309                     MSDOS_DIR_BITS);
 310         }
 311 }
 312 
 313 
 314 /*
 315  * Now an ugly part: this set of directory scan routines works on clusters
 316  * rather than on inodes and sectors. They are necessary to locate the '..'
 317  * directory "inode". raw_scan_sector operates in four modes:
 318  *
 319  * name     number   ino      action
 320  * -------- -------- -------- -------------------------------------------------
 321  * non-NULL -        X        Find an entry with that name
 322  * NULL     non-NULL non-NULL Find an entry whose data starts at *number
 323  * NULL     non-NULL NULL     Count subdirectories in *number. (*)
 324  * NULL     NULL     non-NULL Find an empty entry
 325  *
 326  * (*) The return code should be ignored. It DOES NOT indicate success or
 327  *     failure. *number has to be initialized to zero.
 328  *
 329  * - = not used, X = a value is returned unless NULL
 330  *
 331  * If res_bh is non-NULL, the buffer is not deallocated but returned to the
 332  * caller on success. res_de is set accordingly.
 333  *
 334  * If cont is non-zero, raw_found continues with the entry after the one
 335  * res_bh/res_de point to.
 336  */
 337 
 338 
 339 #define RSS_NAME /* search for name */ \
 340     done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
 341      !(data[entry].attr & ATTR_VOLUME);
 342 
 343 #define RSS_START /* search for start cluster */ \
 344     done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number;
 345 
 346 #define RSS_FREE /* search for free entry */ \
 347     { \
 348         done = IS_FREE(data[entry].name); \
 349         if (done) { \
 350             inode = iget(sb,sector*MSDOS_DPS+entry); \
 351             if (inode) { \
 352             /* Directory slots of busy deleted files aren't available yet. */ \
 353                 done = !MSDOS_I(inode)->i_busy; \
 354                 iput(inode); \
 355             } \
 356         } \
 357     }
 358 
 359 #define RSS_COUNT /* count subdirectories */ \
 360     { \
 361         done = 0; \
 362         if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
 363             (*number)++; \
 364     }
 365 
 366 static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
 367     int *number,int *ino,struct buffer_head **res_bh,
 368     struct msdos_dir_entry **res_de,char scantype)
 369 {
 370         struct buffer_head *bh;
 371         struct msdos_dir_entry *data;
 372         struct inode *inode;
 373         int entry,start,done;
 374 
 375         if (!(bh = bread(sb->s_dev,sector,SECTOR_SIZE))) return -EIO;
 376         data = (struct msdos_dir_entry *) bh->b_data;
 377         for (entry = 0; entry < MSDOS_DPS; entry++) {
 378 /* RSS_COUNT:  if (data[entry].name == name) done=true else done=false. */
 379                 if (name) {
 380                         RSS_NAME
 381                         if (done && scantype) {   /* scantype != SCAN_ANY */
 382                                 done = (data[entry].attr & ATTR_HIDDEN)
 383                                         ? (scantype==SCAN_HID)
 384                                         : (scantype==SCAN_NOTHID);
 385                         }
 386                 } else {
 387                         if (!ino) RSS_COUNT
 388                         else {
 389                                 if (number) RSS_START
 390                                 else RSS_FREE
 391                         }
 392                 }
 393                 if (done) {
 394                         if (ino) *ino = sector*MSDOS_DPS+entry;
 395                         start = CF_LE_W(data[entry].start);
 396                         if (!res_bh) brelse(bh);
 397                         else {
 398                                 *res_bh = bh;
 399                                 *res_de = &data[entry];
 400                         }
 401                         return start;
 402                 }
 403         }
 404         brelse(bh);
 405         return -ENOENT;
 406 }
 407 
 408 
 409 /*
 410  * raw_scan_root performs raw_scan_sector on the root directory until the
 411  * requested entry is found or the end of the directory is reached.
 412  */
 413 
 414 static int raw_scan_root(struct super_block *sb,const char *name,int *number,int *ino,
     /* [previous][next][first][last][top][bottom][index][help] */
 415     struct buffer_head **res_bh,struct msdos_dir_entry **res_de,char scantype)
 416 {
 417         int count,cluster;
 418 
 419         for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
 420                 if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
 421                     name,number,ino,res_bh,res_de,scantype)) >= 0) return cluster;
 422         }
 423         return -ENOENT;
 424 }
 425 
 426 
 427 /*
 428  * raw_scan_nonroot performs raw_scan_sector on a non-root directory until the
 429  * requested entry is found or the end of the directory is reached.
 430  */
 431 
 432 static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
 433     int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
 434     **res_de,char scantype)
 435 {
 436         int count,cluster;
 437 
 438 #ifdef DEBUG
 439         printk("raw_scan_nonroot: start=%d\n",start);
 440 #endif
 441         do {
 442                 for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
 443                         if ((cluster = raw_scan_sector(sb,(start-2)*
 444                             MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
 445                             count,name,number,ino,res_bh,res_de,scantype)) >= 0)
 446                                 return cluster;
 447                 }
 448                 if (!(start = fat_access(sb,start,-1))) {
 449                         fs_panic(sb,"FAT error");
 450                         break;
 451                 }
 452 #ifdef DEBUG
 453         printk("next start: %d\n",start);
 454 #endif
 455         }
 456         while (start != -1);
 457         return -ENOENT;
 458 }
 459 
 460 
 461 /*
 462  * raw_scan performs raw_scan_sector on any sector.
 463  *
 464  * NOTE: raw_scan must not be used on a directory that is is the process of
 465  *       being created.
 466  */
 467 
 468 static int raw_scan(struct super_block *sb, int start, const char *name,
     /* [previous][next][first][last][top][bottom][index][help] */
 469     int *number, int *ino, struct buffer_head **res_bh,
 470     struct msdos_dir_entry **res_de, char scantype)
 471 {
 472         if (start) return raw_scan_nonroot
 473                 (sb,start,name,number,ino,res_bh,res_de,scantype);
 474         else return raw_scan_root
 475                 (sb,name,number,ino,res_bh,res_de,scantype);
 476 }
 477 
 478 
 479 /*
 480  * msdos_parent_ino returns the inode number of the parent directory of dir.
 481  * File creation has to be deferred while msdos_parent_ino is running to
 482  * prevent renames.
 483  */
 484 
 485 int msdos_parent_ino(struct inode *dir,int locked)
     /* [previous][next][first][last][top][bottom][index][help] */
 486 {
 487         static int zero = 0;
 488         int error,curr,prev,nr;
 489 
 490         if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
 491         if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
 492         if (!locked) lock_creation(); /* prevent renames */
 493         if ((curr = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,
 494             &zero,NULL,NULL,NULL,SCAN_ANY)) < 0) {
 495                 if (!locked) unlock_creation();
 496                 return curr;
 497         }
 498         if (!curr) nr = MSDOS_ROOT_INO;
 499         else {
 500                 if ((prev = raw_scan(dir->i_sb,curr,MSDOS_DOTDOT,&zero,NULL,
 501                     NULL,NULL,SCAN_ANY)) < 0) {
 502                         if (!locked) unlock_creation();
 503                         return prev;
 504                 }
 505                 if ((error = raw_scan(dir->i_sb,prev,NULL,&curr,&nr,NULL,
 506                     NULL,SCAN_ANY)) < 0) {
 507                         if (!locked) unlock_creation();
 508                         return error;
 509                 }
 510         }
 511         if (!locked) unlock_creation();
 512         return nr;
 513 }
 514 
 515 
 516 /*
 517  * msdos_subdirs counts the number of sub-directories of dir. It can be run
 518  * on directories being created.
 519  */
 520 
 521 int msdos_subdirs(struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {
 523         int count;
 524 
 525         count = 0;
 526         if (dir->i_ino == MSDOS_ROOT_INO)
 527                 (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL,SCAN_ANY);
 528         else {
 529                 if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */
 530                 else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
 531                     NULL,&count,NULL,NULL,NULL,SCAN_ANY);
 532         }
 533         return count;
 534 }
 535 
 536 
 537 /*
 538  * Scans a directory for a given file (name points to its formatted name) or
 539  * for an empty directory slot (name is NULL). Returns an error code or zero.
 540  */
 541 
 542 int msdos_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
     /* [previous][next][first][last][top][bottom][index][help] */
 543     struct msdos_dir_entry **res_de,int *ino, char scantype)
 544 {
 545         int res;
 546 
 547         res = (name)
 548                 ? raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
 549                     name, NULL, ino, res_bh, res_de, scantype)
 550                 : raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
 551                     NULL, NULL, ino, res_bh, res_de, scantype);
 552         return res<0 ? res : 0;
 553 }

/* [previous][next][first][last][top][bottom][index][help] */