FENIX_coreutils/ln.c

120 lines
2.6 KiB
C
Executable File

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int link_file(char *, char *);
int force = 0; /* -f flag */
int do_symlink = 0; /* -s flag */
int follow_link = 0; /* -L/-P flag */
int main(int argc, char * argv[]) {
int file_start = 1;
int source_count = 0;
char * path_dir;
char * ln_name;
if(argc < 3) {
fprintf(stderr, "%s: missing file operand\n", argv[0]);
exit(1);
}
if(strcmp(argv[file_start], "-L") == 0) {
follow_link = AT_SYMLINK_FOLLOW;
file_start++;
}
else if(strcmp(argv[file_start], "-P") == 0) {
follow_link = 0;
file_start++;
}
if(strcmp(argv[file_start], "-f") == 0) {
force = 1;
file_start++;
}
else if(strcmp(argv[file_start], "-s") == 0) {
do_symlink = 1;
file_start++;
}
else if(strcmp(argv[file_start], "-fs") == 0
|| strcmp(argv[file_start], "-sf") == 0) {
force = 1;
do_symlink = 1;
file_start++;
}
if(strcmp(argv[file_start], "-L") == 0) {
follow_link = AT_SYMLINK_FOLLOW;
file_start++;
}
else if(strcmp(argv[file_start], "-P") == 0) {
follow_link = 0;
file_start++;
}
if((argc - file_start) < 2) {
fprintf(stderr, "%s: missing file operand\n", argv[0]);
exit(1);
}
source_count = argc - (file_start + 1);
if(source_count == 1) {
int ret = link_file(argv[file_start], argv[file_start+1]);
if(ret == 1) {
fprintf(stderr, "%s: failed to create link '%s': File exists\n",
argv[0], argv[file_start + 1]);
exit(1);
}
return 0;
}
else {
path_dir = argv[argc - 1];
for(int i = file_start; i < (argc - 1); i++) {
int length = strlen(path_dir);
length += strlen(argv[i]);
ln_name = calloc(length + 2, sizeof(*ln_name));
strcpy(ln_name, path_dir);
strcat(ln_name, "/");
strcat(ln_name, argv[i]);
int ret = link_file(argv[i], ln_name);
if(ret == 1) {
fprintf(stderr, "%s: failed to create link '%s': File exists\n",
argv[0], ln_name);
exit(1);
}
free(ln_name);
}
}
}
int link_file(char * source, char * dest) {
struct stat buf;
lstat(source, &buf);
if(strcmp(source, dest) == 0 && !force) {
return 1;
}
else if(access(dest, F_OK) != -1 && !force) {
return 1;
}
else if(access(dest, F_OK) != -1 && force) {
unlink(dest);
}
if(do_symlink) {
return symlink(source, dest);
}
else if(S_ISLNK(buf.st_mode)) {
return linkat(AT_FDCWD, source, AT_FDCWD, dest, follow_link);
}
else {
return link(source, dest);
}
}