0
0
mirror of https://github.com/termux-pacman/glibc-packages.git synced 2024-11-13 15:09:21 +00:00
glibc-packages/gpkg/fakehardlink/fakehardlink.c
2023-11-10 23:08:04 +03:00

92 lines
2.5 KiB
C

/* - libfakehardlink.so
A library that allows you to replace the `link` and `linkat` functions
with fake ones that create symbolic links instead of hard ones.
Version: 1.0
By: @Maxython <mixython@gmail.com>
*/
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <libgen.h>
#include <time.h>
#include <string.h>
const char* libfakehardlink_get_full_path_of_file(const char* file) {
char path_file[PATH_MAX] = "";
if (file[0] == '/') {
sprintf(path_file, "%s", file);
} else {
getcwd(path_file, sizeof(path_file));
sprintf(path_file, "%s/%s", path_file, file);
sprintf(path_file, "%s/%s", realpath(dirname(strdup(path_file)), NULL), basename(strdup(path_file)));
}
return strdup(path_file);
}
const char* libfakehardlink_get_short_path(char* address, char* file) {
char short_path[PATH_MAX] = "";
char *token1, *token2;
address = strdup(&address[1]);
file = dirname(strdup(&file[1]));
char *address_buff = dirname(strdup(address));
while ((token2 = strsep(&file, "/"))) {
if (address_buff)
token1 = strsep(&address_buff, "/");
else
token1 = "";
if (strcmp(token1, token2) != 0)
sprintf(short_path, "../%s", strdup(short_path));
else
strsep(&address, "/");
}
if (address)
sprintf(short_path, "%s%s", short_path, address);
return strdup(short_path);
}
int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) {
if (access(newpath, F_OK) == 0) {
errno = EEXIST;
return -1;
}
if (access(oldpath, F_OK) == -1) {
errno = EFAULT;
return -1;
}
struct stat sb;
if (stat(oldpath, &sb) == 0 && S_ISDIR(sb.st_mode)) {
errno = EPERM;
return -1;
}
const char* oldcwd = libfakehardlink_get_full_path_of_file(oldpath);
if (strcmp(getenv("FAKEHARDLINK_DYNAMIC_LINKS"), "1") == 0) {
char org_file_path[PATH_MAX];
if (lstat(oldcwd, &sb) == 0 && !S_ISLNK(sb.st_mode)) {
sprintf(org_file_path, "%s/.%s-fakehardlink-%ld", dirname(strdup(oldcwd)), basename(strdup(oldcwd)), time(NULL));
rename(oldcwd, org_file_path);
symlink(org_file_path, oldcwd);
} else {
readlink(oldcwd, org_file_path, sizeof(org_file_path));
}
oldcwd = org_file_path;
} else {
if (strcmp(getenv("FAKEHARDLINK_SHORT_LINKS"), "1") == 0)
oldcwd = libfakehardlink_get_short_path((char*)oldcwd, (char*)libfakehardlink_get_full_path_of_file(newpath));
}
return symlinkat(oldcwd, newdirfd, newpath);
}
int link(const char *from, const char *to) {
return linkat(AT_FDCWD, from, AT_FDCWD, to, 0);
}