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

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