#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include 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); } }