📄 namei.c
字号:
chkstk(); if (ret == 0){ /* This UMSDOS_lookup does not look very useful. It makes sure that the inode of the file will be correctly setup (umsdos_patch_inode()) in case it is already in use. Not very efficient ... */ struct inode *inode; new_dir->i_count++; PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags)); ret = UMSDOS_lookup (new_dir,new_name,new_len ,&inode);chkstk(); if (ret != 0){ printk ("UMSDOS: partial rename for file %s\n" ,new_info.entry.name); }else{ /* Update f_pos so notify_change will succeed if the file was already in use. */ umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);chkstk(); iput (inode); } } } } }else{ /* sticky bit set on new_dir */ PRINTK(("sticky set on new ")); ret = -EPERM; } }else{ /* sticky bit set on old_dir */ PRINTK(("sticky set on old ")); ret = -EPERM; } } umsdos_unlockcreate(old_dir); umsdos_unlockcreate(new_dir); } iput (old_dir); iput (new_dir); PRINTK (("\n")); return ret;}/* Setup un Symbolic link or a (pseudo) hard link Return a negative error code or 0 if ok.*/static int umsdos_symlink_x( struct inode * dir, const char * name, int len, const char * symname, /* name will point to this path */ int mode, char flags){ /* #Specification: symbolic links / strategy A symbolic link is simply a file which hold a path. It is implemented as a normal MSDOS file (not very space efficient :-() I see 2 different way to do it. One is to place the link data in unused entry of the EMD file. The other is to have a separate file dedicated to hold all symbolic links data. Let's go for simplicity... */ struct inode *inode; int ret; dir->i_count++; /* We keep the inode in case we need it */ /* later */ ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode); PRINTK (("umsdos_symlink ret %d ",ret)); if (ret == 0){ int len = strlen(symname); struct file filp; filp.f_pos = 0; /* Make the inode acceptable to MSDOS */ ret = umsdos_file_write_kmem (inode,&filp,symname,len); iput (inode); if (ret >= 0){ if (ret != len){ ret = -EIO; printk ("UMSDOS: " "Can't write symbolic link data\n"); }else{ ret = 0; } } if (ret != 0){ UMSDOS_unlink (dir,name,len); dir = NULL; } } iput (dir); PRINTK (("\n")); return ret;}/* Setup un Symbolic link. Return a negative error code or 0 if ok.*/int UMSDOS_symlink( struct inode * dir, const char * name, int len, const char * symname) /* name will point to this path */{ return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);}/* Add a link to an inode in a directory*/int UMSDOS_link ( struct inode * oldinode, struct inode * dir, const char * name, int len){ /* #Specification: hard link / strategy Well ... hard link are difficult to implement on top of an MsDOS fat file system. Unlike UNIX file systems, there are no inode. A directory entry hold the functionality of the inode and the entry. We will used the same strategy as a normal Unix file system (with inode) except we will do it symbolically (using paths). Because anything can happen during a DOS session (defragment, directory sorting, etc...), we can't rely on MsDOS pseudo inode number to record the link. For this reason, the link will be done using hidden symbolic links. The following scenario illustrate how it work. Given a file /foo/file # ln /foo/file /tmp/file2 become internally mv /foo/file /foo/-LINK1 ln -s /foo/-LINK1 /foo/file ln -s /foo/-LINK1 /tmp/file2 # Using this strategy, we can operate on /foo/file or /foo/file2. We can remove one and keep the other, like a normal Unix hard link. We can rename /foo/file or /tmp/file2 independently. The entry -LINK1 will be hidden. It will hold a link count. When all link are erased, the hidden file is erased too. */ /* #Specification: weakness / hard link The strategy for hard link introduces a side effect that may or may not be acceptable. Here is the sequence # mkdir subdir1 touch subdir1/file mkdir subdir2 ln subdir1/file subdir2/file rm subdir1/file rmdir subdir1 rmdir: subdir1: Directory not empty # This happen because there is an invisible file (--link) in subdir1 which is referenced by subdir2/file. Any idea ? */ /* #Specification: weakness / hard link / rename directory Another weakness of hard link come from the fact that it is based on hidden symbolic links. Here is an example. # mkdir /subdir1 touch /subdir1/file mkdir /subdir2 ln /subdir1/file subdir2/file mv /subdir1 subdir3 ls -l /subdir2/file # Since /subdir2/file is a hidden symbolic link to /subdir1/..hlinkNNN, accessing it will fail since /subdir1 does not exist anymore (has been renamed). */ int ret = 0; if (S_ISDIR(oldinode->i_mode)){ /* #Specification: hard link / directory A hard link can't be made on a directory. EPERM is returned in this case. */ ret = -EPERM; }else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){ struct inode *olddir; ret = umsdos_get_dirowner(oldinode,&olddir); PRINTK (("umsdos_link dir_owner = %d -> %p [%d] " ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count)); if (ret == 0){ struct umsdos_dirent entry; umsdos_lockcreate2(dir,olddir); ret = umsdos_inode2entry (olddir,oldinode,&entry); if (ret == 0){ PRINTK (("umsdos_link :%s: ino %d flags %d " ,entry.name ,oldinode->i_ino,entry.flags)); if (!(entry.flags & UMSDOS_HIDDEN)){ /* #Specification: hard link / first hard link The first time a hard link is done on a file, this file must be renamed and hidden. Then an internal symbolic link must be done on the hidden file. The second link is done after on this hidden file. It is expected that the Linux MSDOS file system keeps the same pseudo inode when a rename operation is done on a file in the same directory. */ struct umsdos_info info; ret = umsdos_newhidden (olddir,&info); if (ret == 0){ olddir->i_count+=2; PRINTK (("olddir[%d] ",olddir->i_count)); ret = umsdos_rename_f (olddir,entry.name ,entry.name_len ,olddir,info.entry.name,info.entry.name_len ,UMSDOS_HIDDEN); if (ret == 0){ char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); if (path == NULL){ ret = -ENOMEM; }else{ PRINTK (("olddir[%d] ",olddir->i_count)); ret = umsdos_locate_path (oldinode,path); PRINTK (("olddir[%d] ",olddir->i_count)); if (ret == 0){ olddir->i_count++; ret = umsdos_symlink_x (olddir ,entry.name ,entry.name_len,path ,S_IFREG|0777,UMSDOS_HLINK); if (ret == 0){ dir->i_count++; ret = umsdos_symlink_x (dir,name,len ,path ,S_IFREG|0777,UMSDOS_HLINK); } } kfree (path); } } } }else{ char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL); if (path == NULL){ ret = -ENOMEM; }else{ ret = umsdos_locate_path (oldinode,path); if (ret == 0){ dir->i_count++; ret = umsdos_symlink_x (dir,name,len,path ,S_IFREG|0777,UMSDOS_HLINK); } kfree (path); } } } umsdos_unlockcreate(olddir); umsdos_unlockcreate(dir); } iput (olddir); } if (ret == 0){ struct iattr newattrs; oldinode->i_nlink++; newattrs.ia_valid = 0; ret = UMSDOS_notify_change(oldinode, &newattrs); } iput (oldinode); iput (dir); PRINTK (("umsdos_link %d\n",ret)); return ret;}/* Add a new file into the alternate directory. The file is added to the real MSDOS directory. If successful, it is then added to the EDM file. Return the status of the operation. 0 mean success.*/int UMSDOS_create ( struct inode *dir, const char *name, /* Name of the file to add */ int len, /* Length of the name */ int mode, /* Permission bit + file type ??? */ struct inode **result) /* Will hold the inode of the newly created */ /* file */{ return umsdos_create_any (dir,name,len,mode,0,0,result);}/* Add a sub-directory in a directory*/int UMSDOS_mkdir( struct inode * dir, const char * name, int len, int mode){ int ret = umsdos_nevercreat(dir,name,len,-EEXIST); if (ret == 0){ struct umsdos_info info; ret = umsdos_parse (name,len,&info); PRINTK (("umsdos_mkdir %d\n",ret)); if (ret == 0){ info.entry.mode = mode | S_IFDIR; info.entry.rdev = 0; info.entry.uid = current->fsuid; info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME; info.entry.flags = 0; umsdos_lockcreate(dir); info.entry.nlink = 1; ret = umsdos_newentry (dir,&info); PRINTK (("newentry %d ",ret)); if (ret == 0){ dir->i_count++; ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode); if (ret != 0){ umsdos_delentry (dir,&info,1); /* #Specification: mkdir / Directory already exist in DOS We do the same thing as for file creation. For all user it is an error. */ }else{ /* #Specification: mkdir / umsdos directory / create EMD When we created a new sub-directory in a UMSDOS directory (one with full UMSDOS semantic), we create immediately an EMD file in the new sub-directory so it inherit UMSDOS semantic. */ struct inode *subdir; ret = umsdos_real_lookup (dir,info.fake.fname ,info.fake.len,&subdir); if (ret == 0){ struct inode *result; ret = msdos_create (subdir,UMSDOS_EMD_FILE ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result); subdir = NULL; iput (result); } if (ret < 0){ printk ("UMSDOS: Can't create empty --linux-.---\n"); } iput (subdir); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -