/* We will search the inode that belongs to this name, currently by a complete linear search through the inodes belonging to this filesystem. This has to be fixed. */ static struct smb_inode_info * smb_find_dir_inode(struct inode *parent, const char *name, int len) { struct smb_server *server = SMB_SERVER(parent); struct smb_inode_info *dir = SMB_INOP(parent); struct smb_inode_info *result = &(server->root); if (name == NULL) { return NULL; } if ((len == 1) && (name[0] == '.')) { return dir; } if ((len == 2) && (name[0] == '.') && (name[1] == '.')) { return dir->dir; } do { if (result->dir == dir) { if (compare_filename(server, name, len, &(result->finfo)) == 0) { return result; } } result = result->next; } while (result != &(server->root)); return NULL; }
static int smb_lookup(struct inode *dir, const char *name, int len, struct inode **result) { struct smb_dirent finfo; struct smb_inode_info *result_info; int error; int found_in_cache; struct smb_inode_info *new_inode_info = NULL; *result = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { printk("smb_lookup: inode is NULL or not a directory.\n"); iput(dir); return -ENOENT; } DDPRINTK("smb_lookup: %s\n", name); /* Fast cheat for . */ if (len == 0 || (len == 1 && name[0] == '.')) { *result = dir; return 0; } /* ..and for .. */ if (len == 2 && name[0] == '.' && name[1] == '.') { struct smb_inode_info *parent = SMB_INOP(dir)->dir; if (parent->state == SMB_INODE_CACHED) { parent->state = SMB_INODE_LOOKED_UP; } *result = iget(dir->i_sb, smb_info_ino(parent)); iput(dir); if (*result == 0) { return -EACCES; } return 0; } result_info = smb_find_dir_inode(dir, name, len); in_tree: if (result_info != NULL) { if (result_info->state == SMB_INODE_CACHED) { result_info->state = SMB_INODE_LOOKED_UP; } *result = iget(dir->i_sb, smb_info_ino(result_info)); iput(dir); if (new_inode_info != NULL) { smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info)); } if (*result == NULL) { return -EACCES; } return 0; } /* If the file is in the dir cache, we do not have to ask the server. */ found_in_cache = 0; if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino) && (c_size != 0)) { int first = c_last_returned_index; int i; i = first; do { if (compare_filename(SMB_SERVER(dir), name, len, &(c_entry[i])) == 0) { finfo = c_entry[i]; found_in_cache = 1; break; } i = (i + 1) % c_size; } while (i != first); } if (found_in_cache == 0) { DPRINTK("smb_lookup: not found in cache: %s\n", name); if (len > SMB_MAXNAMELEN) { iput(dir); return -ENAMETOOLONG; } error = smb_proc_getattr(dir, name, len, &finfo); if (error < 0) { iput(dir); return error; } finfo.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1); } new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info), GFP_KERNEL); /* Here somebody else might have inserted the inode */ result_info = smb_find_dir_inode(dir, name, len); if (result_info != NULL) { goto in_tree; } if (new_inode_info == NULL) { iput(dir); return -ENOMEM; } new_inode_info->finfo = finfo; DPRINTK("attr: %x\n", finfo.attr); if ((*result = smb_iget(dir, new_inode_info)) == NULL) { iput(dir); return -EACCES; } DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long) result_info); iput(dir); return 0; }
//returns sector number where directory is located, negative = error int dir_lookup(char* path) { char dname[MAX_PATH_LEN+1]; dname[MAX_PATH_LEN] = '\0'; strncpy(dname, path, MAX_PATH_LEN); char* dname_part = NULL; dname_part = strtok(dname, "/"); int dlocation = start_of_root_dir(); //special case for root directory char root_dir_dname[] = "."; if(strcmp(path, root_dir_dname) == 0) { return start_of_root_dir(); } bool found = false; //traverse the directory structure while(dname_part != NULL) { found = false; debug_printf("looking for directory %s\n", dname_part); // printf(" ====looking for directory %s\n", dname_part); // printf(" dir_entries_sector() = %d \n",dir_entries_sector()); while(!found) { //read sector into a memory block uint8_t dir_sector[bytes_sector()]; read_block(dlocation, &dir_sector); fat_file_t dir_files[dir_entries_sector()]; memcpy(&dir_files, &dir_sector, (size_t)bytes_sector()); //search the memory block for matching name for(int i = 0; i < dir_entries_sector(); ++i) { if(dir_files[i].name[0] == 0x00) { //not found, don't need to keep looking // printf(" //not found, don't need to keep looking"); break; } else if(dir_files[i].name[0] == deleted_file) { //deleted continue; } else if(is_lfn(dir_files[i].attr)) { //LFN entry continue; } else if(dir_files[i].attr.vol == 1 || dir_files[i].attr.dir == 0 || dir_files[i].attr.device == 1) { //volume label, not a directory, device file continue; } if(compare_filename(dname_part, dir_files[i]) == 0) { //got a directory with the correct name dlocation = data_cluster_to_sector(dir_files[i].first_cluster); // printf(" dir_files[i].first_cluster: %d \n", dir_files[i].first_cluster); found = true; break; } } if(found) { break; } //directory not found yet, need to pick the next sector to search //(if available) if(dlocation < start_of_data()) { if(dlocation < start_of_root_dir() + root_dir_sectors()) { //there are more root directory sectors to search dlocation++; } else { //directory doesn't exist return -1; } } else { if((dlocation + 1 - start_of_data()) % sectors_cluster() != 0) { //more sectors in this cluster dlocation++; } else if(next_cluster_for_sector(dlocation) <= max_cluster) { //continues into another cluster uint16_t next_c = next_cluster_for_sector(dlocation); dlocation = data_cluster_to_sector(next_c); } else { //directory doesn't exist return -1; } } } // printf(" dlocation: %d \n", dlocation); dname_part = strtok(NULL, "/"); } return dlocation; }
//returns file entry number in directory or -1 for not found int file_lookup(char* name, int *directory_sector) { int dlocation = *directory_sector; bool root_dir = true; if(dlocation >= start_of_data()) { root_dir = false; } debug_printf("looking for file %s\n", name); while(true) { uint8_t dir_sector[bytes_sector()]; read_block(dlocation, &dir_sector); fat_file_t dir_files[dir_entries_sector()]; memcpy(&dir_files, &dir_sector, (size_t)bytes_sector()); //search the memory block for matching name for(int i = 0; i < dir_entries_sector(); ++i) { if(dir_files[i].name[0] == 0x00) { //not found, don't need to keep looking break; } else if(dir_files[i].name[0] == deleted_file) { //deleted continue; } else if(is_lfn(dir_files[i].attr)) { //LFN entry continue; } else if(dir_files[i].attr.vol == 1 || dir_files[i].attr.device == 1) { //volume label, device file continue; } if(compare_filename(name, dir_files[i]) == 0) { //got a directory with the correct name *directory_sector = dlocation; return i; } } //file not found yet, need to pick the next sector to search //if there is actually a next sector if(root_dir) { if(dlocation < start_of_root_dir() + root_dir_sectors()) { //there are more root directory sectors to search dlocation++; } else { //file doesn't exist return -1; } } else { if((dlocation + 1 - start_of_data()) % sectors_cluster() != 0) { //more sectors to search in this cluster dlocation++; } else if(next_cluster_for_sector(dlocation) <= max_cluster) { //continues into another cluster uint16_t next_c = next_cluster_for_sector(dlocation); dlocation = data_cluster_to_sector(next_c); } else { return -1; } } } return -1; }
/* Known issue: central dir must be < BUFSIZE bytes */ static int find_matching_cd_entry (FILE *fp, char *match, t_end_of_cent_dir *ecd, t_central_dir_ent *cd) { int i, j, found = 0, err; int count, read; char *p; /* we'll read the entire central directory or BUFSIZE bytes, whichever is smaller */ if (ecd->size_of_cent_dir > BUFSIZE) count = BUFSIZE; else count = ecd->size_of_cent_dir; /* read from start of central directory */ err = fseek (fp, ecd->offset_to_start_of_cent_dir, SEEK_SET); if (err==0) { read = fread (input_buffer, 1, count, fp); if (read!=count) { ERRORMSG ("Error in zipfile: couldn't read %d bytes from central directory\n", count); err = -1; } } else ERRORMSG ("Error in zipfile: couldn't fseek to start of central directory\n"); if (err==0) { /* loop through entries in central directory for suitable match */ for (i=0, p=input_buffer; found==0 && i<ecd->total_entries_cent_dir; i++) { char filename[256]; read_central_dir_entry (p, cd); /* copy filename and force to upper case */ for (j=0; j<cd->filename_length && j<254; j++) filename[j] = toupper (cd->filename[j]); filename[j] = '\0'; /* compare filename */ if (!compare_filename (filename, match)) { found = 1; /* check for suitability */ if (cd->compression_method != 0x0000 && cd->compression_method != 0x0008 ) { found = 0; ERRORMSG ("Error in zipfile: compression method for file %s unsupported.\n", match); ERRORMSG ("Method: $%04x must be $0000 (Stored) or $0008 (Deflated)\n", cd->compression_method); } if (cd->version_needed_to_extract > 0x14) { found = 0; ERRORMSG ("Error in zipfile: version for file %s too new.\n", match); ERRORMSG ("Version: $%02x must be $14 or less\n", cd->version_needed_to_extract); } if (cd->os_needed_to_extract != 0x00) { found = 0; ERRORMSG ("Error in zipfile: OS for file %s not supported.\n", match); ERRORMSG ("OS: $%02x must be $00\n",cd->os_needed_to_extract); } if (cd->disk_number_start != ecd->number_of_this_disk) { found = 0; ERRORMSG ("Error in zipfile: zipfile cannot span disks\n"); } } /* skip to next entry in central dir */ p += ZIPCFN + cd->filename_length + cd->extra_field_length + cd->file_comment_length; } } if (!found) err = -1; return err; }