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

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