118 lines
2.6 KiB
C
118 lines
2.6 KiB
C
|
#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);
|
||
|
}
|
||
|
}
|