Impl. handling symbolic links
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 3s
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 3s
This commit is contained in:
parent
20cb6cb3aa
commit
58269d751c
4 changed files with 120 additions and 17 deletions
|
@ -19,6 +19,8 @@
|
||||||
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
||||||
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_
|
||||||
|
|
||||||
|
static const unsigned int MAX_SYMBOLIC_LINK_SIZE = 512;
|
||||||
|
|
||||||
/// Returns non-zero if this system is big-endian.
|
/// Returns non-zero if this system is big-endian.
|
||||||
int simple_archiver_helper_is_big_endian(void);
|
int simple_archiver_helper_is_big_endian(void);
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,13 @@
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
int print_list_fn(void *data, __attribute__((unused)) void *ud) {
|
int print_list_fn(void *data, __attribute__((unused)) void *ud) {
|
||||||
const char *cstr = data;
|
const SDArchiverFileInfo *file_info = data;
|
||||||
printf(" %s\n", cstr);
|
if (file_info->link_dest == NULL) {
|
||||||
|
printf(" REGULAR FILE: %s\n", file_info->filename);
|
||||||
|
} else {
|
||||||
|
printf(" SYMBOLIC LINK: %s -> %s\n", file_info->filename,
|
||||||
|
file_info->link_dest);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
119
src/parser.c
119
src/parser.c
|
@ -30,10 +30,12 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "data_structures/hash_map.h"
|
#include "data_structures/hash_map.h"
|
||||||
#include "data_structures/linked_list.h"
|
#include "data_structures/linked_list.h"
|
||||||
|
#include "helpers.h"
|
||||||
#include "parser_internal.h"
|
#include "parser_internal.h"
|
||||||
|
|
||||||
/// Gets the first non "./"-like character in the filename.
|
/// Gets the first non "./"-like character in the filename.
|
||||||
|
@ -87,6 +89,34 @@ unsigned int simple_archiver_parser_internal_filename_idx(
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simple_archiver_parser_internal_remove_end_slash(char *filename) {
|
||||||
|
int len = strlen(filename);
|
||||||
|
int idx;
|
||||||
|
for (idx = len; idx-- > 0;) {
|
||||||
|
if (filename[idx] != '/') {
|
||||||
|
++idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (idx < len && idx > 0) {
|
||||||
|
filename[idx] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_archiver_internal_free_file_info_fn(void *data) {
|
||||||
|
SDArchiverFileInfo *file_info = data;
|
||||||
|
if (file_info) {
|
||||||
|
if (file_info->filename) {
|
||||||
|
free(file_info->filename);
|
||||||
|
}
|
||||||
|
if (file_info->link_dest) {
|
||||||
|
free(file_info->link_dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
int list_get_last_fn(void *data, void *ud) {
|
int list_get_last_fn(void *data, void *ud) {
|
||||||
char **last = ud;
|
char **last = ud;
|
||||||
*last = data;
|
*last = data;
|
||||||
|
@ -188,6 +218,7 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
int arg_length = strlen(argv[0] + arg_idx) + 1;
|
int arg_length = strlen(argv[0] + arg_idx) + 1;
|
||||||
out->working_files[0] = malloc(arg_length);
|
out->working_files[0] = malloc(arg_length);
|
||||||
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
|
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
|
||||||
|
simple_archiver_parser_internal_remove_end_slash(out->working_files[0]);
|
||||||
out->working_files[1] = NULL;
|
out->working_files[1] = NULL;
|
||||||
} else {
|
} else {
|
||||||
int working_size = 1;
|
int working_size = 1;
|
||||||
|
@ -209,6 +240,8 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
// Set last element to the arg.
|
// Set last element to the arg.
|
||||||
out->working_files[working_size - 1] = malloc(size);
|
out->working_files[working_size - 1] = malloc(size);
|
||||||
strncpy(out->working_files[working_size - 1], argv[0] + arg_idx, size);
|
strncpy(out->working_files[working_size - 1], argv[0] + arg_idx, size);
|
||||||
|
simple_archiver_parser_internal_remove_end_slash(
|
||||||
|
out->working_files[working_size - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,16 +289,36 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
|
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(struct stat));
|
||||||
fstatat(AT_FDCWD, *iter, &st, AT_SYMLINK_NOFOLLOW);
|
fstatat(AT_FDCWD, *iter, &st, AT_SYMLINK_NOFOLLOW);
|
||||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFREG || (st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
// Is a symbolic link. TODO handle this.
|
// Is a regular file or a symbolic link.
|
||||||
} else if ((st.st_mode & S_IFMT) == S_IFREG) {
|
|
||||||
// Is a regular file.
|
|
||||||
int len = strlen(*iter) + 1;
|
int len = strlen(*iter) + 1;
|
||||||
char *filename = malloc(len);
|
char *filename = malloc(len);
|
||||||
strncpy(filename, *iter, len);
|
strncpy(filename, *iter, len);
|
||||||
if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) {
|
if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) {
|
||||||
simple_archiver_list_add(files_list, filename, NULL);
|
SDArchiverFileInfo *file_info = malloc(sizeof(SDArchiverFileInfo));
|
||||||
|
file_info->filename = filename;
|
||||||
|
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
|
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
||||||
|
ssize_t count = readlinkat(AT_FDCWD, filename, file_info->link_dest,
|
||||||
|
MAX_SYMBOLIC_LINK_SIZE - 1);
|
||||||
|
if (count >= MAX_SYMBOLIC_LINK_SIZE - 1) {
|
||||||
|
file_info->link_dest[MAX_SYMBOLIC_LINK_SIZE - 1] = 0;
|
||||||
|
} else if (count > 0) {
|
||||||
|
file_info->link_dest[count] = 0;
|
||||||
|
} else {
|
||||||
|
// Failure.
|
||||||
|
free(file_info->link_dest);
|
||||||
|
free(file_info);
|
||||||
|
free(filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file_info->link_dest = NULL;
|
||||||
|
}
|
||||||
|
simple_archiver_list_add(files_list, file_info,
|
||||||
|
simple_archiver_internal_free_file_info_fn);
|
||||||
simple_archiver_hash_map_insert(&hash_map, &hash_map_sentinel, filename,
|
simple_archiver_hash_map_insert(&hash_map, &hash_map_sentinel, filename,
|
||||||
len - 1, container_no_free_fn,
|
len - 1, container_no_free_fn,
|
||||||
container_no_free_fn);
|
container_no_free_fn);
|
||||||
|
@ -297,14 +350,48 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
char *combined_path = malloc(combined_size);
|
char *combined_path = malloc(combined_size);
|
||||||
snprintf(combined_path, combined_size, "%s/%s", next,
|
snprintf(combined_path, combined_size, "%s/%s", next,
|
||||||
dir_entry->d_name);
|
dir_entry->d_name);
|
||||||
|
unsigned int valid_idx =
|
||||||
|
simple_archiver_parser_internal_filename_idx(combined_path);
|
||||||
|
if (valid_idx > 0) {
|
||||||
|
char *new_path = malloc(combined_size - valid_idx);
|
||||||
|
strncpy(new_path, combined_path + valid_idx,
|
||||||
|
combined_size - valid_idx);
|
||||||
|
free(combined_path);
|
||||||
|
combined_path = new_path;
|
||||||
|
combined_size -= valid_idx;
|
||||||
|
}
|
||||||
|
memset(&st, 0, sizeof(struct stat));
|
||||||
fstatat(AT_FDCWD, combined_path, &st, AT_SYMLINK_NOFOLLOW);
|
fstatat(AT_FDCWD, combined_path, &st, AT_SYMLINK_NOFOLLOW);
|
||||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFREG ||
|
||||||
// Is a symbolic link. TODO handle this.
|
(st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
} else if ((st.st_mode & S_IFMT) == S_IFREG) {
|
// Is a file or a symbolic link.
|
||||||
// Is a file.
|
|
||||||
if (simple_archiver_hash_map_get(hash_map, combined_path,
|
if (simple_archiver_hash_map_get(hash_map, combined_path,
|
||||||
combined_size - 1) == NULL) {
|
combined_size - 1) == NULL) {
|
||||||
simple_archiver_list_add(files_list, combined_path, NULL);
|
SDArchiverFileInfo *file_info =
|
||||||
|
malloc(sizeof(SDArchiverFileInfo));
|
||||||
|
file_info->filename = combined_path;
|
||||||
|
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
|
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
||||||
|
ssize_t count =
|
||||||
|
readlinkat(AT_FDCWD, combined_path, file_info->link_dest,
|
||||||
|
MAX_SYMBOLIC_LINK_SIZE - 1);
|
||||||
|
if (count >= MAX_SYMBOLIC_LINK_SIZE - 1) {
|
||||||
|
file_info->link_dest[MAX_SYMBOLIC_LINK_SIZE - 1] = 0;
|
||||||
|
} else if (count > 0) {
|
||||||
|
file_info->link_dest[count] = 0;
|
||||||
|
} else {
|
||||||
|
// Failure.
|
||||||
|
free(file_info->link_dest);
|
||||||
|
free(file_info);
|
||||||
|
free(combined_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file_info->link_dest = NULL;
|
||||||
|
}
|
||||||
|
simple_archiver_list_add(
|
||||||
|
files_list, file_info,
|
||||||
|
simple_archiver_internal_free_file_info_fn);
|
||||||
simple_archiver_hash_map_insert(
|
simple_archiver_hash_map_insert(
|
||||||
&hash_map, &hash_map_sentinel, combined_path,
|
&hash_map, &hash_map_sentinel, combined_path,
|
||||||
combined_size - 1, container_no_free_fn,
|
combined_size - 1, container_no_free_fn,
|
||||||
|
@ -336,13 +423,15 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
// Remove leading "./" entries from files_list.
|
// Remove leading "./" entries from files_list.
|
||||||
for (SDArchiverLLNode *iter = files_list->head->next;
|
for (SDArchiverLLNode *iter = files_list->head->next;
|
||||||
iter != files_list->tail; iter = iter->next) {
|
iter != files_list->tail; iter = iter->next) {
|
||||||
unsigned int idx = simple_archiver_parser_internal_filename_idx(iter->data);
|
SDArchiverFileInfo *file_info = iter->data;
|
||||||
|
unsigned int idx =
|
||||||
|
simple_archiver_parser_internal_filename_idx(file_info->filename);
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
int len = strlen((char *)iter->data) + 1 - idx;
|
int len = strlen(file_info->filename) + 1 - idx;
|
||||||
char *substr = malloc(len);
|
char *substr = malloc(len);
|
||||||
strncpy(substr, (char *)iter->data + idx, len);
|
strncpy(substr, file_info->filename + idx, len);
|
||||||
free(iter->data);
|
free(file_info->filename);
|
||||||
iter->data = substr;
|
file_info->filename = substr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,12 @@ typedef struct SDArchiverParsed {
|
||||||
char **working_files;
|
char **working_files;
|
||||||
} SDArchiverParsed;
|
} SDArchiverParsed;
|
||||||
|
|
||||||
|
typedef struct SDArchiverFileInfo {
|
||||||
|
char *filename;
|
||||||
|
/// Is NULL if not a symbolic link.
|
||||||
|
char *link_dest;
|
||||||
|
} SDArchiverFileInfo;
|
||||||
|
|
||||||
void simple_archiver_print_usage(void);
|
void simple_archiver_print_usage(void);
|
||||||
|
|
||||||
SDArchiverParsed simple_archiver_create_parsed(void);
|
SDArchiverParsed simple_archiver_create_parsed(void);
|
||||||
|
@ -50,6 +56,7 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
|
|
||||||
void simple_archiver_free_parsed(SDArchiverParsed *parsed);
|
void simple_archiver_free_parsed(SDArchiverParsed *parsed);
|
||||||
|
|
||||||
|
/// Each entry in the linked list is an SDArchiverFileInfo object.
|
||||||
SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
const SDArchiverParsed *parsed);
|
const SDArchiverParsed *parsed);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue