/* Write an entry in the EMD file. Return 0 if ok, -EIO if some error. */ int umsdos_writeentry ( struct inode *dir, struct inode *emd_dir, struct umsdos_info *info, int free_entry) /* This entry is deleted, so Write all 0's */ { int ret = 0; struct file filp; struct umsdos_dirent *entry = &info->entry; struct umsdos_dirent entry0; if (free_entry){ /* #Specification: EMD file / empty entries Unused entry in the EMD file are identify by the name_len field equal to 0. However to help future extension (or bug correction :-( ), empty entries are filled with 0. */ memset (&entry0,0,sizeof(entry0)); entry = &entry0; }else if (entry->name_len > 0){ memset (entry->name+entry->name_len,'\0' ,sizeof(entry->name)-entry->name_len); /* #Specification: EMD file / spare bytes 10 bytes are unused in each record of the EMD. They are set to 0 all the time. So it will be possible to do new stuff and rely on the state of those bytes in old EMD file around. */ memset (entry->spare,0,sizeof(entry->spare)); } filp.f_pos = info->f_pos; filp.f_reada = 0; ret = umsdos_emd_dir_write(emd_dir,&filp,(char*)entry,info->recsize); if (ret != 0){ printk ("UMSDOS: problem with EMD file. Can't write\n"); }else{ dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt = 1; } return ret; }
int UMSDOS_notify_change(struct inode *inode, struct iattr *attr) { int ret = 0; if ((ret = inode_change_ok(inode, attr)) != 0) return ret; if (inode->i_nlink > 0){ /* #Specification: notify_change / i_nlink > 0 notify change is only done for inode with nlink > 0. An inode with nlink == 0 is no longer associated with any entry in the EMD file, so there is nothing to update. */ unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner; if (inode == inode->i_sb->s_mounted){ /* #Specification: root inode / attributes I don't know yet how this should work. Normally the attributes (permissions bits, owner, times) of a directory are stored in the EMD file of its parent. One thing we could do is store the attributes of the root inode in its own EMD file. A simple entry named "." could be used for this special case. It would be read once when the file system is mounted and update in UMSDOS_notify_change() (right here). I am not sure of the behavior of the root inode for a real UNIX file system. For now, this is a nop. */ }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){ /* This inode is not a EMD file nor an inode used internally by MSDOS, so we can update its status. See emd.c */ struct inode *emd_owner = iget (inode->i_sb,i_emd_owner); PRINTK (("notify change %p ",inode)); if (emd_owner == NULL){ printk ("UMSDOS: emd_owner = NULL ???"); ret = -EPERM; }else{ struct file filp; struct umsdos_dirent entry; filp.f_pos = inode->u.umsdos_i.pos; filp.f_reada = 0; PRINTK (("pos = %d ",filp.f_pos)); /* Read only the start of the entry since we don't touch */ /* the name */ ret = umsdos_emd_dir_read (emd_owner,&filp,(char*)&entry ,UMSDOS_REC_SIZE); if (ret == 0){ if (attr->ia_valid & ATTR_UID) entry.uid = attr->ia_uid; if (attr->ia_valid & ATTR_GID) entry.gid = attr->ia_gid; if (attr->ia_valid & ATTR_MODE) entry.mode = attr->ia_mode; if (attr->ia_valid & ATTR_ATIME) entry.atime = attr->ia_atime; if (attr->ia_valid & ATTR_MTIME) entry.mtime = attr->ia_mtime; if (attr->ia_valid & ATTR_CTIME) entry.ctime = attr->ia_ctime; entry.nlink = inode->i_nlink; filp.f_pos = inode->u.umsdos_i.pos; ret = umsdos_emd_dir_write (emd_owner,&filp,(char*)&entry ,UMSDOS_REC_SIZE); PRINTK (("notify pos %d ret %d nlink %d " ,inode->u.umsdos_i.pos ,ret,entry.nlink)); /* #Specification: notify_change / msdos fs notify_change operation are done only on the EMD file. The msdos fs is not even called. */ } iput (emd_owner); } PRINTK (("\n")); } } if (ret == 0) inode_setattr(inode, attr); return ret; }
/* * Write an entry in the EMD file. * Return 0 if OK, -EIO if some error. * * Note: the caller must hold a lock on the parent directory. */ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info, int free_entry) { struct inode *dir = parent->d_inode; struct umsdos_dirent *entry = &info->entry; struct dentry *emd_dentry; int ret; struct umsdos_dirent entry0; struct file filp; emd_dentry = umsdos_get_emd_dentry(parent); ret = PTR_ERR(emd_dentry); if (IS_ERR(emd_dentry)) goto out; /* make sure there's an EMD file */ ret = -EIO; if (!emd_dentry->d_inode) { printk(KERN_WARNING "umsdos_writeentry: no EMD file in %s/%s\n", parent->d_parent->d_name.name, parent->d_name.name); goto out_dput; } if (free_entry) { /* #Specification: EMD file / empty entries * Unused entries in the EMD file are identified * by the name_len field equal to 0. However to * help future extension (or bug correction :-( ), * empty entries are filled with 0. */ memset (&entry0, 0, sizeof (entry0)); entry = &entry0; } else if (entry->name_len > 0) { memset (entry->name + entry->name_len, '\0', sizeof (entry->name) - entry->name_len); /* #Specification: EMD file / spare bytes * 10 bytes are unused in each record of the EMD. They * are set to 0 all the time, so it will be possible * to do new stuff and rely on the state of those * bytes in old EMD files. */ memset (entry->spare, 0, sizeof (entry->spare)); } fill_new_filp (&filp, emd_dentry); filp.f_pos = info->f_pos; filp.f_reada = 0; filp.f_flags = O_RDWR; /* write the entry and update the parent timestamps */ ret = umsdos_emd_dir_write (&filp, (char *) entry, info->recsize); if (!ret) { dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); } else printk ("UMSDOS: problem with EMD file: can't write\n"); out_dput: dput(emd_dentry); out: Printk (("umsdos_writeentry /mn/: returning %d...\n", ret)); return ret; }