2009-10-21 16 views
15

¿Cómo se puede crear un nuevo descriptor de archivo a partir de un descriptor de archivo existente para que el nuevo descriptor no comparta la misma estructura/entrada de archivo interno en la tabla de archivos? Específicamente, los atributos como el desplazamiento de archivos (y preferiblemente los permisos, el uso compartido y los modos) no deben compartirse entre los descriptores de archivos nuevo y antiguo.Descriptor de archivo duplicado con su propio desplazamiento de archivo

En Windows y Linux, dup() duplicará el descriptor de archivo, pero ambos descriptores aún apuntan a la misma estructura de archivos en la tabla de archivos del proceso. Cualquier búsqueda en cualquiera de los descriptores también ajustará la posición para los otros descriptores.

Nota

Desde entonces, he recibido respuestas para Windows y Linux y ajustado a la pregunta un poco demasiado a menudo, lo que ha hecho que sea difícil para las personas para responder. Ajustaré mis votos y aceptaré la respuesta más clara que cubre Windows y Linux. Disculpas a todos, todavía soy nuevo en el paradigma SO. ¡Gracias por las buenas respuestas!

Respuesta

12

Básicamente, lo que realmente desea es tener un descriptor de archivo, y básicamente abrir el mismo archivo una y otra vez, para obtener una posición separada, compartir, modo, etc. Y quiere hacer esto en Windows (donde el "descriptor de archivo" es básicamente un objeto extraño, no es algo que se utiliza directamente por el sistema operativo o la biblioteca en tiempo de ejecución en absoluto.

Sorprendentemente, hay es una manera de hacer eso, por lo menos con la EM VC++. Todos los pasos excepto dos usan solo la API de Win32, por lo que portar a otros compiladores/bibliotecas debería ser bastante razonable (creo que la mayoría de las versiones de estas dos funciones). Esas son para convertir un descriptor de archivo de estilo Unix a un Win3 nativo 2 identificador de archivo y conversión de un identificador de archivo Win32 nativo a un descriptor de archivo de estilo Unix.

  1. convierte un archivo descriptor de identificador de archivo nativo con _get_osfhandle()
  2. obtener un nombre para el archivo con GetFileInformationByHandleEx (FILE_NAME_INFO)
  3. Uso CreateFile para abrir un nuevo identificador para ese archivo
  4. crear un descriptor de archivo para que el mango con _open_osfhandle()

Et voilà, tenemos un nuevo descriptor de archivo se refiere anillo al mismo archivo, pero con sus propios permisos, posición, etc.

Hacia el final de su pregunta, lo hace parecer que también quiere los "permisos", pero eso no parece ser real sentido: los permisos se adjuntan al archivo en sí, no a la forma en que se abre el archivo, por lo que abrir o volver a abrir el archivo no tiene ningún efecto en los permisos del archivo. Si realmente quieres saberlo, puedes obtenerlo con GetFileInformationByHandle, pero ten en cuenta que los permisos de archivos en Windows son bastante diferentes de los permisos de archivos (tradicionales) en Unix. Unix tiene permisos de propietario/grupo/mundo en todos los archivos, y la mayoría de los sistemas también tienen ACL (aunque hay más variaciones en cómo funcionan). Windows no tiene permisos en absoluto (por ejemplo, archivos en FAT o FAT32) o usa ACL (por ejemplo, archivos en NTFS), pero nada que sea realmente equivalente a los permisos tradicionales de propietario/grupo/mundo a los que la mayoría de la gente está acostumbrada en Unix.

Quizás esté utilizando "permisos" para referirse a si el archivo estaba abierto para lectura, escritura o ambos. Conseguir eso es considerablemente más feo que cualquiera de los precedentes. El problema es que la mayor parte se encuentra en la biblioteca, no en Win32, por lo que probablemente no haya forma de hacerlo que esté cerca de ser portátil entre los compiladores. Con MS VC++ 9.0 SP1 (no garantizado para cualquier otra compilador) se puede hacer esto:

#include <stdio.h> 

int get_perms(int fd) { 
    int i; 
FILE * base = __iob_func(); 

    for (i=0; i<_IOB_ENTRIES; i++) 
     if (base[i]._file == fd) 
      return base[i]._flag;  // we've found our file 
    return 0; // file wasn't found. 
} 

Dado que este involucrado algún espeleología, escribí una prueba rápida para verificar que realmente podría funcionar:

#ifdef TEST 
#include <io.h> 

void show_perms(int perms, char const *caption) { 
printf("File opened for %s\n", caption); 
printf("Read permission = %d\n", (perms & _IOREAD)!=0); 
printf("Write permission = %d\n", (perms & _IOWRT)!=0); 
} 

int main(int argc, char **argv) { 
FILE *file1, *file2; 
int perms1, perms2; 

file1=fopen(argv[1], "w"); 
perms1 = get_perms(_fileno(file1)); 
fclose(file1); 

file2=fopen(argv[1], "r"); 
perms2 = get_perms(_fileno(file2)); 
fclose(file2); 

show_perms(perms1, "writing"); 
show_perms(perms2, "reading"); 
return 0; 
} 
#endif 

y los resultados parecen indicar el éxito:

File opened for writing 
Read permission = 0 
Write permission = 1 
File opened for reading 
Read permission = 1 
Write permission = 0 

a continuación, puede prueba que volvió bandera contra _IOREAD, _IOWRT y _IORW, que son definido en stdio.h. A pesar de mis advertencias previas, probablemente debería señalar que sospecho (aunque ciertamente no puedo garantizar) que esta parte de la biblioteca es bastante estable, por lo que las posibilidades reales de cambios importantes son probablemente mínimas.

En la otra dirección, sin embargo, básicamente no hay ninguna posibilidad en absoluto que funcione con cualquier otra biblioteca. Es podría (pero ciertamente no se garantiza) para trabajar con los otros compiladores que usan la biblioteca MS, como Intel, MinGW o Comeau utilizando MS VC++ como su back-end. De ellos, yo diría que lo más probable es que sea Comeau, y el MinGW menos probable (pero eso es solo una suposición, hay muchas posibilidades de que no funcione con ninguno de ellos).

  1. requiere el redistribuible Win32 FileID API Library
+0

una gran respuesta. No estaba al tanto de que abrir un archivo impidió su desvinculación o cambio de nombre, incluso si se habilitó el uso compartido completo. esto significa que recuperar el nombre del archivo pertenece a un manejador es perfectamente seguro, ya que no puede cambiar siempre que un descriptor de archivo o 'HANDLE' permanezca abierto a esa ruta. –

+0

¿Cómo puedo hacer lo mismo en Linux? gracias – alaamh

+0

@alaamh: ¿has mirado a través de las otras respuestas? Un par de ellos hablan sobre cómo hacer el mismo tipo de cosas en Linux. –

2

Por lo tanto, recomiendo leer sobre esto un poco más. El dup() y las funciones relacionadas sirven para crear un valor duplicado en la tabla de descriptores de archivos que apunta a la misma entrada en la tabla de archivos abiertos. Esto es previsto para tener el mismo desplazamiento. Si llama al open(), creará una nueva entrada para abrir la tabla de archivos.

No tiene sentido crear un duplicado de un descriptor de archivo y ese nuevo descriptor de archivo tiene un desplazamiento diferente en la tabla de archivos abiertos (esto parece contradecir lo que significa la palabra "duplicado").

No estoy seguro de cuál es su pregunta en realidad. Quiero decir, no es lo mismo que un duplicado. Se podía leer:

/proc/self/fd/[descriptor]

y obtener la cadena que se utiliza para abrir ese descriptor de archivo; tenga en cuenta que esto puede proporcionar algunos escollos, algunos de los cuales usted notó en su observación de llamar nuevamente al open().

Quizás pueda explicar un poco más y puedo intentar actualizar para ayudar.

+0

@BobbyShaftoe, ha reiterado mi pregunta: P El comportamiento de abrir/proc/self/fd/[descriptor] es lo que busco, sin embargo, una forma más portátil y orientada a las llamadas del sistema de hacer esto preferible. –

+1

@Anacrolix, no realmente. Usted lo editó para agregar ese bit allí. :) De todos modos, me temo que no hay tal animal, ciertamente no es una llamada al sistema o realmente portátil y confiable. – BobbyShaftoe

+0

@BobbyShaftoe: es posible que desee observar que la pregunta se ha cambiado a 'Solo Windows', lo cual es totalmente injusto para quienes respondieron la pregunta cuando no existía tal calificación. –

0

¿Por qué no basta con abrir el archivo por segunda vez con open() o CreateFile() en las ventanas? Esto le da toda la libertad de los diferentes derechos de acceso y compensación por separado.

Esto, por supuesto, tiene el inconveniente de que no puede abrir el archivo exclusivamente, pero resuelve su problema de manera muy simple.

+3

Bueno, estoy interesado en "reabrir" dado un identificador de archivo y nada más. En Linux, no se garantiza que el archivo original se haya movido o haya sido desvinculado. En Windows, después de algunas pruebas parece que no se puede manipular una entrada en el sistema de archivos, siempre y cuando alguien tenga un control sobre ella. –

Cuestiones relacionadas