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

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