The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/fat/misc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/fat/misc.c
    3  *
    4  *  Written 1992,1993 by Werner Almesberger
    5  *  22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
    6  *               and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
    7  */
    8 
    9 #include <linux/fs.h>
   10 #include <linux/msdos_fs.h>
   11 #include <linux/sched.h>
   12 #include <linux/kernel.h>
   13 #include <linux/errno.h>
   14 #include <linux/string.h>
   15 #include <linux/stat.h>
   16 
   17 #if 0
   18 #  define PRINTK(x)     printk x
   19 #else
   20 #  define PRINTK(x)
   21 #endif
   22 #define Printk(x)       printk x
   23 
   24 /* Well-known binary file extensions - of course there are many more */
   25 
   26 static char ascii_extensions[] =
   27   "TXT" "ME " "HTM" "1ST" "LOG" "   "   /* text files */
   28   "C  " "H  " "CPP" "LIS" "PAS" "FOR"  /* programming languages */
   29   "F  " "MAK" "INC" "BAS"               /* programming languages */
   30   "BAT" "SH "                           /* program code :) */
   31   "INI"                                 /* config files */
   32   "PBM" "PGM" "DXF"                     /* graphics */
   33   "TEX";                                /* TeX */
   34 
   35 
   36 /*
   37  * fat_fs_panic reports a severe file system problem and sets the file system
   38  * read-only. The file system can be made writable again by remounting it.
   39  */
   40 
   41 void fat_fs_panic(struct super_block *s,const char *msg)
   42 {
   43         int not_ro;
   44 
   45         not_ro = !(s->s_flags & MS_RDONLY);
   46         if (not_ro) s->s_flags |= MS_RDONLY;
   47         printk("Filesystem panic (dev %s).\n  %s\n", kdevname(s->s_dev), msg);
   48         if (not_ro)
   49                 printk("  File system has been set read-only\n");
   50 }
   51 
   52 
   53 /*
   54  * fat_is_binary selects optional text conversion based on the conversion mode
   55  * and the extension part of the file name.
   56  */
   57 
   58 int fat_is_binary(char conversion,char *extension)
   59 {
   60         char *walk;
   61 
   62         switch (conversion) {
   63                 case 'b':
   64                         return 1;
   65                 case 't':
   66                         return 0;
   67                 case 'a':
   68                         for (walk = ascii_extensions; *walk; walk += 3)
   69                                 if (!strncmp(extension,walk,3)) return 0;
   70                         return 1;       /* default binary conversion */
   71                 default:
   72                         printk("Invalid conversion mode - defaulting to "
   73                             "binary.\n");
   74                         return 1;
   75         }
   76 }
   77 
   78 void lock_fat(struct super_block *sb)
   79 {
   80         down(&(MSDOS_SB(sb)->fat_lock));
   81 }
   82 
   83 void unlock_fat(struct super_block *sb)
   84 {
   85         up(&(MSDOS_SB(sb)->fat_lock));
   86 }
   87 
   88 /* Flushes the number of free clusters on FAT32 */
   89 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
   90 void fat_clusters_flush(struct super_block *sb)
   91 {
   92         struct buffer_head *bh;
   93         struct fat_boot_fsinfo *fsinfo;
   94 
   95         bh = fat_bread(sb, MSDOS_SB(sb)->fsinfo_sector);
   96         if (bh == NULL) {
   97                 printk("FAT bread failed in fat_clusters_flush\n");
   98                 return;
   99         }
  100 
  101         fsinfo = (struct fat_boot_fsinfo *)bh->b_data;
  102         /* Sanity check */
  103         if (!IS_FSINFO(fsinfo)) {
  104                 printk("FAT: Did not find valid FSINFO signature.\n"
  105                        "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
  106                        CF_LE_L(fsinfo->signature1), CF_LE_L(fsinfo->signature2),
  107                        MSDOS_SB(sb)->fsinfo_sector);
  108                 return;
  109         }
  110         fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
  111         fsinfo->next_cluster = CF_LE_L(MSDOS_SB(sb)->prev_free);
  112         fat_mark_buffer_dirty(sb, bh);
  113         fat_brelse(sb, bh);
  114 }
  115 
  116 /*
  117  * fat_add_cluster tries to allocate a new cluster and adds it to the
  118  * file represented by inode.
  119  */
  120 int fat_add_cluster(struct inode *inode)
  121 {
  122         struct super_block *sb = inode->i_sb;
  123         int count, nr, limit, last, curr, file_cluster;
  124         int cluster_size = MSDOS_SB(sb)->cluster_size;
  125         int res = -ENOSPC;
  126         
  127         lock_fat(sb);
  128         
  129         if (MSDOS_SB(sb)->free_clusters == 0) {
  130                 unlock_fat(sb);
  131                 return res;
  132         }
  133         limit = MSDOS_SB(sb)->clusters;
  134         nr = limit; /* to keep GCC happy */
  135         for (count = 0; count < limit; count++) {
  136                 nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2;
  137                 if (fat_access(sb, nr, -1) == 0)
  138                         break;
  139         }
  140         if (count >= limit) {
  141                 MSDOS_SB(sb)->free_clusters = 0;
  142                 unlock_fat(sb);
  143                 return res;
  144         }
  145         
  146         MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
  147         fat_access(sb, nr, EOF_FAT(sb));
  148         if (MSDOS_SB(sb)->free_clusters != -1)
  149                 MSDOS_SB(sb)->free_clusters--;
  150         if (MSDOS_SB(sb)->fat_bits == 32)
  151                 fat_clusters_flush(sb);
  152         
  153         unlock_fat(sb);
  154         
  155         /* We must locate the last cluster of the file to add this
  156            new one (nr) to the end of the link list (the FAT).
  157            
  158            Here file_cluster will be the number of the last cluster of the
  159            file (before we add nr).
  160            
  161            last is the corresponding cluster number on the disk. We will
  162            use last to plug the nr cluster. We will use file_cluster to
  163            update the cache.
  164         */
  165         last = file_cluster = 0;
  166         if ((curr = MSDOS_I(inode)->i_start) != 0) {
  167                 fat_cache_lookup(inode, INT_MAX, &last, &curr);
  168                 file_cluster = last;
  169                 while (curr && curr != -1){
  170                         file_cluster++;
  171                         if (!(curr = fat_access(sb, last = curr,-1))) {
  172                                 fat_fs_panic(sb, "File without EOF");
  173                                 return res;
  174                         }
  175                 }
  176         }
  177         if (last) {
  178                 fat_access(sb, last, nr);
  179                 fat_cache_add(inode, file_cluster, nr);
  180         } else {
  181                 MSDOS_I(inode)->i_start = nr;
  182                 MSDOS_I(inode)->i_logstart = nr;
  183                 mark_inode_dirty(inode);
  184         }
  185         if (file_cluster
  186             != inode->i_blocks / cluster_size / (sb->s_blocksize / 512)) {
  187                 printk ("file_cluster badly computed!!! %d <> %ld\n",
  188                         file_cluster,
  189                         inode->i_blocks / cluster_size / (sb->s_blocksize / 512));
  190                 fat_cache_inval_inode(inode);
  191         }
  192         inode->i_blocks += (1 << MSDOS_SB(sb)->cluster_bits) / 512;
  193 
  194         return nr;
  195 }
  196 
  197 struct buffer_head *fat_extend_dir(struct inode *inode)
  198 {
  199         struct super_block *sb = inode->i_sb;
  200         int nr, sector, last_sector;
  201         struct buffer_head *bh, *res = NULL;
  202         int cluster_size = MSDOS_SB(sb)->cluster_size;
  203 
  204         if (MSDOS_SB(sb)->fat_bits != 32) {
  205                 if (inode->i_ino == MSDOS_ROOT_INO)
  206                         return res;
  207         }
  208 
  209         nr = fat_add_cluster(inode);
  210         if (nr < 0)
  211                 return res;
  212         
  213         sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size;
  214         last_sector = sector + cluster_size;
  215         if (MSDOS_SB(sb)->cvf_format && MSDOS_SB(sb)->cvf_format->zero_out_cluster)
  216                 MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode, nr);
  217         else {
  218                 for ( ; sector < last_sector; sector++) {
  219 #ifdef DEBUG
  220                         printk("zeroing sector %d\n", sector);
  221 #endif
  222                         if (!(bh = fat_getblk(sb, sector)))
  223                                 printk("getblk failed\n");
  224                         else {
  225                                 memset(bh->b_data, 0, sb->s_blocksize);
  226                                 fat_set_uptodate(sb, bh, 1);
  227                                 fat_mark_buffer_dirty(sb, bh);
  228                                 if (!res)
  229                                         res = bh;
  230                                 else
  231                                         fat_brelse(sb, bh);
  232                         }
  233                 }
  234         }
  235         if (inode->i_size & (sb->s_blocksize - 1)) {
  236                 fat_fs_panic(sb, "Odd directory size");
  237                 inode->i_size = (inode->i_size + sb->s_blocksize)
  238                         & ~(sb->s_blocksize - 1);
  239         }
  240         inode->i_size += 1 << MSDOS_SB(sb)->cluster_bits;
  241         MSDOS_I(inode)->mmu_private += 1 << MSDOS_SB(sb)->cluster_bits;
  242         mark_inode_dirty(inode);
  243 
  244         return res;
  245 }
  246 
  247 /* Linear day numbers of the respective 1sts in non-leap years. */
  248 
  249 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
  250                   /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
  251 
  252 
  253 extern struct timezone sys_tz;
  254 
  255 
  256 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
  257 
  258 int date_dos2unix(unsigned short time,unsigned short date)
  259 {
  260         int month,year,secs;
  261 
  262         /* first subtract and mask after that... Otherwise, if
  263            date == 0, bad things happen */
  264         month = ((date >> 5) - 1) & 15;
  265         year = date >> 9;
  266         secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
  267             ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
  268             month < 2 ? 1 : 0)+3653);
  269                         /* days since 1.1.70 plus 80's leap day */
  270         secs += sys_tz.tz_minuteswest*60;
  271         return secs;
  272 }
  273 
  274 
  275 /* Convert linear UNIX date to a MS-DOS time/date pair. */
  276 
  277 void fat_date_unix2dos(int unix_date,unsigned short *time,
  278     unsigned short *date)
  279 {
  280         int day,year,nl_day,month;
  281 
  282         unix_date -= sys_tz.tz_minuteswest*60;
  283 
  284         /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
  285         if (unix_date < 315532800)
  286                 unix_date = 315532800;
  287 
  288         *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
  289             (((unix_date/3600) % 24) << 11);
  290         day = unix_date/86400-3652;
  291         year = day/365;
  292         if ((year+3)/4+365*year > day) year--;
  293         day -= (year+3)/4+365*year;
  294         if (day == 59 && !(year & 3)) {
  295                 nl_day = day;
  296                 month = 2;
  297         }
  298         else {
  299                 nl_day = (year & 3) || day <= 59 ? day : day-1;
  300                 for (month = 0; month < 12; month++)
  301                         if (day_n[month] > nl_day) break;
  302         }
  303         *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
  304 }
  305 
  306 
  307 /* Returns the inode number of the directory entry at offset pos. If bh is
  308    non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
  309    returned in bh.
  310    AV. Most often we do it item-by-item. Makes sense to optimize.
  311    AV. OK, there we go: if both bh and de are non-NULL we assume that we just
  312    AV. want the next entry (took one explicit de=NULL in vfat/namei.c).
  313    AV. It's done in fat_get_entry() (inlined), here the slow case lives.
  314    AV. Additionally, when we return -1 (i.e. reached the end of directory)
  315    AV. we make bh NULL. 
  316  */
  317 
  318 int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
  319     struct msdos_dir_entry **de, int *ino)
  320 {
  321         struct super_block *sb = dir->i_sb;
  322         struct msdos_sb_info *sbi = MSDOS_SB(sb);
  323         int sector, offset;
  324 
  325         while (1) {
  326                 offset = *pos;
  327                 PRINTK (("get_entry offset %d\n",offset));
  328                 if (*bh)
  329                         fat_brelse(sb, *bh);
  330                 *bh = NULL;
  331                 if ((sector = fat_bmap(dir,offset >> sb->s_blocksize_bits)) == -1)
  332                         return -1;
  333                 PRINTK (("get_entry sector %d %p\n",sector,*bh));
  334                 PRINTK (("get_entry sector apres brelse\n"));
  335                 if (!sector)
  336                         return -1; /* beyond EOF */
  337                 *pos += sizeof(struct msdos_dir_entry);
  338                 if (!(*bh = fat_bread(sb, sector))) {
  339                         printk("Directory sread (sector 0x%x) failed\n",sector);
  340                         continue;
  341                 }
  342                 PRINTK (("get_entry apres sread\n"));
  343 
  344                 offset &= sb->s_blocksize - 1;
  345                 *de = (struct msdos_dir_entry *) ((*bh)->b_data + offset);
  346                 *ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
  347 
  348                 return 0;
  349         }
  350 }
  351 
  352 
  353 /*
  354  * Now an ugly part: this set of directory scan routines works on clusters
  355  * rather than on inodes and sectors. They are necessary to locate the '..'
  356  * directory "inode". raw_scan_sector operates in four modes:
  357  *
  358  * name     number   ino      action
  359  * -------- -------- -------- -------------------------------------------------
  360  * non-NULL -        X        Find an entry with that name
  361  * NULL     non-NULL non-NULL Find an entry whose data starts at *number
  362  * NULL     non-NULL NULL     Count subdirectories in *number. (*)
  363  * NULL     NULL     non-NULL Find an empty entry
  364  *
  365  * (*) The return code should be ignored. It DOES NOT indicate success or
  366  *     failure. *number has to be initialized to zero.
  367  *
  368  * - = not used, X = a value is returned unless NULL
  369  *
  370  * If res_bh is non-NULL, the buffer is not deallocated but returned to the
  371  * caller on success. res_de is set accordingly.
  372  *
  373  * If cont is non-zero, raw_found continues with the entry after the one
  374  * res_bh/res_de point to.
  375  */
  376 
  377 
  378 #define RSS_NAME /* search for name */ \
  379     done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
  380      !(data[entry].attr & ATTR_VOLUME);
  381 
  382 #define RSS_START /* search for start cluster */ \
  383     done = !IS_FREE(data[entry].name) \
  384       && ( \
  385            ( \
  386              (MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
  387            ) \
  388            | CF_LE_W(data[entry].start) \
  389          ) == *number;
  390 
  391 #define RSS_FREE /* search for free entry */ \
  392     { \
  393         done = IS_FREE(data[entry].name); \
  394     }
  395 
  396 #define RSS_COUNT /* count subdirectories */ \
  397     { \
  398         done = 0; \
  399         if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
  400             (*number)++; \
  401     }
  402 
  403 static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
  404     int *number,int *ino,struct buffer_head **res_bh,
  405     struct msdos_dir_entry **res_de)
  406 {
  407         struct buffer_head *bh;
  408         struct msdos_dir_entry *data;
  409         int entry,start,done;
  410 
  411         if (!(bh = fat_bread(sb,sector)))
  412                 return -EIO;
  413         data = (struct msdos_dir_entry *) bh->b_data;
  414         for (entry = 0; entry < MSDOS_SB(sb)->dir_per_block; entry++) {
  415 /* RSS_COUNT:  if (data[entry].name == name) done=true else done=false. */
  416                 if (name) {
  417                         RSS_NAME
  418                 } else {
  419                         if (!ino) RSS_COUNT
  420                         else {
  421                                 if (number) RSS_START
  422                                 else RSS_FREE
  423                         }
  424                 }
  425                 if (done) {
  426                         if (ino)
  427                                 *ino = sector * MSDOS_SB(sb)->dir_per_block + entry;
  428                         start = CF_LE_W(data[entry].start);
  429                         if (MSDOS_SB(sb)->fat_bits == 32) {
  430                                 start |= (CF_LE_W(data[entry].starthi) << 16);
  431                         }
  432                         if (!res_bh)
  433                                 fat_brelse(sb, bh);
  434                         else {
  435                                 *res_bh = bh;
  436                                 *res_de = &data[entry];
  437                         }
  438                         return start;
  439                 }
  440         }
  441         fat_brelse(sb, bh);
  442         return -ENOENT;
  443 }
  444 
  445 
  446 /*
  447  * raw_scan_root performs raw_scan_sector on the root directory until the
  448  * requested entry is found or the end of the directory is reached.
  449  */
  450 
  451 static int raw_scan_root(struct super_block *sb,const char *name,int *number,int *ino,
  452     struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
  453 {
  454         int count,cluster;
  455 
  456         for (count = 0;
  457              count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block;
  458              count++) {
  459                 if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
  460                                                name,number,ino,res_bh,res_de)) >= 0)
  461                         return cluster;
  462         }
  463         return -ENOENT;
  464 }
  465 
  466 
  467 /*
  468  * raw_scan_nonroot performs raw_scan_sector on a non-root directory until the
  469  * requested entry is found or the end of the directory is reached.
  470  */
  471 
  472 static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
  473     int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
  474     **res_de)
  475 {
  476         int count,cluster;
  477 
  478 #ifdef DEBUG
  479         printk("raw_scan_nonroot: start=%d\n",start);
  480 #endif
  481         do {
  482                 for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
  483                         if ((cluster = raw_scan_sector(sb,(start-2)*
  484                             MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
  485                             count,name,number,ino,res_bh,res_de)) >= 0)
  486                                 return cluster;
  487                 }
  488                 if (!(start = fat_access(sb,start,-1))) {
  489                         fat_fs_panic(sb,"FAT error");
  490                         break;
  491                 }
  492 #ifdef DEBUG
  493         printk("next start: %d\n",start);
  494 #endif
  495         }
  496         while (start != -1);
  497         return -ENOENT;
  498 }
  499 
  500 
  501 /*
  502  * raw_scan performs raw_scan_sector on any sector.
  503  *
  504  * NOTE: raw_scan must not be used on a directory that is is the process of
  505  *       being created.
  506  */
  507 
  508 static int raw_scan(struct super_block *sb, int start, const char *name,
  509     int *number, int *ino, struct buffer_head **res_bh,
  510     struct msdos_dir_entry **res_de)
  511 {
  512         if (start)
  513                 return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de);
  514         else
  515                 return raw_scan_root(sb,name,number,ino,res_bh,res_de);
  516 }
  517 
  518 /*
  519  * fat_subdirs counts the number of sub-directories of dir. It can be run
  520  * on directories being created.
  521  */
  522 int fat_subdirs(struct inode *dir)
  523 {
  524         int count;
  525 
  526         count = 0;
  527         if ((dir->i_ino == MSDOS_ROOT_INO) &&
  528             (MSDOS_SB(dir->i_sb)->fat_bits != 32)) {
  529                 (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
  530         } else {
  531                 if ((dir->i_ino != MSDOS_ROOT_INO) &&
  532                     !MSDOS_I(dir)->i_start) return 0; /* in mkdir */
  533                 else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
  534                     NULL,&count,NULL,NULL,NULL);
  535         }
  536         return count;
  537 }
  538 
  539 
  540 /*
  541  * Scans a directory for a given file (name points to its formatted name) or
  542  * for an empty directory slot (name is NULL). Returns an error code or zero.
  543  */
  544 
  545 int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
  546     struct msdos_dir_entry **res_de,int *ino)
  547 {
  548         int res;
  549 
  550         res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
  551                        name, NULL, ino, res_bh, res_de);
  552         return res<0 ? res : 0;
  553 }

Cache object: 25b5dfd15bfa5cfcea124745ca9e81ac


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.