Annotation of linux/fs/msdos/misc.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *  linux/fs/msdos/misc.c
                      3:  *
                      4:  *  Written 1992 by Werner Almesberger
                      5:  */
                      6: 
                      7: #include <linux/msdos_fs.h>
                      8: #include <linux/sched.h>
                      9: #include <linux/kernel.h>
                     10: #include <linux/errno.h>
                     11: #include <linux/string.h>
                     12: #include <linux/stat.h>
                     13: 
                     14: static char bin_extensions[] =
                     15:   "EXECOMAPPSYSOVLOBJLIB"              /* program code */
                     16:   "ARCZIPLHALZHZOOTARZ  ARJTZ "                /* common archivers */
                     17:   "GIFBMPTIFGL JPGPCX"                 /* graphics */
                     18:   "TFMVF GF PK PXLDVI";                        /* TeX */
                     19: 
                     20: 
                     21: /* Select binary/text conversion */
                     22: 
                     23: int is_binary(char conversion,char *extension)
                     24: {
                     25:        char *walk;
                     26: 
                     27:        switch (conversion) {
                     28:                case 'b':
                     29:                        return 1;
                     30:                case 't':
                     31:                        return 0;
                     32:                case 'a':
                     33:                        for (walk = bin_extensions; *walk; walk += 3)
                     34:                                if (!strncmp(extension,walk,3)) return 1;
                     35:                        return 0;
                     36:                default:
                     37:                        panic("Invalid conversion mode");
                     38:        }
                     39: }
                     40: 
                     41: 
                     42: static struct wait_queue *creation_wait = NULL;
                     43: static creation_lock = 0;
                     44: 
                     45: 
                     46: void lock_creation(void)
                     47: {
                     48:        while (creation_lock) sleep_on(&creation_wait);
                     49:        creation_lock = 1;
                     50: }
                     51: 
                     52: 
                     53: void unlock_creation(void)
                     54: {
                     55:        creation_lock = 0;
                     56:        wake_up(&creation_wait);
                     57: }
                     58: 
                     59: 
                     60: int msdos_add_cluster(struct inode *inode)
                     61: {
                     62:        static struct wait_queue *wait = NULL;
                     63:        static int lock = 0;
                     64:        static int previous = 0; /* works best if one FS is being used */
                     65:        int count,this,limit,last,current,sector;
                     66:        void *data;
                     67:        struct buffer_head *bh;
                     68: 
                     69:        if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
                     70:        while (lock) sleep_on(&wait);
                     71:        lock = 1;
                     72:        limit = MSDOS_SB(inode->i_sb)->clusters;
                     73:        this = limit; /* to keep GCC happy */
                     74:        for (count = 0; count < limit; count++) {
                     75:                this = ((count+previous) % limit)+2;
                     76:                if (fat_access(inode->i_sb,this,-1) == 0) break;
                     77:        }
                     78: #ifdef DEBUG
                     79: printk("free cluster: %d\r\n",this);
                     80: #endif
                     81:        previous = (count+previous+1) % limit;
                     82:        if (count >= limit) {
                     83:                lock = 0;
                     84:                wake_up(&wait);
                     85:                return -ENOSPC;
                     86:        }
                     87:        fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
                     88:            0xff8 : 0xfff8);
                     89:        lock = 0;
                     90:        wake_up(&wait);
                     91: #ifdef DEBUG
                     92: printk("set to %x\r\n",fat_access(inode->i_sb,this,-1));
                     93: #endif
                     94:        if (!S_ISDIR(inode->i_mode)) {
                     95:                last = inode->i_size ? get_cluster(inode,(inode->i_size-1)/
                     96:                    SECTOR_SIZE/MSDOS_SB(inode->i_sb)->cluster_size) : 0;
                     97:        }
                     98:        else {
                     99:                last = 0;
                    100:                if (current = inode->i_data[D_START]) {
                    101:                        cache_lookup(inode,0x7fffffff,&last,&current);
                    102:                        while (current && current != -1)
                    103:                                if (!(current = fat_access(inode->i_sb,
                    104:                                    last = current,-1)))
                    105:                                        panic("File without EOF");
                    106:                        }
                    107:        }
                    108: #ifdef DEBUG
                    109: printk("last = %d\r\n",last);
                    110: #endif
                    111:        if (last) fat_access(inode->i_sb,last,this);
                    112:        else {
                    113:                inode->i_data[D_START] = this;
                    114:                inode->i_dirt = 1;
                    115:        }
                    116: #ifdef DEBUG
                    117: if (last) printk("next set to %d\r\n",fat_access(inode->i_sb,last,-1));
                    118: #endif
                    119:        for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
                    120:            current++) {
                    121:                sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)*
                    122:                    MSDOS_SB(inode->i_sb)->cluster_size+current;
                    123: #ifdef DEBUG
                    124: printk("zeroing sector %d\r\n",sector);
                    125: #endif
                    126:                if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
                    127:                    !(sector & 1)) {
                    128:                        if (!(bh = getblk(inode->i_dev,sector >> 1, BLOCK_SIZE)))
                    129:                                printk("getblk failed\r\n");
                    130:                        else {
                    131:                                memset(bh->b_data,0,BLOCK_SIZE);
                    132:                                bh->b_uptodate = 1;
                    133:                        }
                    134:                        current++;
                    135:                }
                    136:                else {
                    137:                        if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
                    138:                                printk("msdos_sread failed\r\n");
                    139:                        else memset(data,0,SECTOR_SIZE);
                    140:                }
                    141:                if (bh) {
                    142:                        bh->b_dirt = 1;
                    143:                        brelse(bh);
                    144:                }
                    145:        }
                    146:        if (S_ISDIR(inode->i_mode)) {
                    147:                if (inode->i_size & (SECTOR_SIZE-1))
                    148:                        panic("Odd directory size");
                    149:                inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
                    150:                    cluster_size;
                    151: #ifdef DEBUG
                    152: printk("size is %d now (%x)\r\n",inode->i_size,inode);
                    153: #endif
                    154:                inode->i_dirt = 1;
                    155:        }
                    156:        return 0;
                    157: }
                    158: 
                    159: 
                    160: /* Linear day numbers of the respective 1sts in non-leap years. */
                    161: 
                    162: static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
                    163:                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
                    164: 
                    165: 
                    166: /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
                    167: 
                    168: int date_dos2unix(unsigned short time,unsigned short date)
                    169: {
                    170:        int month,year;
                    171: 
                    172:        month = ((date >> 5) & 15)-1;
                    173:        year = date >> 9;
                    174:        return (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
                    175:            ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
                    176:            month < 2 ? 1 : 0)+3653);
                    177:                        /* days since 1.1.70 plus 80's leap day */
                    178: }
                    179: 
                    180: 
                    181: /* Convert linear UNIX date to a MS-DOS time/date pair. */
                    182: 
                    183: void date_unix2dos(int unix_date,unsigned short *time,
                    184:     unsigned short *date)
                    185: {
                    186:        int day,year,nl_day,month;
                    187: 
                    188:        *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
                    189:            (((unix_date/3600) % 24) << 11);
                    190:        day = unix_date/86400-3652;
                    191:        year = day/365;
                    192:        if ((year+3)/4+365*year > day) year--;
                    193:        day -= (year+3)/4+365*year;
                    194:        if (day == 59 && !(year & 3)) {
                    195:                nl_day = day;
                    196:                month = 2;
                    197:        }
                    198:        else {
                    199:                nl_day = (year & 3) || day <= 59 ? day : day-1;
                    200:                for (month = 0; month < 12; month++)
                    201:                        if (day_n[month] > nl_day) break;
                    202:        }
                    203:        *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
                    204: }
                    205: 
                    206: 
                    207: /* Returns the inode number of the directory entry at offset pos. If bh is
                    208:    non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
                    209:    returned in bh. */
                    210: 
                    211: int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
                    212:     struct msdos_dir_entry **de)
                    213: {
                    214:        int sector,offset;
                    215:        void *data;
                    216: 
                    217:        while (1) {
                    218:                offset = *pos;
                    219:                if ((sector = msdos_smap(dir,*pos >> SECTOR_BITS)) == -1)
                    220:                        return -1;
                    221:                if (!sector)
                    222:                        return -1; /* FAT error ... */
                    223:                *pos += sizeof(struct msdos_dir_entry);
                    224:                if (*bh)
                    225:                        brelse(*bh);
                    226:                if (!(*bh = msdos_sread(dir->i_dev,sector,&data)))
                    227:                        continue;
                    228:                *de = (struct msdos_dir_entry *) (data+(offset &
                    229:                    (SECTOR_SIZE-1)));
                    230:                return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
                    231:                    MSDOS_DIR_BITS);
                    232:        }
                    233: }
                    234: 
                    235: 
                    236: /* Scans a directory for a given file (name points to its formatted name) or
                    237:    for an empty directory slot (name is NULL). Returns the inode number. */
                    238: 
                    239: int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
                    240:     struct msdos_dir_entry **res_de,int *ino)
                    241: {
                    242:        int pos;
                    243:        struct msdos_dir_entry *de;
                    244:        struct inode *inode;
                    245: 
                    246:        pos = 0;
                    247:        *res_bh = NULL;
                    248:        while ((*ino = msdos_get_entry(dir,&pos,res_bh,&de)) > -1) {
                    249:                if (name) {
                    250:                        if (de->name[0] && ((unsigned char *) (de->name))[0]
                    251:                            != DELETED_FLAG && !(de->attr & ATTR_VOLUME) &&
                    252:                            !strncmp(de->name,name,MSDOS_NAME)) break;
                    253:                }
                    254:                else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
                    255:                            DELETED_FLAG) {
                    256:                                if (!(inode = iget(dir->i_dev,*ino))) break;
                    257:                                if (!inode->i_data[D_BUSY]) {
                    258:                                        iput(inode);
                    259:                                        break;
                    260:                                }
                    261:        /* skip deleted files that haven't been closed yet */
                    262:                                iput(inode);
                    263:                        }
                    264:        }
                    265:        if (*ino == -1) {
                    266:                if (*res_bh) brelse(*res_bh);
                    267:                *res_bh = NULL;
                    268:                return name ? -ENOENT : -ENOSPC;
                    269:        }
                    270:        *res_de = de;
                    271:        return 0;
                    272: }
                    273: 
                    274: 
                    275: /* Now an ugly part: this set of directory scan routines works on clusters
                    276:    rather than on inodes and sectors. They are necessary to locate the '..'
                    277:    directory "inode". */
                    278: 
                    279: 
                    280: static int raw_found(struct super_block *sb,int sector,char *name,int number,
                    281:     int *ino)
                    282: {
                    283:        struct buffer_head *bh;
                    284:        struct msdos_dir_entry *data;
                    285:        int entry,start;
                    286: 
                    287:        if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
                    288:        for (entry = 0; entry < MSDOS_DPS; entry++)
                    289:                if (name ? !strncmp(data[entry].name,name,MSDOS_NAME) :
                    290:                    *(unsigned char *) data[entry].name != DELETED_FLAG &&
                    291:                    data[entry].start == number) {
                    292:                        if (ino) *ino = sector*MSDOS_DPS+entry;
                    293:                        start = data[entry].start;
                    294:                        brelse(bh);
                    295:                        return start;
                    296:                }
                    297:        brelse(bh);
                    298:        return -1;
                    299: }
                    300: 
                    301: 
                    302: static int raw_scan_root(struct super_block *sb,char *name,int number,int *ino)
                    303: {
                    304:        int count,cluster;
                    305: 
                    306:        for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
                    307:                if ((cluster = raw_found(sb,MSDOS_SB(sb)->dir_start+count,name,
                    308:                    number,ino)) >= 0) return cluster;
                    309:        }
                    310:        return -ENOENT;
                    311: }
                    312: 
                    313: 
                    314: static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
                    315:     int number,int *ino)
                    316: {
                    317:        int count,cluster;
                    318: 
                    319:        do {
                    320:                for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
                    321:                        if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)->
                    322:                            cluster_size+MSDOS_SB(sb)->data_start+count,name,
                    323:                            number,ino)) >= 0) return cluster;
                    324:                }
                    325:                if (!(start = fat_access(sb,start,-1))) panic("FAT error");
                    326:        }
                    327:        while (start != -1);
                    328:        return -ENOENT;
                    329: }
                    330: 
                    331: 
                    332: static int raw_scan(struct super_block *sb,int start,char *name,int number,
                    333:     int *ino)
                    334: {
                    335:     if (start) return raw_scan_nonroot(sb,start,name,number,ino);
                    336:     else return raw_scan_root(sb,name,number,ino);
                    337: }
                    338: 
                    339: 
                    340: int msdos_parent_ino(struct inode *dir,int locked)
                    341: {
                    342:        int error,current,prev,this;
                    343: 
                    344:        if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
                    345:        if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
                    346:        if (!locked) lock_creation(); /* prevent renames */
                    347:        if ((current = raw_scan(dir->i_sb,dir->i_data[D_START],MSDOS_DOTDOT,0,
                    348:            NULL)) < 0) {
                    349:                if (!locked) unlock_creation();
                    350:                return current;
                    351:        }
                    352:        if (!current) this = MSDOS_ROOT_INO;
                    353:        else {
                    354:                if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,0,NULL)) <
                    355:                    0) {
                    356:                        if (!locked) unlock_creation();
                    357:                        return prev;
                    358:                }
                    359:                if ((error = raw_scan(dir->i_sb,prev,NULL,current,&this)) < 0) {
                    360:                        if (!locked) unlock_creation();
                    361:                        return error;
                    362:                }
                    363:        }
                    364:        if (!locked) unlock_creation();
                    365:        return this;
                    366: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.