anchor.diff:      establish_dataset_attached_to_hardlink/1,
       establish_dataset_attached_to_file_symlink/1,
       establish_dataset_attached_to_dir_symlink/1,
  -    establish_dataset_attached_to_hardlink_and_remove_hardlink/1,
  -    establish_dataset_attached_to_file_symlink_and_remove_symlink/1,
  -    establish_dataset_attached_to_dir_symlink_and_remove_symlink/1,
       detach_and_reattach_dataset/1,
       remove_attached_dataset/1,
       remove_detached_dataset/1,
       remove_file_should_detach_dataset/1,
  +    remove_hardlink_should_detach_dataset/1,
  +    remove_file_symlink_should_detach_dataset/1,
  +    remove_dir_symlink_should_detach_dataset/1,
  +    remove_file_pointed_by_hardlink/1,
  +    remove_file_pointed_by_symlink/1,
  +    remove_dir_pointed_by_symlink/1,
       reattach_if_root_file_is_deleted_should_fail/1,
       remove_detached_dataset_if_root_file_has_already_been_deleted/1,
       establish_dataset_on_not_existing_file_should_fail/1,
  
positive.code:     ?assertNoTopDatasets(P1Node, UserSessIdP1, SpaceId, attached).
  
  
  
  detach_and_reattach_dataset(_Config) ->
      [P1Node] = oct_background:get_provider_nodes(krakow),
      UserSessIdP1 = oct_background:get_user_session_id(user1, krakow),
      SpaceId = oct_background:get_space_id(space1),
      SpaceGuid = fslogic_uuid:spaceid_to_space_dir_guid(SpaceId),
      ProtectionFlags = ?RAND_PROTECTION_FLAGS(),
      {ok, Guid} = lfm_proxy:mkdir(P1Node, UserSessIdP1, SpaceGuid, ?DIR_NAME(), ?DEFAULT_DIR_PERMS),
      {ok, DatasetId} = ?assertMatch({ok, _}, lfm_proxy:establish_dataset(P1Node, UserSessIdP1, {guid, Guid}, ProtectionFlags)),
  
      ?assertAttachedDataset(P1Node, UserSessIdP1, DatasetId, Guid, undefined, ProtectionFlags),
      ?assertDatasetMembership(P1Node, UserSessIdP1, Guid, ?DIRECT_DATASET_MEMBERSHIP, ProtectionFlags),
      ?assertFileEffDatasetSummary(P1Node, UserSessIdP1, Guid, DatasetId, [], ProtectionFlags),
  
      % detach dataset
      detach(P1Node, UserSessIdP1, DatasetId),
  
      {ok, Path} = lfm_proxy:get_file_path(P1Node, UserSessIdP1, Guid),
      ?assertDetachedDataset(P1Node, UserSessIdP1, DatasetId, Guid, undefined, Path, ?DIRECTORY_TYPE, ProtectionFlags),
      ?assertDatasetMembership(P1Node, UserSessIdP1, Guid, ?NONE_DATASET_MEMBERSHIP, ?no_flags_mask),
      ?assertFileEffDatasetSummary(P1Node, UserSessIdP1, Guid, DatasetId, [], ?no_flags_mask),
  
      % reattach dataset
      ?assertMatch(ok, reattach(P1Node, UserSessIdP1, DatasetId)),
  
      ?assertAttachedDataset(P1Node, UserSessIdP1, DatasetId, Guid, undefined, ProtectionFlags),
      ?assertDatasetMembership(P1Node, UserSessIdP1, Guid, ?DIRECT_DATASET_MEMBERSHIP, ProtectionFlags),
      ?assertFileEffDatasetSummary(P1Node, UserSessIdP1, Guid, DatasetId, [], ProtectionFlags).
  
  remove_attached_dataset(_Config) ->
      [P1Node] = oct_background:get_provider_nodes(krakow),
      UserSessIdP1 = oct_background:get_user_session_id(user1, krakow),
      User2SessIdP1 = oct_background:get_user_session_id(user2, krakow),
      UserId2 = oct_background:get_user_id(user2),
      SpaceId = oct_background:get_space_id(space1),
      % assign user2 privilege to manage datasets
      ozw_test_rpc:space_set_user_privileges(SpaceId, UserId2, [?SPACE_MANAGE_DATASETS | privileges:space_member()]),
  
      SpaceId = oct_background:get_space_id(space1),
      SpaceGuid = fslogic_uuid:spaceid_to_space_dir_guid(SpaceId),
      ParentDirName = ?DIR_NAME(),
      DirName = ?DIR_NAME(),
      ProtectionFlags = ?RAND_PROTECTION_FLAGS(),
      {ok, ParentGuid} = lfm_proxy:mkdir(P1Node, User2SessIdP1, SpaceGuid, ParentDirName, ?DEFAULT_DIR_PERMS),
      {ok, Guid} = lfm_proxy:mkdir(P1Node, User2SessIdP1, ParentGuid, DirName, ?DEFAULT_DIR_PERMS),
  
      {ok, DatasetId} = ?assertMatch({ok, _},
          lfm_proxy:establish_dataset(P1Node, User2SessIdP1, {guid, Guid}, ProtectionFlags), ?ATTEMPTS),
  
      ?assertAttachedDataset(P1Node, User2SessIdP1, DatasetId, Guid, undefined, ProtectionFlags),
      ?assertDatasetMembership(P1Node, User2SessIdP1, Guid, ?DIRECT_DATASET_MEMBERSHIP, ProtectionFlags),
      ?assertFileEffDatasetSummary(P1Node, User2SessIdP1, Guid, DatasetId, [], ProtectionFlags),
  
      % traverse permission to file is required to remove attached dataset
      ok = lfm_proxy:set_perms(P1Node, UserSessIdP1, {guid, ParentGuid}, 8#444),
      % user2 should not be able to remove the dataset
      ?assertMatch({error, ?EACCES}, lfm_proxy:remove_dataset(P1Node, User2SessIdP1, DatasetId)),
  
      % revert permissions
      ok = lfm_proxy:set_perms(P1Node, UserSessIdP1, {guid, ParentGuid}, ?DEFAULT_DIR_PERMS),
      % now user2 should be able to remove the dataset
      ?assertMatch(ok, lfm_proxy:remove_dataset(P1Node, User2SessIdP1, DatasetId)),
  
      ?assertNoDataset(P1Node, User2SessIdP1, DatasetId),
      ?assertDatasetMembership(P1Node, User2SessIdP1, Guid, ?NONE_DATASET_MEMBERSHIP, ?no_flags_mask),
      ?assertFileEffDatasetSummary(P1Node, User2SessIdP1, Guid, undefined, [], ?no_flags_mask),
      ?assertNoTopDatasets(P1Node, User2SessIdP1, SpaceId, attached),
      ?assertNoTopDatasets(P1Node, User2SessIdP1, SpaceId, detached).
  
  
  remove_detached_dataset(_Config) ->
      [P1Node] = oct_background:get_provider_nodes(krakow),
      UserSessIdP1 = oct_background:get_user_session_id(user1, krakow),
      User2SessIdP1 = oct_background:get_user_session_id(user2, krakow),
      UserId2 = oct_background:get_user_id(user2),
      % assign user2 privilege to manage datasets
      SpaceId = oct_background:get_space_id(space1),
      ozw_test_rpc:space_set_user_privileges(SpaceId, UserId2, [?SPACE_MANAGE_DATASETS | privileges:space_member()]),
      SpaceGuid = fslogic_uuid:spaceid_to_space_dir_guid(SpaceId),
      DirName = ?DIR_NAME(),
      ParentDirName = ?DIR_NAME(),
      ProtectionFlags = ?RAND_PROTECTION_FLAGS(),
      {ok, ParentGuid} = lfm_proxy:mkdir(P1Node, User2SessIdP1, SpaceGuid, ParentDirName, ?DEFAULT_DIR_PERMS),
      {ok, Guid} = lfm_proxy:mkdir(P1Node, User2SessIdP1, ParentGuid, DirName, ?DEFAULT_DIR_PERMS),
      {ok, Path} = lfm_proxy:get_file_path(P1Node, User2SessIdP1, Guid),
      {ok, DatasetId} = ?assertMatch({ok, _},
          lfm_proxy:establish_dataset(P1Node, User2SessIdP1, {guid, Guid}, ProtectionFlags), ?ATTEMPTS),
      ?assertAttachedDataset(P1Node, User2SessIdP1, DatasetId, Guid, undefined, ProtectionFlags),
      ?assertDatasetMembership(P1Node, User2SessIdP1, Guid, ?DIRECT_DATASET_MEMBERSHIP, ProtectionFlags),
      ?assertFileEffDatasetSummary(P1Node, User2SessIdP1, Guid, DatasetId, [], ProtectionFlags),
  
      ok = detach(P1Node, User2SessIdP1, DatasetId),
      ?assertDetachedDataset(P1Node, User2SessIdP1, DatasetId, Guid, undefined, Path, ?DIRECTORY_TYPE, ProtectionFlags),
      ?assertDatasetMembership(P1Node, User2SessIdP1, Guid, ?NONE_DATASET_MEMBERSHIP, ?no_flags_mask),
      ?assertFileEffDatasetSummary(P1Node, User2SessIdP1, Guid, DatasetId, [], ?no_flags_mask),
  
      % traverse permission to file is NOT required to remove detached dataset
      ok = lfm_proxy:set_perms(P1Node, UserSessIdP1, {guid, ParentGuid}, 8#444),
      % user2 should be able to remove the dataset
      ?assertMatch(ok, lfm_proxy:remove_dataset(P1Node, User2SessIdP1, DatasetId)),
  
      ?assertNoDataset(P1Node, User2SessIdP1, DatasetId),
  
      % revert perms to perform operations on file
      ok = lfm_proxy:set_perms(P1Node, UserSessIdP1, {guid, ParentGuid}, ?DEFAULT_DIR_PERMS),
  
      ?assertDatasetMembership(P1Node, User2SessIdP1, Guid, ?NONE_DATASET_MEMBERSHIP, ?no_flags_mask),
      ?assertFileEffDatasetSummary(P1Node, User2SessIdP1, Guid, undefined, [], ?no_flags_mask),
      ?assertNoTopDatasets(P1Node, User2SessIdP1, SpaceId, attached),
      ?assertNoTopDatasets(P1Node, User2SessIdP1, SpaceId, detached).
  
  remove_file_should_detach_dataset(_Config) ->
      [P1Node] = oct_background:get_provider_nodes(krakow),
      UserSessIdP1 = oct_background:get_user_session_id(user1, krakow),
      SpaceId = oct_background:get_space_id(space1),
      SpaceGuid = fslogic_uuid:spaceid_to_space_dir_guid(SpaceId),
      DirName = ?DIR_NAME(),
      ProtectionFlags = ?METADATA_PROTECTION,
      {ok, Guid} = lfm_proxy:mkdir(P1Node, UserSessIdP1, SpaceGuid, DirName, ?DEFAULT_DIR_PERMS),
      {ok, Path} = lfm_proxy:get_file_path(P1Node, UserSessIdP1, Guid),
      {ok, DatasetId} = ?assertMatch({ok, _}, lfm_proxy:establish_dataset(P1Node, UserSessIdP1, {guid, Guid}, ProtectionFlags)),
  
      ?assertAttachedDataset(P1Node, UserSessIdP1, DatasetId, Guid, undefined, ProtectionFlags),
      ?assertDatasetMembership(P1Node, UserSessIdP1, Guid, ?DIRECT_DATASET_MEMBERSHIP, ProtectionFlags),
      ?assertFileEffDatasetSummary(P1Node, UserSessIdP1, Guid, DatasetId, [], ProtectionFlags),
  
      ok = lfm_proxy:unlink(P1Node, UserSessIdP1, {guid, Guid}),
  
      ?assertDetachedDataset(P1Node, UserSessIdP1, DatasetId, Guid, undefined, Path, ?DIRECTORY_TYPE, ProtectionFlags),
      ?assertMatch({error, ?ENOENT}, lfm_proxy:get_details(P1Node, UserSessIdP1, {guid, Guid})),
      ?assertMatch({error, ?ENOENT}, lfm_proxy:get_file_eff_dataset_summary(P1Node, UserSessIdP1, {guid, Guid})),
      ?assertNoTopDatasets(P1Node, UserSessIdP1, SpaceId, attached).
  
  reattach_if_root_file_is_deleted_should_fail(_Config) ->
      [P1Node] = oct_background:get_provider_nodes(krakow),
  
negative.code:     ?assertFileEffDatasetSummary(P1Node, UserSessIdP1, FileGuid, undefined, [], ?no_flags_mask),
      % delete symlink, dataset should be detached
      lfm_proxy:unlink(P1Node, UserSessIdP1, {guid, LinkGuid}),
      ?assertDetachedDataset(P1Node, UserSessIdP1, DatasetId, FileGuid, undefined, LinkPath, ?DIRECTORY_TYPE, ProtectionFlags),
      ?assertMatch({error, ?ENOENT}, lfm_proxy:get_details(P1Node, UserSessIdP1, {guid, LinkGuid})),
      ?assertMatch({error, ?ENOENT}, lfm_proxy:get_file_eff_dataset_summary(P1Node, UserSessIdP1, {guid, LinkGuid})),
      ?assertNoTopDatasets(P1Node, UserSessIdP1, SpaceId, attached).
  
  
  remove_dir_symlink_should_detach_dataset(_Config) ->
      [P1Node] = oct_background:get_provider_nodes(krakow),
      UserSessIdP1 = oct_background:get_user_session_id(user1, krakow),
      SpaceId = oct_background:get_space_id(space1),
  