222 lines
4.8 KiB
C
222 lines
4.8 KiB
C
#include "directive.h"
|
|
|
|
#include <stdio.h>
|
|
#include <dirent.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <sys/stat.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
|
|
#include "kvec.h"
|
|
#include "global.h"
|
|
#include "error.h"
|
|
#include "file_utils.h"
|
|
|
|
typedef struct {
|
|
char * name;
|
|
struct stat st;
|
|
} entry_t;
|
|
|
|
static
|
|
int entry_cmp(const void * a, const void * b) { // For qsort()
|
|
const entry_t * const A = a;
|
|
const entry_t * const B = b;
|
|
return strcmp(A->name, B->name);
|
|
}
|
|
|
|
static kvec_t(entry_t) entries;
|
|
static kvec_t(const char*) directory_queue;
|
|
|
|
|
|
|
|
static
|
|
int add_directory(const char * const folder) {
|
|
DIR * dir = opendir(folder);
|
|
CHECK_OPEN(dir, folder, return 1);
|
|
|
|
char full_path[1024];
|
|
struct stat file_stat;
|
|
struct dirent * mydirent;
|
|
entry_t entry;
|
|
while ((mydirent = readdir(dir)) != NULL) {
|
|
if (strcmp(mydirent->d_name, ".") == 0
|
|
|| strcmp(mydirent->d_name, "..") == 0) {
|
|
continue;
|
|
}
|
|
|
|
sprintf(full_path, "%s/%s",
|
|
folder,
|
|
mydirent->d_name
|
|
);
|
|
|
|
int e = stat(full_path, &file_stat);
|
|
if (e == -1) {
|
|
errorn(E_FILE_ACCESS, full_path);
|
|
return 1;
|
|
}
|
|
|
|
entry = (entry_t) {
|
|
.name = strdup(full_path),
|
|
.st = file_stat,
|
|
};
|
|
kv_push(entry_t, entries, entry);
|
|
|
|
if (is_recursive
|
|
&& (kv_A(entries, entries.n-1).st.st_mode & S_IFDIR)) {
|
|
kv_push(const char*, directory_queue, kv_A(entries, entries.n-1).name);
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
}
|
|
|
|
int init_directive_c(const char * folder) {
|
|
init_file_utils(is_dry_run);
|
|
kv_init(entries);
|
|
kv_init(directory_queue);
|
|
|
|
kv_push(const char*, directory_queue, folder);
|
|
while (directory_queue.n) {
|
|
add_directory(kv_pop(directory_queue));
|
|
}
|
|
|
|
qsort(
|
|
entries.a,
|
|
entries.n,
|
|
sizeof(entry_t),
|
|
entry_cmp
|
|
);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int deinit_directive_c(void) {
|
|
for (int i = 0; i < entries.n; i++) {
|
|
free(kv_A(entries, i).name);
|
|
}
|
|
|
|
kv_destroy(directory_queue);
|
|
kv_destroy(entries);
|
|
deinit_file_utis();
|
|
}
|
|
|
|
int make_directive_file(FILE * f) {
|
|
for (int i = 0; i < entries.n; i++) {
|
|
entry_t * entry = &kv_A(entries, i);
|
|
// ID
|
|
fprintf(f, "%03d",
|
|
i
|
|
);
|
|
// Permissions
|
|
if (do_permissions) {
|
|
char permissions[11];
|
|
|
|
fprintf(f, "\t%s",
|
|
mode_to_str(entry->st.st_mode, permissions)
|
|
);
|
|
}
|
|
// Owner
|
|
if (do_owner) {
|
|
struct passwd * pw = getpwuid(entry->st.st_uid);
|
|
struct group * gr = getgrgid(entry->st.st_gid);
|
|
|
|
fprintf(f, "\t%s:%s",
|
|
pw->pw_name,
|
|
gr->gr_name
|
|
);
|
|
}
|
|
// Name
|
|
fprintf(f, "\t%s",
|
|
entry->name
|
|
);
|
|
// if Directory
|
|
if (entry->st.st_mode & S_IFDIR) {
|
|
putc('/', f);
|
|
}
|
|
|
|
putc('\n', f);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline
|
|
char * next_field(const char * s) {
|
|
while (*s != '\t'
|
|
&& *s != '\n'
|
|
&& *s != '\0') {
|
|
++s;
|
|
}
|
|
return (char*)(++s);
|
|
}
|
|
|
|
int execute_directive_file(FILE * f) {
|
|
#define NEXT_FIELD do { \
|
|
if (*(sp = next_field(sp)) == '\0') { \
|
|
errorn(E_FORMAT); \
|
|
return 1; \
|
|
} \
|
|
} while (0)
|
|
const int LINE_SIZE = 1024;
|
|
char line[LINE_SIZE];
|
|
char buffer[1024];
|
|
char * sp;
|
|
int expected_id = 0;
|
|
int id;
|
|
|
|
while (fgets(line, LINE_SIZE, f) != NULL) {
|
|
sp = line;
|
|
|
|
// ID
|
|
int e = sscanf(line, "%d\t", &id);
|
|
// creation
|
|
if (e != 1) {
|
|
sscanf(sp, "%s\n", buffer);
|
|
mytouch(buffer);
|
|
continue;
|
|
}
|
|
// deletion
|
|
while (expected_id != id) {
|
|
const char * last_filename = kv_A(entries, expected_id).name;
|
|
mydelete(last_filename);
|
|
++expected_id;
|
|
}
|
|
++expected_id;
|
|
NEXT_FIELD;
|
|
|
|
entry_t * entry = &kv_A(entries, id);
|
|
|
|
// Permission
|
|
if (do_permissions) {
|
|
mode_t mode;
|
|
sscanf(sp, "%s\t", buffer);
|
|
mode = str_to_mode(buffer);
|
|
|
|
if (entry->st.st_mode != mode) {
|
|
mychmod(entry->name, mode);
|
|
}
|
|
NEXT_FIELD;
|
|
}
|
|
|
|
// Owner
|
|
if (do_owner) {
|
|
char buffer2[113];
|
|
sscanf(sp, "%s:%s\t", buffer, buffer2);
|
|
//mychown(filename, buffer, buffer2);
|
|
NEXT_FIELD;
|
|
}
|
|
|
|
// Name
|
|
sscanf(sp, "%s\n", buffer);
|
|
size_t len = strlen(buffer);
|
|
if (buffer[len-1] == '/') {
|
|
buffer[len-1] = '\0';
|
|
}
|
|
|
|
if (strcmp(entry->name, buffer)) {
|
|
mymove(entry->name, buffer);
|
|
}
|
|
}
|
|
}
|