static int read_next_dir_buffer (FatTraverseInfo* trav_info) { FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs); PED_ASSERT (!trav_info->is_legacy_root_dir); trav_info->this_buffer = trav_info->next_buffer; if (trav_info->this_buffer < 2 || trav_info->this_buffer >= fs_info->cluster_count + 2) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, "Cluster %ld in directory %s is outside file system!", (long) trav_info->this_buffer, trav_info->dir_name); return 0; } trav_info->next_buffer = fat_table_get (fs_info->fat, trav_info->this_buffer); return fat_read_cluster (trav_info->fs, (void *) trav_info->dir_entries, trav_info->this_buffer); }
static int fatfs_lookup(void *priv, const char *name, struct vfs_node *dir) { struct fatfs_dirent *dirent = (struct fatfs_dirent *)priv; struct fatfs_priv *fsop = dirent->fs; size_t bytes_per_cluster = (fsop->bytes_per_sector * fsop->sectors_per_cluster); char *cluster_buffer = (char *)malloc(bytes_per_cluster); if (dirent->flag & 0xFF00) { return fatfs_root(fsop, name, dir); }else if (!IS_DIR(dirent->flag)) { return -1; } size_t valid_cluster = dirent->entry; size_t dpcnt = bytes_per_cluster / 32; struct fat_entry *dirents, entry; dirents = (struct fat_entry *)cluster_buffer; struct fat_opvector *opv = fsop->opvector; while (valid_cluster < opv->fat_max_cluster) { size_t cluster; if (-1 == fat_read_cluster(fsop, valid_cluster, cluster_buffer)) { free(cluster_buffer); return -1; } if (0 == fat_dirent_lookup(dirents, dpcnt, name, &entry)) { VFS_MALLOC(struct fatfs_dirent, dirent); dirent->length = entry.length; dirent->entry = entry.cluster_entry| (entry.cluster_high << 16); dirent->entry &= opv->fat_cluster_mask; printf("found: %d\n", dirent->entry); dirent->flag = entry.attribute; dirent->fs = fsop; dir->vops = &fatfs_vops; dir->priv = dirent; free(cluster_buffer); return 0; } if (-1 == (*opv->fat_next_cluster)(fsop, valid_cluster, &cluster)) { free(cluster_buffer); return -1; } valid_cluster = cluster; } free(cluster_buffer); return -1; }
int fatfs_pread(struct fatfs_dirent *file, void *buf, size_t count, size_t off) { if (!IS_DIR(file->flag)) { if (off > file->length) return -1; if (off + count > file->length) count = file->length - off; } if (count == 0) return 0; if (off < file->offset) { file->cluster = file->entry; file->offset = 0; } size_t i; struct fatfs_priv *fs = (struct fatfs_priv *)file->fs; size_t bytes_per_cluster = (fs->bytes_per_sector * fs->sectors_per_cluster); size_t cluster_count = (offset - file->offset) / bytes_per_cluster; struct fat_opvector *opv = fs->opvector; while (cluster_count > 0) { size_t cluster; if ((*opv->fat_next_cluster)(fs, file->cluster, &cluster) == -1) { return -1; } if (cluster >= opv->fat_max_cluster) { return 0; } file->offset += bytes_per_cluster; file->cluster = cluster; cluster_count--; } char *cluster_buffer = (char *)malloc(bytes_per_cluster); assert(cluster_buffer); if (fat_read_cluster(fs, file->cluster, cluster_buffer)) { free(cluster_buffer); return -1; } size_t cluster_offset = off - file->offset; size_t cpcnt = bytes_per_cluster > cluster_offset + count? count: bytes_per_cluster - cluster_offset; memcpy(buf, cluster_buffer + cluster_offset, cpcnt); free(cluster_buffer); off += cpcnt; count -= cpcnt; int hr = 0; while (off < file->length && count > 0) { if ((hr = fatfs_pread(file, (char*)buf + cpcnt, count, off)) == -1) { return -1; } if (hr == 0) { break; } off += hr; count -= hr; cpcnt += hr; } return cpcnt; }
INT32 fat_file_read(struct inode *inode, struct file * filp, INT8 * buf, INT32 len) { FAT_DIR_ENTRY d_entry = {0,}; FAT_SB_INFO* sb = NULL; UINT32 fpos = 0; UINT32 fsize = 0; UINT32 secperclu = 0; INT32 rcount = 0; UINT32 rsize = 0; UINT32 cursec, secnum; UINT32 clunum, secoff; UINT8* secbuf; INT8* bufp = NULL; INT32 iResult = _ERR_FAT_SUCCESS; d_entry = inode->u.fat_i.entry; sb = &(inode->i_sb->u.fat_sb); fpos = filp->f_pos; fsize = d_entry.DIR_FileSize; secperclu = (UINT32)sb->iSecPerClus; bufp = buf; // set the rsize. if(fpos > fsize) { D( ( DL_FATERROR, "in fat_file_read. fpos(%d) > fsize(%d).\n",fpos,fsize) ); return _ERR_FAT_READ_EXCEED; } else if(fpos+len > fsize) { rsize = fsize - fpos; } else { rsize = len; } // malloc the secbuf for read sector. secbuf = FAT_SECT_BUF_ALLOC(); if(NULL == secbuf) { D(( DL_FATERROR,"in fat_file_read,1.FAT_SECT_BUF_ALLOC() failed.")); DSM_ASSERT(0,"in fat_file_read,1.FAT_SECT_BUF_ALLOC() failed."); return _ERR_FAT_MALLOC_FAILED; } // get the wcluser number. iResult = fat_fpos2CSO(filp->f_inode, fpos, &clunum, &secnum, &secoff, (UINT32*)NULL); if (iResult != _ERR_FAT_SUCCESS) { // Out of file size,error. D( ( DL_FATERROR, "fat_file_read: fat_fpos2CSO error!!!\n") ); g_TstFsErrCode = 1019; iResult = _ERR_FAT_ERROR; goto end; } cursec = secnum; while(!fat_is_last_cluster(sb, clunum)) { for(cursec = secnum; cursec < secperclu; cursec++) { // DSM_MemSet(secbuf, 0x00, DEFAULT_SECSIZE); iResult = fat_read_cluster(sb, clunum, cursec, secbuf); if(_ERR_FAT_SUCCESS != iResult) { D( ( DL_FATERROR, "Call fat_read_cluster() failed. Local error code:%d. clunum = 0x%x, secnum = 0x%x.\n",iResult, clunum, cursec) ); iResult = _ERR_FAT_READ_SEC_FAILED; goto end; } if(0 == secoff) { if(rsize > DEFAULT_SECSIZE) { DSM_MemCpy(bufp, secbuf, DEFAULT_SECSIZE); filp->f_pos += DEFAULT_SECSIZE; bufp += DEFAULT_SECSIZE; rsize -= DEFAULT_SECSIZE; rcount += DEFAULT_SECSIZE; secoff = 0; } else if (rsize == DEFAULT_SECSIZE) { DSM_MemCpy(bufp, secbuf, DEFAULT_SECSIZE); filp->f_pos += DEFAULT_SECSIZE; bufp += DEFAULT_SECSIZE; rsize -= DEFAULT_SECSIZE; rcount += DEFAULT_SECSIZE; secoff = 0; goto end; } else //secoff + rsize <= DEFAULT_SECSIZE (1) { DSM_MemCpy(bufp, secbuf, rsize); filp->f_pos += rsize; bufp += rsize; secoff = secoff + rsize; rcount += rsize; rsize = 0; goto end; } } else // secoff > 0 { if(secoff + rsize > DEFAULT_SECSIZE) { DSM_MemCpy(bufp, secbuf+secoff, DEFAULT_SECSIZE-secoff); filp->f_pos += (DEFAULT_SECSIZE-secoff); bufp += (DEFAULT_SECSIZE-secoff); rsize -= (DEFAULT_SECSIZE-secoff); rcount += (DEFAULT_SECSIZE-secoff); secoff = 0; } else //secoff + rsize <= DEFAULT_SECSIZE (1) { DSM_MemCpy(bufp, secbuf+secoff, rsize); filp->f_pos += rsize; bufp += rsize; secoff = secoff + rsize; rcount += rsize; rsize = 0; goto end; } } } // Get next cluster, secnum, secoff iResult = fat_fpos2CSO(filp->f_inode, filp->f_pos, &clunum, &secnum, &secoff, (UINT32*)NULL); if (iResult != _ERR_FAT_SUCCESS) { // Out of file size,error. D( ( DL_FATERROR, "fat_file_read: fat_fpos2CSO error2 !!!\n") ); iResult = _ERR_FAT_ERROR; g_TstFsErrCode = 1020; goto end; } DSM_ASSERT((BOOL)(clunum >= 2),"clunum = %d.",clunum); } end: if(NULL != secbuf) { FAT_SECT_BUF_FREE((SECT_BUF*)secbuf); } rcount = _ERR_FAT_SUCCESS == iResult ? rcount: iResult; return rcount; }
static int fatfs_rename(vnode_t dvp1, vnode_t vp1, char *name1, vnode_t dvp2, vnode_t vp2, char *name2) { struct fatfsmount *fmp; struct fatfs_node np1; struct fat_dirent *de1, *de2; int error; fmp = dvp1->v_mount->m_data; mutex_lock(&fmp->lock); error = fatfs_lookup_node(dvp1, name1, &np1); if (error) goto out; de1 = &np1.dirent; if (IS_FILE(de1)) { /* Remove destination file, first */ error = fatfs_remove(dvp2, vp1, name2); if (error == EIO) goto out; /* Change file name of directory entry */ fat_convert_name(name2, (char *)de1->name); /* Same directory ? */ if (dvp1 == dvp2) { /* Change the name of existing file */ error = fatfs_put_node(fmp, &np1); if (error) goto out; } else { /* Create new directory entry */ error = fatfs_add_node(dvp2, &np1); if (error) goto out; /* Remove souce file */ error = fatfs_remove(dvp1, vp2, name1); if (error) goto out; } } else { /* remove destination directory */ error = fatfs_rmdir(dvp2, NULL, name2); if (error == EIO) goto out; /* Change file name of directory entry */ fat_convert_name(name2, (char *)de1->name); /* Same directory ? */ if (dvp1 == dvp2) { /* Change the name of existing directory */ error = fatfs_put_node(fmp, &np1); if (error) goto out; } else { /* Create new directory entry */ error = fatfs_add_node(dvp2, &np1); if (error) goto out; /* Update "." and ".." for renamed directory */ if (fat_read_cluster(fmp,(de1->cluster_hi << 16) | de1->cluster)) { error = EIO; goto out; } de2 = (struct fat_dirent *)fmp->io_buf; de2->cluster_hi = de1->cluster_hi; de2->cluster = de1->cluster; de2->time = TEMP_TIME; de2->date = TEMP_DATE; de2++; de2->cluster_hi = (dvp2->v_blkno & 0xFFFF0000) >> 16; de2->cluster = dvp2->v_blkno & 0x0000FFFF; de2->time = TEMP_TIME; de2->date = TEMP_DATE; if (fat_write_cluster(fmp,(de1->cluster_hi << 16) | de1->cluster)) { error = EIO; goto out; } /* Remove souce directory */ error = fatfs_rmdir(dvp1, NULL, name1); if (error) goto out; } } out: mutex_unlock(&fmp->lock); return error; }
static int fatfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) { struct fatfsmount *fmp; struct fatfs_node *np; struct fat_dirent *de; int nr_copy, nr_write, buf_pos, i, cl_size, error; u_long file_pos, end_pos; u_long cl; DPRINTF(("fatfs_write: vp=%x size=%d\n", vp, size)); *result = 0; fmp = vp->v_mount->m_data; if (vp->v_type == VDIR) return EISDIR; if (vp->v_type != VREG) return EINVAL; mutex_lock(&fmp->lock); /* Check if file position exceeds the end of file. */ end_pos = vp->v_size; file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset; if (file_pos + size > end_pos) { /* Expand the file size before writing to it */ end_pos = file_pos + size; error = fat_expand_file(fmp, vp->v_blkno, end_pos); if (error) { error = EIO; goto out; } /* Update directory entry */ np = vp->v_data; de = &np->dirent; de->size = end_pos; error = fatfs_put_node(fmp, np); if (error) goto out; vp->v_size = end_pos; } /* Seek to the cluster for the file offset */ error = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl); if (error) goto out; buf_pos = file_pos % fmp->cluster_size; cl_size = size / fmp->cluster_size + 1; nr_write = 0; i = 0; do { /* First and last cluster must be read before write */ if (i == 0 || i == cl_size) { if (fat_read_cluster(fmp, cl)) { error = EIO; goto out; } } nr_copy = fmp->cluster_size; if (buf_pos > 0) nr_copy -= buf_pos; if (buf_pos + size < fmp->cluster_size) nr_copy = size; memcpy(fmp->io_buf + buf_pos, buf, nr_copy); if (fat_write_cluster(fmp, cl)) { error = EIO; goto out; } file_pos += nr_copy; nr_write += nr_copy; size -= nr_copy; if (size <= 0) break; error = fat_next_cluster(fmp, cl, &cl); if (error) goto out; buf = (void *)((u_long)buf + nr_copy); buf_pos = 0; i++; } while (!IS_EOFCL(fmp, cl)); fp->f_offset = file_pos; /* * XXX: Todo! * de.time = ? * de.date = ? * if (dirent_set(fp, &de)) * return EIO; */ *result = nr_write; error = 0; out: mutex_unlock(&fmp->lock); return error; }
static int fatfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) { struct fatfsmount *fmp; int nr_read, nr_copy, buf_pos, error; u_long cl, file_pos; DPRINTF(("fatfs_read: vp=%x\n", vp)); *result = 0; fmp = vp->v_mount->m_data; if (vp->v_type == VDIR) return EISDIR; if (vp->v_type != VREG) return EINVAL; /* Check if current file position is already end of file. */ file_pos = fp->f_offset; if (file_pos >= vp->v_size) return 0; mutex_lock(&fmp->lock); /* Get the actual read size. */ if (vp->v_size - file_pos < size) size = vp->v_size - file_pos; /* Seek to the cluster for the file offset */ error = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl); if (error) goto out; /* Read and copy data */ nr_read = 0; buf_pos = file_pos % fmp->cluster_size; do { if (fat_read_cluster(fmp, cl)) { error = EIO; goto out; } nr_copy = fmp->cluster_size; if (buf_pos > 0) nr_copy -= buf_pos; if (buf_pos + size < fmp->cluster_size) nr_copy = size; memcpy(buf, fmp->io_buf + buf_pos, nr_copy); file_pos += nr_copy; nr_read += nr_copy; size -= nr_copy; if (size <= 0) break; error = fat_next_cluster(fmp, cl, &cl); if (error) goto out; buf = (void *)((u_long)buf + nr_copy); buf_pos = 0; } while (!IS_EOFCL(fmp, cl)); fp->f_offset = file_pos; *result = nr_read; error = 0; out: mutex_unlock(&fmp->lock); return error; }