помощник rsync в программе C

Привет, ребята, как дела ?? Я только что закончил создание вспомогательной программы rsync, которая считывает его файл конфигурации с помощью программы, которую я также создал, и удаляет некоторые каталоги кеша, которые я включил в файл конфигурации, а также несколько команд для очистки системы, затем он создает каталог на моем жестком диске с дата сегодня и начинает резервное копирование системы. Для этого инструмента я использовал C, я знаю, что это может показаться странным выбором для программы-оболочки, написанной на C, но, по правде говоря, мне нравится создавать инструменты на C, поэтому я не знаю, что насчет вас, ребята, но я думаю, что результаты не Плохо. Итак, вот код:

  1. errors.h
#ifndef ERRORS_H
#define ERRORS_H

void handle_files_error(const char *, char *);
int check_input_size(int, int);
void handle_general_error(const char *);
void handle_strstr_error(const char *);

#endif
  1. errors.c
/*
*This header is for handling errors 
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "errors.h"

/*
*This function will handle errors that occurres 
*while managing files and prints the right message.
*/
void handle_files_error(const char *message, char *file_path) {
    char full_message[300];

    if(check_input_size(sizeof(full_message), strlen(message)+strlen(file_path))) { //Check the final full_message size
        fprintf(stderr, "The size of the inserted string in errors.c -> handle_files_error is invalid.n"); 
        exit(EXIT_FAILURE);
    }
    strcpy(full_message, message);
    strcat(full_message, file_path);
    perror(full_message);
    exit(EXIT_FAILURE);
}

/*
*This function will check if the size of the input is 
*valid and can fit in the array without overflowing it.
*0 for valid, 1 otherwise.
*/
int check_input_size(int valid_size, int input_size) {
    if(input_size < valid_size)
        return 0;
    else 
        return 1;
}

/*
*This function will handle general errors and display 
*the relevant message.
*/
void handle_general_error(const char *message) {
    fprintf(stderr, "%sn", message);
    exit(EXIT_FAILURE);
}

/*
*This function will handle errors for the strstr() function 
*and it will display the write message if a string wasnt found.
*/
void handle_strstr_error(const char *serched_str) {
    fprintf(stderr, "Error occurred while serching for unit : %s.n", serched_str);
}
  1. config_man.h
#ifndef CONFIG_MAN_H
#define CONFIG_MAN_H

int check_file_existence(char *);
void create_config_file(char *, const char*);
void write_config_unit(char *, const char *, const char *);
char *read_config_unit(char *, const char *);
int check_unit_existence(const char *, char *);
void read_reg_syntax(char *, char *, int);
int read_list_syntax(char *, char *, int);

#endif
  1. config_man.c
/*
*This header contains all required functions to manage configuration files.
*/ 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "errors.h" //Header for error handling
#include "config_man.h"

/*
*The function will check if the given file in the 
*file path exists. It retruns 1 for yes and 0 for no.
*/
int check_file_existence(char *file_path) {
    FILE *fp;

    fp = fopen(file_path, "r");
    if(fp == NULL) //if file doesnt exists 
        return 0;
    fclose(fp);
    return 1;
}

/*
*A function to create a configuration file with the given path.
*Then it'll write a comentted discription and instruction for this file.
*/ 
void create_config_file(char *file_path, const char *description) {
    FILE *fp;
    const char *config_instruct = {
        "################################################################n"
        "#--------------------------------------------------------------#n"
        "#                        [Instructions]                        #n"
        "#--------------------------------------------------------------#n"
        "################################################################n"
        "# Please it's very important to make sure there are 3 charact- #n"
        "# ers between the unit name and its configurations.            #n"
        "# For example:                                                 #n"
        "#                                                              #n"
        "# UnitName = configurations                                    #n"
        "#                                                              #n"
        "# As you can see there are 3 characters between the unit name  #n"
        "# and the configurations (2 spaces and an equal sign). Be awa- #n"
        "# re that each new line terminates the unit's configurations.  #n"
        "# If the unit's configurations are too long you can put it in- #n"
        "# side a pair of braces and make it a list. For example:       #n"
        "#                                                              #n"
        "# VeryLongUnit = {                                             #n"
        "#    config_1                                                  #n"
        "#    config_2                                                  #n"
        "#    config_3                                                  #n"
        "#    config_4                                                  #n"
        "# }  <- Don't forget to close the list                         #n"
        "#                                                              #n"
        "# If the list is group of commands you can add '&&' to the end #n"
        "# of each line. If the command requires root privileges you    #n"
        "# can just add sudo to the command. For example:               #n"
        "#                                                              #n"
        "# CommandsUnit = {                                             #n"
        "#    command 1 &&                                              #n"
        "#    sudo root_command 2 &&                                    #n"
        "#    command 3 &&                                              #n"
        "#    sudo root_command 3 &&                                    #n"
        "#    command 4                                                 #n"
        "# }                                                            #n"
        "#                                                              #n"
        "# Be aware that every new line in the list syntax is converted #n"
        "# into a space, and '}' terminates the list.                   #n"
        "# Note: Please if you want to use indention for the list, only #n"
        "# use tabs, becuase they are ignored while reading a list.     #n"
        "# Lastly as you can see hashes ("https://codereview.stackexchange.com/questions/257190/#") are ignored.              #n"
        "# By the way, sorry for the hard syntax I really tried to make #n"
        "# as easy as I can and that's the result. I hope you like it :)#n"
        "################################################################n"
    };

    fp = fopen(file_path, "w");
    if(fp == NULL) //Check if error occurred
        handle_files_error("An error occurred in create_config_file() while creating ", file_path);
    fprintf(fp, "%sn", description);
    fprintf(fp, "%sn", config_instruct);
    fclose(fp);
}

/*
*This function takes a unit name and a description then it'll 
*write the description to it so youll know how to configure it.
*/
void write_config_unit(char *file_path, const char *unit_name, const char *unit_desc) {
    FILE *fp;

    fp = fopen(file_path, "a");
    if(fp == NULL) //Check if error occurred
        handle_files_error("An error occurred in write_config_unit() while opening ", file_path);
    fprintf(fp, "%s", unit_name);
    fprintf(fp, "%s", " = ");
    fprintf(fp, "%sn", unit_desc);
    fclose(fp); 
}

/*
*This function will read all the config file, it'll
*ignore every commented line (with "https://codereview.stackexchange.com/questions/257190/#"), it will search 
*for the desired unit's confgis. If the unit exists it will 
*return a pointer to it, otherwise it will return NULL.
*/
char *read_config_unit(char *file_path, const char *unit_name) {
    FILE *fp;
    char unit_buffer[400]; //Buffer for the unit name and its configs 
    char *configs_beginning; //Pointer to the targeted unit's configs beginning
    static char read_configs[500]; //Array for the read configs
    unsigned int config_status = 0; //1 = list, 0 = one line configurations

    fp = fopen(file_path, "r");
    if(fp == NULL) //Check if error occurred
        handle_files_error("An error occurred in read_config_file() while reading ", file_path);
    memset(read_configs, ' ', sizeof(read_configs)); //Make sure the static array is empty 
    //Loop in the file's content 
    while(fgets(unit_buffer, 400, fp) != NULL) { 
        //If the beginning of a line is commented or empty
        if(*unit_buffer=="https://codereview.stackexchange.com/questions/257190/#" || *unit_buffer=='n' || *unit_buffer==' ') 
            continue; //Ignore and read next line
        if(config_status) { //If list was found
            if(read_list_syntax(unit_buffer, read_configs, sizeof(read_configs))) //If reading list
                continue; //read the next line of the list
            fclose(fp);
            return read_configs;
        }
        else {
            if(check_unit_existence(unit_name, unit_buffer))  //If unit wasnt found in line
                continue; //Read the next one 
            /*The address of the beginning of the unit's configurations =
            beginning of the line + len of the unit name + 3 bytes (2 spaces and '=' sign)*/
            configs_beginning = unit_buffer + strlen(unit_name) + 3;
            if(*(configs_beginning) == '{') { //If unit configs is beginning of a list
                config_status = 1;
                continue; 
            }
            else {
                read_reg_syntax(configs_beginning, read_configs, sizeof(read_configs));
                fclose(fp);
                return read_configs;
            }
        }
    }

    fclose(fp);
    return NULL;
}

/*
*This function reads the regular configurations syntax,
*Then passes it to the config_buffer.
*/
void read_reg_syntax(char *config_beginning, char *configs_buffer, int buffer_size) {
    int i = 0;

    while(1) 
        switch(config_beginning[i]) {
            case 'n':
                configs_buffer[i] = ' '; //teminate line
                return; //exit
            case ' ': //Line is terminated
                return; //exit
            default:
                //Check for overflow
                if(check_input_size(buffer_size, i+1)) {
                    fprintf(stderr, "The size of the inserted string in config_man.c -> read_reg_syntax is invalid.n");
                    exit(EXIT_FAILURE);
                }
                //insert char into the configs_buffer
                configs_buffer[i] = config_beginning[i];
                i++;
                break;
            }
}

/*
*This function will read the syntax of a list, if finished reading itll 
*return 0, if still reading it will return 1 to read the next line.
*/
int read_list_syntax(char *line_beginning, char *configs_buffer, int buffer_size) {
    int char_cnt, i;

    char_cnt = strlen(configs_buffer); //number of characters in configs_buffer
    i = 0;  
    while(1) { //Loop and read line until reaching 'n' or ';'
        switch(line_beginning[i]) {
            case '}': //If end of list
                configs_buffer[char_cnt] = ' '; //terminate line
                return 0; //Finished reading list
            case 't': //Ignore indention 
                break;
            case 'n': //Convert to one space 
                //Make sure there is no overflow
                if(check_input_size(buffer_size, char_cnt+1)) {
                    fprintf(stderr, "The size of the inserted string in config_man.c -> read_list_syntax is invalid.n");
                    exit(EXIT_FAILURE);
                }
                configs_buffer[char_cnt] = ' ';
                return 1; //Read next line
            default:
                //Make sure there is no overflow
                if(check_input_size(buffer_size, char_cnt+1)) {
                    fprintf(stderr, "The size of the inserted string in config_man.c -> read_list_syntax is invalid.n");
                    exit(EXIT_FAILURE);
                }
                configs_buffer[char_cnt] = line_beginning[i];
                char_cnt++;
                break;
        }
        i++;
    }
}

/*
*This function takes a unit name and pointer to the beginning
*of the unit's line and it then it finds the unit's name which is
*the first word then it checks if the founded unit and the passed 
*one are equal and the same.
*0 = equal, 1 = not equal
*/
int check_unit_existence(const char *unit_name, char *line_begin) {
    unsigned int i;
    char unit_to_check[50]; //Array for the unit name that needs to be checked

    //Get unit name
    for(i=0; line_begin[i]!='n' && line_begin[i]!='t' && line_begin[i]!=' ' && line_begin[i]!=' '; i++) {
        //Make sure there is no overflow
        if(check_input_size(sizeof(unit_to_check), i+1)) {
                    fprintf(stderr, "The size of the inserted string in config_man.c -> check_unit_existence is invalid.n");
                    exit(EXIT_FAILURE);
                } 
        unit_to_check[i] = line_begin[i];
    }
    if(strcmp(unit_name, unit_to_check) == 0) //If equal 
        return 0;
    else //Not equal
        return 1;
}
  1. sys_backup.h
#ifndef SYS_BACKUP_H
#define SYS_BACKUP_H

void delete_dirs(char *);
void get_date(int *);
char *make_backup_dir(char *, int *);
void backup_sys(const char *, char *);

#endif
  1. sys_backup.c
/*
*This program will make some cleaning that you regularly do 
*before the full system backup. And then itll create new dir 
*in your storage device with date, to make the system backup in
*it useng rsync. The program will use system() to connect all the
*command line tools together and automate this process. Lastly 
*its good to note that tho program reads all the commands and 
*your customaized cleaning process from a config file with the 
*following path: ~/.config/sys_backup
*/
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include "config_man.h" //For config files managment 
#include "errors.h" //Error handling header
#include "sys_backup.h"

int main() {
    const char *config_desc = {
        "################################################################n"
        "# This configuration file purposes are to provide to the       #n"
        "# sys_backup.c program the right cleaning process and storage  #n"
        "# device path, customized to your own needs and preferences.   #n"
        "################################################################"
    };
    const char *units_list[] = {
        "DirsToClean", "CleaningCommands", "DevicePath", 
        "RsyncCommand", " "
    };
    const char *units_desc[] = {
        "Dirs path you regularly clean, like some cache dirs",
        "{n"
        "tCommands for cleaning your sysem, like:n"
        "tsudo pacman -Sc (for deleting uninstalled packagesn"
        "tfrom the cache in arch based distros)n"
        "}", 
        "Your storage device path hdd, usb or whatever you use",  
        "sudo rsync -aAXHv --exclude={"/dev/*","/proc/*","/sys/*""
        ","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} / ", 
        " "
    };
    char *config_path = "/.config/sys_backup";
    char config_full_path[60];
    char *home, *configurations, *backup_path;
    int date[3]; //Array for the date of today
    unsigned int i;

    /*Get configuration's file path*/
    home = getenv("HOME"); //Get home path 
    //Check for overflow 
    if(check_input_size(sizeof(config_full_path), strlen(home)+strlen(config_path))) {
        fprintf(stderr, "The size of the inserted string in sys_backup.c -> main() is invalid.n");
        exit(EXIT_FAILURE);
    }
    strcpy(config_full_path, home);
    strcat(config_full_path, config_path);
    
    if(check_file_existence(config_full_path) == 0) { //Check if config file exists
        create_config_file(config_full_path, config_desc);
        for(i=0; *units_desc[i]!=' '; i++)
            write_config_unit(config_full_path, *(units_list+i), *(units_desc+i));
        printf("Please configure the prorgram's config file in the following path: %s.n", config_full_path);
        return 0;
    }
    /*Read the configured units*/
    if((configurations=read_config_unit(config_full_path, units_list[0])) == NULL) { //Unit wasnt found
        handle_strstr_error(units_list[0]);
        exit(EXIT_FAILURE);
    }
    delete_dirs(configurations);
    
    if((configurations=read_config_unit(config_full_path, units_list[1])) == NULL) { //Unit wasnt found
        handle_strstr_error(units_list[1]);
        exit(EXIT_FAILURE);
    }
    system(configurations);
    
    if((configurations=read_config_unit(config_full_path, units_list[2])) == NULL) { //Unit wasnt found
        handle_strstr_error(units_list[2]);
        exit(EXIT_FAILURE);
    }
    get_date(date); //Get the date of today and pass it to the date array
    backup_path = make_backup_dir(configurations, date); //Create backup dir and get its path
    
    if((configurations=read_config_unit(config_full_path, units_list[3])) == NULL) { //Unit wasnt found
        handle_strstr_error(units_list[3]);
        exit(EXIT_FAILURE);
    }
    backup_sys(configurations, backup_path); //Backup system in the created dir
    return 0;
}

/*
*This function will delete the given argument dirs.
*/
void delete_dirs(char *dirs_path) {
    char full_command[700];
    const char *command = "rm -rf ";
    const char *danger_message = {
        "Nice try, but we wont let you destroy your system ;)n"
        "Please make sure that DirsToClean unit is configured properly "
        "and there is no sign of standalone root tree ("/")."
    };
    unsigned int i;

    //Loop in dirs_path yo make sure no one removing the root tree by mistake
    for(i=0; i<strlen(dirs_path); i++)
        if(dirs_path[i]==' ' && dirs_path[i+1]=="https://codereview.stackexchange.com/" && dirs_path[i+2]==' ') {
            fprintf(stderr, "%sn", danger_message);
            exit(EXIT_FAILURE);
        }
    //Check for overflow
    if(check_input_size(sizeof(full_command), strlen(dirs_path)+strlen(command))) {
        fprintf(stderr, "The size of the inserted string in sys_backup.c -> delete_dirs is invalid.n");
        exit(EXIT_FAILURE);
    }
    //Copy command to buffer (rm -rf dirs_path) to delete dirs.
    strcpy(full_command, command);
    strcat(full_command, dirs_path);

    system(full_command); //Execute command
}

/*
*This function will get the date of today, and it'll insert it to the passed date array.
*/
void get_date(int *date) {
    long int sec_since_epoch;
    struct tm current_time, *time_ptr;

    sec_since_epoch = time(0); 
    time_ptr = &current_time; //Set time pointer to the current_time struct
    localtime_r(&sec_since_epoch, time_ptr);

    //Pass today's date to the array 
    *date = time_ptr->tm_mday;
    *(date+1) = time_ptr->tm_mon + 1; //+1 because months range from 0 - 11
    *(date+2) =  time_ptr->tm_year - 100; //-100 because tm_year is number of passed years since 1900
}

/*
*A function that gets pointer to int array that contains the
*date of today and create a backup dir in the passed path 
*passed date. Then it will return the full path of the created dir. 
*/
char *make_backup_dir(char *device_path, int *date_array) {
    char dir_name[10], full_command[200];
    const char *command = "mkdir ";
    static char backup_path[150]; //The returned full backup path 

    //Convert the date_array to a string so will use it to name the dir in the device path
    sprintf(dir_name, "%02d", *date_array);
    sprintf((dir_name+3), "%02d", *(date_array+1));
    sprintf(dir_name, "%02d", *date_array);
    sprintf(dir_name+6, "%d", *(date_array+2));
    dir_name[2] = dir_name[5] = '-';
    //Check for overflow
    if(check_input_size(sizeof(backup_path), strlen(device_path)+strlen(dir_name))) {
        fprintf(stderr, "The size of the inserted string in sys_backup.c -> make_backup_dir is invalid.n");
        exit(EXIT_FAILURE);
    }
    strcpy(backup_path, device_path);
    strcat(backup_path, dir_name); //Complete the full dir path 
    //Check for overflow
    if(check_input_size(sizeof(full_command), strlen(command)+strlen(backup_path))) {
        fprintf(stderr, "The size of the inserted string in sys_backup.c -> make_backup_dir is invalid.n");
        exit(EXIT_FAILURE);
    }
    strcpy(full_command, command); //Insert command to the full_command
    strcat(full_command, backup_path); //Complete the command
    
    system(full_command); //Execute the command 
    return backup_path;
}

/*
*This function will make the full system backup using rsync to the passed dir path.
*/
void backup_sys(const char *command, char *backup_path) {
    char full_command[500];

    /*Prepare command*/
    //Check for overflow
    if(check_input_size(sizeof(full_command), strlen(command)+strlen(backup_path)+sizeof("/"))) {
        fprintf(stderr, "The size of the inserted string in sys_backup.c -> backup_sys is invalid.n");
        exit(EXIT_FAILURE);
    }
    strcpy(full_command, command);
    strcat(full_command, backup_path);
    strcat(full_command, "/");
    
    system(full_command); //Execute the command 
}
  1. Вот пример конфигурации
################################################################
# This configuration file purposes are to provide to the       #
# sys_backup.c program the right cleaning process and storage  #
# device path, customized to your own needs and preferences.   #
################################################################
################################################################
#--------------------------------------------------------------#
#                        [Instructions]                        #
#--------------------------------------------------------------#
################################################################
# Please it's very important to make sure there are 3 charact- #
# ers between the unit name and its configurations.            #
# For example:                                                 #
#                                                              #
# UnitName = configurations                                    #
#                                                              #
# As you can see there are 3 characters between the unit name  #
# and the configurations (2 spaces and an equal sign). Be awa- #
# re that each new line terminates the unit's configurations.  #
# If the unit's configurations are too long you can put it in- #
# side a pair of braces and make it a list. For example:       #
#                                                              #
# VeryLongUnit = {                                             #
#    config_1                                                  #
#    config_2                                                  #
#    config_3                                                  #
#    config_4                                                  #
# }  <- Don't forget to close the list                         #
#                                                              #
# If the list is group of commands you can add '&&' to the end #
# of each line. If the command requires root privileges you    #
# can just add sudo to the command. For example:               #
#                                                              #
# CommandsUnit = {                                             #
#    command 1 &&                                              #
#    sudo root_command 2 &&                                    #
#    command 3 &&                                              #
#    sudo root_command 3 &&                                    #
#    command 4                                                 #
# }                                                            #
#                                                              #
# Be aware that every new line in the list syntax is converted #
# into a space, and '}' terminates the list.                   #
# Note: Please if you want to use indention for the list, only #
# use tabs, becuase they are ignored while reading a list.     #
# Lastly as you can see hashes ("https://codereview.stackexchange.com/questions/257190/#") are ignored.              #
# By the way, sorry for the hard syntax I really tried to make #
# as easy as I can and that's the result. I hope you like it :)#
################################################################

DirsToClean = {
    ~/.cache/spotify
    ~/.cache/mozilla/firefox/9jizeht4.default-release/thumbnails
    ~/.cache/tracker3
    ~/.cache/mozilla/firefox/9jizeht4.default-release/cache2
    ~/.cache/zoom
    ~/.local/share/Trash/files/*
    ~/.cache/torbrowser/download/*
    ~/.cache/yarn
}

CleaningCommands = {
    sudo pacman -Sc &&
    sudo paccache -rk2 &&
    sudo journalctl --vacuum-time=1weeks
}

DevicePath = /run/media/yan/HDD/

#This is the default command which backups all the necessary directories.
#You can of course change it to your needs.
RsyncCommand = sudo rsync -aAXHv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} / 

Я хотел бы получить честные отзывы и отзывы, которые помогут мне улучшить код и, что более важно, мои навыки программирования. Вот ссылка на репозиторий программы, если вам легче ее там прочитать:
https://github.com/yankh764/full-system-backup

Спасибо за любой обзор.

1 ответ
1

Язык

Я знаю, что выбор программы-оболочки, написанной на C, может показаться странным.

Ага, об этом. Для практики нормально; но в целом C не подходит для этой работы. Более абстрактный язык сценариев, такой как Python, купит вам более короткий код с большей безопасностью памяти, большей переносимостью операционной системы и встроенной поддержкой для лучшей обработки альтернативных кодировок символов, локалей и т. Д. И т. Д. И т. Д.

Опечатка

erros.h -> errors.h

serching -> searching

prorgram -> program

Постоянные параметры

void handle_files_error(const char *message, char *file_path) {

должен иметь const перед file_path также.

Усечение вместо отказа

handle_files_error является неприятным последствием использования языка без управления памятью и будет сравнительно тривиальным для языка с управлением памятью. Даже если вы будете придерживаться C, прерывание слишком длинного сообщения будет наименее удобным из ваших вариантов. Вместо этого обрежьте до длины вашего буфера; или еще лучше вообще не иметь буфера и просто fprintf к stderr.

Служебные функции

check_input_size не должно существовать и делает код менее разборчивым, чем простое сравнение длины на месте.

Конфигурация по умолчанию

Весь этот механизм default-config-if-missing:

    if(check_file_existence(config_full_path) == 0) { //Check if config file exists
        create_config_file(config_full_path, config_desc);
        for(i=0; *units_desc[i]!=' '; i++)
            write_config_unit(config_full_path, *(units_list+i), *(units_desc+i));
        printf("Please configure the prorgram's config file in the following path: %s.n", config_full_path);
        return 0;
    }

может уйти. Обычно программы Linux требуют наличия конфигурационного файла, а если его нет, то сразу выходят из строя; или (несколько более сложный) принять набор настроек по умолчанию в памяти. Запись файла конфигурации по умолчанию, если таковой не существует, вызывает удивление.

Неявный указатель на массив

Этот синтаксис немного пугает:

const char *danger_message = {
    "Nice try, but we wont let you destroy your system ;)n"
    "Please make sure that DirsToClean unit is configured properly "
    "and there is no sign of standalone root tree ("/")."
};

Вы используете литерал массива, но затем выгружаете информацию о массиве и сохраняете только указатель. По этой причине снимите фигурные скобки — достаточно одного строкового литерала.

Даты по ссылке

get_date проблематично. Вы предполагаете, что int *date на самом деле представляет собой массив из трех целых чисел. Почему бы просто не передать три отдельных указателя? Таким образом, намерение становится более ясным и явным.

Даже если вы сохранили текущий стиль указателя — чего не следует — назначения массива

*date = time_ptr->tm_mday;
*(date+1) = time_ptr->tm_mon + 1; //+1 because months range from 0 - 11
*(date+2) =  time_ptr->tm_year - 100; //-100 because tm_year is number of passed years since 1900

должен превратиться в

date[0] = time_ptr->tm_mday;
date[1] = time_ptr->tm_mon + 1; //+1 because months range from 0 - 11
date[2] = time_ptr->tm_year - 100; //-100 because tm_year is number of passed years since 1900

Но опять же, это будет однострочный текст на Python.

Повторяется sprintf

Здесь вам нужно избегать ручных смещений:

sprintf(dir_name, "%02d", *date_array);
sprintf((dir_name+3), "%02d", *(date_array+1));
sprintf(dir_name, "%02d", *date_array);
sprintf(dir_name+6, "%d", *(date_array+2));));
dir_name[2] = dir_name[5] = '-';

Вместо,

sprintf(dir_name, "%02d-%02d-%d", date_array[0], date_array[1], date_array[2]);

Безопасность

Существует множество возможностей злоупотребления этой программой. Вы формируете строки командной строки, используя хрупкий стиль ручного смещения памяти в буферах фиксированного размера, а затем передаете это в system. Читать это для аромата. Это рецепт катастрофы.

Вместо того, чтобы обстреливать mkdir например, просто назови это с C.

  • Спасибо за ваш честный отзыв и этот полный обзор. Я очень ценю его @Reinderien, и мне очень жаль, что я не знаю всего этого, но я вроде как новичок, поэтому я пытаюсь учиться на книгах, документах, обзорах и отзывах от вас, ребята. Так что спасибо за попытку помочь, я, конечно, модифицировал код, улучшил его и попытался сделать его как можно лучше, и даже, возможно, плохо сделаю другую его версию в скрипте python или bash.

    – yan_kh


  • 1

    Большой! Если вы все же реализуете вышеуказанные улучшения, отправьте второй вопрос с новым кодом. Спасибо!

    — Райндериен

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *