/* * fat32/fat32_file.c - fat32 file related operations * * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless * Copyright (c) 2011,2012 UPMC Sorbonne Universites * * This file is part of ALMOS-kernel. * * ALMOS-kernel is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-kernel is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-kernel; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include VFS_OPEN_FILE(vfat_open) { return 0; } VFS_LSEEK_FILE(vfat_lseek) { return 0; } VFS_CLOSE_FILE(vfat_close) { return 0; } VFS_RELEASE_FILE(vfat_release) { assert(file->fr_pv == NULL); return 0; } VFS_READ_DIR(vfat_readdir) { struct vfat_DirEntry_s dir; struct page_s *page; struct mapper_s *mapper; vfat_cluster_t node_cluster; uint8_t *buff; uint32_t found; mapper = file->fr_inode->i_mapper; found = 0; /* TODO: dont call mapper every time, as page can be reused */ while(!found) { //FIXME: synchro : either use a lock or force the writer to //write the first byte of the name as the last thing he do //when adding an entry //also lock file offset ? if ((page = mapper_get_page(mapper, file->fr_offset >> PMM_PAGE_SHIFT, MAPPER_SYNC_OP)) == NULL) return VFS_IO_ERR; buff = ppm_page2addr(page); buff += file->fr_offset % PMM_PAGE_SIZE; memcpy(&dir, buff, sizeof(dir)); if(dir.DIR_Name[0] == 0x00) { vfat_dmsg(3,"vfat_readdir: entries termination found (0x00)\n"); goto VFS_READ_DIR_EODIR; } if(dir.DIR_Name[0] == 0xE5) { vfat_dmsg(3,"entry was freeed previously\n"); vfat_getshortname((char*)dir.DIR_Name, (char*)dirent->u_name); vfat_dmsg(3,"it was %s\n",dirent->u_name); goto VFS_READ_DIR_NEXT; } if(dir.DIR_Attr == 0x0F) { vfat_dmsg(3,"this entry is a long one\n"); vfat_getshortname((char*)dir.DIR_Name, (char*)dirent->u_name); vfat_dmsg(3,"trying to read its name %s\n",dirent->u_name); goto VFS_READ_DIR_NEXT; } if(dir.DIR_Name[0] == '.') goto VFS_READ_DIR_NEXT; found = 1; vfat_getshortname((char *)dir.DIR_Name, (char*)dirent->u_name); //dirent->d_size = dir.DIR_FileSize; dirent->u_attr = 0; if(dir.DIR_Attr & VFAT_ATTR_DIRECTORY) dirent->u_attr = VFS_DIR; if(dir.DIR_Attr & VFAT_ATTR_SYSTEM) dirent->u_attr |= VFS_SYS; if(dir.DIR_Attr & VFAT_ATTR_ARCHIVE) dirent->u_attr |= VFS_ARCHIVE; if(dir.DIR_Attr & VFAT_ATTR_READ_ONLY) dirent->u_attr |= VFS_RD_ONLY; node_cluster = dir.DIR_FstClusHI << 16; node_cluster |= (0x0000FFFF & dir.DIR_FstClusLO); if((!node_cluster) && (dirent->u_attr & VFS_SYS) && (dirent->u_attr & VFS_RD_ONLY) && (dirent->u_attr & VFS_DIR)) { dirent->u_attr |= VFS_DEV; dirent->u_attr &= ~(VFS_SYS | VFS_RD_ONLY | VFS_DIR); } else if((!node_cluster) && (dirent->u_attr & VFS_SYS) && (dirent->u_attr & VFS_RD_ONLY)) { dirent->u_attr |= VFS_FIFO; dirent->u_attr &= ~(VFS_SYS | VFS_RD_ONLY); } VFS_READ_DIR_NEXT: file->fr_offset += sizeof(struct vfat_DirEntry_s); } VFS_READ_DIR_EODIR: return (found) ? 0 : VFS_EODIR; } const struct vfs_file_op_s vfat_f_op = { .open = vfat_open, .read = vfs_default_read, .write = vfs_default_write, .lseek = NULL, .readdir = vfat_readdir, .close = vfat_close, .release = vfat_release, .mmap = vfs_default_mmap_file, .munmap = vfs_default_munmap_file };