summaryrefslogtreecommitdiffstats
path: root/fs/hfsplus/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/hfsplus/dir.c')
-rw-r--r--fs/hfsplus/dir.c33
1 files changed, 21 insertions, 12 deletions
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 82c223765478..01a6fe3a395c 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -66,21 +66,28 @@ again:
}
cnid = be32_to_cpu(entry.file.id);
if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) &&
- entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR)) {
+ entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
+ (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb).hidden_dir).create_date ||
+ entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode).create_date) &&
+ HFSPLUS_SB(sb).hidden_dir) {
struct qstr str;
char name[32];
if (dentry->d_fsdata) {
- err = -ENOENT;
- inode = NULL;
- goto out;
+ /*
+ * We found a link pointing to another link,
+ * so ignore it and treat it as regular file.
+ */
+ cnid = (unsigned long)dentry->d_fsdata;
+ linkid = 0;
+ } else {
+ dentry->d_fsdata = (void *)(unsigned long)cnid;
+ linkid = be32_to_cpu(entry.file.permissions.dev);
+ str.len = sprintf(name, "iNode%d", linkid);
+ str.name = name;
+ hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str);
+ goto again;
}
- dentry->d_fsdata = (void *)(unsigned long)cnid;
- linkid = be32_to_cpu(entry.file.permissions.dev);
- str.len = sprintf(name, "iNode%d", linkid);
- str.name = name;
- hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str);
- goto again;
} else if (!dentry->d_fsdata)
dentry->d_fsdata = (void *)(unsigned long)cnid;
} else {
@@ -330,7 +337,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
if (res)
return res;
- inode->i_nlink--;
+ if (inode->i_nlink > 0)
+ inode->i_nlink--;
hfsplus_delete_inode(inode);
if (inode->i_ino != cnid && !inode->i_nlink) {
if (!atomic_read(&HFSPLUS_I(inode).opencnt)) {
@@ -339,7 +347,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
hfsplus_delete_inode(inode);
} else
inode->i_flags |= S_DEAD;
- }
+ } else
+ inode->i_nlink = 0;
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);