home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / msdos / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  13.5 KB  |  523 lines

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