Exemplo n.º 1
0
static void parseavar(struct ttfinfo *info, FILE *ttf) {
    int axis_count, pair_count;
    int i,j;

    if ( info->variations==NULL || info->avar_start==0 || info->avar_len==0 )
return;

    fseek(ttf,info->avar_start,SEEK_SET);
    if ( getlong(ttf)!=0x00010000 ) {	/* I only understand version 1 */
	VariationFree(info);
return;
    }
    axis_count = getlong(ttf);
    if ( axis_count!=info->variations->axis_count ) {
	LogError( _("Hmm, the axis count in the 'avar' table is different from that in the 'fvar' table.\n") );
	VariationFree(info);
return;
    }
    for ( i=0; i<axis_count; ++i ) {
	pair_count = getushort(ttf);
	if ( pair_count!=0 ) {
	    info->variations->axes[i].mapfrom = malloc(pair_count*sizeof(real));
	    info->variations->axes[i].mapto= malloc(pair_count*sizeof(real));
	    for ( j=0; j<pair_count; ++j ) {
		info->variations->axes[i].mapfrom[j] = getushort(ttf)/16384.0;
		info->variations->axes[i].mapto[j] = getushort(ttf)/16384.0;
	    }
	}
    }
    if ( ftell(ttf)-info->avar_start>info->avar_len) {
	LogError( _("Hmm, the 'avar' table is too long.\n") );
	VariationFree(info);
return;
    }
}
Exemplo n.º 2
0
static int *readpackedpoints(FILE *ttf) {
    int *points;
    int n, runcnt, i, j, first;

    n = getc(ttf);
    if ( n==EOF )
	n = 0;
    if ( n&0x80 )
	n = getc(ttf)|((n&0x7f)<<8);
    points = malloc((n+1)*sizeof(int));
    if ( n==0 )
	points[0] = ALL_POINTS;
    else {
	i = 0;
	while ( i<n ) {
	    runcnt = getc(ttf);
	    if ( runcnt&0x80 ) {
		runcnt = (runcnt&0x7f);
		points[i++] = first = getushort(ttf);
		/* first point not included in runcount */
		for ( j=0; j<runcnt && i<n; ++j )
		    points[i++] = (first += getushort(ttf));
	    } else {
		points[i++] = first = getc(ttf);
		for ( j=0; j<runcnt && i<n; ++j )
		    points[i++] = (first += getc(ttf));
	    }
	}
	points[n] = END_OF_POINTS;
    }
return( points );
}
Exemplo n.º 3
0
/*
 * taken from dos files
 */
uint16_t get_dirent(struct direntry *dirent, char *buffer) {
    uint16_t followclust = 0;
    memset(buffer, 0, MAXFILENAME);

    int i;
    char name[9];
    char extension[4];
    uint16_t file_cluster;
    name[8] = ' ';
    extension[3] = ' ';
    memcpy(name, &(dirent->deName[0]), 8);
    memcpy(extension, dirent->deExtension, 3);
    if (name[0] == SLOT_EMPTY) return followclust;

    /* skip over deleted entries */
    if (((uint8_t)name[0]) == SLOT_DELETED) return followclust;

    // dot entry ("." or "..")
    // skip it
    if (((uint8_t)name[0]) == 0x2E) return followclust;

    /* names are space padded - remove the spaces */
    for (i = 8; i > 0; i--) {
        if (name[i] == ' ') name[i] = '\0';
        else break;
    }

    /* remove the spaces from extensions */
    for (i = 3; i > 0; i--) {
        if (extension[i] == ' ') extension[i] = '\0';
        else break;
    }

    if ((dirent->deAttributes & ATTR_WIN95LFN) == ATTR_WIN95LFN) {
        // ignore any long file name extension entries
        //
        // printf("Win95 long-filename entry seq 0x%0x\n", 
        //          dirent->deName[0]);
    } else if ((dirent->deAttributes & ATTR_DIRECTORY) != 0) {
        // don't deal with hidden directories; MacOS makes these
        // for trash directories and such; just ignore them.
        if ((dirent->deAttributes & ATTR_HIDDEN) != ATTR_HIDDEN) {
            strcpy(buffer, name);
            file_cluster = getushort(dirent->deStartCluster);
            followclust = file_cluster;
        }
    } else {
        /*
         * a "regular" file entry
         * print attributes, size, starting cluster, etc.
         */
        strcpy(buffer, name);
        if (strlen(extension))  {
            strcat(buffer, ".");
            strcat(buffer, extension);
        }
    }

    return followclust;
}
Exemplo n.º 4
0
/*
 * repair an inconsistent file
 */
void repair(struct direntry *dirent, uint8_t *image_buf, struct bpb33 *bpb, int actual_size) {
    
    uint16_t cluster = getushort(dirent->deStartCluster);
    uint16_t cluster_size = bpb->bpbBytesPerSec * bpb->bpbSecPerClust;
    uint16_t prev_cluster = cluster;

    uint16_t num_bytes = 0;
    
    // accumulate all the related clusters in the FAT
    while (num_bytes < actual_size) {
        num_bytes += cluster_size;
        prev_cluster = cluster;
        cluster = get_fat_entry(cluster, image_buf, bpb);
    }
    
    if (num_bytes != 0) {
        set_fat_entry(prev_cluster, eof_cluster, image_buf, bpb);
    }
    
    // update all other clusters attached and mark them as free
    while (!is_end_of_file(cluster)) {
        uint16_t old_cluster = cluster;
        cluster = get_fat_entry(cluster, image_buf, bpb);
        set_fat_entry(old_cluster, free_cluster, image_buf, bpb);
    }
}
Exemplo n.º 5
0
/* 
 * given a directory entry the function counts the number of
 * clusters referred to by the entry.
 */
int count_clusters(struct direntry *dirent, 
                   uint8_t *image_buf, struct bpb33 *bpb) {
    uint16_t cluster = getushort(dirent->deStartCluster);
    uint16_t cluster_size = bpb->bpbBytesPerSec * bpb->bpbSecPerClust;
    int num_bytes = 0; uint16_t prev_cluster = cluster;
    append_clusters(cluster);
    if (is_end_of_file(cluster)) num_bytes = 512;
    while (!is_end_of_file(cluster) && cluster < usable_clusters) {   
        if (cluster == bad_cluster) {
            printf("Bad cluster: cluster number %d \n\n", cluster);
            set_fat_entry(prev_cluster, eof_cluster, image_buf, bpb);
            break;
        }
        if (cluster == free_cluster) {
            set_fat_entry(prev_cluster, eof_cluster, image_buf, bpb);
            break;   
        }
        num_bytes += cluster_size;
        prev_cluster = cluster;
        cluster = get_fat_entry(cluster, image_buf, bpb);
        if (prev_cluster == cluster) {
            printf("Self referential cluster. \n\n");
            set_fat_entry(prev_cluster, eof_cluster, image_buf, bpb);
            break;   
        }
        append_clusters(cluster);
    }

    return num_bytes;
}
Exemplo n.º 6
0
static int *readpackeddeltas(FILE *ttf,int n) {
    int *deltas;
    int runcnt, i, j;

    deltas = malloc(n*sizeof(int));

    i = 0;
    while ( i<n ) {
	runcnt = getc(ttf);
	if ( runcnt&0x80 ) {
	    /* runcnt zeros get added */
	    for ( j=0; j<=(runcnt&0x3f) && i<n ; ++j )
		deltas[i++] = 0;
	} else if ( runcnt&0x40 ) {
	    /* runcnt shorts from the stack */
	    for ( j=0 ; j<=(runcnt&0x3f) && i<n ; ++j )
		deltas[i++] = (int16) getushort(ttf);
	} else {
	    /* runcnt signed bytes from the stack */
	    for ( j=0; j<=(runcnt&0x3f) && i<n; ++j )
		deltas[i++] = (int8) getc(ttf);
	}
	if ( j<=(runcnt&0x3f) ) {
	    if ( n>0 )
		deltas[0] = BAD_DELTA;
	}
    }
return( deltas );
}
Exemplo n.º 7
0
int fatreadnext() {
	if (bytes_left <= 0)
		return 0;

	if (current_sector == cluster_size) {
		secno = start_fat + (current_cluster >> 8);
		if (secno != buf_fat_secno) {
			rc = readblock(secno, buf_fat);
			buf_fat_secno = secno;
		};
		current_cluster = getushort(buf_fat+2*(current_cluster & 255));
		current_sector = 0;
	};
Exemplo n.º 8
0
SplineFont *SFReadIkarus(char *fontname) {
    SplineFont *sf;
    FILE *file = fopen(fontname,"rb");
    int ch1, ch2, rpos, wpos, i;
    int hlen, ilen, jlen, llen, mlen;
    int numchars, maxnum, opt_pt_size;
    double italic_angle;
    char fnam[13], fullname[81];
    int32 *offsets, *numbers;

    if ( file==NULL )
return( NULL );
    hlen = getushort(file);		/* Length of font header */
    ilen = getushort(file);		/* Length of name section */
    getushort(file);			/* Number on URW list */
    fread(fnam,1,12,file);		/* 6 words of filename */
    fread(fullname,1,80,file);		/* 40 words of fontname (human readable) */
    fnam[12] = fullname[80] = '\0';
    ch1 = getc(file);
    ch2 = getc(file);
    if ( ch1=='i' || ch2=='k' )
	/* Docs don't mention this, but lower case is ok too */;
    else if ( ch1!='I' || ch2!='K' ) {
	if ( (ch1=='D' && ch2=='I') || (ch1=='V' && ch2=='C') ||
		(ch1=='V' && ch2=='S') || (ch1=='V' && ch2=='E') || 
		(ch1=='S' && ch2=='C') || (ch1=='S' && ch2=='N') || 
		(ch1=='B' && ch2=='I') || (ch1=='G' && isdigit(ch2)) ||
		(ch1=='d' && ch2=='i') || (ch1=='v' && ch2=='c') ||
		(ch1=='v' && ch2=='s') || (ch1=='v' && ch2=='e') || 
		(ch1=='s' && ch2=='c') || (ch1=='s' && ch2=='n') || 
		(ch1=='b' && ch2=='i') || (ch1=='g' && isdigit(ch2)))
	    LogError( _("This is probably a valid URW font, but it is in a format (%c%c) which FontForge\ndoes not support. FontForge only supports 'IK' format fonts.\n"), ch1, ch2 );
	else if ( ch1==0 && ch2==0 && ilen==55 )
	    LogError( _("This looks like an ikarus format which I have seen examples of, but for which\nI have no documentation. FontForge does not support it yet.\n") );
	fclose(file);
return( NULL );
    } else if ( ilen<55 || hlen<=ilen ) {
	fclose(file);
return( NULL );
    }
    if ( ilen!=55 )
	LogError( _("Unexpected size for name section of URW font (expected 55, got %d)\n"), ilen );

    fseek(file,2*ilen+2,SEEK_SET);
    jlen = getushort(file);
    if ( jlen<12 || hlen<=jlen+ilen ) {
	fclose(file);
return( NULL );
    }
    if ( jlen!=12 )
	LogError( _("Unexpected size for font info section of URW font (expected 12, got %d)\n"), jlen );
    if ( getushort(file)!=1 ) {		/* 1=> typeface */
	fclose(file);
return( NULL );
    }
    numchars = getushort(file);
    /* cap height = */ getushort(file);
    /* body size = */ getushort(file);
    /* x-height = */ getushort(file);
    /* descender? = */ getushort(file);
    /* line thickness = */ getushort(file);
    /* stroke thickness = */ getushort(file);
    italic_angle = getushort(file)/10.0 * 3.1415926535897932/180.0;
    opt_pt_size = getushort(file);
    /* average char width = */ getushort(file);

    fseek(file,2*ilen+2*jlen+2,SEEK_SET);
    llen = getushort(file);		/* the hierarchy section is unused in font files */
    if ( llen!=1 || hlen<=jlen+ilen+llen ) {
	fclose(file);
return( NULL );
    }

    mlen = getushort(file);
    /* Peter Karow's book documents that hlen==jlen+ilen+llen+mlen+1, but this*/
    /*  does not appear to be the case. */
    if ( hlen<jlen+ilen+llen+mlen+1 || mlen<3*numchars+3 ) {
	fclose(file);
return( NULL );
    }
    /* last record */ getushort(file);
    /* last word of last record */ getushort(file);

    offsets = malloc(numchars*sizeof(int32));
    numbers = malloc(numchars*sizeof(int32));
    maxnum = 0;
    for ( i=0; i<numchars; ++i ) {
	numbers[i] = getushort(file);
	if ( numbers[i]>maxnum ) maxnum = numbers[i];
	rpos = getushort(file);		/* record pos (1 record=2048 words) */
	wpos = getushort(file);		/* word pos in record */
	offsets[i] = (rpos-1)*4096 + 2*(wpos-1);
    }

    sf = SplineFontBlank(numchars/*maxnum+1*/);
    IkarusFontname(sf,fullname,fnam);
    sf->italicangle = italic_angle;
    sf->ascent = 12000; sf->descent = 3000;	/* Ikarus fonts live in a 15,000 em world */
    for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
	sf->glyphs[i]->width = sf->glyphs[i]->vwidth = 15000;
    sf->map = EncMapNew(numchars,numchars,&custom);

    for ( i=0; i<numchars; ++i ) {
	fseek(file,offsets[i],SEEK_SET);
	IkarusReadChar(SFMakeChar(sf,sf->map,i),file);
    }
    if ( loaded_fonts_same_as_new && new_fonts_are_order2 )
	SFConvertToOrder2(sf);

    free(numbers); free(offsets);
    fclose(file);
return( sf );
}
Exemplo n.º 9
0
int
msdosfs_readdir(void *v)
{
	struct vop_readdir_args *ap = v;
	int error = 0;
	int diff;
	long n;
	int blsize;
	long on;
	long lost;
	long count;
	uint32_t dirsperblk;
	uint32_t cn, lbn;
	uint32_t fileno;
	long bias = 0;
	daddr64_t bn;
	struct buf *bp;
	struct denode *dep = VTODE(ap->a_vp);
	struct msdosfsmount *pmp = dep->de_pmp;
	struct direntry *dentp;
	struct dirent dirbuf;
	struct uio *uio = ap->a_uio;
	u_long *cookies = NULL;
	int ncookies = 0;
	off_t offset, wlast = -1;
	int chksum = -1;

#ifdef MSDOSFS_DEBUG
	printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
	    ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
#endif

	/*
	 * msdosfs_readdir() won't operate properly on regular files since
	 * it does i/o only with the filesystem vnode, and hence can
	 * retrieve the wrong block from the buffer cache for a plain file.
	 * So, fail attempts to readdir() on a plain file.
	 */
	if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
		return (ENOTDIR);

	/*
	 * To be safe, initialize dirbuf
	 */
	bzero(dirbuf.d_name, sizeof(dirbuf.d_name));

	/*
	 * If the user buffer is smaller than the size of one dos directory
	 * entry or the file offset is not a multiple of the size of a
	 * directory entry, then we fail the read.
	 */
	count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
	offset = uio->uio_offset;
	if (count < sizeof(struct direntry) ||
	    (offset & (sizeof(struct direntry) - 1)))
		return (EINVAL);
	lost = uio->uio_resid - count;
	uio->uio_resid = count;

	if (ap->a_ncookies) {
		ncookies = uio->uio_resid / sizeof(struct direntry) + 3;
		cookies = malloc(ncookies * sizeof(u_long), M_TEMP, M_WAITOK);
		*ap->a_cookies = cookies;
		*ap->a_ncookies = ncookies;
	}

	dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);

	/*
	 * If they are reading from the root directory then, we simulate
	 * the . and .. entries since these don't exist in the root
	 * directory.  We also set the offset bias to make up for having to
	 * simulate these entries. By this I mean that at file offset 64 we
	 * read the first entry in the root directory that lives on disk.
	 */
	if (dep->de_StartCluster == MSDOSFSROOT
	    || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
#if 0
		printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
		    offset);
#endif
		bias = 2 * sizeof(struct direntry);
		if (offset < bias) {
			for (n = (int)offset / sizeof(struct direntry);
			     n < 2; n++) {
			        if (FAT32(pmp))
				        dirbuf.d_fileno = pmp->pm_rootdirblk;
				else
				        dirbuf.d_fileno = 1;
				dirbuf.d_type = DT_DIR;
				switch (n) {
				case 0:
					dirbuf.d_namlen = 1;
					strlcpy(dirbuf.d_name, ".",
					    sizeof dirbuf.d_name);
					break;
				case 1:
					dirbuf.d_namlen = 2;
					strlcpy(dirbuf.d_name, "..",
					    sizeof dirbuf.d_name);
					break;
				}
				dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
				if (uio->uio_resid < dirbuf.d_reclen)
					goto out;
				error = uiomove((caddr_t) &dirbuf,
						dirbuf.d_reclen, uio);
				if (error)
					goto out;
				offset += sizeof(struct direntry);
				if (cookies) {
					*cookies++ = offset;
					if (--ncookies <= 0)
						goto out;
				}
			}
		}
	}

	while (uio->uio_resid > 0) {
		lbn = de_cluster(pmp, offset - bias);
		on = (offset - bias) & pmp->pm_crbomask;
		n = min(pmp->pm_bpcluster - on, uio->uio_resid);
		diff = dep->de_FileSize - (offset - bias);
		if (diff <= 0)
			break;
		n = min(n, diff);
		if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0)
			break;
		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
		if (error) {
			brelse(bp);
			return (error);
		}
		n = min(n, blsize - bp->b_resid);

		/*
		 * Convert from dos directory entries to fs-independent
		 * directory entries.
		 */
		for (dentp = (struct direntry *)(bp->b_data + on);
		     (char *)dentp < bp->b_data + on + n;
		     dentp++, offset += sizeof(struct direntry)) {
#if 0
			printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
			    dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
#endif
			/*
			 * If this is an unused entry, we can stop.
			 */
			if (dentp->deName[0] == SLOT_EMPTY) {
				brelse(bp);
				goto out;
			}
			/*
			 * Skip deleted entries.
			 */
			if (dentp->deName[0] == SLOT_DELETED) {
				chksum = -1;
				wlast = -1;
				continue;
			}

			/*
			 * Handle Win95 long directory entries
			 */
			if (dentp->deAttributes == ATTR_WIN95) {
				struct winentry *wep;
				if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
					continue;
				wep = (struct winentry *)dentp;
				chksum = win2unixfn(wep, &dirbuf, chksum);
				if (wep->weCnt & WIN_LAST)
					wlast = offset;
				continue;
			}

			/*
			 * Skip volume labels
			 */
			if (dentp->deAttributes & ATTR_VOLUME) {
				chksum = -1;
				wlast = -1;
				continue;
			}

			/*
			 * This computation of d_fileno must match
			 * the computation of va_fileid in
			 * msdosfs_getattr.
			 */
			fileno = getushort(dentp->deStartCluster);
			if (FAT32(pmp))
			    fileno |= getushort(dentp->deHighClust) << 16;

			if (dentp->deAttributes & ATTR_DIRECTORY) {
				/* Special-case root */
				if (fileno == MSDOSFSROOT)  {
					fileno = FAT32(pmp) ?
					    pmp->pm_rootdirblk : 1;
				}

				dirbuf.d_fileno = fileno;
				dirbuf.d_type = DT_DIR;
			} else {
				if (getulong(dentp->deFileSize) == 0) {
					uint64_t fileno64;

					fileno64 = (cn == MSDOSFSROOT) ?
					    roottobn(pmp, 0) : cntobn(pmp, cn);

					fileno64 *= dirsperblk;
					fileno64 += dentp -
					    (struct direntry *)bp->b_data;

					fileno = fileidhash(fileno64);
				}

				dirbuf.d_fileno = fileno;
				dirbuf.d_type = DT_REG;
			}

			if (chksum != winChksum(dentp->deName))
				dirbuf.d_namlen = dos2unixfn(dentp->deName,
				    (u_char *)dirbuf.d_name,
				    pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
			else
				dirbuf.d_name[dirbuf.d_namlen] = 0;
			chksum = -1;
			dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
			if (uio->uio_resid < dirbuf.d_reclen) {
				brelse(bp);
				/* Remember long-name offset. */
				if (wlast != -1)
					offset = wlast;
				goto out;
			}
			wlast = -1;
			error = uiomove((caddr_t) &dirbuf,
					dirbuf.d_reclen, uio);
			if (error) {
				brelse(bp);
				goto out;
			}
			if (cookies) {
				*cookies++ = offset + sizeof(struct direntry);
				if (--ncookies <= 0) {
					brelse(bp);
					goto out;
				}
			}
		}
		brelse(bp);
	}

out:
	/* Subtract unused cookies */
	if (ap->a_ncookies)
		*ap->a_ncookies -= ncookies;

	uio->uio_offset = offset;
	uio->uio_resid += lost;
	if (dep->de_FileSize - (offset - bias) <= 0)
		*ap->a_eofflag = 1;
	else
		*ap->a_eofflag = 0;
	return (error);
}
Exemplo n.º 10
0
void check_lost_files(int usedClusters[], uint16_t cluster, uint8_t *image_buf, struct bpb33* bpb)
{
    // A value of 1 means that the cluster is used somewhere.
    usedClusters[cluster] = 1;

    struct direntry *dirent;
    int d, i;
    dirent = (struct direntry*) cluster_to_addr(cluster, image_buf, bpb);
    int clust_size = bpb->bpbBytesPerSec * bpb->bpbSecPerClust;

    while (1) {
        for (d = 0; d < clust_size; d += sizeof(struct direntry)) {
            char name[9];
            char extension[4];
            uint32_t size;
            uint16_t file_cluster;
            name[8] = ' ';
            extension[3] = ' ';
            memcpy(name, &(dirent->deName[0]), 8);
            memcpy(extension, dirent->deExtension, 3);

            if (name[0] == SLOT_EMPTY)
                return;

            /* skip over deleted entries */
            if (((uint8_t)name[0]) == SLOT_DELETED)
                continue;

            /* names are space padded - remove the spaces */
            for (i = 8; i > 0; i--) {
                if (name[i] == ' ')
                    name[i] = '\0';
                else
                    break;
            }

            /* remove the spaces from extensions */
            for (i = 3; i > 0; i--) {
                if (extension[i] == ' ')
                    extension[i] = '\0';
                else
                    break;
            }

            /* don't print "." or ".." directories */
            if (strcmp(name, ".") == 0) {
                dirent++;
                continue;
            }
            if (strcmp(name, "..") == 0) {
                dirent++;
                continue;
            }

            if ((dirent->deAttributes & ATTR_VOLUME) != 0) {
            } else if ((dirent->deAttributes & ATTR_DIRECTORY) != 0) {
                file_cluster = getushort(dirent->deStartCluster);
                check_lost_files(usedClusters, file_cluster, image_buf, bpb);
            } else {
                /* We have a file. We should follow the file and remove all the used clusters from our collection! */
                size = getulong(dirent->deFileSize);
                uint16_t file_cluster_begin = getushort(dirent->deStartCluster);
                //uint16_t cluster, uint32_t bytes_remaining, uint8_t *image_buf, struct bpb33* bpb
                mark_file_clusters_used(usedClusters, file_cluster_begin, size, image_buf, bpb);
            }

            dirent++;
        }

        /* We've reached the end of the cluster for this directory. Where's the next cluster? */
        if (cluster == 0) {
            // root dir is special
            dirent++;
        } else {
            cluster = get_fat_entry(cluster, image_buf, bpb);
            dirent = (struct direntry*) cluster_to_addr(cluster, image_buf, bpb);
        }
    }
}
Exemplo n.º 11
0
int
msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l, struct msdosfs_args *argp)
{
	struct msdosfsmount *pmp;
	struct buf *bp;
	dev_t dev = devvp->v_rdev;
	union bootsector *bsp;
	struct byte_bpb33 *b33;
	struct byte_bpb50 *b50;
	struct byte_bpb710 *b710;
	uint8_t SecPerClust;
	int	ronly, error, tmp;
	int	bsize;
	uint64_t psize;
	unsigned secsize;

	/* Flush out any old buffers remaining from a previous use. */
	if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
		return (error);

	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;

	bp  = NULL; /* both used in error_exit */
	pmp = NULL;

	error = fstrans_mount(mp);
	if (error)
		goto error_exit;

	error = getdisksize(devvp, &psize, &secsize);
	if (error) {
		if (argp->flags & MSDOSFSMNT_GEMDOSFS)
			goto error_exit;

		/* ok, so it failed.  we most likely don't need the info */
		secsize = DEV_BSIZE;
		psize = 0;
		error = 0;
	}

	if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
		bsize = secsize;
		if (bsize != 512) {
			DPRINTF(("Invalid block bsize %d for GEMDOS\n", bsize));
			error = EINVAL;
			goto error_exit;
		}
	} else
		bsize = 0;

	/*
	 * Read the boot sector of the filesystem, and then check the
	 * boot signature.  If not a dos boot sector then error out.
	 */
	if ((error = bread(devvp, 0, secsize, NOCRED, 0, &bp)) != 0)
		goto error_exit;
	bsp = (union bootsector *)bp->b_data;
	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
	b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;

	if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
		if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
		    || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
			DPRINTF(("bootsig0 %d bootsig1 %d\n", 
			    bsp->bs50.bsBootSectSig0,
			    bsp->bs50.bsBootSectSig1));
			error = EINVAL;
			goto error_exit;
		}
	}

	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
	memset(pmp, 0, sizeof *pmp);
	pmp->pm_mountp = mp;

	/*
	 * Compute several useful quantities from the bpb in the
	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
	 * the fields that are different between dos 5 and dos 3.3.
	 */
	SecPerClust = b50->bpbSecPerClust;
	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
	pmp->pm_FATs = b50->bpbFATs;
	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
	pmp->pm_Sectors = getushort(b50->bpbSectors);
	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
	pmp->pm_Heads = getushort(b50->bpbHeads);
	pmp->pm_Media = b50->bpbMedia;

	if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
		/* XXX - We should probably check more values here */
    		if (!pmp->pm_BytesPerSec || !SecPerClust
	    		|| pmp->pm_SecPerTrack > 63) {
			DPRINTF(("bytespersec %d secperclust %d "
			    "secpertrack %d\n", 
			    pmp->pm_BytesPerSec, SecPerClust,
			    pmp->pm_SecPerTrack));
			error = EINVAL;
			goto error_exit;
		}
	}

	if (pmp->pm_Sectors == 0) {
		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
	} else {
		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
		pmp->pm_HugeSectors = pmp->pm_Sectors;
	}

	if (pmp->pm_RootDirEnts == 0) {
		unsigned short vers = getushort(b710->bpbFSVers);
		/*
		 * Some say that bsBootSectSig[23] must be zero, but
		 * Windows does not require this and some digital cameras
		 * do not set these to zero.  Therefore, do not insist.
		 */
		if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) {
			DPRINTF(("sectors %d fatsecs %lu vers %d\n",
			    pmp->pm_Sectors, pmp->pm_FATsecs, vers));
			error = EINVAL;
			goto error_exit;
		}
		pmp->pm_fatmask = FAT32_MASK;
		pmp->pm_fatmult = 4;
		pmp->pm_fatdiv = 1;
		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);

		/* mirrorring is enabled if the FATMIRROR bit is not set */
		if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0)
			pmp->pm_flags |= MSDOSFS_FATMIRROR;
		else
			pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
	} else
		pmp->pm_flags |= MSDOSFS_FATMIRROR;

	if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
		if (FAT32(pmp)) {
			DPRINTF(("FAT32 for GEMDOS\n"));
			/*
			 * GEMDOS doesn't know FAT32.
			 */
			error = EINVAL;
			goto error_exit;
		}

		/*
		 * Check a few values (could do some more):
		 * - logical sector size: power of 2, >= block size
		 * - sectors per cluster: power of 2, >= 1
		 * - number of sectors:   >= 1, <= size of partition
		 */
		if ( (SecPerClust == 0)
		  || (SecPerClust & (SecPerClust - 1))
		  || (pmp->pm_BytesPerSec < bsize)
		  || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
		  || (pmp->pm_HugeSectors == 0)
		  || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
		      > psize)) {
			DPRINTF(("consistency checks for GEMDOS\n"));
			error = EINVAL;
			goto error_exit;
		}
		/*
		 * XXX - Many parts of the msdosfs driver seem to assume that
		 * the number of bytes per logical sector (BytesPerSec) will
		 * always be the same as the number of bytes per disk block
		 * Let's pretend it is.
		 */
		tmp = pmp->pm_BytesPerSec / bsize;
		pmp->pm_BytesPerSec  = bsize;
		pmp->pm_HugeSectors *= tmp;
		pmp->pm_HiddenSects *= tmp;
		pmp->pm_ResSectors  *= tmp;
		pmp->pm_Sectors     *= tmp;
		pmp->pm_FATsecs     *= tmp;
		SecPerClust         *= tmp;
	}

	/* Check that fs has nonzero FAT size */
	if (pmp->pm_FATsecs == 0) {
		DPRINTF(("FATsecs is 0\n"));
		error = EINVAL;
		goto error_exit;
	}

	pmp->pm_fatblk = pmp->pm_ResSectors;
	if (FAT32(pmp)) {
		pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
		pmp->pm_firstcluster = pmp->pm_fatblk
			+ (pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
	} else {
		pmp->pm_rootdirblk = pmp->pm_fatblk +
			(pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
				       + pmp->pm_BytesPerSec - 1)
			/ pmp->pm_BytesPerSec;/* in sectors */
		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
	}

	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
	    SecPerClust;
	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
	pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;

	if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
		if (pmp->pm_nmbrofclusters <= (0xff0 - 2)) {
			pmp->pm_fatmask = FAT12_MASK;
			pmp->pm_fatmult = 3;
			pmp->pm_fatdiv = 2;
		} else {
			pmp->pm_fatmask = FAT16_MASK;
			pmp->pm_fatmult = 2;
			pmp->pm_fatdiv = 1;
		}
	} else if (pmp->pm_fatmask == 0) {
		if (pmp->pm_maxcluster
		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
			/*
			 * This will usually be a floppy disk. This size makes
			 * sure that one FAT entry will not be split across
			 * multiple blocks.
			 */
			pmp->pm_fatmask = FAT12_MASK;
			pmp->pm_fatmult = 3;
			pmp->pm_fatdiv = 2;
		} else {
			pmp->pm_fatmask = FAT16_MASK;
			pmp->pm_fatmult = 2;
			pmp->pm_fatdiv = 1;
		}
	}
	if (FAT12(pmp))
		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
	else
		pmp->pm_fatblocksize = MAXBSIZE;

	pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
	pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;

	/*
	 * Compute mask and shift value for isolating cluster relative byte
	 * offsets and cluster numbers from a file offset.
	 */
	pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;

	/*
	 * Check for valid cluster size
	 * must be a power of 2
	 */
	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
		DPRINTF(("bpcluster %lu cnshift %lu\n", 
		    pmp->pm_bpcluster, pmp->pm_cnshift));
		error = EINVAL;
		goto error_exit;
	}

	/*
	 * Cluster size must be within limit of MAXBSIZE.
	 * Many FAT filesystems will not have clusters larger than
	 * 32KiB due to limits in Windows versions before Vista.
	 */
	if (pmp->pm_bpcluster > MAXBSIZE) {
		DPRINTF(("bpcluster %lu > MAXBSIZE %d\n",
		    pmp->pm_bpcluster, MAXBSIZE));
		error = EINVAL;
		goto error_exit;
	}

	/*
	 * Release the bootsector buffer.
	 */
	brelse(bp, BC_AGE);
	bp = NULL;

	/*
	 * Check FSInfo.
	 */
	if (pmp->pm_fsinfo) {
		struct fsinfo *fp;

		/*
		 * XXX	If the fsinfo block is stored on media with
		 *	2KB or larger sectors, is the fsinfo structure
		 *	padded at the end or in the middle?
		 */
		if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo),
		    pmp->pm_BytesPerSec, NOCRED, 0, &bp)) != 0)
			goto error_exit;
		fp = (struct fsinfo *)bp->b_data;
		if (!memcmp(fp->fsisig1, "RRaA", 4)
		    && !memcmp(fp->fsisig2, "rrAa", 4)
		    && !memcmp(fp->fsisig3, "\0\0\125\252", 4)
		    && !memcmp(fp->fsisig4, "\0\0\125\252", 4))
			pmp->pm_nxtfree = getulong(fp->fsinxtfree);
		else
			pmp->pm_fsinfo = 0;
		brelse(bp, 0);
		bp = NULL;
	}

	/*
	 * Check and validate (or perhaps invalidate?) the fsinfo structure?
	 * XXX
	 */
	if (pmp->pm_fsinfo) {
		if ((pmp->pm_nxtfree == 0xffffffffUL) ||
		    (pmp->pm_nxtfree > pmp->pm_maxcluster))
			pmp->pm_fsinfo = 0;
	}

	/*
	 * Allocate memory for the bitmap of allocated clusters, and then
	 * fill it in.
	 */
	pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS)
				   / N_INUSEBITS)
				  * sizeof(*pmp->pm_inusemap),
				  M_MSDOSFSFAT, M_WAITOK);

	/*
	 * fillinusemap() needs pm_devvp.
	 */
	pmp->pm_dev = dev;
	pmp->pm_devvp = devvp;

	/*
	 * Have the inuse map filled in.
	 */
	if ((error = fillinusemap(pmp)) != 0) {
		DPRINTF(("fillinusemap %d\n", error));
		goto error_exit;
	}

	/*
	 * If they want FAT updates to be synchronous then let them suffer
	 * the performance degradation in exchange for the on disk copy of
	 * the FAT being correct just about all the time.  I suppose this
	 * would be a good thing to turn on if the kernel is still flakey.
	 */
	if (mp->mnt_flag & MNT_SYNCHRONOUS)
		pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;

	/*
	 * Finish up.
	 */
	if (ronly)
		pmp->pm_flags |= MSDOSFSMNT_RONLY;
	else
		pmp->pm_fmod = 1;
	mp->mnt_data = pmp;
	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_MSDOS);
	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
	mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp);
	mp->mnt_flag |= MNT_LOCAL;
	mp->mnt_dev_bshift = pmp->pm_bnshift;
	mp->mnt_fs_bshift = pmp->pm_cnshift;

	/*
	 * If we ever do quotas for DOS filesystems this would be a place
	 * to fill in the info in the msdosfsmount structure. You dolt,
	 * quotas on dos filesystems make no sense because files have no
	 * owners on dos filesystems. of course there is some empty space
	 * in the directory entry where we could put uid's and gid's.
	 */

	spec_node_setmountedfs(devvp, mp);

	return (0);

error_exit:
	fstrans_unmount(mp);
	if (bp)
		brelse(bp, BC_AGE);
	if (pmp) {
		if (pmp->pm_inusemap)
			free(pmp->pm_inusemap, M_MSDOSFSFAT);
		free(pmp, M_MSDOSFSMNT);
		mp->mnt_data = NULL;
	}
	return (error);
}
Exemplo n.º 12
0
/************PRINT_DIRENT***************/
uint16_t print_dirent(struct direntry *dirent, int indent, uint8_t *image_buf, struct bpb33* bpb, int *refcount )
{
    uint16_t followclust = 0;

    int i;
    char name[9];
    char extension[4];
    uint32_t size;
    uint16_t file_cluster;
    name[8] = ' ';
    extension[3] = ' ';
    memcpy(name, &(dirent->deName[0]), 8);
    memcpy(extension, dirent->deExtension, 3);
    if (name[0] == SLOT_EMPTY)
    {
	return followclust;
    }

    /* skip over deleted entries */
    if (((uint8_t)name[0]) == SLOT_DELETED)
    {
	return followclust;
    }

    if (((uint8_t)name[0]) == 0x2E)
    {
	// dot entry ("." or "..")
	// skip it
        return followclust;
    }

    /* names are space padded - remove the spaces */
    for (i = 8; i > 0; i--) 
    {
	if (name[i] == ' ') 
	    name[i] = '\0';
	else 
	    break;
    }

    /* remove the spaces from extensions */
    for (i = 3; i > 0; i--) 
    {
	if (extension[i] == ' ') 
	    extension[i] = '\0';
	else 
	    break;
    }

    if ((dirent->deAttributes & ATTR_WIN95LFN) == ATTR_WIN95LFN)
    {
	// ignore any long file name extension entries
	//
	// printf("Win95 long-filename entry seq 0x%0x\n", dirent->deName[0]);
    }
    else if ((dirent->deAttributes & ATTR_VOLUME) != 0) 
    {
	printf("Volume: %s\n", name);
    } 
    else if ((dirent->deAttributes & ATTR_DIRECTORY) != 0) 
    {
        // don't deal with hidden directories; MacOS makes these
        // for trash directories and such; just ignore them.
	if ((dirent->deAttributes & ATTR_HIDDEN) != ATTR_HIDDEN)
        {
	    print_indent(indent);
    	    printf("%s/ (directory)\n", name);
            file_cluster = getushort(dirent->deStartCluster);
            followclust = file_cluster;
        }
    }
    else 
    {
        /*
         * a "regular" file entry
         * print attributes, size, starting cluster, etc.
         */
	int ro = (dirent->deAttributes & ATTR_READONLY) == ATTR_READONLY;
	int hidden = (dirent->deAttributes & ATTR_HIDDEN) == ATTR_HIDDEN;
	int sys = (dirent->deAttributes & ATTR_SYSTEM) == ATTR_SYSTEM;
	int arch = (dirent->deAttributes & ATTR_ARCHIVE) == ATTR_ARCHIVE;

	size = getulong(dirent->deFileSize);
	print_indent(indent);
	printf("%s.%s (%u bytes) (starting cluster %d) %c%c%c%c\n", 
	       name, extension, size, getushort(dirent->deStartCluster),
	       ro?'r':' ', 
               hidden?'h':' ', 
               sys?'s':' ', 
               arch?'a':' ');

		
		int cluster_count = 0;
        
		uint16_t curr_cluster = getushort(dirent->deStartCluster);
		uint16_t original_cluster = curr_cluster;
        
        uint16_t previous;

        while(is_valid_cluster(curr_cluster,bpb))
		{
            refcount[curr_cluster]++;
			if(refcount[curr_cluster] > 1) //problem
			{
				printf("ERROR REFCOUNT > 1 FOR:  %d, refcount = %d\n", curr_cluster, refcount[curr_cluster]);  
				dirent->deName[0] = SLOT_DELETED;
				refcount[curr_cluster]--;
			}

			previous = curr_cluster;
			curr_cluster = get_fat_entry(curr_cluster, image_buf, bpb);
			if(previous == curr_cluster) //points to itself
			{
				printf("ERROR POINTS TO SELF\n");
				set_fat_entry(curr_cluster, FAT12_MASK & CLUST_EOFS, image_buf, bpb);
				cluster_count++;
				break;
			}
			if(curr_cluster == (FAT12_MASK & CLUST_BAD))
			{
				printf("BAD CLUSTER\n");
				set_fat_entry(curr_cluster, FAT12_MASK & CLUST_FREE, image_buf, bpb);
				set_fat_entry(previous, FAT12_MASK & CLUST_EOFS, image_buf, bpb);
				break;
			}
			cluster_count++;
		}
		
		int clusters = 0;
		if(size%512 == 0)
		{
			clusters = size/512;
		}
		else
		{
			clusters = (size/512)+1;
		}
		if(clusters < cluster_count)
		{
			printf("ERROR: FILE SIZE TOO SMALL FOR NUM CLUSTERS\n");
			curr_cluster = get_fat_entry(original_cluster+clusters - 1, image_buf, bpb);
			printf("FIXED \n");
			while(is_valid_cluster(curr_cluster, bpb))
			{
				previous = curr_cluster;
				set_fat_entry(previous, FAT12_MASK & CLUST_FREE, image_buf, bpb);
				curr_cluster = get_fat_entry(curr_cluster, image_buf, bpb);
			}
			set_fat_entry(original_cluster +clusters -1, FAT12_MASK &CLUST_EOFS, image_buf, bpb);
			}
		else if(clusters > cluster_count)
		{
			printf("ERROR: FILE SIZE TOO LARGE FOR NUM CLUSTERS\n");
			uint32_t correct_size = cluster_count * bpb->bpbBytesPerSec;
			putulong(dirent->deFileSize, correct_size);
			printf("FIXED \n");
		}
		

    }

    return followclust;
}
Exemplo n.º 13
0
/*
 * When we search a directory the blocks containing directory entries are
 * read and examined.  The directory entries contain information that would
 * normally be in the inode of a unix filesystem.  This means that some of
 * a directory's contents may also be in memory resident denodes (sort of
 * an inode).  This can cause problems if we are searching while some other
 * process is modifying a directory.  To prevent one process from accessing
 * incompletely modified directory information we depend upon being the
 * sole owner of a directory block.  bread/brelse provide this service.
 * This being the case, when a process modifies a directory it must first
 * acquire the disk block that contains the directory entry to be modified.
 * Then update the disk block and the denode, and then write the disk block
 * out to disk.  This way disk blocks containing directory entries and in
 * memory denode's will be in synch.
 */
int
msdosfs_lookup(void *v)
{
	struct vop_lookup_v2_args /* {
		struct vnode *a_dvp;
		struct vnode **a_vpp;
		struct componentname *a_cnp;
	} */ *ap = v;
	struct vnode *vdp = ap->a_dvp;
	struct vnode **vpp = ap->a_vpp;
	struct componentname *cnp = ap->a_cnp;
	daddr_t bn;
	int error;
	int slotcount;
	int slotoffset = 0;
	int frcn;
	u_long cluster;
	int blkoff;
	int diroff;
	int blsize;
	int isadir;		/* ~0 if found direntry is a directory	 */
	u_long scn;		/* starting cluster number		 */
	struct vnode *pdp;
	struct denode *dp;
	struct denode *tdp;
	struct msdosfsmount *pmp;
	struct buf *bp = 0;
	struct direntry *dep;
	u_char dosfilename[12];
	int flags;
	int nameiop = cnp->cn_nameiop;
	int wincnt = 1;
	int chksum = -1, chksum_ok;
	int olddos = 1;

	flags = cnp->cn_flags;

#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): looking for %.*s\n",
		(int)cnp->cn_namelen, cnp->cn_nameptr);
#endif
	dp = VTODE(vdp);
	pmp = dp->de_pmp;
	*vpp = NULL;
#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
	    vdp, dp, dp->de_Attributes);
#endif

	/*
	 * Check accessiblity of directory.
	 */
	if ((error = VOP_ACCESS(vdp, VEXEC, cnp->cn_cred)) != 0)
		return (error);

	if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
		return (EROFS);

	/*
	 * We now have a segment name to search for, and a directory to search.
	 *
	 * Before tediously performing a linear scan of the directory,
	 * check the name cache to see if the directory/name pair
	 * we are looking for is known already.
	 */
	if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen,
			 cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
		return *vpp == NULLVP ? ENOENT: 0;
	}

	/*
	 * If they are going after the . or .. entry in the root directory,
	 * they won't find it.  DOS filesystems don't have them in the root
	 * directory.  So, we fake it. deget() is in on this scam too.
	 */
	if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' &&
	    (cnp->cn_namelen == 1 ||
		(cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
		isadir = ATTR_DIRECTORY;
		scn = MSDOSFSROOT;
#ifdef MSDOSFS_DEBUG
		printf("msdosfs_lookup(): looking for . or .. in root directory\n");
#endif
		cluster = MSDOSFSROOT;
		blkoff = MSDOSFSROOT_OFS;
		goto foundroot;
	}

	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
	    cnp->cn_namelen, 0)) {
	case 0:
		return (EINVAL);
	case 1:
		break;
	case 2:
		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
		    cnp->cn_namelen) + 1;
		break;
	case 3:
		olddos = 0;
		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
		    cnp->cn_namelen) + 1;
		break;
	}
	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
		wincnt = 1;

	/*
	 * Suppress search for slots unless creating
	 * file and at end of pathname, in which case
	 * we watch for a place to put the new file in
	 * case it doesn't already exist.
	 */
	slotcount = wincnt;
	if ((nameiop == CREATE || nameiop == RENAME) &&
	    (flags & ISLASTCN))
		slotcount = 0;

#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): dos filename: %s\n", dosfilename);
#endif
	/*
	 * Search the directory pointed at by vdp for the name pointed at
	 * by cnp->cn_nameptr.
	 */
	tdp = NULL;
	/*
	 * The outer loop ranges over the clusters that make up the
	 * directory.  Note that the root directory is different from all
	 * other directories.  It has a fixed number of blocks that are not
	 * part of the pool of allocatable clusters.  So, we treat it a
	 * little differently. The root directory starts at "cluster" 0.
	 */
	diroff = 0;
	for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
		if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
			if (error == E2BIG)
				break;
			return (error);
		}
		error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED,
		    0, &bp);
		if (error) {
			return (error);
		}
		for (blkoff = 0; blkoff < blsize;
		     blkoff += sizeof(struct direntry),
		     diroff += sizeof(struct direntry)) {
			dep = (struct direntry *)((char *)bp->b_data + blkoff);
			/*
			 * If the slot is empty and we are still looking
			 * for an empty then remember this one.  If the
			 * slot is not empty then check to see if it
			 * matches what we are looking for.  If the slot
			 * has never been filled with anything, then the
			 * remainder of the directory has never been used,
			 * so there is no point in searching it.
			 */
			if (dep->deName[0] == SLOT_EMPTY ||
			    dep->deName[0] == SLOT_DELETED) {
				/*
				 * Drop memory of previous long matches
				 */
				chksum = -1;

				if (slotcount < wincnt) {
					slotcount++;
					slotoffset = diroff;
				}
				if (dep->deName[0] == SLOT_EMPTY) {
					brelse(bp, 0);
					goto notfound;
				}
			} else {
				/*
				 * If there wasn't enough space for our
				 * winentries, forget about the empty space
				 */
				if (slotcount < wincnt)
					slotcount = 0;

				/*
				 * Check for Win95 long filename entry
				 */
				if (dep->deAttributes == ATTR_WIN95) {
					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
						continue;

					chksum = winChkName((const u_char *)cnp->cn_nameptr,
							    cnp->cn_namelen,
							    (struct winentry *)dep,
							    chksum);
					continue;
				}

				/*
				 * Ignore volume labels (anywhere, not just
				 * the root directory).
				 */
				if (dep->deAttributes & ATTR_VOLUME) {
					chksum = -1;
					continue;
				}

				/*
				 * Check for a checksum or name match
				 */
				chksum_ok = (chksum == winChksum(dep->deName));
				if (!chksum_ok && (
					!olddos ||
					memcmp(&dosfilename[0],dep->deName,8) ||
					memcmp(&dosfilename[8],dep->deExtension,3))) {
					chksum = -1;
					continue;
				}
#ifdef MSDOSFS_DEBUG
				printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
				    blkoff, diroff);
#endif
				/*
				 * Remember where this directory
				 * entry came from for whoever did
				 * this lookup.
				 */
				dp->de_fndoffset = diroff;
				if (chksum_ok && nameiop == RENAME) {
					/*
					 * Target had correct long name
					 * directory entries, reuse them
					 * as needed.
					 */
					dp->de_fndcnt = wincnt - 1;
				} else {
					/*
					 * Long name directory entries
					 * not present or corrupt, can only
					 * reuse dos directory entry.
					 */
					dp->de_fndcnt = 0;
				}

				goto found;
			}
		}	/* for (blkoff = 0; .... */
		/*
		 * Release the buffer holding the directory cluster just
		 * searched.
		 */
		brelse(bp, 0);
	}	/* for (frcn = 0; ; frcn++) */

notfound:
	/*
	 * We hold no disk buffers at this point.
	 */

	/*
	 * If we get here we didn't find the entry we were looking for. But
	 * that's ok if we are creating or renaming and are at the end of
	 * the pathname and the directory hasn't been removed.
	 */
#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): op %d, refcnt %ld, slotcount %d, slotoffset %d\n",
	    nameiop, dp->de_refcnt, slotcount, slotoffset);
#endif
	if ((nameiop == CREATE || nameiop == RENAME) &&
	    (flags & ISLASTCN) && dp->de_refcnt != 0) {
		/*
		 * Access for write is interpreted as allowing
		 * creation of files in the directory.
		 */
		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred);
		if (error)
			return (error);

		/*
		 * Fixup the slot description to point to the place where
		 * we might put the new DOS direntry (putting the Win95
		 * long name entries before that)
		 */
		if (!slotcount) {
			slotcount = 1;
			slotoffset = diroff;
		}
		if (wincnt > slotcount) {
			slotoffset +=
				sizeof(struct direntry) * (wincnt - slotcount);
		}

		/*
		 * Return an indication of where the new directory
		 * entry should be put.
		 */
		dp->de_fndoffset = slotoffset;
		dp->de_fndcnt = wincnt - 1;

		/*
		 * We return with the directory locked, so that
		 * the parameters we set up above will still be
		 * valid if we actually decide to do a direnter().
		 * We return ni_vp == NULL to indicate that the entry
		 * does not currently exist; we leave a pointer to
		 * the (locked) directory inode in ndp->ni_dvp.
		 *
		 * NB - if the directory is unlocked, then this
		 * information cannot be used.
		 */
		return (EJUSTRETURN);
	}

#if 0
	/*
	 * Insert name into cache (as non-existent) if appropriate.
	 *
	 * XXX Negative caching is broken for msdosfs because the name
	 * cache doesn't understand peculiarities such as case insensitivity
	 * and 8.3 filenames.  Hence, it may not invalidate all negative
	 * entries if a file with this name is later created.
	 * e.g. creating a file 'foo' won't invalidate a negative entry 
	 * for 'FOO'.
	 */
	if (nameiop != CREATE)
		cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
			    cnp->cn_flags);
#endif

	return (ENOENT);

found:
	/*
	 * NOTE:  We still have the buffer with matched directory entry at
	 * this point.
	 */
	isadir = dep->deAttributes & ATTR_DIRECTORY;
	scn = getushort(dep->deStartCluster);
	if (FAT32(pmp)) {
		scn |= getushort(dep->deHighClust) << 16;
		if (scn == pmp->pm_rootdirblk) {
			/*
			 * There should actually be 0 here.
			 * Just ignore the error.
			 */
			scn = MSDOSFSROOT;
		}
	}

	if (isadir) {
		cluster = scn;
		if (cluster == MSDOSFSROOT)
			blkoff = MSDOSFSROOT_OFS;
		else
			blkoff = 0;
	} else if (cluster == MSDOSFSROOT)
		blkoff = diroff;

	/*
	 * Now release buf to allow deget to read the entry again.
	 * Reserving it here and giving it to deget could result
	 * in a deadlock.
	 */
	brelse(bp, 0);

foundroot:
	/*
	 * If we entered at foundroot, then we are looking for the . or ..
	 * entry of the filesystems root directory.  isadir and scn were
	 * setup before jumping here.  And, bp is already null.
	 */
	if (FAT32(pmp) && scn == MSDOSFSROOT)
		scn = pmp->pm_rootdirblk;

	/*
	 * If deleting, and at end of pathname, return
	 * parameters which can be used to remove file.
	 * Lock the inode, being careful with ".".
	 */
	if (nameiop == DELETE && (flags & ISLASTCN)) {
		/*
		 * Don't allow deleting the root.
		 */
		if (blkoff == MSDOSFSROOT_OFS)
			return EINVAL;

		/*
		 * Write access to directory required to delete files.
		 */
		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred);
		if (error)
			return (error);

		/*
		 * Return pointer to current entry in dp->i_offset.
		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
		 */
		if (dp->de_StartCluster == scn && isadir) {	/* "." */
			vref(vdp);
			*vpp = vdp;
			return (0);
		}
		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
			return (error);
		*vpp = DETOV(tdp);
		VOP_UNLOCK(*vpp);
		return (0);
	}

	/*
	 * If rewriting (RENAME), return the inode and the
	 * information required to rewrite the present directory
	 * Must get inode of directory entry to verify it's a
	 * regular file, or empty directory.
	 */
	if (nameiop == RENAME && (flags & ISLASTCN)) {

		if (vdp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);

		if (blkoff == MSDOSFSROOT_OFS)
			return EINVAL;

		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred);
		if (error)
			return (error);

		/*
		 * Careful about locking second inode.
		 * This can only occur if the target is ".".
		 */
		if (dp->de_StartCluster == scn && isadir)
			return (EISDIR);

		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
			return (error);
		*vpp = DETOV(tdp);
		VOP_UNLOCK(*vpp);
		return (0);
	}

	/*
	 * Step through the translation in the name.  We do not `vput' the
	 * directory because we may need it again if a symbolic link
	 * is relative to the current directory.  Instead we save it
	 * unlocked as "pdp".  We must get the target inode before unlocking
	 * the directory to insure that the inode will not be removed
	 * before we get it.  We prevent deadlock by always fetching
	 * inodes from the root, moving down the directory tree. Thus
	 * when following backward pointers ".." we must unlock the
	 * parent directory before getting the requested directory.
	 * There is a potential race condition here if both the current
	 * and parent directories are removed before the VFS_VGET for the
	 * inode associated with ".." returns.  We hope that this occurs
	 * infrequently since we cannot avoid this race condition without
	 * implementing a sophisticated deadlock detection algorithm.
	 * Note also that this simple deadlock detection scheme will not
	 * work if the file system has any hard links other than ".."
	 * that point backwards in the directory structure.
	 */
	pdp = vdp;
	if (flags & ISDOTDOT) {
		VOP_UNLOCK(pdp);	/* race to get the inode */
		error = deget(pmp, cluster, blkoff, &tdp);
		vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
		if (error) {
			return error;
		}
		*vpp = DETOV(tdp);
	} else if (dp->de_StartCluster == scn && isadir) {
		vref(vdp);	/* we want ourself, ie "." */
		*vpp = vdp;
	} else {
		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
			return (error);
		*vpp = DETOV(tdp);
	}

	/*
	 * Insert name into cache if appropriate.
	 */
	cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags);

	if (*vpp != vdp)
		VOP_UNLOCK(*vpp);

	return 0;
}
Exemplo n.º 14
0
void check_file_length(uint16_t cluster, uint8_t *image_buf, struct bpb33* bpb)
{
    struct direntry *dirent;
    int d, i;
    dirent = (struct direntry*) cluster_to_addr(cluster, image_buf, bpb);
    int clust_size = bpb->bpbBytesPerSec * bpb->bpbSecPerClust;

    while (1) {
        for (d = 0; d < clust_size; d += sizeof(struct direntry)) {
            char name[9];
            char extension[4];
            uint32_t size;
            uint16_t file_cluster;
            name[8] = ' ';
            extension[3] = ' ';
            memcpy(name, &(dirent->deName[0]), 8);
            memcpy(extension, dirent->deExtension, 3);

            if (name[0] == SLOT_EMPTY)
                return;

            /* skip over deleted entries */
            if (((uint8_t)name[0]) == SLOT_DELETED)
                continue;

            /* names are space padded - remove the spaces */
            for (i = 8; i > 0; i--) {
                if (name[i] == ' ')
                    name[i] = '\0';
                else
                    break;
            }

            /* remove the spaces from extensions */
            for (i = 3; i > 0; i--) {
                if (extension[i] == ' ')
                    extension[i] = '\0';
                else
                    break;
            }

            /* don't print "." or ".." directories */
            if (strcmp(name, ".") == 0) {
                dirent++;
                continue;
            }
            if (strcmp(name, "..") == 0) {
                dirent++;
                continue;
            }

            if ((dirent->deAttributes & ATTR_VOLUME) != 0) {
                continue;
            } else if ((dirent->deAttributes & ATTR_DIRECTORY) != 0) {
                file_cluster = getushort(dirent->deStartCluster);
                check_file_length(file_cluster, image_buf, bpb);
            } else {
                size = getulong(dirent->deFileSize);
                file_cluster = getushort(dirent->deStartCluster);
                uint16_t fat_size_clusters = get_file_length(file_cluster, image_buf, bpb);

                uint32_t size_clusters = (size + (clust_size - 1)) / clust_size;
                uint32_t fat_size = fat_size_clusters * clust_size;
                if (size_clusters != fat_size_clusters) {
                    printf("%s.%s %u %u\n", name, extension, size, fat_size);

                    uint16_t begin_cluster = file_cluster + size_clusters - 1;
                    uint16_t end_cluster = file_cluster + fat_size_clusters;
                    free_clusters(begin_cluster, end_cluster, image_buf, bpb);
                }
            }

            dirent++;
        }

        /* We've reached the end of the cluster for this directory. Where's the next cluster? */
        if (cluster == 0) {
            // root dir is special
            dirent++;
        } else {
            cluster = get_fat_entry(cluster, image_buf, bpb);
            dirent = (struct direntry*) cluster_to_addr(cluster, image_buf, bpb);
        }
    }
}
Exemplo n.º 15
0
static int
mountmsdosfs(struct vnode *devvp, struct mount *mp)
{
	struct msdosfsmount *pmp;
	struct buf *bp;
	struct cdev *dev;
	union bootsector *bsp;
	struct byte_bpb33 *b33;
	struct byte_bpb50 *b50;
	struct byte_bpb710 *b710;
	u_int8_t SecPerClust;
	u_long clusters;
	int ronly, error;
	struct g_consumer *cp;
	struct bufobj *bo;

	bp = NULL;		/* This and pmp both used in error_exit. */
	pmp = NULL;
	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;

	dev = devvp->v_rdev;
	dev_ref(dev);
	DROP_GIANT();
	g_topology_lock();
	error = g_vfs_open(devvp, &cp, "msdosfs", ronly ? 0 : 1);
	g_topology_unlock();
	PICKUP_GIANT();
	VOP_UNLOCK(devvp, 0);
	if (error)
		goto error_exit;

	bo = &devvp->v_bufobj;

	/*
	 * Read the boot sector of the filesystem, and then check the
	 * boot signature.  If not a dos boot sector then error out.
	 *
	 * NOTE: 8192 is a magic size that works for ffs.
	 */
	error = bread(devvp, 0, 8192, NOCRED, &bp);
	if (error)
		goto error_exit;
	bp->b_flags |= B_AGE;
	bsp = (union bootsector *)bp->b_data;
	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
	b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;

#ifndef MSDOSFS_NOCHECKSIG
	if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
	    || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
		error = EINVAL;
		goto error_exit;
	}
#endif

	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
	pmp->pm_mountp = mp;
	pmp->pm_cp = cp;
	pmp->pm_bo = bo;

	lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0);

	/*
	 * Initialize ownerships and permissions, since nothing else will
	 * initialize them iff we are mounting root.
	 */
	pmp->pm_uid = UID_ROOT;
	pmp->pm_gid = GID_WHEEL;
	pmp->pm_mask = pmp->pm_dirmask = S_IXUSR | S_IXGRP | S_IXOTH |
	    S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR;

	/*
	 * Experimental support for large MS-DOS filesystems.
	 * WARNING: This uses at least 32 bytes of kernel memory (which is not
	 * reclaimed until the FS is unmounted) for each file on disk to map
	 * between the 32-bit inode numbers used by VFS and the 64-bit
	 * pseudo-inode numbers used internally by msdosfs. This is only
	 * safe to use in certain controlled situations (e.g. read-only FS
	 * with less than 1 million files).
	 * Since the mappings do not persist across unmounts (or reboots), these
	 * filesystems are not suitable for exporting through NFS, or any other
	 * application that requires fixed inode numbers.
	 */
	vfs_flagopt(mp->mnt_optnew, "large", &pmp->pm_flags, MSDOSFS_LARGEFS);

	/*
	 * Compute several useful quantities from the bpb in the
	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
	 * the fields that are different between dos 5 and dos 3.3.
	 */
	SecPerClust = b50->bpbSecPerClust;
	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
	if (pmp->pm_BytesPerSec < DEV_BSIZE) {
		error = EINVAL;
		goto error_exit;
	}
	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
	pmp->pm_FATs = b50->bpbFATs;
	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
	pmp->pm_Sectors = getushort(b50->bpbSectors);
	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
	pmp->pm_Heads = getushort(b50->bpbHeads);
	pmp->pm_Media = b50->bpbMedia;

	/* calculate the ratio of sector size to DEV_BSIZE */
	pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;

	/*
	 * We don't check pm_Heads nor pm_SecPerTrack, because
	 * these may not be set for EFI file systems. We don't
	 * use these anyway, so we're unaffected if they are
	 * invalid.
	 */
	if (!pmp->pm_BytesPerSec || !SecPerClust) {
		error = EINVAL;
		goto error_exit;
	}

	if (pmp->pm_Sectors == 0) {
		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
	} else {
		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
		pmp->pm_HugeSectors = pmp->pm_Sectors;
	}
	if (!(pmp->pm_flags & MSDOSFS_LARGEFS)) {
		if (pmp->pm_HugeSectors > 0xffffffff /
		    (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1) {
			/*
			 * We cannot deal currently with this size of disk
			 * due to fileid limitations (see msdosfs_getattr and
			 * msdosfs_readdir)
			 */
			error = EINVAL;
			vfs_mount_error(mp,
			    "Disk too big, try '-o large' mount option");
			goto error_exit;
		}
	}

	if (pmp->pm_RootDirEnts == 0) {
		if (pmp->pm_FATsecs
		    || getushort(b710->bpbFSVers)) {
			error = EINVAL;
#ifdef MSDOSFS_DEBUG
			printf("mountmsdosfs(): bad FAT32 filesystem\n");
#endif
			goto error_exit;
		}
		pmp->pm_fatmask = FAT32_MASK;
		pmp->pm_fatmult = 4;
		pmp->pm_fatdiv = 1;
		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
		if (getushort(b710->bpbExtFlags) & FATMIRROR)
			pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
		else
			pmp->pm_flags |= MSDOSFS_FATMIRROR;
	} else
		pmp->pm_flags |= MSDOSFS_FATMIRROR;

	/*
	 * Check a few values (could do some more):
	 * - logical sector size: power of 2, >= block size
	 * - sectors per cluster: power of 2, >= 1
	 * - number of sectors:   >= 1, <= size of partition
	 * - number of FAT sectors: >= 1
	 */
	if ( (SecPerClust == 0)
	  || (SecPerClust & (SecPerClust - 1))
	  || (pmp->pm_BytesPerSec < DEV_BSIZE)
	  || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
	  || (pmp->pm_HugeSectors == 0)
	  || (pmp->pm_FATsecs == 0)
	  || (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE)
	) {
		error = EINVAL;
		goto error_exit;
	}

	pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
	pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;	/* XXX not used? */
	pmp->pm_FATsecs     *= pmp->pm_BlkPerSec;
	SecPerClust         *= pmp->pm_BlkPerSec;

	pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;

	if (FAT32(pmp)) {
		pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
		pmp->pm_firstcluster = pmp->pm_fatblk
			+ (pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
	} else {
		pmp->pm_rootdirblk = pmp->pm_fatblk +
			(pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_rootdirsize = howmany(pmp->pm_RootDirEnts *
			sizeof(struct direntry), DEV_BSIZE); /* in blocks */
		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
	}

	pmp->pm_maxcluster = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
	    SecPerClust + 1;
	pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;	/* XXX not used? */

	if (pmp->pm_fatmask == 0) {
		if (pmp->pm_maxcluster
		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
			/*
			 * This will usually be a floppy disk. This size makes
			 * sure that one fat entry will not be split across
			 * multiple blocks.
			 */
			pmp->pm_fatmask = FAT12_MASK;
			pmp->pm_fatmult = 3;
			pmp->pm_fatdiv = 2;
		} else {
			pmp->pm_fatmask = FAT16_MASK;
			pmp->pm_fatmult = 2;
			pmp->pm_fatdiv = 1;
		}
	}

	clusters = (pmp->pm_fatsize / pmp->pm_fatmult) * pmp->pm_fatdiv;
	if (pmp->pm_maxcluster >= clusters) {
#ifdef MSDOSFS_DEBUG
		printf("Warning: number of clusters (%ld) exceeds FAT "
		    "capacity (%ld)\n", pmp->pm_maxcluster + 1, clusters);
#endif
		pmp->pm_maxcluster = clusters - 1;
	}

	if (FAT12(pmp))
		pmp->pm_fatblocksize = 3 * 512;
	else
		pmp->pm_fatblocksize = PAGE_SIZE;
	pmp->pm_fatblocksize = roundup(pmp->pm_fatblocksize,
	    pmp->pm_BytesPerSec);
	pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
	pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;

	/*
	 * Compute mask and shift value for isolating cluster relative byte
	 * offsets and cluster numbers from a file offset.
	 */
	pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;

	/*
	 * Check for valid cluster size
	 * must be a power of 2
	 */
	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
		error = EINVAL;
		goto error_exit;
	}

	/*
	 * Release the bootsector buffer.
	 */
	brelse(bp);
	bp = NULL;

	/*
	 * Check the fsinfo sector if we have one.  Silently fix up our
	 * in-core copy of fp->fsinxtfree if it is unknown (0xffffffff)
	 * or too large.  Ignore fp->fsinfree for now, since we need to
	 * read the entire FAT anyway to fill the inuse map.
	 */
	if (pmp->pm_fsinfo) {
		struct fsinfo *fp;

		if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec,
		    NOCRED, &bp)) != 0)
			goto error_exit;
		fp = (struct fsinfo *)bp->b_data;
		if (!bcmp(fp->fsisig1, "RRaA", 4)
		    && !bcmp(fp->fsisig2, "rrAa", 4)
		    && !bcmp(fp->fsisig3, "\0\0\125\252", 4)) {
			pmp->pm_nxtfree = getulong(fp->fsinxtfree);
			if (pmp->pm_nxtfree > pmp->pm_maxcluster)
				pmp->pm_nxtfree = CLUST_FIRST;
		} else
			pmp->pm_fsinfo = 0;
		brelse(bp);
		bp = NULL;
	}

	/*
	 * Finish initializing pmp->pm_nxtfree (just in case the first few
	 * sectors aren't properly reserved in the FAT).  This completes
	 * the fixup for fp->fsinxtfree, and fixes up the zero-initialized
	 * value if there is no fsinfo.  We will use pmp->pm_nxtfree
	 * internally even if there is no fsinfo.
	 */
	if (pmp->pm_nxtfree < CLUST_FIRST)
		pmp->pm_nxtfree = CLUST_FIRST;

	/*
	 * Allocate memory for the bitmap of allocated clusters, and then
	 * fill it in.
	 */
	pmp->pm_inusemap = malloc(howmany(pmp->pm_maxcluster + 1, N_INUSEBITS)
				  * sizeof(*pmp->pm_inusemap),
				  M_MSDOSFSFAT, M_WAITOK);

	/*
	 * fillinusemap() needs pm_devvp.
	 */
	pmp->pm_devvp = devvp;
	pmp->pm_dev = dev;

	/*
	 * Have the inuse map filled in.
	 */
	MSDOSFS_LOCK_MP(pmp);
	error = fillinusemap(pmp);
	MSDOSFS_UNLOCK_MP(pmp);
	if (error != 0)
		goto error_exit;

	/*
	 * If they want fat updates to be synchronous then let them suffer
	 * the performance degradation in exchange for the on disk copy of
	 * the fat being correct just about all the time.  I suppose this
	 * would be a good thing to turn on if the kernel is still flakey.
	 */
	if (mp->mnt_flag & MNT_SYNCHRONOUS)
		pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;

	/*
	 * Finish up.
	 */
	if (ronly)
		pmp->pm_flags |= MSDOSFSMNT_RONLY;
	else {
		if ((error = markvoldirty(pmp, 1)) != 0) {
			(void)markvoldirty(pmp, 0);
			goto error_exit;
		}
		pmp->pm_fmod = 1;
	}
	mp->mnt_data =  pmp;
	mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
	MNT_ILOCK(mp);
	mp->mnt_flag |= MNT_LOCAL;
	mp->mnt_kern_flag |= MNTK_USES_BCACHE;
	MNT_IUNLOCK(mp);

	if (pmp->pm_flags & MSDOSFS_LARGEFS)
		msdosfs_fileno_init(mp);

	return 0;

error_exit:
	if (bp)
		brelse(bp);
	if (cp != NULL) {
		DROP_GIANT();
		g_topology_lock();
		g_vfs_close(cp);
		g_topology_unlock();
		PICKUP_GIANT();
	}
	if (pmp) {
		lockdestroy(&pmp->pm_fatlock);
		if (pmp->pm_inusemap)
			free(pmp->pm_inusemap, M_MSDOSFSFAT);
		free(pmp, M_MSDOSFSMNT);
		mp->mnt_data = NULL;
	}
	dev_rel(dev);
	return (error);
}
Exemplo n.º 16
0
static void parsecvar(struct ttfinfo *info, FILE *ttf) {
    struct ttf_table *cvt;
    int tuplecount;
    uint32 offset;
    int *sharedpoints=NULL;
    int i;
    int warned = false;

    for ( cvt = info->tabs; cvt!=NULL && cvt->tag!=CHR('c','v','t',' '); cvt=cvt->next );
    if ( cvt==NULL )
return;

    fseek(ttf,info->cvar_start,SEEK_SET);
    if ( getlong(ttf)!=0x00010000 ) {	/* I only understand version 1 */
	/* I think I can live without cvt variations... */
	/* So I shan't free the structure */
return;
    }

    tuplecount = getushort(ttf);
    offset = info->cvar_start+getushort(ttf);
    /* The documentation implies there are flags packed into the tuplecount */
    /*  but John Jenkins tells me that shared points don't apply to cvar */
    /*  Might as well parse it just in case */
    if ( tuplecount&0x8000 ) {
	uint32 here = ftell(ttf);
	fseek(ttf,offset,SEEK_SET);
	sharedpoints = readpackedpoints(ttf);
	offset = ftell(ttf);
	fseek(ttf,here,SEEK_SET);
    }
    for ( i=0; i<(tuplecount&0xfff); ++i ) {
	int tupleDataSize, tupleIndex;
	tupleDataSize = getushort(ttf);
	tupleIndex = getushort(ttf);
	/* there is no provision here for a global tuple coordinate section */
	/*  so John says there are no tuple indeces. Just embedded tuples */
	if ( tupleIndex&0x4000 ) {
	    if ( !warned )
		LogError( _("Warning: 'cvar' contains intermediate tuple data.\n FontForge doesn't support this.\n") );
	    warned = true;
	    if ( tupleIndex&0x8000 )
		fseek(ttf,2*info->variations->axis_count,SEEK_CUR);
	    if ( tupleIndex&0x4000 )
		fseek(ttf,4*info->variations->axis_count,SEEK_CUR);
	} else {
	    int *localpoints=NULL;
	    uint32 here;
	    int j,k,ti;
	    ti = tupleIndex&0xfff;
	    if ( tupleIndex&0x8000 ) {
		real *coords = malloc(info->variations->axis_count*sizeof(real));
		for ( j=0; j<info->variations->axis_count; ++j )
		    coords[j] = ((int16) getushort(ttf))/16384.0;
		for ( k=0 ; k<info->variations->tuple_count; ++k ) {
		    for ( j=0; j<info->variations->axis_count; ++j )
			if ( coords[j]!=info->variations->tuples[k].coords[j] )
		    break;
		    if ( j==info->variations->axis_count )
		break;
		}
                free(coords);
		ti = -1;
		if ( k!=info->variations->tuple_count )
		    ti = k;
	    }
	    if ( ti!=-1 ) {
		here = ftell(ttf);
		fseek(ttf,offset,SEEK_SET);
		if ( tupleIndex&0x2000 )
		    localpoints = readpackedpoints(ttf);
		VaryCvts(info,ti,(tupleIndex&0x2000)?localpoints:sharedpoints,ttf,cvt);
		free(localpoints);
		fseek(ttf,here,SEEK_SET);
	    }
	}
	offset += tupleDataSize;
    }
    free(sharedpoints);
}
Exemplo n.º 17
0
/*
 * When we search a directory the blocks containing directory entries are
 * read and examined.  The directory entries contain information that would
 * normally be in the inode of a unix filesystem.  This means that some of
 * a directory's contents may also be in memory resident denodes (sort of
 * an inode).  This can cause problems if we are searching while some other
 * process is modifying a directory.  To prevent one process from accessing
 * incompletely modified directory information we depend upon being the
 * sole owner of a directory block.  bread/brelse provide this service.
 * This being the case, when a process modifies a directory it must first
 * acquire the disk block that contains the directory entry to be modified.
 * Then update the disk block and the denode, and then write the disk block
 * out to disk.  This way disk blocks containing directory entries and in
 * memory denode's will be in synch.
 */
static int
msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
    struct componentname *cnp, u_int64_t *dd_inum)
{
	struct mbnambuf nb;
	daddr_t bn;
	int error;
	int slotcount;
	int slotoffset = 0;
	int frcn;
	u_long cluster;
	int blkoff;
	int diroff;
	int blsize;
	int isadir;		/* ~0 if found direntry is a directory	 */
	u_long scn;		/* starting cluster number		 */
	struct vnode *pdp;
	struct denode *dp;
	struct denode *tdp;
	struct msdosfsmount *pmp;
	struct buf *bp = 0;
	struct direntry *dep = NULL;
	u_char dosfilename[12];
	int flags = cnp->cn_flags;
	int nameiop = cnp->cn_nameiop;
	int unlen;
	u_int64_t inode1;

	int wincnt = 1;
	int chksum = -1, chksum_ok;
	int olddos = 1;

#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
#endif
	dp = VTODE(vdp);
	pmp = dp->de_pmp;
#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
	    vdp, dp, dp->de_Attributes);
#endif

 restart:
	if (vpp != NULL)
		*vpp = NULL;
	/*
	 * If they are going after the . or .. entry in the root directory,
	 * they won't find it.  DOS filesystems don't have them in the root
	 * directory.  So, we fake it. deget() is in on this scam too.
	 */
	if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' &&
	    (cnp->cn_namelen == 1 ||
		(cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
		isadir = ATTR_DIRECTORY;
		scn = MSDOSFSROOT;
#ifdef MSDOSFS_DEBUG
		printf("msdosfs_lookup(): looking for . or .. in root directory\n");
#endif
		cluster = MSDOSFSROOT;
		blkoff = MSDOSFSROOT_OFS;
		goto foundroot;
	}

	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
	    cnp->cn_namelen, 0, pmp)) {
	case 0:
		return (EINVAL);
	case 1:
		break;
	case 2:
		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
		    cnp->cn_namelen, pmp) + 1;
		break;
	case 3:
		olddos = 0;
		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
		    cnp->cn_namelen, pmp) + 1;
		break;
	}
	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) {
		wincnt = 1;
		olddos = 1;
	}
	unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen);

	/*
	 * Suppress search for slots unless creating
	 * file and at end of pathname, in which case
	 * we watch for a place to put the new file in
	 * case it doesn't already exist.
	 */
	slotcount = wincnt;
	if ((nameiop == CREATE || nameiop == RENAME) &&
	    (flags & ISLASTCN))
		slotcount = 0;

#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): dos version of filename %s, length %ld\n",
	    dosfilename, cnp->cn_namelen);
#endif
	/*
	 * Search the directory pointed at by vdp for the name pointed at
	 * by cnp->cn_nameptr.
	 */
	tdp = NULL;
	mbnambuf_init(&nb);
	/*
	 * The outer loop ranges over the clusters that make up the
	 * directory.  Note that the root directory is different from all
	 * other directories.  It has a fixed number of blocks that are not
	 * part of the pool of allocatable clusters.  So, we treat it a
	 * little differently. The root directory starts at "cluster" 0.
	 */
	diroff = 0;
	for (frcn = 0;; frcn++) {
		error = pcbmap(dp, frcn, &bn, &cluster, &blsize);
		if (error) {
			if (error == E2BIG)
				break;
			return (error);
		}
		error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
		if (error) {
			brelse(bp);
			return (error);
		}
		for (blkoff = 0; blkoff < blsize;
		     blkoff += sizeof(struct direntry),
		     diroff += sizeof(struct direntry)) {
			dep = (struct direntry *)(bp->b_data + blkoff);
			/*
			 * If the slot is empty and we are still looking
			 * for an empty then remember this one.  If the
			 * slot is not empty then check to see if it
			 * matches what we are looking for.  If the slot
			 * has never been filled with anything, then the
			 * remainder of the directory has never been used,
			 * so there is no point in searching it.
			 */
			if (dep->deName[0] == SLOT_EMPTY ||
			    dep->deName[0] == SLOT_DELETED) {
				/*
				 * Drop memory of previous long matches
				 */
				chksum = -1;
				mbnambuf_init(&nb);

				if (slotcount < wincnt) {
					slotcount++;
					slotoffset = diroff;
				}
				if (dep->deName[0] == SLOT_EMPTY) {
					brelse(bp);
					goto notfound;
				}
			} else {
				/*
				 * If there wasn't enough space for our winentries,
				 * forget about the empty space
				 */
				if (slotcount < wincnt)
					slotcount = 0;

				/*
				 * Check for Win95 long filename entry
				 */
				if (dep->deAttributes == ATTR_WIN95) {
					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
						continue;

					chksum = win2unixfn(&nb,
					    (struct winentry *)dep, chksum,
					    pmp);
					continue;
				}

				chksum = winChkName(&nb,
				    (const u_char *)cnp->cn_nameptr, unlen,
				    chksum, pmp);
				if (chksum == -2) {
					chksum = -1;
					continue;
				}

				/*
				 * Ignore volume labels (anywhere, not just
				 * the root directory).
				 */
				if (dep->deAttributes & ATTR_VOLUME) {
					chksum = -1;
					continue;
				}

				/*
				 * Check for a checksum or name match
				 */
				chksum_ok = (chksum == winChksum(dep->deName));
				if (!chksum_ok
				    && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
					chksum = -1;
					continue;
				}
#ifdef MSDOSFS_DEBUG
				printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
				    blkoff, diroff);
#endif
				/*
				 * Remember where this directory
				 * entry came from for whoever did
				 * this lookup.
				 */
				dp->de_fndoffset = diroff;
				if (chksum_ok && nameiop == RENAME) {
					/*
					 * Target had correct long name
					 * directory entries, reuse them
					 * as needed.
					 */
					dp->de_fndcnt = wincnt - 1;
				} else {
					/*
					 * Long name directory entries
					 * not present or corrupt, can only
					 * reuse dos directory entry.
					 */
					dp->de_fndcnt = 0;
				}

				goto found;
			}
		}	/* for (blkoff = 0; .... */
		/*
		 * Release the buffer holding the directory cluster just
		 * searched.
		 */
		brelse(bp);
	}	/* for (frcn = 0; ; frcn++) */

notfound:
	/*
	 * We hold no disk buffers at this point.
	 */

	/*
	 * Fixup the slot description to point to the place where
	 * we might put the new DOS direntry (putting the Win95
	 * long name entries before that)
	 */
	if (!slotcount) {
		slotcount = 1;
		slotoffset = diroff;
	}
	if (wincnt > slotcount)
		slotoffset += sizeof(struct direntry) * (wincnt - slotcount);

	/*
	 * If we get here we didn't find the entry we were looking for. But
	 * that's ok if we are creating or renaming and are at the end of
	 * the pathname and the directory hasn't been removed.
	 */
#ifdef MSDOSFS_DEBUG
	printf("msdosfs_lookup(): op %d, refcnt %ld\n",
	    nameiop, dp->de_refcnt);
	printf("               slotcount %d, slotoffset %d\n",
	       slotcount, slotoffset);
#endif
	if ((nameiop == CREATE || nameiop == RENAME) &&
	    (flags & ISLASTCN) && dp->de_refcnt != 0) {
		/*
		 * Access for write is interpreted as allowing
		 * creation of files in the directory.
		 */
		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread);
		if (error)
			return (error);
		/*
		 * Return an indication of where the new directory
		 * entry should be put.
		 */
		dp->de_fndoffset = slotoffset;
		dp->de_fndcnt = wincnt - 1;

		/*
		 * We return with the directory locked, so that
		 * the parameters we set up above will still be
		 * valid if we actually decide to do a direnter().
		 * We return ni_vp == NULL to indicate that the entry
		 * does not currently exist; we leave a pointer to
		 * the (locked) directory inode in ndp->ni_dvp.
		 * The pathname buffer is saved so that the name
		 * can be obtained later.
		 *
		 * NB - if the directory is unlocked, then this
		 * information cannot be used.
		 */
		cnp->cn_flags |= SAVENAME;
		return (EJUSTRETURN);
	}
#if 0
	/*
	 * Insert name into cache (as non-existent) if appropriate.
	 *
	 * XXX Negative caching is broken for msdosfs because the name
	 * cache doesn't understand peculiarities such as case insensitivity
	 * and 8.3 filenames.  Hence, it may not invalidate all negative
	 * entries if a file with this name is later created.
	 */
	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
		cache_enter(vdp, *vpp, cnp);
#endif
	return (ENOENT);

found:
	/*
	 * NOTE:  We still have the buffer with matched directory entry at
	 * this point.
	 */
	isadir = dep->deAttributes & ATTR_DIRECTORY;
	scn = getushort(dep->deStartCluster);
	if (FAT32(pmp)) {
		scn |= getushort(dep->deHighClust) << 16;
		if (scn == pmp->pm_rootdirblk) {
			/*
			 * There should actually be 0 here.
			 * Just ignore the error.
			 */
			scn = MSDOSFSROOT;
		}
	}

	if (isadir) {
		cluster = scn;
		if (cluster == MSDOSFSROOT)
			blkoff = MSDOSFSROOT_OFS;
		else
			blkoff = 0;
	} else if (cluster == MSDOSFSROOT)
		blkoff = diroff;

	/*
	 * Now release buf to allow deget to read the entry again.
	 * Reserving it here and giving it to deget could result
	 * in a deadlock.
	 */
	brelse(bp);
	bp = 0;
	
foundroot:
	/*
	 * If we entered at foundroot, then we are looking for the . or ..
	 * entry of the filesystems root directory.  isadir and scn were
	 * setup before jumping here.  And, bp is already null.
	 */
	if (FAT32(pmp) && scn == MSDOSFSROOT)
		scn = pmp->pm_rootdirblk;

	if (dd_inum != NULL) {
		*dd_inum = (uint64_t)pmp->pm_bpcluster * scn + blkoff;
		return (0);
	}

	/*
	 * If deleting, and at end of pathname, return
	 * parameters which can be used to remove file.
	 */
	if (nameiop == DELETE && (flags & ISLASTCN)) {
		/*
		 * Don't allow deleting the root.
		 */
		if (blkoff == MSDOSFSROOT_OFS)
			return (EBUSY);

		/*
		 * Write access to directory required to delete files.
		 */
		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread);
		if (error)
			return (error);

		/*
		 * Return pointer to current entry in dp->i_offset.
		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
		 */
		if (dp->de_StartCluster == scn && isadir) {	/* "." */
			VREF(vdp);
			*vpp = vdp;
			return (0);
		}
		error = deget(pmp, cluster, blkoff, &tdp);
		if (error)
			return (error);
		*vpp = DETOV(tdp);
		return (0);
	}

	/*
	 * If rewriting (RENAME), return the inode and the
	 * information required to rewrite the present directory
	 * Must get inode of directory entry to verify it's a
	 * regular file, or empty directory.
	 */
	if (nameiop == RENAME && (flags & ISLASTCN)) {
		if (blkoff == MSDOSFSROOT_OFS)
			return (EBUSY);

		error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_thread);
		if (error)
			return (error);

		/*
		 * Careful about locking second inode.
		 * This can only occur if the target is ".".
		 */
		if (dp->de_StartCluster == scn && isadir)
			return (EISDIR);

		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
			return (error);
		*vpp = DETOV(tdp);
		cnp->cn_flags |= SAVENAME;
		return (0);
	}

	/*
	 * Step through the translation in the name.  We do not `vput' the
	 * directory because we may need it again if a symbolic link
	 * is relative to the current directory.  Instead we save it
	 * unlocked as "pdp".  We must get the target inode before unlocking
	 * the directory to insure that the inode will not be removed
	 * before we get it.  We prevent deadlock by always fetching
	 * inodes from the root, moving down the directory tree. Thus
	 * when following backward pointers ".." we must unlock the
	 * parent directory before getting the requested directory.
	 */
	pdp = vdp;
	if (flags & ISDOTDOT) {
		error = msdosfs_deget_dotdot(pdp, cluster, blkoff, vpp);
		if (error) {
			*vpp = NULL;
			return (error);
		}
		/*
		 * Recheck that ".." still points to the inode we
		 * looked up before pdp lock was dropped.
		 */
		error = msdosfs_lookup_(pdp, NULL, cnp, &inode1);
		if (error) {
			vput(*vpp);
			*vpp = NULL;
			return (error);
		}
		if (VTODE(*vpp)->de_inode != inode1) {
			vput(*vpp);
			goto restart;
		}
	} else if (dp->de_StartCluster == scn && isadir) {
		VREF(vdp);	/* we want ourself, ie "." */
		*vpp = vdp;
	} else {
		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
			return (error);
		*vpp = DETOV(tdp);
	}

	/*
	 * Insert name into cache if appropriate.
	 */
	if (cnp->cn_flags & MAKEENTRY)
		cache_enter(vdp, *vpp, cnp);
	return (0);
}
Exemplo n.º 18
0
static void IkarusReadChar(SplineChar *sc,FILE *file) {
    int n, i, j, number, following, units, ncontours, ptmax;
    DBounds bb;
    int32 base;
    struct contour {
	int32 offset;
	int dir, nest, col, npts;
    } *contours;
    BasePoint *bps;
    uint8 *ptype;
    int x,y;

    /* record len of char = */ getushort(file);
    /* word len of char = */ getushort(file);

    n = getushort(file);
    number = getushort(file);
    IkarusNameFromURWNumber(sc,number);
    following = getushort(file);
    if ( following!=0 )
	LogError( _("This character (gid=%d) has a following part (%d). I'm not sure what that means, please send me ([email protected]) a copy of this font so I can test with it.\n"),
		sc->orig_pos, following );
    for ( i=3; i<n ; ++i )
	getushort(file);	/* Just in case the name section is bigger now */

    n = getushort(file);
    /* sort (leter,logo,line graphic,frame etc.) = */ getushort(file);
    /* num points = */ getushort(file);
    sc->width = getushort(file);
    /* lsb = */ getushort(file);
    /* xmax-xmin = */ getushort(file);
    /* rsb = */ getushort(file);
    bb.minx = (short) getushort(file);
    bb.maxx = (short) getushort(file);
    bb.miny = (short) getushort(file);
    bb.maxy = (short) getushort(file);
    for ( i=12 ; i<n; ++i )
	getushort(file);

    units = getushort(file);
    if ( units!=1 )
	sc->width *= units;

    n = getushort(file)*2048;
    n += getushort(file);		/* Length of contour section in words */
    ncontours = (n-2)/6;
    contours = malloc(ncontours*sizeof(struct contour));
    ptmax = 0;
    for ( i=0; i<ncontours; ++i ) {
	contours[i].offset = getushort(file)*4096;
	contours[i].offset += 2*getushort(file)-2;
	contours[i].dir = getushort(file);
	contours[i].nest = getushort(file);
	contours[i].col = getushort(file);
	contours[i].npts = getushort(file);
	if ( contours[i].npts > ptmax )
	    ptmax = contours[i].npts;
    }
    bps = malloc(ptmax*sizeof(BasePoint));
    ptype = malloc(ptmax*sizeof(uint8));

    base = ftell(file);
    /* 2 words here giving length (in records/words) of image data */

    for ( i=0; i<ncontours; ++i ) {
	fseek(file,base+contours[i].offset,SEEK_SET);
	for ( j=0; j<contours[i].npts; ++j ) {
	    x = (short) getushort(file);
	    y = (short) getushort(file);
	    if ( x<0 && y>0 )
		ptype[j] = -1;		/* Start point */
	    else if ( x<0 /* && y<0 */)
		ptype[j] = pt_corner;
	    else if ( /* x>0 && */ y>0 )
		ptype[j] = pt_curve;
	    else /* if ( x>0 && y<0 ) */
		ptype[j] = pt_tangent;
	    if ( x<0 ) x=-x;
	    if ( y<0 ) y=-y;
	    x += bb.minx-1;
	    y += bb.miny-1;
	    bps[j].x = units*x; bps[j].y = units*y;
	}
	IkarusAddContour(sc,contours[i].npts,bps,ptype,contours[i].nest);
    }

    free(contours);
    free(bps);
    free(ptype);
}
Exemplo n.º 19
0
/*
 * When we search a directory the blocks containing directory entries are
 * read and examined.  The directory entries contain information that would
 * normally be in the inode of a unix filesystem.  This means that some of
 * a directory's contents may also be in memory resident denodes (sort of
 * an inode).  This can cause problems if we are searching while some other
 * process is modifying a directory.  To prevent one process from accessing
 * incompletely modified directory information we depend upon being the
 * sole owner of a directory block.  bread/brelse provide this service.
 * This being the case, when a process modifies a directory it must first
 * acquire the disk block that contains the directory entry to be modified.
 * Then update the disk block and the denode, and then write the disk block
 * out to disk.  This way disk blocks containing directory entries and in
 * memory denode's will be in synch.
 *
 * msdosfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
 *		  struct componentname *a_cnp)
 */
int
msdosfs_lookup(struct vop_old_lookup_args *ap)
{
	struct mbnambuf nb;
	struct vnode *vdp = ap->a_dvp;
	struct vnode **vpp = ap->a_vpp;
	struct componentname *cnp = ap->a_cnp;
	daddr_t bn;
	int error;
	int lockparent;
	int wantparent;
	int slotcount;
	int slotoffset = 0;
	int frcn;
	u_long cluster;
	int blkoff;
	int diroff;
	int blsize;
	int isadir;		/* ~0 if found direntry is a directory	 */
	u_long scn;		/* starting cluster number		 */
	struct vnode *pdp;
	struct denode *dp;
	struct denode *tdp;
	struct msdosfsmount *pmp;
	struct buf *bp = NULL;
	struct direntry *dep = NULL;
	u_char dosfilename[12];
	int flags = cnp->cn_flags;
	int nameiop = cnp->cn_nameiop;
	int unlen;

	int wincnt = 1;
	int chksum = -1;
	int olddos = 1;
	cnp->cn_flags &= ~CNP_PDIRUNLOCK;

#ifdef MSDOSFS_DEBUG
	kprintf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
#endif
	dp = VTODE(vdp);
	pmp = dp->de_pmp;
	*vpp = NULL;
	lockparent = flags & CNP_LOCKPARENT;
	wantparent = flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
#ifdef MSDOSFS_DEBUG
	kprintf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
	    vdp, dp, dp->de_Attributes);
#endif

	/*
	 * If they are going after the . or .. entry in the root directory,
	 * they won't find it.  DOS filesystems don't have them in the root
	 * directory.  So, we fake it. deget() is in on this scam too.
	 */
	if ((vdp->v_flag & VROOT) && cnp->cn_nameptr[0] == '.' &&
	    (cnp->cn_namelen == 1 ||
		(cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
		isadir = ATTR_DIRECTORY;
		scn = MSDOSFSROOT;
#ifdef MSDOSFS_DEBUG
		kprintf("msdosfs_lookup(): looking for . or .. in root directory\n");
#endif
		cluster = MSDOSFSROOT;
		blkoff = MSDOSFSROOT_OFS;
		goto foundroot;
	}
	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
	    cnp->cn_namelen, 0, pmp)) {
	case 0:
		return (EINVAL);
	case 1:
		break;
	case 2:
		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
		    cnp->cn_namelen, pmp) + 1;
		break;
	case 3:
		olddos = 0;
		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
		    cnp->cn_namelen, pmp) + 1;
		break;
	}
	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) {
		wincnt = 1;
		olddos = 1;
	}
	unlen = winLenFixup(cnp->cn_nameptr, cnp->cn_namelen);

	/*
	 * Suppress search for slots unless creating
	 * file and at end of pathname, in which case
	 * we watch for a place to put the new file in
	 * case it doesn't already exist.
	 */
	slotcount = wincnt;
	if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)
		slotcount = 0;

#ifdef MSDOSFS_DEBUG
	kprintf("msdosfs_lookup(): dos version of filename %s, length %ld\n",
	    dosfilename, cnp->cn_namelen);
#endif
	/*
	 * Search the directory pointed at by vdp for the name pointed at
	 * by cnp->cn_nameptr.
	 */
	tdp = NULL;
	mbnambuf_init(&nb);
	/*
	 * The outer loop ranges over the clusters that make up the
	 * directory.  Note that the root directory is different from all
	 * other directories.  It has a fixed number of blocks that are not
	 * part of the pool of allocatable clusters.  So, we treat it a
	 * little differently. The root directory starts at "cluster" 0.
	 */
	diroff = 0;
	for (frcn = 0;; frcn++) {
		error = pcbmap(dp, frcn, &bn, &cluster, &blsize);
		if (error) {
			if (error == E2BIG)
				break;
			return (error);
		}
		error = bread(pmp->pm_devvp, de_bntodoff(pmp, bn), blsize, &bp);
		if (error) {
			brelse(bp);
			return (error);
		}
		for (blkoff = 0; blkoff < blsize;
		     blkoff += sizeof(struct direntry),
		     diroff += sizeof(struct direntry)) {
			dep = (struct direntry *)(bp->b_data + blkoff);
			/*
			 * If the slot is empty and we are still looking
			 * for an empty then remember this one.  If the
			 * slot is not empty then check to see if it
			 * matches what we are looking for.  If the slot
			 * has never been filled with anything, then the
			 * remainder of the directory has never been used,
			 * so there is no point in searching it.
			 */
			if (dep->deName[0] == SLOT_EMPTY ||
			    dep->deName[0] == SLOT_DELETED) {
				/*
				 * Drop memory of previous long matches
				 */
				chksum = -1;
				mbnambuf_init(&nb);

				if (slotcount < wincnt) {
					slotcount++;
					slotoffset = diroff;
				}
				if (dep->deName[0] == SLOT_EMPTY) {
					brelse(bp);
					goto notfound;
				}
			} else {
				/*
				 * If there wasn't enough space for our winentries,
				 * forget about the empty space
				 */
				if (slotcount < wincnt)
					slotcount = 0;

				/*
				 * Check for Win95 long filename entry
				 */
				if (dep->deAttributes == ATTR_WIN95) {
				if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
						continue;
					chksum = win2unixfn(&nb,
                                            (struct winentry *)dep, chksum,
                                            pmp);
					continue;
				}

                                chksum = winChkName(&nb,
                                    (const u_char *)cnp->cn_nameptr, unlen,
                                    chksum, pmp);
				if (chksum == -2) {
                                        chksum = -1;
                                        continue;
                                }

				/*
				 * Ignore volume labels (anywhere, not just
				 * the root directory).
				 */
				if (dep->deAttributes & ATTR_VOLUME) {
					chksum = -1;
					continue;
				}

				/*
				 * Check for a checksum or name match
				 */
				if (chksum != winChksum(dep->deName)
				    && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
					chksum = -1;
					continue;
				}
#ifdef MSDOSFS_DEBUG
				kprintf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
				    blkoff, diroff);
#endif
				/*
				 * Remember where this directory
				 * entry came from for whoever did
				 * this lookup.
				 */
				dp->de_fndoffset = diroff;
				dp->de_fndcnt = wincnt - 1;

				goto found;
			}
		}	/* for (blkoff = 0; .... */
		/*
		 * Release the buffer holding the directory cluster just
		 * searched.
		 */
		brelse(bp);
	}	/* for (frcn = 0; ; frcn++) */

notfound:
	/*
	 * We hold no disk buffers at this point.
	 */

	/*
	 * Fixup the slot description to point to the place where
	 * we might put the new DOS direntry (putting the Win95
	 * long name entries before that)
	 */
	if (!slotcount) {
		slotcount = 1;
		slotoffset = diroff;
	}
	if (wincnt > slotcount)
		slotoffset += sizeof(struct direntry) * (wincnt - slotcount);

	/*
	 * If we get here we didn't find the entry we were looking for. But
	 * that's ok if we are creating or renaming and are at the end of
	 * the pathname and the directory hasn't been removed.
	 */
#ifdef MSDOSFS_DEBUG
	kprintf("msdosfs_lookup(): op %d, refcnt %ld\n",
	    nameiop, dp->de_refcnt);
	kprintf("               slotcount %d, slotoffset %d\n",
	       slotcount, slotoffset);
#endif
	if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) &&
	    dp->de_refcnt > 0) {
		/*
		 * Access for write is interpreted as allowing
		 * creation of files in the directory.
		 */
		error = VOP_EACCESS(vdp, VWRITE, cnp->cn_cred);
		if (error)
			return (error);
		/*
		 * Return an indication of where the new directory
		 * entry should be put.
		 */
		dp->de_fndoffset = slotoffset;
		dp->de_fndcnt = wincnt - 1;

		/*
		 * We return with the directory locked, so that
		 * the parameters we set up above will still be
		 * valid if we actually decide to do a direnter().
		 * We return ni_vp == NULL to indicate that the entry
		 * does not currently exist; we leave a pointer to
		 * the (locked) directory inode in ndp->ni_dvp.
		 * The pathname buffer is saved so that the name
		 * can be obtained later.
		 *
		 * NB - if the directory is unlocked, then this
		 * information cannot be used.
		 */
		if (!lockparent) {
			vn_unlock(vdp);
			cnp->cn_flags |= CNP_PDIRUNLOCK;
		}
		return (EJUSTRETURN);
	}
	return (ENOENT);

found:
	/*
	 * NOTE:  We still have the buffer with matched directory entry at
	 * this point.
	 */
	isadir = dep->deAttributes & ATTR_DIRECTORY;
	scn = getushort(dep->deStartCluster);
	if (FAT32(pmp)) {
		scn |= getushort(dep->deHighClust) << 16;
		if (scn == pmp->pm_rootdirblk) {
			/*
			 * There should actually be 0 here.
			 * Just ignore the error.
			 */
			scn = MSDOSFSROOT;
		}
	}

	if (isadir) {
		cluster = scn;
		if (cluster == MSDOSFSROOT)
			blkoff = MSDOSFSROOT_OFS;
		else
			blkoff = 0;
	} else if (cluster == MSDOSFSROOT)
		blkoff = diroff;

	/*
	 * Now release buf to allow deget to read the entry again.
	 * Reserving it here and giving it to deget could result
	 * in a deadlock.
	 */
	brelse(bp);
	bp = NULL;
	
foundroot:
	/*
	 * If we entered at foundroot, then we are looking for the . or ..
	 * entry of the filesystems root directory.  isadir and scn were
	 * setup before jumping here.  And, bp is already null.
	 */
	if (FAT32(pmp) && scn == MSDOSFSROOT)
		scn = pmp->pm_rootdirblk;

	/*
	 * If deleting, and at end of pathname, return
	 * parameters which can be used to remove file.
	 * If the wantparent flag isn't set, we return only
	 * the directory (in ndp->ni_dvp), otherwise we go
	 * on and lock the inode, being careful with ".".
	 */
	if (nameiop == NAMEI_DELETE) {
		/*
		 * Don't allow deleting the root.
		 */
		if (blkoff == MSDOSFSROOT_OFS)
			return EROFS;				/* really? XXX */

		/*
		 * Write access to directory required to delete files.
		 */
		error = VOP_EACCESS(vdp, VWRITE, cnp->cn_cred);
		if (error)
			return (error);

		/*
		 * Return pointer to current entry in dp->i_offset.
		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
		 */
		if (dp->de_StartCluster == scn && isadir) {	/* "." */
			vref(vdp);
			*vpp = vdp;
			return (0);
		}
		error = deget(pmp, cluster, blkoff, &tdp);
		if (error)
			return (error);
		*vpp = DETOV(tdp);
		if (!lockparent) {
			vn_unlock(vdp);
			cnp->cn_flags |= CNP_PDIRUNLOCK;
		}
		return (0);
	}

	/*
	 * If rewriting (RENAME), return the inode and the
	 * information required to rewrite the present directory
	 * Must get inode of directory entry to verify it's a
	 * regular file, or empty directory.
	 */
	if (nameiop == NAMEI_RENAME && wantparent) {
		if (blkoff == MSDOSFSROOT_OFS)
			return EROFS;			/* really? XXX */

		error = VOP_EACCESS(vdp, VWRITE, cnp->cn_cred);
		if (error)
			return (error);

		/*
		 * Careful about locking second inode.
		 * This can only occur if the target is ".".
		 */
		if (dp->de_StartCluster == scn && isadir)
			return (EISDIR);

		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
			return (error);
		*vpp = DETOV(tdp);
		if (!lockparent) {
			vn_unlock(vdp);
			cnp->cn_flags |= CNP_PDIRUNLOCK;
		}
		return (0);
	}

	/*
	 * Step through the translation in the name.  We do not `vput' the
	 * directory because we may need it again if a symbolic link
	 * is relative to the current directory.  Instead we save it
	 * unlocked as "pdp".  We must get the target inode before unlocking
	 * the directory to insure that the inode will not be removed
	 * before we get it.  We prevent deadlock by always fetching
	 * inodes from the root, moving down the directory tree. Thus
	 * when following backward pointers ".." we must unlock the
	 * parent directory before getting the requested directory.
	 * There is a potential race condition here if both the current
	 * and parent directories are removed before the VFS_VGET for the
	 * inode associated with ".." returns.  We hope that this occurs
	 * infrequently since we cannot avoid this race condition without
	 * implementing a sophisticated deadlock detection algorithm.
	 * Note also that this simple deadlock detection scheme will not
	 * work if the file system has any hard links other than ".."
	 * that point backwards in the directory structure.
	 */
	pdp = vdp;
	if (flags & CNP_ISDOTDOT) {
		vn_unlock(pdp);
		cnp->cn_flags |= CNP_PDIRUNLOCK;
		error = deget(pmp, cluster, blkoff,  &tdp);
		if (error) {
			vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); 
			cnp->cn_flags &= ~CNP_PDIRUNLOCK;
			return (error);
		}
		if (lockparent) {
			error = vn_lock(pdp, LK_EXCLUSIVE | LK_FAILRECLAIM);
			if (error) {
				vput(DETOV(tdp));
				return (error);
			}
			cnp->cn_flags &= ~CNP_PDIRUNLOCK;
		}
		*vpp = DETOV(tdp);
	} else if (dp->de_StartCluster == scn && isadir) {
		vref(vdp);	/* we want ourself, ie "." */
		*vpp = vdp;
	} else {
		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
			return (error);
		if (!lockparent) {
			vn_unlock(pdp);
			cnp->cn_flags |= CNP_PDIRUNLOCK;
		}
		*vpp = DETOV(tdp);
	}
	return (0);
}
Exemplo n.º 20
0
static void parsegvar(struct ttfinfo *info, FILE *ttf) {
    /* I'm only going to support a subset of the gvar. Only the global tuples */
    int axiscount, globaltc, gvarflags, gc, i,j,g;
    uint32 tupoff, dataoff, *gvars;
    struct variations *v = info->variations;
    int warned=false;

    fseek(ttf,info->gvar_start,SEEK_SET);
    if ( getlong(ttf)!=0x00010000 ) {	/* I only understand version 1 */
	VariationFree(info);
return;
    }
    axiscount = getushort(ttf);
    if ( axiscount!=info->variations->axis_count ) {
	LogError( _("Hmm, the axis count in the 'gvar' table is different from that in the 'fvar' table.\n") );
	VariationFree(info);
return;
    }
    globaltc = getushort(ttf);
    tupoff = getlong(ttf) + info->gvar_start;
    gc = getushort(ttf);
    gvarflags = getushort(ttf);
    dataoff = getlong(ttf) + info->gvar_start;
    if ( globaltc==0 || globaltc>AppleMmMax ) {
	if ( globaltc==0 )
	    LogError( _("Hmm, no global tuples specified in the 'gvar' table.\n") );
	else
	    LogError( _("Hmm, too many global tuples specified in the 'gvar' table.\n FontForge only supports %d\n"), AppleMmMax );
	VariationFree(info);
return;
    }
    if ( gc>info->glyph_cnt ) {
	LogError( _("Hmm, more glyph variation data specified than there are glyphs in font.\n") );
	VariationFree(info);
return;
    }

    gvars = malloc((gc+1)*sizeof(uint32));
    if ( gvarflags&1 ) {	/* 32 bit data */
	for ( i=0; i<=gc; ++i )
	    gvars[i] = getlong(ttf)+dataoff;
    } else {
	for ( i=0; i<=gc; ++i )
	    gvars[i] = getushort(ttf)*2 +dataoff;	/* Undocumented *2 */
    }

    v->tuple_count = globaltc;
    v->tuples = calloc(globaltc,sizeof(struct tuples));
    fseek(ttf,tupoff,SEEK_SET);
    for ( i=0; i<globaltc; ++i ) {
	v->tuples[i].coords = malloc(axiscount*sizeof(float));
	for ( j=0; j<axiscount; ++j )
	    v->tuples[i].coords[j] = ((short) getushort(ttf))/16384.0;
	v->tuples[i].chars = InfoCopyGlyphs(info);
    }

    for ( g=0; g<gc; ++g ) if ( gvars[g]!=gvars[g+1] ) {
	int tc;
	uint32 datoff;
	int *sharedpoints=NULL;
	fseek(ttf,gvars[g],SEEK_SET);
	tc = getushort(ttf);
	datoff = gvars[g]+getushort(ttf);
	if ( tc&0x8000 ) {
	    uint32 here = ftell(ttf);
	    fseek(ttf,datoff,SEEK_SET);
	    sharedpoints = readpackedpoints(ttf);
	    datoff = ftell(ttf);
	    fseek(ttf,here,SEEK_SET);
	}
	for ( i=0; i<(tc&0xfff); ++i ) {
	    int tupleDataSize, tupleIndex;
	    tupleDataSize = getushort(ttf);
	    tupleIndex = getushort(ttf);
	    if ( tupleIndex&0xc000 ) {
		if ( !warned )
		    LogError( _("Warning: Glyph %d contains either private or intermediate tuple data.\n FontForge supports neither.\n"),
			    g);
		warned = true;
		if ( tupleIndex&0x8000 )
		    fseek(ttf,2*axiscount,SEEK_CUR);
		if ( tupleIndex&0x4000 )
		    fseek(ttf,4*axiscount,SEEK_CUR);
	    } else {
		int *localpoints=NULL;
		uint32 here = ftell(ttf);
		fseek(ttf,datoff,SEEK_SET);
		if ( tupleIndex&0x2000 )
		    localpoints = readpackedpoints(ttf);
		VaryGlyphs(info,tupleIndex&0xfff,g,
			(tupleIndex&0x2000)?localpoints:sharedpoints,ttf);
		free(localpoints);
		fseek(ttf,here,SEEK_SET);
	    }
	    datoff += tupleDataSize;
	}
	free(sharedpoints);
    }
    free(gvars);
}
Exemplo n.º 21
0
/* Check if the disk is MSDOS disk and return its subtypes */
bool is_msdos(char *devnode, int *fssubtype)
{
	union bootsector *bsp;
	struct byte_bpb710 *b710;
	u_int32_t FATSectors;
	u_int32_t TotalSectors;
	u_int32_t countOfClusters;
	u_int32_t DataSectors;
	u_int32_t RootDirSectors;
    u_int16_t BytesPerSector;
    u_int8_t SectorsPerCluster;
	char *buffer = NULL;
	int fd = 0;
	bool retval = false;

	/* default fssubtype to non-existing value */
	*fssubtype = -1;
	
	buffer = (char *)malloc(MAX_DOS_BLOCKSIZE);
	if (!buffer) {
		goto out;
	}
	
	/* open the device */	
	fd = open(devnode, O_RDONLY | O_NDELAY, 0);
	if (fd <= 0) {
		goto out;
	}
	
	/* read the block */
	if (getblk(fd, 0, MAX_DOS_BLOCKSIZE, buffer) < MAX_DOS_BLOCKSIZE) {
		goto out;
	}
	
	bsp = (union bootsector *)buffer;
    b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
   
	/* The first three bytes are an Intel x86 jump instruction.  It should be one
     * of the following forms:
     *    0xE9 0x?? 0x??
     *    0xEC 0x?? 0x90
     * where 0x?? means any byte value is OK.
     */
    if (bsp->bs50.bsJump[0] != 0xE9
        && (bsp->bs50.bsJump[0] != 0xEB || bsp->bs50.bsJump[2] != 0x90)) {
		goto out;
    }

    /* We only work with 512, 1024, and 2048 byte sectors */
	BytesPerSector = getushort(b710->bpbBytesPerSec);
	if ((BytesPerSector < 0x200) || (BytesPerSector & (BytesPerSector - 1)) || (BytesPerSector > 0x800)) {
		goto out;
	}
	
	/* Check to make sure valid sectors per cluster */
    SectorsPerCluster = b710->bpbSecPerClust;
    if ((SectorsPerCluster == 0 ) || (SectorsPerCluster & (SectorsPerCluster - 1))) {
		goto out;
	}

	RootDirSectors = ((getushort(b710->bpbRootDirEnts) * 32) + (BytesPerSector - 1)) / BytesPerSector;

	if (getushort(b710->bpbFATsecs)) {
		FATSectors = getushort(b710->bpbFATsecs);
	} else {
		FATSectors = getulong(b710->bpbBigFATsecs);
	}

	if (getushort(b710->bpbSectors)) {
		TotalSectors = getushort(b710->bpbSectors);
	} else {
		TotalSectors = getulong(b710->bpbHugeSectors);
	}

	DataSectors = TotalSectors - (getushort(b710->bpbResSectors) + (b710->bpbFATs * FATSectors) + RootDirSectors); 
	
	countOfClusters = DataSectors/(b710->bpbSecPerClust);

	if (countOfClusters < 4085) {
		/* FAT12 */
		*fssubtype = 0;
	} else if (countOfClusters < 65525) {
		/* FAT16 */
		*fssubtype = 1;
	} else {
		/* FAT32 */
		*fssubtype = 2;
	}

	retval = true;
	
out:
	if (buffer) {
		free(buffer);
	}
	if (fd > 0) {
		close(fd);
	}
	return retval;
}
Exemplo n.º 22
0
static void parsefvar(struct ttfinfo *info, FILE *ttf) {
    int data_off, axis_count, instance_count, cnt;
    int i,j;

    fseek(ttf,info->fvar_start,SEEK_SET);
    if ( getlong(ttf)!=0x00010000 )	/* I only understand version 1 */
return;
    data_off = getushort(ttf);
    cnt = getushort(ttf);
    if ( cnt>2 )
	LogError( _("Hmm, this 'fvar' table has more count/size pairs than I expect\n") );
    else if ( cnt<2 ) {
	LogError( _("Hmm, this 'fvar' table has too few count/size pairs, I shan't parse it\n") );
return;
    }
    axis_count = getushort(ttf);
    if ( axis_count==0 || axis_count>4 ) {
	if ( axis_count==0 )
	    LogError( _("Hmm, this 'fvar' table has no axes, that doesn't make sense.\n") );
	else
	    LogError( _("Hmm, this 'fvar' table has more axes than FontForge can handle.\n") );
return;
    }
    if ( getushort(ttf)!=20 ) {
	LogError( _("Hmm, this 'fvar' table has an unexpected size for an axis, I shan't parse it\n") );
return;
    }
    instance_count = getushort(ttf);
    if ( getushort(ttf)!=4+4*axis_count ) {
	LogError( _("Hmm, this 'fvar' table has an unexpected size for an instance, I shan't parse it\n") );
return;
    }
    if ( data_off+axis_count*20+instance_count*(4+4*axis_count)> info->fvar_len ) {
	LogError( _("Hmm, this 'fvar' table is too short\n") );
return;
    }

    info->variations = calloc(1,sizeof(struct variations));
    info->variations->axis_count = axis_count;
    info->variations->instance_count = instance_count;
    info->variations->axes = calloc(axis_count,sizeof(struct taxis));
    info->variations->instances = calloc(instance_count,sizeof(struct tinstance));
    for ( i=0; i<instance_count; ++i )
	info->variations->instances[i].coords = malloc(axis_count*sizeof(real));

    fseek(ttf,info->fvar_start+data_off,SEEK_SET);
    for ( i=0; i<axis_count; ++i ) {
	struct taxis *a = &info->variations->axes[i];
	a->tag = getlong(ttf);
	a->min = getlong(ttf)/65536.0;
	a->def = getlong(ttf)/65536.0;
	a->max = getlong(ttf)/65536.0;
	/* flags = */ getushort(ttf);
	a->nameid = getushort(ttf);
    }
    for ( i=0; i<instance_count; ++i ) {
	struct tinstance *ti = &info->variations->instances[i];
	ti->nameid = getushort(ttf);
	/* flags = */ getushort(ttf);
	for ( j=0 ; j<axis_count; ++j )
	    ti->coords[j] = getlong(ttf)/65536.0;
    }
}
Exemplo n.º 23
0
int
fatfindfile(char *fname)
{
	int		rc, i, j;

	putstr("--MBR--\n");
	rc = readblock(DOSBBSECTOR, buf);

	if (dos_partition(0)->dp_typ != 6) {
		putstr("bad partition type\n");
		return -1;
	};

	start = getulong(dos_partition(0)->dp_start);
	dump_long("start ", start);

	putstr("--BOOT--\n");
	rc = readblock(start, buf);
	if (getushort(bootsector->bpbBytesPerSec) != 512) {
		putstr("bad sector size\n");
		return -1;
	};

	cluster_size = bootsector->bpbSecPerClust;
	dump_long("cluster_size ", cluster_size);

	start_fat = start + getushort(bootsector->bpbResSectors);
	dump_long("start_fat ", start_fat);

	root_size = getushort(bootsector->bpbRootDirEnts);
	root_size = (root_size * 32+511)/512;
	dump_long("root_size ", root_size);

	dump_long("FATsecs ", getushort(bootsector->bpbFATsecs));
	dump_long("FATs ", bootsector->bpbFATs);
	start_root = start_fat + bootsector->bpbFATs * getushort(bootsector->bpbFATsecs);
	start = start_root + root_size - 2 * cluster_size; /* first data sector for 0-based clusters */
	dump_long("start_root ", start_root);

	current_cluster = 0;

	putstr("--ROOT--\n");
	for(j = 0; j<root_size; j++) {
		rc = readblock(start_root + j, buf);
		for(i = 0; i<16; i++) {
			rc = (direntry(i)->deName)[0];
			if (rc == SLOT_EMPTY || rc == SLOT_DELETED) continue;

			rc = direntry(i)->deAttributes & (ATTR_VOLUME|ATTR_DIRECTORY);
			if (rc) continue;

			current_cluster = getushort(direntry(i)->deStartCluster);
			bytes_left = getulong(direntry(i)->deFileSize);

			putstr(direntry(i)->deName);
			putnl();
			/* printf("%12s %02x %ld %ld\n", 
					direntry(i)->deName, 
					direntry(i)->deAttributes & 0x18, 
					current_cluster,
					bytes_left
					); */

			if (!strncmp(direntry(i)->deName, fname, 11)) {
				break;
			};
			current_cluster = 0;
		};
		if (current_cluster) break;
	};

	if (!current_cluster) {
		putstr("file not found\n");
		return -1;
	};
	current_sector = 0;
	putstr("File ok\n");
	return 0;
}
Exemplo n.º 24
0
/*
 * Check to see if the directory described by target is in some
 * subdirectory of source.  This prevents something like the following from
 * succeeding and leaving a bunch or files and directories orphaned. mv
 * /a/b/c /a/b/c/d/e/f Where c and f are directories.
 *
 * source - the inode for /a/b/c
 * target - the inode for /a/b/c/d/e/f
 *
 * Returns 0 if target is NOT a subdirectory of source.
 * Otherwise returns a non-zero error number.
 * The target inode is always unlocked on return.
 */
int
doscheckpath(struct denode *source, struct denode *target)
{
	u_long scn;
	struct msdosfsmount *pmp;
	struct direntry *ep;
	struct denode *dep;
	struct buf *bp = NULL;
	int error = 0;

	dep = target;
	if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
	    (source->de_Attributes & ATTR_DIRECTORY) == 0) {
		error = ENOTDIR;
		goto out;
	}
	if (dep->de_StartCluster == source->de_StartCluster) {
		error = EEXIST;
		goto out;
	}
	if (dep->de_StartCluster == MSDOSFSROOT)
		goto out;
	pmp = dep->de_pmp;
#ifdef	DIAGNOSTIC
	if (pmp != source->de_pmp)
		panic("doscheckpath: source and target on different filesystems");
#endif
	if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
		goto out;

	for (;;) {
		if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
			error = ENOTDIR;
			break;
		}
		scn = dep->de_StartCluster;
		error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, scn)),
			      pmp->pm_bpcluster, NOCRED, 0, &bp);
		if (error)
			break;

		ep = (struct direntry *) bp->b_data + 1;
		if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
		    memcmp(ep->deName, "..         ", 11) != 0) {
			error = ENOTDIR;
			break;
		}
		scn = getushort(ep->deStartCluster);
		if (FAT32(pmp))
			scn |= getushort(ep->deHighClust) << 16;

		if (scn == source->de_StartCluster) {
			error = EINVAL;
			break;
		}
		if (scn == MSDOSFSROOT)
			break;
		if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
			/*
			 * scn should be 0 in this case,
			 * but we silently ignore the error.
			 */
			break;
		}

		vput(DETOV(dep));
		brelse(bp, 0);
		bp = NULL;
		/* NOTE: deget() clears dep on error */
		if ((error = deget(pmp, scn, 0, &dep)) != 0)
			break;
	}
out:
	if (bp)
		brelse(bp, 0);
	if (error == ENOTDIR)
		printf("doscheckpath(): .. not a directory?\n");
	if (dep != NULL)
		vput(DETOV(dep));
	return (error);
}
Exemplo n.º 25
0
uint16_t print_dirent(struct direntry *dirent, int indent)
{
    uint16_t followclust = 0;

    int i;
    char name[9];
    char extension[4];
    uint32_t size;
    uint16_t file_cluster;
    name[8] = ' ';
    extension[3] = ' ';
    memcpy(name, &(dirent->deName[0]), 8);
    memcpy(extension, dirent->deExtension, 3);
    if (name[0] == SLOT_EMPTY)
    {
	return followclust;
    }

    /* skip over deleted entries */
    if (((uint8_t)name[0]) == SLOT_DELETED)
    {
	return followclust;
    }

    if (((uint8_t)name[0]) == 0x2E)
    {
	// dot entry ("." or "..")
	// skip it
        return followclust;
    }

    /* names are space padded - remove the spaces */
    for (i = 8; i > 0; i--) 
    {
	if (name[i] == ' ') 
	    name[i] = '\0';
	else 
	    break;
    }

    /* remove the spaces from extensions */
    for (i = 3; i > 0; i--) 
    {
	if (extension[i] == ' ') 
	    extension[i] = '\0';
	else 
	    break;
    }

    if ((dirent->deAttributes & ATTR_WIN95LFN) == ATTR_WIN95LFN)
    {
	// ignore any long file name extension entries
	//
	// printf("Win95 long-filename entry seq 0x%0x\n", dirent->deName[0]);
    }
    else if ((dirent->deAttributes & ATTR_VOLUME) != 0) 
    {
	printf("Volume: %s\n", name);
    } 
    else if ((dirent->deAttributes & ATTR_DIRECTORY) != 0) 
    {
        // don't deal with hidden directories; MacOS makes these
        // for trash directories and such; just ignore them.
	if ((dirent->deAttributes & ATTR_HIDDEN) != ATTR_HIDDEN)
        {
	    print_indent(indent);
    	    printf("%s/ (directory)\n", name);
            file_cluster = getushort(dirent->deStartCluster);
            followclust = file_cluster;
        }
    }
    else 
    {
        /*
         * a "regular" file entry
         * print attributes, size, starting cluster, etc.
         */
	int ro = (dirent->deAttributes & ATTR_READONLY) == ATTR_READONLY;
	int hidden = (dirent->deAttributes & ATTR_HIDDEN) == ATTR_HIDDEN;
	int sys = (dirent->deAttributes & ATTR_SYSTEM) == ATTR_SYSTEM;
	int arch = (dirent->deAttributes & ATTR_ARCHIVE) == ATTR_ARCHIVE;

	size = getulong(dirent->deFileSize);
	print_indent(indent);
	printf("%s.%s (%u bytes) (starting cluster %d) %c%c%c%c\n", 
	       name, extension, size, getushort(dirent->deStartCluster),
	       ro?'r':' ', 
               hidden?'h':' ', 
               sys?'s':' ', 
               arch?'a':' ');
    }

    return followclust;
}
Exemplo n.º 26
0
int
msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
    struct msdosfs_args *argp)
{
	struct msdosfsmount *pmp;
	struct buf *bp;
	dev_t dev = devvp->v_rdev;
	union bootsector *bsp;
	struct byte_bpb33 *b33;
	struct byte_bpb50 *b50;
	struct byte_bpb710 *b710;
	extern struct vnode *rootvp;
	u_int8_t SecPerClust;
	int	ronly, error, bmapsiz;
	uint32_t fat_max_clusters;

	/*
	 * Disallow multiple mounts of the same device.
	 * Disallow mounting of a device that is currently in use
	 * (except for root, which might share swap device for miniroot).
	 * Flush out any old buffers remaining from a previous use.
	 */
	if ((error = vfs_mountedon(devvp)) != 0)
		return (error);
	if (vcount(devvp) > 1 && devvp != rootvp)
		return (EBUSY);
	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
	VOP_UNLOCK(devvp, 0, p);
	if (error)
		return (error);

	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
	if (error)
		return (error);

	bp  = NULL; /* both used in error_exit */
	pmp = NULL;

	/*
	 * Read the boot sector of the filesystem, and then check the
	 * boot signature.  If not a dos boot sector then error out.
	 */
	if ((error = bread(devvp, 0, 4096, NOCRED, &bp)) != 0)
		goto error_exit;
	bp->b_flags |= B_AGE;
	bsp = (union bootsector *)bp->b_data;
	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
	b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP;

	pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
	pmp->pm_mountp = mp;

	/*
	 * Compute several useful quantities from the bpb in the
	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
	 * the fields that are different between dos 5 and dos 3.3.
	 */
	SecPerClust = b50->bpbSecPerClust;
	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
	pmp->pm_FATs = b50->bpbFATs;
	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
	pmp->pm_Sectors = getushort(b50->bpbSectors);
	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
	pmp->pm_Heads = getushort(b50->bpbHeads);
	pmp->pm_Media = b50->bpbMedia;

	/* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */
	pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;

    	if (!pmp->pm_BytesPerSec || !SecPerClust || pmp->pm_SecPerTrack > 64) {
		error = EFTYPE;
		goto error_exit;
	}

	if (pmp->pm_Sectors == 0) {
		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
	} else {
		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
		pmp->pm_HugeSectors = pmp->pm_Sectors;
	}

	if (pmp->pm_RootDirEnts == 0) {
		if (pmp->pm_Sectors || pmp->pm_FATsecs ||
		    getushort(b710->bpbFSVers)) {
		        error = EINVAL;
			goto error_exit;
		}
		pmp->pm_fatmask = FAT32_MASK;
		pmp->pm_fatmult = 4;
		pmp->pm_fatdiv = 1;
		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
		if (getushort(b710->bpbExtFlags) & FATMIRROR)
		        pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
		else
		        pmp->pm_flags |= MSDOSFS_FATMIRROR;
	} else
	        pmp->pm_flags |= MSDOSFS_FATMIRROR;

	/*
	 * More sanity checks:
	 *	MSDOSFS sectors per cluster: >0 && power of 2
	 *	MSDOSFS sector size: >= DEV_BSIZE && power of 2
	 *	HUGE sector count: >0
	 * 	FAT sectors: >0
	 */
	if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) ||
	    (pmp->pm_BytesPerSec < DEV_BSIZE) ||
	    (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) ||
	    (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0)) {
		error = EINVAL;
		goto error_exit;
	}		
	
	pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
	pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;
	pmp->pm_FATsecs *= pmp->pm_BlkPerSec;
	pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
	SecPerClust *= pmp->pm_BlkPerSec;

	if (FAT32(pmp)) {
	        pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
		pmp->pm_firstcluster = pmp->pm_fatblk
		        + (pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
	} else {
	        pmp->pm_rootdirblk = pmp->pm_fatblk +
		        (pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
				       + DEV_BSIZE - 1) / DEV_BSIZE;
		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
	}

	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
	    SecPerClust;
	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
	pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;

	if (pmp->pm_fatmask == 0) {
		if (pmp->pm_maxcluster
		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
			/*
			 * This will usually be a floppy disk. This size makes
			 * sure that one fat entry will not be split across
			 * multiple blocks.
			 */
			pmp->pm_fatmask = FAT12_MASK;
			pmp->pm_fatmult = 3;
			pmp->pm_fatdiv = 2;
		} else {
			pmp->pm_fatmask = FAT16_MASK;
			pmp->pm_fatmult = 2;
			pmp->pm_fatdiv = 1;
		}
	}
	if (FAT12(pmp))
		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
	else
		pmp->pm_fatblocksize = MAXBSIZE;

	/*
	 * We now have the number of sectors in each FAT, so can work
	 * out how many clusters can be represented in a FAT.  Let's
	 * make sure the file system doesn't claim to have more clusters
	 * than this.
	 *
	 * We perform the calculation like we do to avoid integer overflow.
	 *
	 * This will give us a count of clusters.  They are numbered
	 * from 0, so the max cluster value is one less than the value
	 * we end up with.
	 */
	fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult;
	fat_max_clusters *= pmp->pm_fatdiv;
	if (pmp->pm_maxcluster >= fat_max_clusters) {
#ifndef SMALL_KERNEL
		printf("msdosfs: reducing max cluster to %d from %d "
		    "due to FAT size\n", fat_max_clusters - 1,
		    pmp->pm_maxcluster);
#endif
		pmp->pm_maxcluster = fat_max_clusters - 1;
	}

	pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
	pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;

	/*
	 * Compute mask and shift value for isolating cluster relative byte
	 * offsets and cluster numbers from a file offset.
	 */
	pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;

	/*
	 * Check for valid cluster size
	 * must be a power of 2
	 */
	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
		error = EFTYPE;
		goto error_exit;
	}

	/*
	 * Release the bootsector buffer.
	 */
	brelse(bp);
	bp = NULL;

	/*
	 * Check FSInfo
	 */
	if (pmp->pm_fsinfo) {
	        struct fsinfo *fp;

		if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp),
		    NOCRED, &bp)) != 0)
		        goto error_exit;
		fp = (struct fsinfo *)bp->b_data;
		if (!bcmp(fp->fsisig1, "RRaA", 4)
		    && !bcmp(fp->fsisig2, "rrAa", 4)
		    && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
		    && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
		        /* Valid FSInfo. */
			;
		else
		        pmp->pm_fsinfo = 0;
		/* XXX make sure this tiny buf doesn't come back in fillinusemap! */
		SET(bp->b_flags, B_INVAL);
		brelse(bp);
		bp = NULL;
	}

	/*
	 * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
	 */

	/*
	 * Allocate memory for the bitmap of allocated clusters, and then
	 * fill it in.
	 */
	bmapsiz = (pmp->pm_maxcluster + N_INUSEBITS - 1) / N_INUSEBITS;
	if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) {
		/* detect multiplicative integer overflow */
		error = EINVAL;
		goto error_exit;
	}
	pmp->pm_inusemap = malloc(bmapsiz * sizeof(*pmp->pm_inusemap),
	    M_MSDOSFSFAT, M_WAITOK | M_CANFAIL);
	if (pmp->pm_inusemap == NULL) {
		error = EINVAL;
		goto error_exit;
	}

	/*
	 * fillinusemap() needs pm_devvp.
	 */
	pmp->pm_dev = dev;
	pmp->pm_devvp = devvp;

	/*
	 * Have the inuse map filled in.
	 */
	if ((error = fillinusemap(pmp)) != 0)
		goto error_exit;

	/*
	 * If they want fat updates to be synchronous then let them suffer
	 * the performance degradation in exchange for the on disk copy of
	 * the fat being correct just about all the time.  I suppose this
	 * would be a good thing to turn on if the kernel is still flakey.
	 */
	if (mp->mnt_flag & MNT_SYNCHRONOUS)
		pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;

	/*
	 * Finish up.
	 */
	if (ronly)
		pmp->pm_flags |= MSDOSFSMNT_RONLY;
	else
		pmp->pm_fmod = 1;
	mp->mnt_data = (qaddr_t)pmp;
        mp->mnt_stat.f_fsid.val[0] = (long)dev;
        mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
#ifdef QUOTA
	/*
	 * If we ever do quotas for DOS filesystems this would be a place
	 * to fill in the info in the msdosfsmount structure. You dolt,
	 * quotas on dos filesystems make no sense because files have no
	 * owners on dos filesystems. of course there is some empty space
	 * in the directory entry where we could put uid's and gid's.
	 */
#endif
	devvp->v_specmountpoint = mp;

	return (0);

error_exit:
	devvp->v_specmountpoint = NULL;
	if (bp)
		brelse(bp);

	vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY, p);
	(void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
	VOP_UNLOCK(devvp, 0, p);

	if (pmp) {
		if (pmp->pm_inusemap)
			free(pmp->pm_inusemap, M_MSDOSFSFAT);
		free(pmp, M_MSDOSFSMNT);
		mp->mnt_data = (qaddr_t)0;
	}
	return (error);
}
Exemplo n.º 27
0
struct msdosfsmount *
msdosfs_mount(struct vnode *devvp, int flags)
{
	struct msdosfsmount *pmp = NULL;
	struct buf *bp;
	union bootsector *bsp;
	struct byte_bpb33 *b33;
	struct byte_bpb50 *b50;
	struct byte_bpb710 *b710;
	uint8_t SecPerClust;
	int	ronly = 0, error, tmp;
	int	bsize;
	struct msdos_options *m = devvp->fs->fs_specific;
	uint64_t psize = m->create_size;
	unsigned secsize = 512;

	DPRINTF(("%s(bread 0)\n", __func__));
	if ((error = bread(devvp, 0, secsize, NULL, 0, &bp)) != 0)
		goto error_exit;

	bsp = (union bootsector *)bp->b_data;
	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
	b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;

	if (!(flags & MSDOSFSMNT_GEMDOSFS)) {
		if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
		    || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
			DPRINTF(("bootsig0 %d bootsig1 %d\n", 
			    bsp->bs50.bsBootSectSig0,
			    bsp->bs50.bsBootSectSig1));
			error = EINVAL;
			goto error_exit;
		}
		bsize = 0;
	} else
		bsize = 512;

	pmp = ecalloc(1, sizeof *pmp);
	/*
	 * Compute several useful quantities from the bpb in the
	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
	 * the fields that are different between dos 5 and dos 3.3.
	 */
	SecPerClust = b50->bpbSecPerClust;
	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
	pmp->pm_FATs = b50->bpbFATs;
	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
	pmp->pm_Sectors = getushort(b50->bpbSectors);
	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
	pmp->pm_Heads = getushort(b50->bpbHeads);
	pmp->pm_Media = b50->bpbMedia;

	DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, RootDirEnts=%u, "
	    "Sectors=%u, FATsecs=%lu, SecPerTrack=%u, Heads=%u, Media=%u)\n",
	    __func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors, pmp->pm_FATs,
	    pmp->pm_RootDirEnts, pmp->pm_Sectors, pmp->pm_FATsecs,
	    pmp->pm_SecPerTrack, pmp->pm_Heads, pmp->pm_Media));
	if (!(flags & MSDOSFSMNT_GEMDOSFS)) {
		/* XXX - We should probably check more values here */
    		if (!pmp->pm_BytesPerSec || !SecPerClust
	    		|| pmp->pm_SecPerTrack > 63) {
			DPRINTF(("bytespersec %d secperclust %d "
			    "secpertrack %d\n", 
			    pmp->pm_BytesPerSec, SecPerClust,
			    pmp->pm_SecPerTrack));
			error = EINVAL;
			goto error_exit;
		}
	}

	if (pmp->pm_Sectors == 0) {
		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
	} else {
		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
		pmp->pm_HugeSectors = pmp->pm_Sectors;
	}

	if (pmp->pm_RootDirEnts == 0) {
		unsigned short vers = getushort(b710->bpbFSVers);
		/*
		 * Some say that bsBootSectSig[23] must be zero, but
		 * Windows does not require this and some digital cameras
		 * do not set these to zero.  Therefore, do not insist.
		 */
		if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) {
			DPRINTF(("sectors %d fatsecs %lu vers %d\n",
			    pmp->pm_Sectors, pmp->pm_FATsecs, vers));
			error = EINVAL;
			goto error_exit;
		}
		pmp->pm_fatmask = FAT32_MASK;
		pmp->pm_fatmult = 4;
		pmp->pm_fatdiv = 1;
		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);

		/* mirrorring is enabled if the FATMIRROR bit is not set */
		if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0)
			pmp->pm_flags |= MSDOSFS_FATMIRROR;
		else
			pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
	} else
		pmp->pm_flags |= MSDOSFS_FATMIRROR;

	if (flags & MSDOSFSMNT_GEMDOSFS) {
		if (FAT32(pmp)) {
			DPRINTF(("FAT32 for GEMDOS\n"));
			/*
			 * GEMDOS doesn't know FAT32.
			 */
			error = EINVAL;
			goto error_exit;
		}

		/*
		 * Check a few values (could do some more):
		 * - logical sector size: power of 2, >= block size
		 * - sectors per cluster: power of 2, >= 1
		 * - number of sectors:   >= 1, <= size of partition
		 */
		if ( (SecPerClust == 0)
		  || (SecPerClust & (SecPerClust - 1))
		  || (pmp->pm_BytesPerSec < bsize)
		  || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
		  || (pmp->pm_HugeSectors == 0)
		  || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
		      > psize)) {
			DPRINTF(("consistency checks for GEMDOS\n"));
			error = EINVAL;
			goto error_exit;
		}
		/*
		 * XXX - Many parts of the msdosfs driver seem to assume that
		 * the number of bytes per logical sector (BytesPerSec) will
		 * always be the same as the number of bytes per disk block
		 * Let's pretend it is.
		 */
		tmp = pmp->pm_BytesPerSec / bsize;
		pmp->pm_BytesPerSec  = bsize;
		pmp->pm_HugeSectors *= tmp;
		pmp->pm_HiddenSects *= tmp;
		pmp->pm_ResSectors  *= tmp;
		pmp->pm_Sectors     *= tmp;
		pmp->pm_FATsecs     *= tmp;
		SecPerClust         *= tmp;
	}

	/* Check that fs has nonzero FAT size */
	if (pmp->pm_FATsecs == 0) {
		DPRINTF(("FATsecs is 0\n"));
		error = EINVAL;
		goto error_exit;
	}

	pmp->pm_fatblk = pmp->pm_ResSectors;
	if (FAT32(pmp)) {
		pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
		pmp->pm_firstcluster = pmp->pm_fatblk
			+ (pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
	} else {
		pmp->pm_rootdirblk = pmp->pm_fatblk +
			(pmp->pm_FATs * pmp->pm_FATsecs);
		pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
				       + pmp->pm_BytesPerSec - 1)
			/ pmp->pm_BytesPerSec;/* in sectors */
		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
	}

	pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
	    SecPerClust;
	pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
	pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;

	if (flags & MSDOSFSMNT_GEMDOSFS) {
		if (pmp->pm_nmbrofclusters <= (0xff0 - 2)) {
			pmp->pm_fatmask = FAT12_MASK;
			pmp->pm_fatmult = 3;
			pmp->pm_fatdiv = 2;
		} else {
			pmp->pm_fatmask = FAT16_MASK;
			pmp->pm_fatmult = 2;
			pmp->pm_fatdiv = 1;
		}
	} else if (pmp->pm_fatmask == 0) {
		if (pmp->pm_maxcluster
		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
			/*
			 * This will usually be a floppy disk. This size makes
			 * sure that one FAT entry will not be split across
			 * multiple blocks.
			 */
			pmp->pm_fatmask = FAT12_MASK;
			pmp->pm_fatmult = 3;
			pmp->pm_fatdiv = 2;
		} else {
			pmp->pm_fatmask = FAT16_MASK;
			pmp->pm_fatmult = 2;
			pmp->pm_fatdiv = 1;
		}
	}
	if (FAT12(pmp))
		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
	else
		pmp->pm_fatblocksize = MAXBSIZE;

	pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
	pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;

	/*
	 * Compute mask and shift value for isolating cluster relative byte
	 * offsets and cluster numbers from a file offset.
	 */
	pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;

	DPRINTF(("%s(fatmask=%lu, fatmult=%u, fatdiv=%u, fatblocksize=%lu, "
	    "fatblocksec=%lu, bnshift=%lu, pbcluster=%lu, crbomask=%lu, "
	    "cnshift=%lu)\n",
	    __func__, pmp->pm_fatmask, pmp->pm_fatmult, pmp->pm_fatdiv,
	    pmp->pm_fatblocksize, pmp->pm_fatblocksec, pmp->pm_bnshift,
	    pmp->pm_bpcluster, pmp->pm_crbomask, pmp->pm_cnshift));
	/*
	 * Check for valid cluster size
	 * must be a power of 2
	 */
	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
		DPRINTF(("bpcluster %lu cnshift %lu\n", 
		    pmp->pm_bpcluster, pmp->pm_cnshift));
		error = EINVAL;
		goto error_exit;
	}

	/*
	 * Release the bootsector buffer.
	 */
	brelse(bp, BC_AGE);
	bp = NULL;

	/*
	 * Check FSInfo.
	 */
	if (pmp->pm_fsinfo) {
		struct fsinfo *fp;

		/*
		 * XXX	If the fsinfo block is stored on media with
		 *	2KB or larger sectors, is the fsinfo structure
		 *	padded at the end or in the middle?
		 */
		DPRINTF(("%s(bread %lu)\n", __func__,
		    (unsigned long)de_bn2kb(pmp, pmp->pm_fsinfo)));
		if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo),
		    pmp->pm_BytesPerSec, NULL, 0, &bp)) != 0)
			goto error_exit;
		fp = (struct fsinfo *)bp->b_data;
		if (!memcmp(fp->fsisig1, "RRaA", 4)
		    && !memcmp(fp->fsisig2, "rrAa", 4)
		    && !memcmp(fp->fsisig3, "\0\0\125\252", 4)
		    && !memcmp(fp->fsisig4, "\0\0\125\252", 4))
			pmp->pm_nxtfree = getulong(fp->fsinxtfree);
		else
			pmp->pm_fsinfo = 0;
		brelse(bp, 0);
		bp = NULL;
	}

	/*
	 * Check and validate (or perhaps invalidate?) the fsinfo structure?
	 * XXX
	 */
	if (pmp->pm_fsinfo) {
		if ((pmp->pm_nxtfree == 0xffffffffUL) ||
		    (pmp->pm_nxtfree > pmp->pm_maxcluster))
			pmp->pm_fsinfo = 0;
	}

	/*
	 * Allocate memory for the bitmap of allocated clusters, and then
	 * fill it in.
	 */
	pmp->pm_inusemap = ecalloc(sizeof(*pmp->pm_inusemap),
	    ((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS));
	/*
	 * fillinusemap() needs pm_devvp.
	 */
	pmp->pm_dev = 0;
	pmp->pm_devvp = devvp;

	/*
	 * Have the inuse map filled in.
	 */
	if ((error = fillinusemap(pmp)) != 0) {
		DPRINTF(("fillinusemap %d\n", error));
		goto error_exit;
	}

	/*
	 * Finish up.
	 */
	if (ronly)
		pmp->pm_flags |= MSDOSFSMNT_RONLY;
	else
		pmp->pm_fmod = 1;

	/*
	 * If we ever do quotas for DOS filesystems this would be a place
	 * to fill in the info in the msdosfsmount structure. You dolt,
	 * quotas on dos filesystems make no sense because files have no
	 * owners on dos filesystems. of course there is some empty space
	 * in the directory entry where we could put uid's and gid's.
	 */

	return pmp;

error_exit:
	if (bp)
		brelse(bp, BC_AGE);
	if (pmp) {
		if (pmp->pm_inusemap)
			free(pmp->pm_inusemap);
		free(pmp);
	}
	errno = error;
	return pmp;
}