unlocker temporales reciclaje que por permanentemente papelera los eliminar duro disco dela dejan definitivamente completo como comando carpeta borrar archivos c winapi ntfs createfile

reciclaje - eliminar archivos temporales de cpanel



Eliminar un archivo basado en la identificación del disco (4)

¿Has examinado FILE_FLAG_POSIX_SEMANTICS? Le permitirá abrir archivos que difieren solo en caso de usar CreateFile .

Editar: Supongo que debería haber leído tu código primero porque veo que estás usando dicha bandera.

Como se describe aquí , el uso de SetFileInformationByHandle con FILE_DISPOSITION_INFO permite establecer un archivo con un código abierto que se eliminará cuando se cierren todos los identificadores.

Sin embargo, estoy tratando de eliminar un archivo basado en su índice de archivo (ID de disco) recuperado por FILE_DISPOSITION_INFO y OpenFileById para eliminar de manera segura los archivos / directorios en un directorio que difieren solo en el caso. Esto es seguro de hacer en mi caso de uso, ya que en un sistema NTFS, los índices de archivo son persistentes hasta su eliminación , negando el uso de ReplaceFile , que maneja la base de código actual.

Sin embargo, cuando intento eliminar el identificador, obtengo el error 87 ( ERROR_INVALID_PARAMETER ). Si elimino utilizando un identificador creado con CreateFileW , no encuentro ningún problema. No puedo hacer esto, sin embargo, ya que Windows no podrá distinguir entre dos archivos / carpetas del mismo caso, aunque NTFS sí.

También soy consciente de que existe una ambigüedad con los archivos con OpenFileById abiertos con OpenFileById , ya que los archivos con OpenFileById comparten el mismo ID de disco. El problema de los archivos enlazados se puede considerar irrelevante para este escenario. Solo borraré directorios por ID, que no se puede vincular.

¿Hay algún parámetro o configuración que me falta en mi llamada a OpenFileById ? De alguna manera, en mi llamada SetFileInformationByHandle ?

Métodos adicionales que he probado:

  • Llamar a DuplicateHandle con el manejador OpenFileById , proporcionando DELETE para dwDesiredAccess y usando eso. Mismo resultado ERROR_INVALID_PARAMETER .
  • Usando ReOpenFile con el manejador OpenFileById , proporcionando DELETE para dwDesiredAccess , y usando eso. Mismo resultado ERROR_INVALID_PARAMETER .
  • Utilizando ReOpenFile con el manejador OpenFileById , proporcionando DELETE para dwDesiredAccess y proporcionando el indicador FILE_FLAG_DELETE_ON_CLOSE . No se proporciona ningún error, pero el archivo permanece después de que se cierran todos los identificadores.

Aquí hay un ejemplo mínimo, pero completo, que reproduce el problema:

#include <stdio.h> #include <sys/stat.h> #include <Windows.h> DWORD getFileID(LPCWSTR path, LARGE_INTEGER *id) { HANDLE h = CreateFileW(path, 0, 0, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, 0); if (h == INVALID_HANDLE_VALUE) return GetLastError(); BY_HANDLE_FILE_INFORMATION info; if (!GetFileInformationByHandle(h, &info)) { DWORD err = GetLastError(); CloseHandle(h); return err; } id->HighPart = info.nFileIndexHigh; id->LowPart = info.nFileIndexLow; CloseHandle(h); return ERROR_SUCCESS; } DWORD deleteFileHandle(HANDLE fileHandle) { FILE_DISPOSITION_INFO info; info.DeleteFileW = TRUE; if (!SetFileInformationByHandle( fileHandle, FileDispositionInfo, &info, sizeof(info))) { return GetLastError(); } return ERROR_SUCCESS; } int wmain(DWORD argc, LPWSTR argv[]) { if (argc != 3) { fwprintf(stderr, L"Arguments: <rootpath> <path>/n"); return 1; } DWORD err; HANDLE rootHandle = CreateFileW( argv[1], 0, 0, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, 0); if (rootHandle == INVALID_HANDLE_VALUE) { err = GetLastError(); fwprintf(stderr, L"Could not open root directory ''%s'', error code %d/n", argv[1], err); return err; } LARGE_INTEGER fileID; err = getFileID(argv[2], &fileID); if (err != ERROR_SUCCESS) { fwprintf(stderr, L"Could not get file ID of file/directory ''%s'', error code %d/n", argv[2], err); CloseHandle(rootHandle); return err; } fwprintf(stdout, L"The file ID of ''%s'' is %lld/n", argv[2], fileID.QuadPart); FILE_ID_DESCRIPTOR idStruct; idStruct.Type = FileIdType; idStruct.FileId = fileID; HANDLE fileHandle = OpenFileById( rootHandle, &idStruct, DELETE, FILE_SHARE_DELETE, 0, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); if (fileHandle == INVALID_HANDLE_VALUE) { err = GetLastError(); CloseHandle(rootHandle); fwprintf(stderr, L"Could not open file by ID %lld, error code %d/n", fileID.QuadPart, err); return err; } err = deleteFileHandle(fileHandle); if (err != ERROR_SUCCESS) { fwprintf(stderr, L"Could not delete file by ID ''%lld'', error code %d/n", fileID.QuadPart, err); } CloseHandle(fileHandle); struct _stat _tmp; fwprintf(stdout, L"File was %ssuccessfully deleted/n", (_wstat(argv[2], &_tmp) == 0) ? L"not " : L""); CloseHandle(rootHandle); return err; }

Cualquier solución debe funcionar con Vista y superior. Sugerencias para mejorar el código también son bienvenidas.


Hay una versión en modo de usuario del modo kernel ZwCreateFile llamado NTCreteFile que, entre otras cosas, le dará todos los derechos de acceso que no puede obtener con OpenFileById (pero puede obtenerlo con CreateFile ). Puede hacer todo lo que CreateFile puede hacer y más. Por ejemplo, incluso puede crear directorios.

La parte buena es que hay una forma POBJECT_ATTRIBUTES (pero entretenida) de especificar un ID de archivo en el argumento POBJECT_ATTRIBUTES también, para que obtengas el mejor de todos los mundos ... excepto que es una API aún más incómoda de llamar que tu ejecución API torpes de Windows.

Hay dos versiones de la documentación. Uno en:

https://msdn.microsoft.com/en-us/library/bb432380(v=vs.85).aspx

y uno en:

https://msdn.microsoft.com/en-us/library/windows/hardware/ff556465(v=vs.85).aspx

... que enlaza a la documentación de ZwCreateFile en:

https://msdn.microsoft.com/en-us/library/windows/hardware/ff566424(v=vs.85).aspx

La razón por la que señalo esto es que el primer artículo omite algunas de las cosas buenas (como abrir archivos por ID) que están documentadas en el último artículo. He encontrado que esto es común y también he descubierto que la mayoría de la funcionalidad Zw xxx documentada realmente existe en las funciones NT xxx equivalentes pero documentadas de forma incompleta. Así que tienes que mantener la boca perfecta para obtener la funcionalidad requerida.


Para hacer que FILE_DISPOSITION_INFO funcione, debe especificar el acceso DELETE en la función CreateFile como se informa en https://msdn.microsoft.com/en-us/library/windows/desktop/aa365539(v=VS.85).aspx :

Debe especificar indicadores de acceso apropiados al crear el identificador de archivo para usar con SetFileInformationByHandle. Por ejemplo, si la aplicación está utilizando FILE_DISPOSITION_INFO con el miembro DeleteFile establecido en TRUE, el archivo necesitaría DELETE el acceso solicitado en la llamada a la función CreateFile. Para ver un ejemplo de esto, consulte la sección Código de ejemplo. Para obtener más información acerca de los permisos de archivos, vea Seguridad de archivos y Derechos de acceso. Es decir

//... HANDLE hFile = CreateFile( TEXT("tempfile"), GENERIC_READ | GENERIC_WRITE | DELETE, //Specify DELETE access! 0 /* exclusive access */, NULL, CREATE_ALWAYS, 0, NULL);

Pero parece que un identificador creado con OpenFileById() no se puede usar porque la función no puede aceptar el indicador DELETE .
Desde https://msdn.microsoft.com/en-us/library/windows/desktop/aa365432(v=vs.85).aspx en OpenFileById() se puede leer: dwDesired

Acceso [en]
El acceso al objeto. El acceso se puede leer, escribir o ambos.

Incluso al configurar DELETE o GENERIC_ALL la función falla.
Si reemplaza el identificador pasado a SetFileInformationByHandle con uno creado con la función CreateFile que tiene el indicador DELETE establecido, como se SetFileInformationByHandle anteriormente, funciona.


Suponga que los archivos son XXX y xxx y desea eliminar XXX.

  1. MoveFile ("XXX", "Creo que es XXX")
  2. Si se cambió el nombre de XXX, DeleteFile ("Creo que es XXX")
  3. De lo contrario, DeleteFile ("XXX"); MoveFile ("Creo que es XXX", "xxx")

En cuanto a OpenFileById, como ha observado, existe una posible ambigüedad con un archivo con varios nombres (también conocidos como enlaces duros). Permitir el acceso DELETE podría causar estragos con esto, con un nombre inesperado que se eliminaría (si se dejara en el sistema de archivos para seleccionar cuál). Sospecho que optaron por el simple caso de no permitir el acceso a DELETE.

Un argumento similar podría hacerse para permitir enlaces duros a directorios. Claro, podrías hacerlo algunas veces correctamente, pero una vez que creaste un ciclo, las cosas se ponen mucho más difíciles ...