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; } }
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 ); }
/* * 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; }
/* * 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); } }
/* * 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; }
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 ); }
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; };
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 ); }
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); }
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); } } }
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); }
/************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; }
/* * 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; }
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); } } }
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); }
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); }
/* * 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); }
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); }
/* * 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); }
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); }
/* 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; }
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; } }
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; }
/* * 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); }
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; }
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); }
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; }