Project

General

Profile

Bug #12142

rmdir on non empty directories triggers FILE_DELETE event even if nothing is deleted

Added by Niclas Rosenvik 10 months ago. Updated 10 months ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
-
Start date:
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:

Description

rmdir on non empty directories triggers FILE_DELETE event even if nothing is deleted.
Here is a test program (test_port.c) for printing events from PORT_SOURCE_FILE.

#include <fcntl.h>
#include <port.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

void print_event(port_event_t *pe);

int
main(int argc, char *argv[])
{

  if (argc != 2) {
    printf("usage: port_test path\n");
    return -1;
  }

  struct stat astat;
  if (stat(argv[1], &astat)){
    perror("stat");
    return -1;
  }
  /* setup file_obj */
  struct file_obj afile_obj;
  afile_obj.fo_atime = astat.st_atim;
  afile_obj.fo_mtime = astat.st_mtim;
  afile_obj.fo_ctime = astat.st_ctim;

  afile_obj.fo_name = argv[1];

  int aport = port_create();
  if (aport == -1) {
    perror("port_create");
    return -1;
  }

  if (port_associate(aport, PORT_SOURCE_FILE,(uintptr_t) &afile_obj, 0, NULL)) {
    perror("port_associate");
    return -1;
  }

  port_event_t pe;
  if (port_get(aport, &pe, NULL)) {
    perror("port_get");
    return -1;
  }

  print_event(&pe);

  return 0;
}

void
print_event(port_event_t *pe)
{
  struct port_event_name {
    char *name;
    int event;
  };

  struct port_event_name penames[11];

  penames[0].name = "FILE_ACCESS";
  penames[0].event = FILE_ACCESS;
  penames[1].name = "FILE_MODIFIED";
  penames[1].event = FILE_MODIFIED;
  penames[2].name = "FILE_ATTRIB";
  penames[2].event = FILE_ATTRIB;
  penames[3].name = "FILE_ACCESS";
  penames[3].event = FILE_ACCESS;
  penames[4].name = "FILE_TRUNC";
  penames[4].event = FILE_TRUNC;
  penames[5].name = "FILE_NOFOLLOW";
  penames[5].event = FILE_NOFOLLOW;
  penames[6].name = "FILE_DELETE";
  penames[6].event = FILE_DELETE;
  penames[7].name = "FILE_RENAME_TO";
  penames[7].event = FILE_RENAME_TO;
  penames[8].name = "FILE_RENAME_FROM";
  penames[8].event = FILE_RENAME_FROM;
  penames[9].name = "UNMOUNTED";
  penames[9].event = UNMOUNTED;
  penames[10].name = "MOUNTEDOVER";
  penames[10].event = MOUNTEDOVER;

  printf("|");
  for (size_t i = 0; i < sizeof(penames)/sizeof(struct port_event_name); ++i) {
    if (pe->portev_events & penames[i].event) {
      printf("%s|", penames[i].name);
    }
  }
  printf("\n");
}

Creating a a directory with a file in it and running the test program:

mkdir /tmp/somedir
touch /tmp/somedir/somefile
./port_test /tmp/somedir

Then running "rmdir /tmp/somedir" results in the output
|FILE_DELETE|

even if the directory was not deleted.
I see this as a bug.

#1

Updated by Gergő Mihály Doma 10 months ago

Can you test this on filesystems other than ZFS?

#2

Updated by Niclas Rosenvik 10 months ago

I tried this on a mounted usb disk with fat32 and it did not occur then.

#3

Updated by John Levon 10 months ago

The cause is pretty simple:

2144 static int                                                                      
2145 zfs_rmdir(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr,                    
2146     caller_context_t *ct, int flags)     

2193         vnevent_rmdir(vp, dvp, name, ct); 

2231         error = zfs_link_destroy(dl, zp, tx, zflg, NULL);                        

So we do the zfs_dirempty() check after sending the event.

The fix might be more complicated though.

Also available in: Atom PDF