sisoputnfrba / foro

Foro de consultas para el trabajo práctico
151 stars 7 forks source link

Duda escribir archivo #2744

Closed matiasrizzatobusta closed 2 years ago

matiasrizzatobusta commented 2 years ago

Hola buenos dias, con mi equipo estamos teniendo un problema al querer escribir en un archivo de swap. La funcion que tenemos funcionaba bien cuando el archivo se creaba dentro de la carpeta memoria, pero cuando quisimos escribir en un archivo dentro de la carpeta swap no estaria andando bien. Lo unico que cambiamos fue lo que recibia la funcion escribir, ya que antes solo le pasabamos el nombre del archivo y ahora un path.

void crear_archivo(char *nuevo_archivo)
{
    char *ruta_final= string_new();

    string_append(&ruta_final, "/home/utnso/swap/");
    string_append(&ruta_final, nuevo_archivo);
    struct stat st = {0};

    if (stat("/home/utnso/swap", &st) == -1) { //poner ruta a la carpeta donde se vana crear los archivos .swap

         mkdir("/home/utnso/swap/", 0700);
         printf("created directory swap successfully! \n");

     }
    if (!verificar_archivo(nuevo_archivo))
     {
         FILE *archivo = fopen(ruta_final, "w+");
         //w+ es para que sea de lectura escritura.si queremos escribir y leer en binario cambiarlo a wb+
         fclose(archivo);
     }
     else
     {
         //error_show("El directorio: %s ya existe\n", ruta_archivo);
     }
     free(ruta_final);
}
char* pasar_a_char(uint32_t num){

    char* terminacion = ".swap";
    //char* str;

    //char* num_char = my_itoa(num,str);
    char* num_char = itoa(num);

    char* nuevo_path = strcat(num_char,terminacion);

    //log_warning(log_memoria,"El nuevo path es: %s",nuevo_path);

    return nuevo_path;
}

void escribir_swap(char* filepath,char* text ,int pagina,int offset){

     printf("Will write text '%s'\n", text);

        int fd = open(filepath, O_RDWR | O_CREAT, (mode_t)0600);

        if (fd == -1)
        {
            perror("Error opening file for writing");
            exit(EXIT_FAILURE);
        }

        ftruncate(fd,0);
        ftruncate(fd,tam_swap);

        // Stretch the file size to the size of the (mmapped) array of char

        size_t textsize = strlen(text) + 1; // + \0 null character

        if (lseek(fd, textsize-1, SEEK_SET) == -1)
        {
            close(fd);
            perror("Error calling lseek() to 'stretch' the file");
            exit(EXIT_FAILURE);
        }

        if (write(fd, "", 1) == -1)
        {
            close(fd);
            perror("Error writing last byte of the file");
            exit(EXIT_FAILURE);
        }

        // Now the file is ready to be mmapped.

        char *map = mmap(NULL, tam_swap, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED , fd, 0);
        if (map == MAP_FAILED)
        {
            close(fd);
            perror("Error mmapping the file");
            exit(EXIT_FAILURE);
        }

        memcpy(map +pagina*tam_pagina +offset,text,textsize);

        // Write it now to disk
        if (msync(map, textsize, MS_SYNC) == -1)
        {
            perror("Could not sync the file to disk");
        }
        printf("direccion pagina 1: %p\n",map);

        // Don't forget to free the mmapped memory
        if (munmap(map, tam_swap) == -1)
        {
            close(fd);
            perror("Error un-mmapping the file");
            exit(EXIT_FAILURE);
        }

        // Un-mmaping doesn't close the file, so we still need to do that.
        close(fd);

}
RaniAgus commented 2 years ago

¡Buenas! Si funcionaba bien en una carpeta y no en otra tiene toda la pinta de ser un problema de permisos. Pueden probar de cambiar el segundo parámetro de mkdir() por 775 (o sea, rwxrwxr-x).

Por otro lado, veo que escribir_swap() escribe un char*: tengan cuidado porque si en alguna parte de esa página que van a mandar a swap hay un byte seteado en 0x00 (o sea, '\0') la escritura va a cortar ahí porque strlen() va leyendo hasta encontrar ese byte.

Saludos

matiasrizzatobusta commented 2 years ago

ahi corregimos lo de escribir, pusimos como

void escribir_swap(char* filepath,char* text ,int pagina,int offset){

    FILE *file = fopen(filepath, "rb+");

    int desp = pagina * tamanio_paginas + offset;

    fseek(file, desp, SEEK_SET);

    fwrite(text, sizeof(text), 1, file);

    fclose(file);

}

en cuanto a los permisos, ahi probe cambiarlo a 775 pero sigo teniendo problemas. La consola de memoria me tira lo siguiente:

[DEBUG] 11:28:15:919 memoria/(9799:9825): El tam del proceso recbido por kernel es: 2048
[DEBUG] 11:28:15:919 memoria/(9799:9825): El float es: 8.000000
[DEBUG] 11:28:15:919 memoria/(9799:9825): El size de la lista de paginas del proceso es: 8
[DEBUG] 11:28:15:919 memoria/(9799:9825): El size de la lista de tablas de 2do nivel es 2
[DEBUG] 11:28:15:919 memoria/(9799:9825): El size de la tabla de primer nivel es: 2
[TRACE] 11:28:15:919 memoria/(9799:9825): envie el inice a kernel 0
Segmentation fault (core dumped)
RaniAgus commented 2 years ago

Desde este lado de la pantalla es difícil adivinar en qué línea se puede llegar a producir el Segmentation fault (core dumped) solo con un log 😕

Para ayudarnos a ayudarte, ¿probaron de usar el debugger para monitorear las variables línea por línea hasta saber dónde rompe?

También les puede ser útil Valgrind, una herramienta que permite detectar errores de manejo de memoria (uso variables sin inicializar, memory leaks, etc). Pueden revisar esta guía y esta charla para guiarse sobre cómo usarla.

Saludos

matiasrizzatobusta commented 2 years ago

Probe hacerme un entorno controlado y probar las funciones ahi y ahi cuando pongo al directorio con los permisos 775 me crea, escribe y lee el archivo bien. Pero cuando lo paso al tp por algun motivo si no creo la carpeta swap a mano ni si quiera me crea el archivo Si la creo a mano yo antes de correr las pruebas, el primer archivo se crea pero no se escribe nada y vuelve a tirar seg fault

RaniAgus commented 2 years ago

Les recomiendo revisar con perror los valores de retorno de las funciones mkdir, fopen, fseek, etc:

FILE *file = fopen(filepath, "rb+");
if (file == NULL) {
    perror("fopen");
}

if (fseek(file, desp, SEEK_SET) == -1) {
    perror("fseek");
}

// y así...

Para saber qué valores de retorno son de error, pueden buscar en los manuales oficiales ejecutando desde la consola man [funcion] (ej: man fopen) y scrolleando hasta la sección "Return value". También los pueden encontrar, por ejemplo, en esta página.

También más allá de probarlo en un entorno controlado, estaría bueno que lo puedan probar en el TP usando el debugger y Valgrind como les comenté más arriba.

Saludos