int fat_open(struct inode* inode) { fat_t* fat = (fat_t*) inode->userdata; if(unlikely(!fat)) { errno = EINVAL; return E_ERR; } if(fat->entry_sector == 0) return E_OK; fat->dev->position = fat->entry_sector * fat->bytes_per_sector; inode_t* child = NULL; static char buf[512]; fat_entry_t* e = (fat_entry_t*) &buf; fat_entry_lfn_t* lfn = (fat_entry_lfn_t*) &buf; int entry = 0; do { if(unlikely(fat_check_entry(fat, &entry) == E_ERR)) break; if(vfs_read(fat->dev, &buf, 32) != 32) { errno = EIO; return E_ERR; } if(e->name[0] == '\0') break; child = (inode_t*) kmalloc(sizeof(inode_t), GFP_ATOMIC); if(unlikely(!child)) { errno = ENOMEM; return E_ERR; } memset(child, 0, sizeof(inode_t)); child->name = (const char*) kmalloc(FAT_MAXFN, GFP_ATOMIC); if(unlikely(!child->name)) { kfree((void*) child); errno = ENOMEM; return E_ERR; } memset((void*) child->name, 0, FAT_MAXFN); if(e->flags == ATTR_LFN) { do { #if CONFIG_LFN lfncat(child->name, lfn->name_2, 2); lfncat(child->name, lfn->name_1, 6); lfncat(child->name, lfn->name_0, 5); #endif if(unlikely(fat_check_entry(fat, &entry) == E_ERR)) { kfree((void*) child->name); kfree((void*) child); errno = ENOENT; return E_ERR; } if(vfs_read(fat->dev, &buf, 32) != 32) { kfree((void*) child->name); kfree((void*) child); errno = EIO; return E_ERR; } } while(lfn->flags == ATTR_LFN); } if(e->name[0] == '\xE5') { kfree((void*) child->name); kfree((void*) child); continue; } if(child->name[0] == '\0') fatcat(child->name, e->name, e->extension); struct inode_childs* cx; for(cx = inode->childs; cx; cx = cx->next) { if(strcmp(cx->inode->name, child->name) == 0) { kfree((void*) child->name); kfree((void*) child); continue; } } fat_t* fc = (fat_t*) kmalloc(sizeof(fat_t), GFP_USER); if(unlikely(!fc)) { kfree((void*) child->name); kfree((void*) child); errno = ENOMEM; return E_ERR; } memcpy(fc, fat, sizeof(fat_t)); int cluster = (e->cluster_high << 16) | (e->cluster_low & 0xFFFF); fc->entry_sector = cluster ? CLUSTER_TO_SECTOR(fc, cluster) : 0 ; child->userdata = (void*) fc; child->ino = vfs_inode(); child->mode = (e->flags & ATTR_DIRECTORY ? S_IFDIR : S_IFREG) | (e->flags & ATTR_RDONLY ? 0444 : 0666) & ~current_task->umask; child->dev = child->rdev = child->nlink = 0; child->uid = current_task->uid; child->gid = current_task->gid; child->size = (off64_t) e->size; child->atime = child->ctime = child->mtime = timer_gettime(); child->parent = inode; child->link = NULL; child->childs = NULL; if(e->flags & ATTR_DIRECTORY) { child->finddir = fat_finddir; child->mknod = fat_mknod; child->rename = NULL; child->unlink = fat_unlink; child->open = fat_open; child->close = fat_close; } else { child->read = NULL; child->write = NULL; } child->chown = NULL; child->chmod = NULL; child->ioctl = NULL; cx = (struct inode_childs*) kmalloc(sizeof(struct inode_childs), GFP_KERNEL); cx->inode = child; cx->next = inode->childs; inode->childs = cx; } while(1); }
struct inode* iso9660_finddir(struct inode* inode, char* name) { if(unlikely(!inode)) { errno = EINVAL; return NULL; } if(unlikely(!inode->userdata)) { errno = EINVAL; return NULL; } iso9660_t* ctx = (iso9660_t*) inode->userdata; KASSERT(ctx); iso9660_dir_t* nodes = (iso9660_dir_t*) kmalloc(iso9660_getlsb32(ctx->dir.length), GFP_USER); iso9660_dir_t* snodes = nodes; KASSERT(nodes); ctx->dev->position = iso9660_getlsb32(ctx->dir.lba) * ISO9660_SECTOR_SIZE; if(unlikely(vfs_read(ctx->dev, nodes, iso9660_getlsb32(ctx->dir.length)) != iso9660_getlsb32(ctx->dir.length))) { kfree(nodes); errno = EIO; return NULL; } /* Skip dots (".", "..") */ nodes = (iso9660_dir_t*) ((uintptr_t) nodes + nodes->size); nodes = (iso9660_dir_t*) ((uintptr_t) nodes + nodes->size); int i; for(i = 0; i < iso9660_getlsb32(ctx->dir.length); i += ISO9660_SECTOR_SIZE) { if(i != 0) nodes = (iso9660_dir_t*) ((uintptr_t) snodes + i); for( ; nodes->size; nodes = (iso9660_dir_t*) ((uintptr_t) nodes + nodes->size) ) { inode_t* child = (inode_t*) kmalloc(sizeof(inode_t), GFP_ATOMIC); if(unlikely(!child)) { errno = ENOMEM; return NULL; } memset(child, 0, sizeof(inode_t)); #if HAVE_ROCKRIDGE register int len = nodes->idlen; if(!(len & 1)) len++; void* rockridge_offset = (void*) ((uintptr_t) &nodes->reserved + len); #endif #if HAVE_ROCKRIDGE child->name = rockridge_getname(rockridge_offset); #else child->name = (const char*) kmalloc(nodes->idlen + 1, GFP_USER); KASSERT(child->name); memset((void*) child->name, 0, nodes->idlen + 1); strncpy((char*) child->name, nodes->reserved, nodes->idlen); iso9660_checkname((char*) child->name); #endif if(strcmp(child->name, name) != 0) { kfree((void*) child->name); kfree((void*) child); continue; } child->ino = vfs_inode(); child->mode = (nodes->flags & ISO9660_FLAGS_DIRECTORY ? S_IFDIR : S_IFREG) | 0666 & ~current_task->umask; child->dev = child->rdev = child->nlink = 0; child->uid = current_task->uid; child->gid = current_task->gid; child->size = (off64_t) iso9660_getlsb32(nodes->length); child->atime = child->ctime = child->mtime = timer_gettime(); child->parent = inode; child->link = NULL; child->childs = NULL; if(nodes->flags & ISO9660_FLAGS_DIRECTORY) { child->open = iso9660_open; child->close = iso9660_close; child->finddir = iso9660_finddir; child->unlink = iso9660_unlink; } else { child->read = iso9660_read; child->write = NULL; } child->chown = NULL; child->chmod = NULL; child->ioctl = NULL; #if HAVE_ROCKRIDGE rockridge_getmode(rockridge_offset, &child->mode, &child->uid, &child->gid, &child->nlink); #endif iso9660_t* cctx = (iso9660_t*) kmalloc(sizeof(iso9660_t), GFP_USER); KASSERT(cctx); memcpy(cctx, ctx, sizeof(iso9660_t)); memcpy(&cctx->dir, nodes, sizeof(iso9660_dir_t)); child->userdata = (void*) cctx; struct inode_childs* cx = (struct inode_childs*) kmalloc(sizeof(struct inode_childs), GFP_KERNEL); cx->inode = child; cx->next = inode->childs; inode->childs = cx; return child; } } kfree(snodes); errno = ENOENT; return NULL; }