Whamcloud - gitweb
LU-11446 e2fsck: check trusted.link when fixing nlink
[tools/e2fsprogs.git] / lib / ext2fs / unlink.c
index 03825c4..3ec04cf 100644 (file)
@@ -1,14 +1,15 @@
 /*
  * unlink.c --- delete links in a ext2fs directory
- * 
+ *
  * Copyright (C) 1993, 1994, 1997 Theodore Ts'o.
  *
  * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
  * %End-Header%
  */
 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #if HAVE_UNISTD_H
@@ -23,29 +24,43 @@ struct link_struct  {
        int             namelen;
        ext2_ino_t      inode;
        int             flags;
+       struct ext2_dir_entry *prev;
        int             done;
-};     
+};
 
 #ifdef __TURBOC__
  #pragma argsused
 #endif
 static int unlink_proc(struct ext2_dir_entry *dirent,
                     int        offset,
-                    int        blocksize,
-                    char       *buf,
+                    int        blocksize EXT2FS_ATTR((unused)),
+                    char       *buf EXT2FS_ATTR((unused)),
                     void       *priv_data)
 {
        struct link_struct *ls = (struct link_struct *) priv_data;
+       struct ext2_dir_entry *prev;
+
+       prev = ls->prev;
+       ls->prev = dirent;
 
-       if (ls->name && ((dirent->name_len & 0xFF) != ls->namelen))
-               return 0;
-       if (ls->name && strncmp(ls->name, dirent->name,
-                               dirent->name_len & 0xFF))
-               return 0;
-       if (ls->inode && (dirent->inode != ls->inode))
-               return 0;
+       if (ls->name) {
+               if (ext2fs_dirent_name_len(dirent) != ls->namelen)
+                       return 0;
+               if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent)))
+                       return 0;
+       }
+       if (!(ls->flags & EXT2FS_UNLINK_FORCE) && ls->inode) {
+               if (dirent->inode != ls->inode)
+                       return 0;
+       } else {
+               if (!dirent->inode)
+                       return 0;
+       }
 
-       dirent->inode = 0;
+       if (offset)
+               prev->rec_len += dirent->rec_len;
+       else
+               dirent->inode = 0;
        ls->done++;
        return DIRENT_ABORT|DIRENT_CHANGED;
 }
@@ -62,16 +77,21 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+       if (!name && !ino)
+               return EXT2_ET_INVALID_ARGUMENT;
+
        if (!(fs->flags & EXT2_FLAG_RW))
                return EXT2_ET_RO_FILSYS;
 
        ls.name = name;
        ls.namelen = name ? strlen(name) : 0;
        ls.inode = ino;
-       ls.flags = 0;
+       ls.flags = flags;
        ls.done = 0;
+       ls.prev = 0;
 
-       retval = ext2fs_dir_iterate(fs, dir, 0, 0, unlink_proc, &ls);
+       retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
+                                   0, unlink_proc, &ls);
        if (retval)
                return retval;