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

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