int umsdos_emd_dir_readentry (struct file *filp, struct umsdos_dirent *entry) { int ret; Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n")); ret = umsdos_emd_dir_read (filp, (char *) entry, UMSDOS_REC_SIZE); if (ret == 0) { /* if no error */ /* Variable size record. Maybe, we have to read some more */ int recsize = umsdos_evalrecsize (entry->name_len); if (recsize > UMSDOS_REC_SIZE) { Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: %d > %d!\n", recsize, UMSDOS_REC_SIZE)); ret = umsdos_emd_dir_read (filp, ((char *) entry) + UMSDOS_REC_SIZE, recsize - UMSDOS_REC_SIZE); } } Printk (("umsdos_emd_dir_readentry /mn/: ret=%d.\n", ret)); if (entry && ret == 0) { Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n", (int) entry->name_len, (int) entry->name_len, entry->name)); } return ret; }
/* Read an entry from the EMD file. Support variable length record. Return -EIO if error, 0 if ok. */ int umsdos_emd_dir_readentry ( struct inode *emd_dir, struct file *filp, struct umsdos_dirent *entry) { int ret = umsdos_emd_dir_read(emd_dir,filp,(char*)entry,UMSDOS_REC_SIZE); if (ret == 0){ /* Variable size record. Maybe, we have to read some more */ int recsize = umsdos_evalrecsize (entry->name_len); if (recsize > UMSDOS_REC_SIZE){ ret = umsdos_emd_dir_read(emd_dir,filp ,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE); } } return ret; }
static int umsdos_find (struct dentry *parent, struct umsdos_info *info) { struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; struct dentry *demd; struct inode *emd_dir; int ret = -ENOENT; struct find_buffer buf; struct { off_t posok; /* Position available to store the entry */ int found; /* A valid empty position has been found. */ off_t one; /* One empty position -> maybe <- large enough */ int onesize; /* size of empty region starting at one */ } empty; Printk (("umsdos_find: locating %s in %s/%s\n", entry->name, parent->d_parent->d_name.name, parent->d_name.name)); /* * Lookup the EMD file in the parent directory. */ demd = umsdos_get_emd_dentry(parent); ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out; /* make sure there's an EMD file ... */ ret = -ENOENT; emd_dir = demd->d_inode; if (!emd_dir) goto out_dput; Printk(("umsdos_find: found EMD file %s/%s, ino=%p\n", demd->d_parent->d_name.name, demd->d_name.name, emd_dir)); fill_new_filp (&buf.filp, demd); buf.pos = 0; buf.size = 0; empty.found = 0; empty.posok = emd_dir->i_size; empty.onesize = 0; while (1) { struct umsdos_dirent *rentry = (struct umsdos_dirent *) (buf.buffer + buf.pos); int file_pos = buf.filp.f_pos - buf.size + buf.pos; if (buf.pos == buf.size) { ret = umsdos_fillbuf (&buf); if (ret < 0) { /* Not found, so note where it can be added */ info->f_pos = empty.posok; break; } } else if (rentry->name_len == 0) { /* We are looking for an empty section at least */ /* as large as recsize. */ if (entry->name_len == 0) { info->f_pos = file_pos; ret = 0; break; } else if (!empty.found) { if (empty.onesize == 0) { /* This is the first empty record of a section. */ empty.one = file_pos; } /* grow the empty section */ empty.onesize += UMSDOS_REC_SIZE; if (empty.onesize == recsize) { /* Here is a large enough section. */ empty.posok = empty.one; empty.found = 1; } } buf.pos += UMSDOS_REC_SIZE; } else { int entry_size = umsdos_evalrecsize (rentry->name_len); if (buf.pos + entry_size > buf.size) { ret = umsdos_fillbuf (&buf); if (ret < 0) { /* Not found, so note where it can be added */ info->f_pos = empty.posok; break; } } else { empty.onesize = 0; /* Reset the free slot search. */ if (entry->name_len == rentry->name_len && memcmp (entry->name, rentry->name, rentry->name_len) == 0) { info->f_pos = file_pos; *entry = *rentry; ret = 0; break; } else { buf.pos += entry_size; } } } } Printk(("umsdos_find: ready to mangle %s, len=%d, pos=%ld\n", entry->name, entry->name_len, (long)info->f_pos)); umsdos_manglename (info); out_dput: dput(demd); out: Printk (("umsdos_find: returning %d\n", ret)); return ret; }
/* General search, locate a name in the EMD file or an empty slot to store it. if info->entry.name_len == 0, search the first empty slot (of the proper size). Caller must do iput on *pt_emd_dir. Return 0 if found, -ENOENT if not found, another error code if other problem. So this routine is used to either find an existing entry or to create a new one, while making sure it is a new one. After you get -ENOENT, you make sure the entry is stuffed correctly and call umsdos_writeentry(). To delete an entry, you find it, zero out the entry (memset) and call umsdos_writeentry(). All this to say that umsdos_writeentry must be call after this function since it rely on the f_pos field of info. */ static int umsdos_find ( struct inode *dir, struct umsdos_info *info, /* Hold name and name_len */ /* Will hold the entry found */ struct inode **pt_emd_dir) /* Will hold the emd_dir inode */ /* or NULL if not found */ { /* #Specification: EMD file structure The EMD file uses a fairly simple layout. It is made of records (UMSDOS_REC_SIZE == 64). When a name can't be written is a single record, multiple contiguous record are allocated. */ int ret = -ENOENT; struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1); if (emd_dir != NULL){ struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; struct { off_t posok; /* Position available to store the entry */ int found; /* A valid empty position has been found */ off_t one; /* One empty position -> maybe <- large enough */ int onesize; /* size of empty region starting at one */ }empty; /* Read several entries at a time to speed up the search */ struct find_buffer buf; buf.pos = 0; buf.size = 0; buf.filp.f_pos = 0; buf.filp.f_reada = 1; empty.found = 0; empty.posok = emd_dir->i_size; empty.onesize = 0; while (1){ struct umsdos_dirent *rentry = (struct umsdos_dirent*) (buf.buffer + buf.pos); int file_pos = buf.filp.f_pos - buf.size + buf.pos; if (buf.pos == buf.size){ ret = umsdos_fillbuf (emd_dir,&buf); if (ret < 0){ /* Not found, so note where it can be added */ info->f_pos = empty.posok; break; } }else if (rentry->name_len == 0){ /* We are looking for an empty section at least */ /* recsize large */ if (entry->name_len == 0){ info->f_pos = file_pos; ret = 0; break; }else if (!empty.found){ if (empty.onesize == 0){ /* This is the first empty record of a section */ empty.one = file_pos; } /* grow the empty section */ empty.onesize += UMSDOS_REC_SIZE; if (empty.onesize == recsize){ /* here is a large enough section */ empty.posok = empty.one; empty.found = 1; } } buf.pos += UMSDOS_REC_SIZE; }else{ int entry_size = umsdos_evalrecsize(rentry->name_len); if (buf.pos+entry_size > buf.size){ ret = umsdos_fillbuf (emd_dir,&buf); if (ret < 0){ /* Not found, so note where it can be added */ info->f_pos = empty.posok; break; } }else{ empty.onesize = 0; /* Reset the free slot search */ if (entry->name_len == rentry->name_len && memcmp(entry->name,rentry->name,rentry->name_len) ==0){ info->f_pos = file_pos; *entry = *rentry; ret = 0; break; }else{ buf.pos += entry_size; } } } } umsdos_manglename(info); } *pt_emd_dir = emd_dir; return ret; }