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

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:
1.1.1.2 ! root       37:                        printk("Invalid conversion mode - defaulting to "
        !            38:                            "binary.\n");
        !            39:                        return 1;
1.1       root       40:        }
                     41: }
                     42: 
                     43: 
1.1.1.2 ! root       44: /* File creation lock. This is system-wide to avoid deadlocks in rename. */
        !            45: /* (rename might deadlock before detecting cross-FS moves.) */
        !            46: 
1.1       root       47: static struct wait_queue *creation_wait = NULL;
                     48: static creation_lock = 0;
                     49: 
                     50: 
                     51: void lock_creation(void)
                     52: {
                     53:        while (creation_lock) sleep_on(&creation_wait);
                     54:        creation_lock = 1;
                     55: }
                     56: 
                     57: 
                     58: void unlock_creation(void)
                     59: {
                     60:        creation_lock = 0;
                     61:        wake_up(&creation_wait);
                     62: }
                     63: 
                     64: 
1.1.1.2 ! root       65: void lock_fat(struct super_block *sb)
        !            66: {
        !            67:        while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
        !            68:        MSDOS_SB(sb)->fat_lock = 1;
        !            69: }
        !            70: 
        !            71: 
        !            72: void unlock_fat(struct super_block *sb)
        !            73: {
        !            74:        MSDOS_SB(sb)->fat_lock = 0;
        !            75:        wake_up(&MSDOS_SB(sb)->fat_wait);
        !            76: }
        !            77: 
        !            78: 
1.1       root       79: int msdos_add_cluster(struct inode *inode)
                     80: {
                     81:        static struct wait_queue *wait = NULL;
                     82:        static int lock = 0;
                     83:        static int previous = 0; /* works best if one FS is being used */
                     84:        int count,this,limit,last,current,sector;
                     85:        void *data;
                     86:        struct buffer_head *bh;
                     87: 
                     88:        if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
1.1.1.2 ! root       89:        if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
1.1       root       90:        while (lock) sleep_on(&wait);
                     91:        lock = 1;
1.1.1.2 ! root       92:        lock_fat(inode->i_sb);
1.1       root       93:        limit = MSDOS_SB(inode->i_sb)->clusters;
                     94:        this = limit; /* to keep GCC happy */
                     95:        for (count = 0; count < limit; count++) {
                     96:                this = ((count+previous) % limit)+2;
                     97:                if (fat_access(inode->i_sb,this,-1) == 0) break;
                     98:        }
                     99: #ifdef DEBUG
1.1.1.2 ! root      100: printk("free cluster: %d\n",this);
1.1       root      101: #endif
                    102:        previous = (count+previous+1) % limit;
                    103:        if (count >= limit) {
1.1.1.2 ! root      104:                MSDOS_SB(inode->i_sb)->free_clusters = 0;
        !           105:                unlock_fat(inode->i_sb);
1.1       root      106:                lock = 0;
                    107:                wake_up(&wait);
                    108:                return -ENOSPC;
                    109:        }
                    110:        fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
                    111:            0xff8 : 0xfff8);
1.1.1.2 ! root      112:        if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
        !           113:                MSDOS_SB(inode->i_sb)->free_clusters--;
        !           114:        unlock_fat(inode->i_sb);
1.1       root      115:        lock = 0;
                    116:        wake_up(&wait);
                    117: #ifdef DEBUG
1.1.1.2 ! root      118: printk("set to %x\n",fat_access(inode->i_sb,this,-1));
1.1       root      119: #endif
1.1.1.2 ! root      120:        last = 0;
        !           121:        if (current = MSDOS_I(inode)->i_start) {
        !           122:                cache_lookup(inode,0x7fffffff,&last,&current);
        !           123:                while (current && current != -1)
        !           124:                        if (!(current = fat_access(inode->i_sb,
        !           125:                            last = current,-1)))
        !           126:                                panic("File without EOF");
1.1       root      127:        }
                    128: #ifdef DEBUG
1.1.1.2 ! root      129: printk("last = %d\n",last);
1.1       root      130: #endif
                    131:        if (last) fat_access(inode->i_sb,last,this);
                    132:        else {
1.1.1.2 ! root      133:                MSDOS_I(inode)->i_start = this;
1.1       root      134:                inode->i_dirt = 1;
                    135:        }
                    136: #ifdef DEBUG
1.1.1.2 ! root      137: if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
1.1       root      138: #endif
                    139:        for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size;
                    140:            current++) {
                    141:                sector = MSDOS_SB(inode->i_sb)->data_start+(this-2)*
                    142:                    MSDOS_SB(inode->i_sb)->cluster_size+current;
                    143: #ifdef DEBUG
1.1.1.2 ! root      144: printk("zeroing sector %d\n",sector);
1.1       root      145: #endif
                    146:                if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
                    147:                    !(sector & 1)) {
                    148:                        if (!(bh = getblk(inode->i_dev,sector >> 1, BLOCK_SIZE)))
1.1.1.2 ! root      149:                                printk("getblk failed\n");
1.1       root      150:                        else {
                    151:                                memset(bh->b_data,0,BLOCK_SIZE);
                    152:                                bh->b_uptodate = 1;
                    153:                        }
                    154:                        current++;
                    155:                }
                    156:                else {
                    157:                        if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
1.1.1.2 ! root      158:                                printk("msdos_sread failed\n");
1.1       root      159:                        else memset(data,0,SECTOR_SIZE);
                    160:                }
                    161:                if (bh) {
                    162:                        bh->b_dirt = 1;
                    163:                        brelse(bh);
                    164:                }
                    165:        }
1.1.1.2 ! root      166:        inode->i_blocks++;
1.1       root      167:        if (S_ISDIR(inode->i_mode)) {
                    168:                if (inode->i_size & (SECTOR_SIZE-1))
                    169:                        panic("Odd directory size");
                    170:                inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
                    171:                    cluster_size;
                    172: #ifdef DEBUG
1.1.1.2 ! root      173: printk("size is %d now (%x)\n",inode->i_size,inode);
1.1       root      174: #endif
                    175:                inode->i_dirt = 1;
                    176:        }
                    177:        return 0;
                    178: }
                    179: 
                    180: 
                    181: /* Linear day numbers of the respective 1sts in non-leap years. */
                    182: 
                    183: static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
                    184:                  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
                    185: 
                    186: 
1.1.1.2 ! root      187: extern struct timezone sys_tz;
        !           188: 
        !           189: 
1.1       root      190: /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
                    191: 
                    192: int date_dos2unix(unsigned short time,unsigned short date)
                    193: {
1.1.1.2 ! root      194:        int month,year,secs;
1.1       root      195: 
                    196:        month = ((date >> 5) & 15)-1;
                    197:        year = date >> 9;
1.1.1.2 ! root      198:        secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
1.1       root      199:            ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
                    200:            month < 2 ? 1 : 0)+3653);
                    201:                        /* days since 1.1.70 plus 80's leap day */
1.1.1.2 ! root      202:        secs += sys_tz.tz_minuteswest*60;
        !           203:        return secs;
1.1       root      204: }
                    205: 
                    206: 
                    207: /* Convert linear UNIX date to a MS-DOS time/date pair. */
                    208: 
                    209: void date_unix2dos(int unix_date,unsigned short *time,
                    210:     unsigned short *date)
                    211: {
                    212:        int day,year,nl_day,month;
                    213: 
1.1.1.2 ! root      214:        unix_date -= sys_tz.tz_minuteswest*60;
1.1       root      215:        *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
                    216:            (((unix_date/3600) % 24) << 11);
                    217:        day = unix_date/86400-3652;
                    218:        year = day/365;
                    219:        if ((year+3)/4+365*year > day) year--;
                    220:        day -= (year+3)/4+365*year;
                    221:        if (day == 59 && !(year & 3)) {
                    222:                nl_day = day;
                    223:                month = 2;
                    224:        }
                    225:        else {
                    226:                nl_day = (year & 3) || day <= 59 ? day : day-1;
                    227:                for (month = 0; month < 12; month++)
                    228:                        if (day_n[month] > nl_day) break;
                    229:        }
                    230:        *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
                    231: }
                    232: 
                    233: 
                    234: /* Returns the inode number of the directory entry at offset pos. If bh is
                    235:    non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
                    236:    returned in bh. */
                    237: 
                    238: int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
                    239:     struct msdos_dir_entry **de)
                    240: {
                    241:        int sector,offset;
                    242:        void *data;
                    243: 
                    244:        while (1) {
                    245:                offset = *pos;
1.1.1.2 ! root      246:                if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
1.1       root      247:                        return -1;
                    248:                if (!sector)
                    249:                        return -1; /* FAT error ... */
                    250:                *pos += sizeof(struct msdos_dir_entry);
                    251:                if (*bh)
                    252:                        brelse(*bh);
1.1.1.2 ! root      253:                if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
        !           254:                        printk("Directory sread (sector %d) failed\n",sector);
1.1       root      255:                        continue;
1.1.1.2 ! root      256:                }
1.1       root      257:                *de = (struct msdos_dir_entry *) (data+(offset &
                    258:                    (SECTOR_SIZE-1)));
                    259:                return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
                    260:                    MSDOS_DIR_BITS);
                    261:        }
                    262: }
                    263: 
                    264: 
                    265: /* Scans a directory for a given file (name points to its formatted name) or
                    266:    for an empty directory slot (name is NULL). Returns the inode number. */
                    267: 
                    268: int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
                    269:     struct msdos_dir_entry **res_de,int *ino)
                    270: {
                    271:        int pos;
                    272:        struct msdos_dir_entry *de;
                    273:        struct inode *inode;
                    274: 
                    275:        pos = 0;
                    276:        *res_bh = NULL;
                    277:        while ((*ino = msdos_get_entry(dir,&pos,res_bh,&de)) > -1) {
                    278:                if (name) {
                    279:                        if (de->name[0] && ((unsigned char *) (de->name))[0]
                    280:                            != DELETED_FLAG && !(de->attr & ATTR_VOLUME) &&
                    281:                            !strncmp(de->name,name,MSDOS_NAME)) break;
                    282:                }
                    283:                else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
                    284:                            DELETED_FLAG) {
                    285:                                if (!(inode = iget(dir->i_dev,*ino))) break;
1.1.1.2 ! root      286:                                if (!MSDOS_I(inode)->i_busy) {
1.1       root      287:                                        iput(inode);
                    288:                                        break;
                    289:                                }
                    290:        /* skip deleted files that haven't been closed yet */
                    291:                                iput(inode);
                    292:                        }
                    293:        }
                    294:        if (*ino == -1) {
                    295:                if (*res_bh) brelse(*res_bh);
                    296:                *res_bh = NULL;
                    297:                return name ? -ENOENT : -ENOSPC;
                    298:        }
                    299:        *res_de = de;
                    300:        return 0;
                    301: }
                    302: 
                    303: 
                    304: /* Now an ugly part: this set of directory scan routines works on clusters
                    305:    rather than on inodes and sectors. They are necessary to locate the '..'
1.1.1.2 ! root      306:    directory "inode". raw_found operates in three modes: if name is non-NULL,
        !           307:    the directory is scanned for an entry with that name. If ino is non-NULL,
        !           308:    the directory is scanned for an entry whose data starts at *number. If name
        !           309:    and ino are NULL, the directory entries are counted in *number. */
1.1       root      310: 
                    311: 
1.1.1.2 ! root      312: static int raw_found(struct super_block *sb,int sector,char *name,int *number,
1.1       root      313:     int *ino)
                    314: {
                    315:        struct buffer_head *bh;
                    316:        struct msdos_dir_entry *data;
1.1.1.2 ! root      317:        int entry,start,done;
1.1       root      318: 
                    319:        if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
1.1.1.2 ! root      320:        for (entry = 0; entry < MSDOS_DPS; entry++) {
        !           321:                if (name) done = !strncmp(data[entry].name,name,MSDOS_NAME);
        !           322:                else {
        !           323:                        if (ino)
        !           324:                                done = *(unsigned char *) data[entry].name !=
        !           325:                                    DELETED_FLAG && data[entry].start ==
        !           326:                                    *number;
        !           327:                        else {
        !           328:                                done = 0;
        !           329:                                if (*data[entry].name && *(unsigned char *)
        !           330:                                    data[entry].name != DELETED_FLAG &&
        !           331:                                    (data[entry].attr & ATTR_DIR)) (*number)++;
        !           332:                        }
        !           333:                }
        !           334:                if (done) {
1.1       root      335:                        if (ino) *ino = sector*MSDOS_DPS+entry;
                    336:                        start = data[entry].start;
                    337:                        brelse(bh);
                    338:                        return start;
                    339:                }
1.1.1.2 ! root      340:        }
1.1       root      341:        brelse(bh);
                    342:        return -1;
                    343: }
                    344: 
                    345: 
1.1.1.2 ! root      346: static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino)
1.1       root      347: {
                    348:        int count,cluster;
                    349: 
                    350:        for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
                    351:                if ((cluster = raw_found(sb,MSDOS_SB(sb)->dir_start+count,name,
                    352:                    number,ino)) >= 0) return cluster;
                    353:        }
                    354:        return -ENOENT;
                    355: }
                    356: 
                    357: 
                    358: static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
1.1.1.2 ! root      359:     int *number,int *ino)
1.1       root      360: {
                    361:        int count,cluster;
                    362: 
1.1.1.2 ! root      363: #ifdef DEBUG
        !           364:        printk("raw_scan_nonroot: start=%d\n",start);
        !           365: #endif
1.1       root      366:        do {
                    367:                for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
                    368:                        if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)->
                    369:                            cluster_size+MSDOS_SB(sb)->data_start+count,name,
                    370:                            number,ino)) >= 0) return cluster;
                    371:                }
                    372:                if (!(start = fat_access(sb,start,-1))) panic("FAT error");
1.1.1.2 ! root      373: #ifdef DEBUG
        !           374:        printk("next start: %d\n",start);
        !           375: #endif
1.1       root      376:        }
                    377:        while (start != -1);
                    378:        return -ENOENT;
                    379: }
                    380: 
                    381: 
                    382: static int raw_scan(struct super_block *sb,int start,char *name,int number,
                    383:     int *ino)
                    384: {
1.1.1.2 ! root      385:     if (start) return raw_scan_nonroot(sb,start,name,&number,ino);
        !           386:     else return raw_scan_root(sb,name,&number,ino);
1.1       root      387: }
                    388: 
                    389: 
                    390: int msdos_parent_ino(struct inode *dir,int locked)
                    391: {
                    392:        int error,current,prev,this;
                    393: 
                    394:        if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
                    395:        if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
                    396:        if (!locked) lock_creation(); /* prevent renames */
1.1.1.2 ! root      397:        if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,0,
1.1       root      398:            NULL)) < 0) {
                    399:                if (!locked) unlock_creation();
                    400:                return current;
                    401:        }
                    402:        if (!current) this = MSDOS_ROOT_INO;
                    403:        else {
                    404:                if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,0,NULL)) <
                    405:                    0) {
                    406:                        if (!locked) unlock_creation();
                    407:                        return prev;
                    408:                }
                    409:                if ((error = raw_scan(dir->i_sb,prev,NULL,current,&this)) < 0) {
                    410:                        if (!locked) unlock_creation();
                    411:                        return error;
                    412:                }
                    413:        }
                    414:        if (!locked) unlock_creation();
                    415:        return this;
                    416: }
1.1.1.2 ! root      417: 
        !           418: 
        !           419: int msdos_subdirs(struct inode *dir)
        !           420: {
        !           421:        int count;
        !           422: 
        !           423:        count = 0;
        !           424:        if (dir->i_ino == MSDOS_ROOT_INO)
        !           425:                (void) raw_scan_root(dir->i_sb,NULL,&count,NULL);
        !           426:        else {
        !           427:                if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */
        !           428:                else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
        !           429:                    NULL,&count,NULL);
        !           430:        }
        !           431:        return count;
        !           432: }

unix.superglobalmegacorp.com

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