Annotation of linux/fs/msdos/misc.c, revision 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.