From c1afdc34484e2eed611e51fbe339c2e26a900dda Mon Sep 17 00:00:00 2001 From: retoor Date: Tue, 6 Jan 2026 14:23:31 +0100 Subject: [PATCH] Initial commit. --- Makefile | 43 + README.md | 147 +++ build/cache.o | Bin 0 -> 8704 bytes build/config.o | Bin 0 -> 9320 bytes build/main.o | Bin 0 -> 5592 bytes build/operations.o | Bin 0 -> 8808 bytes build/utils.o | Bin 0 -> 11296 bytes build/webdav.o | Bin 0 -> 21448 bytes fusedav | Bin 0 -> 51120 bytes include/cache.h | 55 ++ include/config.h | 28 + include/operations.h | 15 + include/utils.h | 28 + include/webdav.h | 56 ++ src/cache.c | 368 ++++++++ src/config.c | 174 ++++ src/main.c | 124 +++ src/operations.c | 350 +++++++ src/utils.c | 403 ++++++++ src/webdav.c | 860 ++++++++++++++++++ webdav/SmartSelect_20260103_165740_Chrome.jpg | Bin 0 -> 108181 bytes webdav/keys.txt | 24 + webdav/tea/docker-compose.yaml~ | 23 + 23 files changed, 2698 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 build/cache.o create mode 100644 build/config.o create mode 100644 build/main.o create mode 100644 build/operations.o create mode 100644 build/utils.o create mode 100644 build/webdav.o create mode 100755 fusedav create mode 100644 include/cache.h create mode 100644 include/config.h create mode 100644 include/operations.h create mode 100644 include/utils.h create mode 100644 include/webdav.h create mode 100644 src/cache.c create mode 100644 src/config.c create mode 100644 src/main.c create mode 100644 src/operations.c create mode 100644 src/utils.c create mode 100644 src/webdav.c create mode 100644 webdav/SmartSelect_20260103_165740_Chrome.jpg create mode 100644 webdav/keys.txt create mode 100644 webdav/tea/docker-compose.yaml~ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0bac7ed --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ +# retoor + +CC = gcc +CFLAGS = -Wall -Wextra -Werror -O2 -fPIC -D_FILE_OFFSET_BITS=64 +CFLAGS += $(shell pkg-config --cflags fuse3 libxml-2.0 libcurl) +LDFLAGS = $(shell pkg-config --libs fuse3 libxml-2.0 libcurl) -lpthread + +TARGET = fusedav +SRC_DIR = src +INC_DIR = include +BUILD_DIR = build + +SOURCES = $(wildcard $(SRC_DIR)/*.c) +OBJECTS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SOURCES)) + +.PHONY: all clean install uninstall + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) $(OBJECTS) -o $@ $(LDFLAGS) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) + $(CC) $(CFLAGS) -I$(INC_DIR) -c $< -o $@ + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +clean: + rm -rf $(BUILD_DIR) $(TARGET) + +install: $(TARGET) + install -d $(DESTDIR)/usr/local/bin + install -m 755 $(TARGET) $(DESTDIR)/usr/local/bin/ + +uninstall: + rm -f $(DESTDIR)/usr/local/bin/$(TARGET) + +deps: + @echo "Required packages:" + @echo " Debian/Ubuntu: sudo apt install libfuse3-dev libcurl4-openssl-dev libxml2-dev" + @echo " Fedora/RHEL: sudo dnf install fuse3-devel libcurl-devel libxml2-devel" + @echo " Arch: sudo pacman -S fuse3 curl libxml2" diff --git a/README.md b/README.md new file mode 100644 index 0000000..cbe68d8 --- /dev/null +++ b/README.md @@ -0,0 +1,147 @@ +# fusedav + +Author: retoor + +WebDAV filesystem client for Linux using FUSE3. Mounts remote WebDAV servers as local directories. + +## Architecture + +``` ++------------------+ +----------------+ +------------------+ +| Local Apps | | FUSE Layer | | WebDAV Server | +| (ls, cp, vim) | --> | (libfuse3) | --> | (Nextcloud, | +| | | | | Apache, etc) | ++------------------+ +----------------+ +------------------+ + | + +-----+-----+ + | | + +--------+ +---------+ + | Cache | | libcurl | + +--------+ +---------+ +``` + +## Features + +- RFC 4918 WebDAV protocol support +- FUSE3 filesystem interface +- Metadata and directory caching with configurable TTL +- HTTP Basic authentication +- HTTPS with certificate verification +- Range requests for partial file reads +- Thread-safe operations + +## Dependencies + +- libfuse3 (FUSE filesystem library) +- libcurl (HTTP client with HTTPS support) +- libxml2 (XML parsing for WebDAV responses) +- pthread (POSIX threads) + +### Installation + +Debian/Ubuntu: +``` +sudo apt install libfuse3-dev libcurl4-openssl-dev libxml2-dev build-essential pkg-config +``` + +Fedora/RHEL: +``` +sudo dnf install fuse3-devel libcurl-devel libxml2-devel gcc make pkg-config +``` + +Arch Linux: +``` +sudo pacman -S fuse3 curl libxml2 base-devel pkg-config +``` + +## Build + +``` +make +``` + +## Usage + +``` +./fusedav --url https://example.com/dav/ --mount-point /mnt/webdav +``` + +### Options + +| Option | Description | +|--------|-------------| +| `-u, --url URL` | WebDAV server URL (required) | +| `-m, --mount-point PATH` | Local mount point directory (required) | +| `-U, --username USER` | HTTP Basic auth username | +| `-p, --password PASS` | HTTP Basic auth password | +| `-c, --cache-ttl MS` | Cache TTL in milliseconds (default: 30000) | +| `-t, --timeout SEC` | Request timeout in seconds (default: 10) | +| `-f, --foreground` | Run in foreground | +| `-d, --debug` | Enable debug output | +| `-h, --help` | Show help | + +### Examples + +Mount with authentication: +``` +./fusedav --url https://cloud.example.com/remote.php/dav/files/user/ \ + --username user \ + --password secret \ + --mount-point /mnt/cloud +``` + +Mount with custom cache settings: +``` +./fusedav --url https://webdav.example.com/ \ + --mount-point /mnt/dav \ + --cache-ttl 60000 \ + --timeout 30 +``` + +Debug mode: +``` +./fusedav --url https://example.com/dav/ \ + --mount-point /mnt/dav \ + --debug +``` + +## Unmounting + +``` +fusermount -u /mnt/webdav +``` + +Or if mounted as root: +``` +sudo umount /mnt/webdav +``` + +## Limitations + +- No WebDAV Class 2 locking (concurrent writes may conflict) +- No symlink or extended attribute support +- Authentication credentials visible in process list +- Sequential write assumption (random writes fetch entire file first) + +## Security Notes + +- Credentials passed via command line are visible in `ps` output +- Consider using environment variables for sensitive data +- SSL certificate verification is enabled by default +- Input paths are validated to prevent directory traversal + +## Error Codes + +| HTTP Status | POSIX Error | +|-------------|-------------| +| 404 Not Found | ENOENT | +| 403 Forbidden | EACCES | +| 401 Unauthorized | EACCES | +| 405 Method Not Allowed | ENOTSUP | +| 409 Conflict | EEXIST | +| 507 Insufficient Storage | ENOSPC | +| 5xx Server Error | EIO | + +## License + +MIT diff --git a/build/cache.o b/build/cache.o new file mode 100644 index 0000000000000000000000000000000000000000..3089931b95620cad5733cab293a185a5d92ac3c5 GIT binary patch literal 8704 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 literal 0 HcmV?d00001 diff --git a/build/config.o b/build/config.o new file mode 100644 index 0000000000000000000000000000000000000000..89388827345b8788901849de43a55b683102c960 GIT binary patch literal 9320 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 literal 0 HcmV?d00001 diff --git a/build/main.o b/build/main.o new file mode 100644 index 0000000000000000000000000000000000000000..5a7f6c1faef9777e570e66de1f6524666056346d GIT binary patch literal 5592 zcmbW4QEVJX8OP`BBsFgExk-RPY1xzuP1<*Y5hZ;{u1Z8gUqGl2o%F-+ zU*D+vuCCcm`hML%XiPcPnp-l$x>5D2Vb!Ts&$z}{-1&U&xKXTCT`wGrY?c0m<9YSa zDAqmCErzgD%7N=Y@A`wnFmlasf$XY9C#=>zqbx@-jfn-fc*-dHZV8=EEik2L!#FA} z4c`r$zDKc)jgD#UW6u_hh7&H3sv2L7hK^F*4GaX+s8>B1ier?jK802Hmj=b>DHLf$ z!Is>E#?I297^#brTXveY&~CW?Vl@aT!a$6a#Yjn|2>Hq#KX%kQ`;UJTDp{>PJ9kmV zTK!e#mMs5mwP!O1>SCo6?oR)>lm2zbYP}-6OV;Dtq<(tk)jqO1dktQmJCXb9)hqo} zlVR<@J7OQyOYJZg4V)=T?S}k0gAu^f$U7?-N z3}2cd%RA|Bsu(^7H92nCN_%gW)3rC#59F`Sw5R))ulHN6+01_HLOETJ)K_Q8S4-NY zcayUyoG5o|^TouX1(MzJg&f>I{^8xbYVvZD2!HPO^j)GY>Hm$#D45G~W|2>;HK2yL z*X3`Zce@WhmGx+%_4?xW3hv#DR%?W8^(w#dsCI-oS*yXDJtkyR~Zuz}CVUFG( zhTHS2Z(41ckjq%NY)8iX?su)#|E{~?yXUq?^Nl7&Dtq)uT`EtL3U!cR(>_4Y1~j-# zPfQ#%b{(5#5e`k7;bV(fsyFJxO(h}4;9Me6i$ z>cP$T4Ve)JqZK|HlK`|iB>LU!!>MmsJT4 zpeo@PP}_^wKD@^8dP0sO=yp`DR_uo32d*eK{hD2=)#qtc+_A*z#oA#iXVB}TC2vN@ zT_2Ybp@NW_s$OwJI|!Xn)alY9FI7S0iRR)iHo~RA4KXjLhzpmnrwd08CkBip-A>-W7PZS5k_e|^m zR`K|_e_;9#G5x_b3_V(ZM*@FZaroZM^l=Y`fa9y8{otYr z0mn^G^B*ui#Q4t@e~j1;#$Qt$aX!NM>&y?&XNT#3mg&F6c!u%cGrp7Yw;BH&<9}5g z^TIb<&+C1~5kGEcn%@sa5)?R3HQ%Z@V&BF1LyYq{A7Pxw`6%N&&i#tV<2kH23f$Xt zJYQyhcsz4VpXd1m)8~1vFwWzzG0x-v8sj|vGm6LKKdU&3EiC>E%ny(Mb*8_S>0f2~ zI74(E{>1cg_tgB)OrQI|#W-Ts`X4YqxP5D$Qdh+Ix|50&Y$M#}FgC=H?`Z!hmy(Pz zKA`HdFoUJV(3uxz5c*NMpliNcbIi~^9SXDLgpM%hgFu*m9Sx{wP5P4YCVkS@Y)HZJ zLptuYMllGp^pTSa(gW3~&#cvpPEDA_`r;z}lNToa1$Rxl+KZ0(0oq+N8KPBacsu}0%sL6x@#qYAz$5d4NPj$Q-J zv6sQsa#Jmm8CAkJmv|fhyWlf!Kc|dNs!|t*uBb9gCC1+y4P>02UiJr+ z0{nB)cDkIUPSoT1Zzu(Quhu@|`9DG(z49+Vs?>KwB@Fq;??uP2^FL1vL*b0z@{+QP zkEh$ZY?2Y|i?^T=%EMkXL@@K(C|h4K$eO_%*sj75I$X-&FP|wW2EH_7{mmbzJr9 z;-<=<&I|Gfr0sS7dW{Vq;~ViNeH91x$H&nIB+>Tx2OD2|^jqj4c{P@>SW})0z3hk8 N2D=)$S$oIr{|93V{gD6w literal 0 HcmV?d00001 diff --git a/build/operations.o b/build/operations.o new file mode 100644 index 0000000000000000000000000000000000000000..80aeab4deaebb29b441993bceadd9c993c94a272 GIT binary patch literal 8808 zcmeI1eQX@X6~O20IJw4Q?;NG7DIrMwq7p(N1qoHC@CQ;`aDhr^Im7{xHi`ncP_+@ICBbe9-)Vuk@6EnB zj~6dhCI0M4do%Of_ujmD^JaI}-q##%DRa4)EG~8no9ju+*xAeH+Ck9_vgNFbee7BF z?=j|Oj8C>~o`o9;?nxEL^e2|Egr~RYsal-y^jDyQr>e!Pv~?jEC|Xi2wF%D$Al(w2 z@T_Kugx|AzSd4=91I3Ai+UEsfFyW~YH8)$rgup;GbZbDvvwA-oK>dz8`GJ|Ipwq<* zE7#OOgPV`}9>KaGrp5Db8=JWK)mcC+UmU|Kt8w!kZvK;-e-W4$9u_KH{Mr@5Mz)F{ zIEq%cZl4(YVs>_R`cFde>;8w@g$GAK_8UC#3?Bl4HuFnvekz8(D2L7$vz>(|U-cSx zp0S%*kTIhtY`$l?l`k4`UTF8#a&xm68=cUAAT)ae#jpDu0-w>3t=mJ}AVfj-Su+b7 zZ{{vs%$^FHf1exCcyM~$n$-(q(>S?bjeUaEGh)>F>qEik;7Se8%~bQkpw7)EpWE^f zTz3P4TSu$U!PpGPRo5qUS7=M9gQ9dC1m;BvS7UCSJi|SZo^9qQuv~5C>&<~;;FZ8B ze)tA73_%IaF32#u_~CY+*IH4}x+b4jcn5AS%NITQ8BoUrZ-KW41rA0ftI zfI41ifPtHQo1ppLpSBkYPMOYkZd%?!iRMf0nHf z`6L!tBo1_&to?TjhnBxndkZ8 zMc?D~jkTGpxoP;^Ve=2%{Bzh`<`X`EKO1>{Pi+`8H+?f|^78v2rD08uwYg?2M_oNN zlZ|z_EaCc?caLVCMW1P7K`O?)(=&-tSUz6Znj^HrRJInK?C;JM{Z?x@>(3PITI&rfb%P$FK*&5yWwOj#&< zJpXt3i;DdU#d2a)$vl_{JWmvy|`TFSN!l^nEHp1UAgxz@X5s} zftfUUa0HuB__}``7$1ek__=c2edY%u7*;;L1zUY9Y$8Zy;Ssz-ARi|it8rIyNV76f z6!K={N~(28Ieao&Prgqelvcir_l!s@c*a3G!=w2tZcetDr!B<^z?Ya)Lf0Bc`ohhZ z@wvE`PXwe^> z*uN7PLO=8SvHpMgmLu@$qdyWB<0mdx>tKUN8R(Xv)mah5=LlY`wXyLgy{2PlHf3b> zzzzNl{@V2$v!c6k9RUzq1Q#Y0W@hW{9SoAWh^!ngEGw*vx$eD#xdy$i%a$#1kHP?` zvy$%JK{c{kYA;b3Y!^}1QC$OdC$-a9H*4O5Wg)FPSKg`>U1eLAYSkgl8`9jNO0+jj zvTtDBqInOY?7{Morsoz3g^{J24hVD_Gulh}vyECvZ| zJyh19RXBRMi8&Vry`Ur{@gZyevy)RYh_QV9jZis2S`u#ZJ3yhG0HtcY#G}B zhJsUA#6H9?im#P&MiaE%DHpq9KGdLFrpU{j$4!ZR2Z_tPUr&61xXk^Vh#w&?@*mo5 zaJiIm-E{vaP@{dFToro&*f!$0VX=rjhq@Ooln)XYc@At3@$t;IWs%3)%zmd2qi|tLsF-O%B68t+V z673ejDLBgATZz*$mhNl@Znup$w>$7Y2fo*V|IC3u>A*3+7V_tq13%%w@tL%coj*G8 zX$L;*z!yUx7qVaNz}GqOdI#R>z&jlHP6xgV_;SeSXDL7B^KCcqD!Ex;y)h3&=^u!v zqeiknmGQ?|BAbbKMem7ZjHr>wl)70X*%wdE^^>WjQMwt8#p0O^+ZBl!gCz)7Q>9K< zJY%H$hf4i)JlfTjOqcqJ-fX73)Jw;E8go6=E!{HG*;Fh#?`|sEHz%A; z^(Iq2CGox1Jf9mk3o()8e z?np8dN%!{~YP1k1#iFrp zxDR1TOOw6Hj1d6`<1wQ@J;Y#yY_bchT~H;`afpFpngXm4xg>q@zSzK!v?@YvjY)1` zxaWaV$Vν?(PcwSyQ^&x$wZ4x7ue$h_p44Qu9pLCEn6^>^XDgU^_@f|7o zON#w93U8+K1CEPpE#+@l_|*!3QsH>+m-4@M;4=zWXTvAPB> zDW6n0p2;M?-@(pF2l-DGj%NsI$4{?vynUU*?;>vZGpESonNiyLrGxxi4tyz{f9&?J zao}wZe3Ur)ukM$k!q+N(9#^=!?(Y$|`{Sbb8rr`~v9nU)S1SB^h2t|s#^b z?|~gQuA?H9ZmTNE%kPQ-8{bdsF=*q|W&3She&>wXxK4IPZCrj26m2|6`7veV(!Vn{ zE`kc|tc@R`{&^ceL-7{@fO|5YJ4jBa8r>jQ1i^1?ERydKJ@|tp)sjm;@p}=A%dl~|FGg%!=G9|1F3q{;d=ptl$#Jw3kMM)Od-W zXOeqmgK9iG;ua24UsmoFR%?Ww!}!-x9LG%p)l{z~PR9wN@Eo^|D{oM`$gX&&qfNWM z97v8Q73_U{)}u{%9+q-apWH8DIlio$N#8!cn+7U<7m@|NWXWm-p;{<@qj<=Ma-0Uj z_~9B!|7H9-fT758xYW`~f7+;3A++WC$vOsXA^j23m*Yt@vM=ia(zlN@O8U6IYLRi1 z^$^^YZB_0$(pMR_?Xo5?OcmPBC?d)j>Fd;&mGoQopMVD1wChii{!_LacKyddccJy` z#Ek*v3^|PJhyTr#`f~ji8XNWY(;pfx(EAbB3(tRceRR{Fdw|$r75*~zfX#n$$GQo> UD7KJ(9e$KRdD^Nt<8 literal 0 HcmV?d00001 diff --git a/build/utils.o b/build/utils.o new file mode 100644 index 0000000000000000000000000000000000000000..58d73995a96f6caced674cc63dbad3c9f6c56336 GIT binary patch literal 11296 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 W-|auT^Uv2_eB7dL6n}bhxBqV|?Y7ha literal 0 HcmV?d00001 diff --git a/build/webdav.o b/build/webdav.o new file mode 100644 index 0000000000000000000000000000000000000000..6deef26042a9531d3978d8788f65a81c0218ded7 GIT binary patch literal 21448 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 literal 0 HcmV?d00001 diff --git a/include/cache.h b/include/cache.h new file mode 100644 index 0000000..8c5adfb --- /dev/null +++ b/include/cache.h @@ -0,0 +1,55 @@ +/* retoor */ + +#ifndef FUSEDAV_CACHE_H +#define FUSEDAV_CACHE_H + +#include +#include +#include +#include + +typedef struct cache_entry { + char *key; + void *value; + size_t value_size; + time_t created_at; + int ttl_ms; + struct cache_entry *next; +} cache_entry_t; + +typedef struct { + cache_entry_t *head; + int max_entries; + int current_entries; + int default_ttl_ms; + pthread_mutex_t lock; +} cache_t; + +typedef struct { + char *name; + int is_directory; + off_t size; + time_t mtime; +} dir_entry_t; + +typedef struct { + dir_entry_t *entries; + int count; +} dir_listing_t; + +cache_t *cache_init(int max_entries, int default_ttl_ms); +void cache_destroy(cache_t *cache); + +int cache_get_stat(cache_t *cache, const char *key, struct stat *st); +int cache_put_stat(cache_t *cache, const char *key, const struct stat *st); + +int cache_get_dir(cache_t *cache, const char *key, dir_listing_t **listing); +int cache_put_dir(cache_t *cache, const char *key, const dir_listing_t *listing); + +void cache_invalidate(cache_t *cache, const char *key); +void cache_invalidate_prefix(cache_t *cache, const char *prefix); +void cache_clear(cache_t *cache); + +void dir_listing_free(dir_listing_t *listing); + +#endif diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..0b02b28 --- /dev/null +++ b/include/config.h @@ -0,0 +1,28 @@ +/* retoor */ + +#ifndef FUSEDAV_CONFIG_H +#define FUSEDAV_CONFIG_H + +#include + +#define DEFAULT_CACHE_TTL_MS 30000 +#define DEFAULT_TIMEOUT_SEC 10 +#define DEFAULT_MAX_CACHE_ENTRIES 1024 +#define DEFAULT_WRITE_BUFFER_SIZE (1024 * 1024) + +typedef struct { + char *webdav_url; + char *username; + char *password; + char *mount_point; + int cache_ttl_ms; + int request_timeout_sec; + int foreground; + int debug; +} config_t; + +int config_parse(int argc, char *argv[], config_t *cfg); +void config_free(config_t *cfg); +void config_print_usage(const char *program_name); + +#endif diff --git a/include/operations.h b/include/operations.h new file mode 100644 index 0000000..1f7ed4c --- /dev/null +++ b/include/operations.h @@ -0,0 +1,15 @@ +/* retoor */ + +#ifndef FUSEDAV_OPERATIONS_H +#define FUSEDAV_OPERATIONS_H + +#define FUSE_USE_VERSION 31 + +#include +#include "webdav.h" + +extern struct fuse_operations fusedav_operations; + +void operations_init(webdav_context_t *ctx); + +#endif diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..72ad90d --- /dev/null +++ b/include/utils.h @@ -0,0 +1,28 @@ +/* retoor */ + +#ifndef FUSEDAV_UTILS_H +#define FUSEDAV_UTILS_H + +#include +#include +#include +#include "cache.h" + +char *url_encode(const char *str); +char *url_decode(const char *str); +char *path_join(const char *base, const char *path); +char *path_parent(const char *path); +char *path_basename(const char *path); +int path_is_root(const char *path); + +int http_status_to_errno(long http_code); + +int parse_propfind_response(const char *xml_data, size_t xml_len, + struct stat *st, dir_listing_t *listing); + +time_t parse_http_date(const char *date_str); + +char *xml_get_text(xmlNodePtr node); +int xml_is_collection(xmlNodePtr node); + +#endif diff --git a/include/webdav.h b/include/webdav.h new file mode 100644 index 0000000..4d2943a --- /dev/null +++ b/include/webdav.h @@ -0,0 +1,56 @@ +/* retoor */ + +#ifndef FUSEDAV_WEBDAV_H +#define FUSEDAV_WEBDAV_H + +#include +#include +#include +#include +#include "cache.h" +#include "config.h" + +typedef struct { + char *webdav_url; + char *username; + char *password; + CURL *curl_handle; + cache_t *metadata_cache; + cache_t *dir_cache; + int cache_ttl_ms; + int request_timeout_sec; + int debug; + pthread_mutex_t lock; +} webdav_context_t; + +typedef struct { + char *path; + char *etag; + off_t file_size; + time_t last_modified; + uint8_t *write_buffer; + size_t write_buffer_pos; + size_t write_buffer_size; + int dirty; +} file_handle_t; + +int webdav_init(webdav_context_t *ctx, const config_t *cfg); +void webdav_cleanup(webdav_context_t *ctx); + +int webdav_get_stat(webdav_context_t *ctx, const char *path, struct stat *st); +int webdav_list_directory(webdav_context_t *ctx, const char *path, dir_listing_t *listing); +ssize_t webdav_read_file(webdav_context_t *ctx, const char *path, + off_t offset, size_t size, uint8_t *buffer); +ssize_t webdav_write_file(webdav_context_t *ctx, const char *path, + off_t offset, size_t size, const uint8_t *buffer); +int webdav_create_file(webdav_context_t *ctx, const char *path); +int webdav_mkdir(webdav_context_t *ctx, const char *path); +int webdav_delete(webdav_context_t *ctx, const char *path); +int webdav_rename(webdav_context_t *ctx, const char *old_path, const char *new_path); +int webdav_truncate(webdav_context_t *ctx, const char *path, off_t size); + +file_handle_t *file_handle_create(const char *path); +void file_handle_destroy(file_handle_t *fh); +int file_handle_flush(webdav_context_t *ctx, file_handle_t *fh); + +#endif diff --git a/src/cache.c b/src/cache.c new file mode 100644 index 0000000..1895136 --- /dev/null +++ b/src/cache.c @@ -0,0 +1,368 @@ +/* retoor */ + +#include +#include +#include +#include "cache.h" + +static int64_t current_time_ms(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; +} + +static int entry_is_valid(cache_entry_t *entry) { + if (!entry) return 0; + int64_t now = current_time_ms(); + int64_t age = now - (int64_t)entry->created_at; + return age < entry->ttl_ms; +} + +static void entry_free(cache_entry_t *entry) { + if (!entry) return; + free(entry->key); + free(entry->value); + free(entry); +} + +cache_t *cache_init(int max_entries, int default_ttl_ms) { + cache_t *cache = calloc(1, sizeof(cache_t)); + if (!cache) return NULL; + + cache->max_entries = max_entries; + cache->default_ttl_ms = default_ttl_ms; + cache->current_entries = 0; + cache->head = NULL; + + if (pthread_mutex_init(&cache->lock, NULL) != 0) { + free(cache); + return NULL; + } + + return cache; +} + +void cache_destroy(cache_t *cache) { + if (!cache) return; + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *entry = cache->head; + while (entry) { + cache_entry_t *next = entry->next; + entry_free(entry); + entry = next; + } + + pthread_mutex_unlock(&cache->lock); + pthread_mutex_destroy(&cache->lock); + free(cache); +} + +static cache_entry_t *find_entry(cache_t *cache, const char *key, + cache_entry_t **prev) { + if (prev) *prev = NULL; + + cache_entry_t *entry = cache->head; + cache_entry_t *previous = NULL; + + while (entry) { + if (strcmp(entry->key, key) == 0) { + if (prev) *prev = previous; + return entry; + } + previous = entry; + entry = entry->next; + } + + return NULL; +} + +static void remove_entry(cache_t *cache, cache_entry_t *entry, + cache_entry_t *prev) { + if (prev) { + prev->next = entry->next; + } else { + cache->head = entry->next; + } + cache->current_entries--; + entry_free(entry); +} + +static void evict_oldest(cache_t *cache) { + if (!cache->head) return; + + cache_entry_t *oldest = cache->head; + cache_entry_t *oldest_prev = NULL; + cache_entry_t *entry = cache->head->next; + cache_entry_t *prev = cache->head; + + while (entry) { + if (entry->created_at < oldest->created_at) { + oldest = entry; + oldest_prev = prev; + } + prev = entry; + entry = entry->next; + } + + remove_entry(cache, oldest, oldest_prev); +} + +int cache_get_stat(cache_t *cache, const char *key, struct stat *st) { + if (!cache || !key || !st) return -1; + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *prev; + cache_entry_t *entry = find_entry(cache, key, &prev); + + if (!entry) { + pthread_mutex_unlock(&cache->lock); + return -1; + } + + if (!entry_is_valid(entry)) { + remove_entry(cache, entry, prev); + pthread_mutex_unlock(&cache->lock); + return -1; + } + + memcpy(st, entry->value, sizeof(struct stat)); + + pthread_mutex_unlock(&cache->lock); + return 0; +} + +int cache_put_stat(cache_t *cache, const char *key, const struct stat *st) { + if (!cache || !key || !st) return -1; + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *prev; + cache_entry_t *existing = find_entry(cache, key, &prev); + + if (existing) { + memcpy(existing->value, st, sizeof(struct stat)); + existing->created_at = (time_t)current_time_ms(); + pthread_mutex_unlock(&cache->lock); + return 0; + } + + if (cache->current_entries >= cache->max_entries) { + evict_oldest(cache); + } + + cache_entry_t *entry = calloc(1, sizeof(cache_entry_t)); + if (!entry) { + pthread_mutex_unlock(&cache->lock); + return -1; + } + + entry->key = strdup(key); + entry->value = malloc(sizeof(struct stat)); + if (!entry->key || !entry->value) { + free(entry->key); + free(entry->value); + free(entry); + pthread_mutex_unlock(&cache->lock); + return -1; + } + + memcpy(entry->value, st, sizeof(struct stat)); + entry->value_size = sizeof(struct stat); + entry->created_at = (time_t)current_time_ms(); + entry->ttl_ms = cache->default_ttl_ms; + + entry->next = cache->head; + cache->head = entry; + cache->current_entries++; + + pthread_mutex_unlock(&cache->lock); + return 0; +} + +static dir_listing_t *copy_dir_listing(const dir_listing_t *src) { + if (!src) return NULL; + + dir_listing_t *dst = calloc(1, sizeof(dir_listing_t)); + if (!dst) return NULL; + + if (src->count == 0) { + dst->entries = NULL; + dst->count = 0; + return dst; + } + + dst->entries = calloc((size_t)src->count, sizeof(dir_entry_t)); + if (!dst->entries) { + free(dst); + return NULL; + } + + dst->count = src->count; + + for (int i = 0; i < src->count; i++) { + dst->entries[i].name = strdup(src->entries[i].name); + dst->entries[i].is_directory = src->entries[i].is_directory; + dst->entries[i].size = src->entries[i].size; + dst->entries[i].mtime = src->entries[i].mtime; + + if (!dst->entries[i].name) { + for (int j = 0; j < i; j++) { + free(dst->entries[j].name); + } + free(dst->entries); + free(dst); + return NULL; + } + } + + return dst; +} + +void dir_listing_free(dir_listing_t *listing) { + if (!listing) return; + + for (int i = 0; i < listing->count; i++) { + free(listing->entries[i].name); + } + free(listing->entries); + free(listing); +} + +int cache_get_dir(cache_t *cache, const char *key, dir_listing_t **listing) { + if (!cache || !key || !listing) return -1; + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *prev; + cache_entry_t *entry = find_entry(cache, key, &prev); + + if (!entry) { + pthread_mutex_unlock(&cache->lock); + return -1; + } + + if (!entry_is_valid(entry)) { + remove_entry(cache, entry, prev); + pthread_mutex_unlock(&cache->lock); + return -1; + } + + *listing = copy_dir_listing((dir_listing_t *)entry->value); + + pthread_mutex_unlock(&cache->lock); + return *listing ? 0 : -1; +} + +int cache_put_dir(cache_t *cache, const char *key, const dir_listing_t *listing) { + if (!cache || !key || !listing) return -1; + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *prev; + cache_entry_t *existing = find_entry(cache, key, &prev); + + if (existing) { + dir_listing_free((dir_listing_t *)existing->value); + existing->value = copy_dir_listing(listing); + existing->created_at = (time_t)current_time_ms(); + pthread_mutex_unlock(&cache->lock); + return existing->value ? 0 : -1; + } + + if (cache->current_entries >= cache->max_entries) { + evict_oldest(cache); + } + + cache_entry_t *entry = calloc(1, sizeof(cache_entry_t)); + if (!entry) { + pthread_mutex_unlock(&cache->lock); + return -1; + } + + entry->key = strdup(key); + entry->value = copy_dir_listing(listing); + if (!entry->key || !entry->value) { + free(entry->key); + dir_listing_free((dir_listing_t *)entry->value); + free(entry); + pthread_mutex_unlock(&cache->lock); + return -1; + } + + entry->created_at = (time_t)current_time_ms(); + entry->ttl_ms = cache->default_ttl_ms; + + entry->next = cache->head; + cache->head = entry; + cache->current_entries++; + + pthread_mutex_unlock(&cache->lock); + return 0; +} + +void cache_invalidate(cache_t *cache, const char *key) { + if (!cache || !key) return; + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *prev; + cache_entry_t *entry = find_entry(cache, key, &prev); + + if (entry) { + remove_entry(cache, entry, prev); + } + + pthread_mutex_unlock(&cache->lock); +} + +void cache_invalidate_prefix(cache_t *cache, const char *prefix) { + if (!cache || !prefix) return; + + size_t prefix_len = strlen(prefix); + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *entry = cache->head; + cache_entry_t *prev = NULL; + + while (entry) { + cache_entry_t *next = entry->next; + + if (strncmp(entry->key, prefix, prefix_len) == 0) { + if (prev) { + prev->next = next; + } else { + cache->head = next; + } + cache->current_entries--; + entry_free(entry); + } else { + prev = entry; + } + + entry = next; + } + + pthread_mutex_unlock(&cache->lock); +} + +void cache_clear(cache_t *cache) { + if (!cache) return; + + pthread_mutex_lock(&cache->lock); + + cache_entry_t *entry = cache->head; + while (entry) { + cache_entry_t *next = entry->next; + entry_free(entry); + entry = next; + } + + cache->head = NULL; + cache->current_entries = 0; + + pthread_mutex_unlock(&cache->lock); +} diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..9811c2b --- /dev/null +++ b/src/config.c @@ -0,0 +1,174 @@ +/* retoor */ + +#include +#include +#include +#include +#include +#include +#include "config.h" + +static struct option long_options[] = { + {"url", required_argument, 0, 'u'}, + {"username", required_argument, 0, 'U'}, + {"password", required_argument, 0, 'p'}, + {"mount-point", required_argument, 0, 'm'}, + {"cache-ttl", required_argument, 0, 'c'}, + {"timeout", required_argument, 0, 't'}, + {"foreground", no_argument, 0, 'f'}, + {"debug", no_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} +}; + +void config_print_usage(const char *program_name) { + fprintf(stderr, "Usage: %s [options]\n\n", program_name); + fprintf(stderr, "Required options:\n"); + fprintf(stderr, " -u, --url URL WebDAV server URL\n"); + fprintf(stderr, " -m, --mount-point PATH Local mount point\n\n"); + fprintf(stderr, "Authentication:\n"); + fprintf(stderr, " -U, --username USER HTTP Basic auth username\n"); + fprintf(stderr, " -p, --password PASS HTTP Basic auth password\n\n"); + fprintf(stderr, "Performance:\n"); + fprintf(stderr, " -c, --cache-ttl MS Cache TTL in milliseconds (default: %d)\n", + DEFAULT_CACHE_TTL_MS); + fprintf(stderr, " -t, --timeout SEC Request timeout in seconds (default: %d)\n", + DEFAULT_TIMEOUT_SEC); + fprintf(stderr, "\nDebug:\n"); + fprintf(stderr, " -f, --foreground Run in foreground\n"); + fprintf(stderr, " -d, --debug Enable debug output\n"); + fprintf(stderr, " -h, --help Show this help\n"); +} + +static int validate_url(const char *url) { + if (!url || strlen(url) == 0) return 0; + return (strncmp(url, "http://", 7) == 0 || strncmp(url, "https://", 8) == 0); +} + +static int validate_mount_point(const char *path) { + if (!path || strlen(path) == 0) return 0; + + struct stat st; + if (stat(path, &st) != 0) { + fprintf(stderr, "Error: Mount point '%s' does not exist\n", path); + return 0; + } + + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "Error: Mount point '%s' is not a directory\n", path); + return 0; + } + + return 1; +} + +static char *normalize_url(const char *url) { + if (!url) return NULL; + + size_t len = strlen(url); + char *result; + + if (len > 0 && url[len - 1] != '/') { + result = malloc(len + 2); + if (!result) return NULL; + strcpy(result, url); + result[len] = '/'; + result[len + 1] = '\0'; + } else { + result = strdup(url); + } + + return result; +} + +int config_parse(int argc, char *argv[], config_t *cfg) { + if (!cfg) return -1; + + memset(cfg, 0, sizeof(*cfg)); + cfg->cache_ttl_ms = DEFAULT_CACHE_TTL_MS; + cfg->request_timeout_sec = DEFAULT_TIMEOUT_SEC; + cfg->foreground = 0; + cfg->debug = 0; + + int opt; + int option_index = 0; + + while ((opt = getopt_long(argc, argv, "u:U:p:m:c:t:fdh", + long_options, &option_index)) != -1) { + switch (opt) { + case 'u': + cfg->webdav_url = normalize_url(optarg); + break; + case 'U': + cfg->username = strdup(optarg); + break; + case 'p': + cfg->password = strdup(optarg); + break; + case 'm': + cfg->mount_point = strdup(optarg); + break; + case 'c': + cfg->cache_ttl_ms = atoi(optarg); + if (cfg->cache_ttl_ms < 0) cfg->cache_ttl_ms = 0; + break; + case 't': + cfg->request_timeout_sec = atoi(optarg); + if (cfg->request_timeout_sec < 1) cfg->request_timeout_sec = 1; + break; + case 'f': + cfg->foreground = 1; + break; + case 'd': + cfg->debug = 1; + cfg->foreground = 1; + break; + case 'h': + config_print_usage(argv[0]); + return 1; + default: + config_print_usage(argv[0]); + return -1; + } + } + + if (!cfg->webdav_url) { + fprintf(stderr, "Error: WebDAV URL is required\n"); + config_print_usage(argv[0]); + return -1; + } + + if (!validate_url(cfg->webdav_url)) { + fprintf(stderr, "Error: Invalid URL '%s' (must start with http:// or https://)\n", + cfg->webdav_url); + return -1; + } + + if (!cfg->mount_point) { + fprintf(stderr, "Error: Mount point is required\n"); + config_print_usage(argv[0]); + return -1; + } + + if (!validate_mount_point(cfg->mount_point)) { + return -1; + } + + if ((cfg->username && !cfg->password) || (!cfg->username && cfg->password)) { + fprintf(stderr, "Error: Both username and password must be provided together\n"); + return -1; + } + + return 0; +} + +void config_free(config_t *cfg) { + if (!cfg) return; + + free(cfg->webdav_url); + free(cfg->username); + free(cfg->password); + free(cfg->mount_point); + + memset(cfg, 0, sizeof(*cfg)); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ed317fc --- /dev/null +++ b/src/main.c @@ -0,0 +1,124 @@ +/* retoor */ + +#define FUSE_USE_VERSION 31 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "webdav.h" +#include "operations.h" + +static webdav_context_t g_webdav_ctx; +static volatile sig_atomic_t g_running = 1; + +static void signal_handler(int sig) { + (void)sig; + g_running = 0; +} + +static void setup_signals(void) { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = signal_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +} + +static int test_connection(webdav_context_t *ctx) { + struct stat st; + int result = webdav_get_stat(ctx, "/", &st); + + if (result != 0) { + fprintf(stderr, "Error: Cannot connect to WebDAV server\n"); + if (result == -EACCES) { + fprintf(stderr, " Authentication failed. Check credentials.\n"); + } else if (result == -ENOENT) { + fprintf(stderr, " Server returned 404. Check URL path.\n"); + } else { + fprintf(stderr, " Error code: %d\n", result); + } + return -1; + } + + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "Error: WebDAV URL does not point to a directory\n"); + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) { + config_t cfg; + int result; + + result = config_parse(argc, argv, &cfg); + if (result != 0) { + return (result > 0) ? 0 : 1; + } + + curl_global_init(CURL_GLOBAL_ALL); + xmlInitParser(); + LIBXML_TEST_VERSION + + result = webdav_init(&g_webdav_ctx, &cfg); + if (result != 0) { + fprintf(stderr, "Error: Failed to initialize WebDAV client\n"); + config_free(&cfg); + curl_global_cleanup(); + xmlCleanupParser(); + return 1; + } + + result = test_connection(&g_webdav_ctx); + if (result != 0) { + webdav_cleanup(&g_webdav_ctx); + config_free(&cfg); + curl_global_cleanup(); + xmlCleanupParser(); + return 1; + } + + operations_init(&g_webdav_ctx); + + setup_signals(); + + int fuse_argc = 0; + char *fuse_argv[10]; + + fuse_argv[fuse_argc++] = argv[0]; + + if (cfg.foreground) { + fuse_argv[fuse_argc++] = "-f"; + } + + if (cfg.debug) { + fuse_argv[fuse_argc++] = "-d"; + } + + fuse_argv[fuse_argc++] = "-o"; + fuse_argv[fuse_argc++] = "default_permissions"; + + fuse_argv[fuse_argc++] = cfg.mount_point; + + struct fuse_args args = FUSE_ARGS_INIT(fuse_argc, fuse_argv); + + result = fuse_main(args.argc, args.argv, &fusedav_operations, NULL); + + webdav_cleanup(&g_webdav_ctx); + config_free(&cfg); + curl_global_cleanup(); + xmlCleanupParser(); + + return result; +} diff --git a/src/operations.c b/src/operations.c new file mode 100644 index 0000000..8fe20ad --- /dev/null +++ b/src/operations.c @@ -0,0 +1,350 @@ +/* retoor */ + +#define FUSE_USE_VERSION 31 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include "operations.h" +#include "webdav.h" +#include "cache.h" +#include "utils.h" + +static webdav_context_t *g_ctx = NULL; + +static webdav_context_t *get_context(void) { + return g_ctx; +} + +static int fusedav_getattr(const char *path, struct stat *stbuf, + struct fuse_file_info *fi) { + (void)fi; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + memset(stbuf, 0, sizeof(struct stat)); + + if (path_is_root(path)) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + stbuf->st_uid = getuid(); + stbuf->st_gid = getgid(); + return 0; + } + + return webdav_get_stat(ctx, path, stbuf); +} + +static int fusedav_readdir(const char *path, void *buf, + fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi, + enum fuse_readdir_flags flags) { + (void)offset; + (void)fi; + (void)flags; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + filler(buf, ".", NULL, 0, 0); + filler(buf, "..", NULL, 0, 0); + + dir_listing_t listing = {0}; + int result = webdav_list_directory(ctx, path, &listing); + + if (result != 0) { + return result; + } + + for (int i = 0; i < listing.count; i++) { + struct stat st = {0}; + st.st_mode = listing.entries[i].is_directory ? + (S_IFDIR | 0755) : (S_IFREG | 0644); + st.st_size = listing.entries[i].size; + st.st_mtime = listing.entries[i].mtime; + st.st_atime = listing.entries[i].mtime; + st.st_ctime = listing.entries[i].mtime; + st.st_uid = getuid(); + st.st_gid = getgid(); + st.st_nlink = listing.entries[i].is_directory ? 2 : 1; + + if (filler(buf, listing.entries[i].name, &st, 0, 0) != 0) { + break; + } + } + + for (int i = 0; i < listing.count; i++) { + free(listing.entries[i].name); + } + free(listing.entries); + + return 0; +} + +static int fusedav_open(const char *path, struct fuse_file_info *fi) { + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + struct stat st; + int result = webdav_get_stat(ctx, path, &st); + + if (result != 0) { + if ((fi->flags & O_CREAT) && result == -ENOENT) { + result = webdav_create_file(ctx, path); + if (result != 0) return result; + } else { + return result; + } + } + + if (S_ISDIR(st.st_mode)) { + return -EISDIR; + } + + file_handle_t *fh = file_handle_create(path); + if (!fh) return -ENOMEM; + + fh->file_size = st.st_size; + fh->last_modified = st.st_mtime; + + fi->fh = (uint64_t)(uintptr_t)fh; + return 0; +} + +static int fusedav_create(const char *path, mode_t mode, + struct fuse_file_info *fi) { + (void)mode; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + int result = webdav_create_file(ctx, path); + if (result != 0) return result; + + file_handle_t *fh = file_handle_create(path); + if (!fh) return -ENOMEM; + + fh->file_size = 0; + fh->last_modified = time(NULL); + + fi->fh = (uint64_t)(uintptr_t)fh; + return 0; +} + +static int fusedav_read(const char *path, char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) { + (void)path; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; + const char *read_path = fh ? fh->path : path; + + ssize_t result = webdav_read_file(ctx, read_path, offset, size, + (uint8_t *)buf); + return (int)result; +} + +static int fusedav_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) { + (void)path; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; + if (!fh) return -EBADF; + + if (fh->write_buffer_pos + size > fh->write_buffer_size) { + int result = file_handle_flush(ctx, fh); + if (result != 0) return result; + + if (size > fh->write_buffer_size) { + ssize_t written = webdav_write_file(ctx, fh->path, offset, + size, (uint8_t *)buf); + return (int)written; + } + } + + memcpy(fh->write_buffer + fh->write_buffer_pos, buf, size); + fh->write_buffer_pos += size; + fh->dirty = 1; + + off_t new_end = offset + (off_t)size; + if (new_end > fh->file_size) { + fh->file_size = new_end; + } + + return (int)size; +} + +static int fusedav_flush(const char *path, struct fuse_file_info *fi) { + (void)path; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; + if (!fh) return 0; + + return file_handle_flush(ctx, fh); +} + +static int fusedav_fsync(const char *path, int isdatasync, + struct fuse_file_info *fi) { + (void)isdatasync; + return fusedav_flush(path, fi); +} + +static int fusedav_release(const char *path, struct fuse_file_info *fi) { + (void)path; + + webdav_context_t *ctx = get_context(); + file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; + + if (fh) { + if (ctx && fh->dirty) { + file_handle_flush(ctx, fh); + } + file_handle_destroy(fh); + } + + fi->fh = 0; + return 0; +} + +static int fusedav_mkdir(const char *path, mode_t mode) { + (void)mode; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + return webdav_mkdir(ctx, path); +} + +static int fusedav_unlink(const char *path) { + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + return webdav_delete(ctx, path); +} + +static int fusedav_rmdir(const char *path) { + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + return webdav_delete(ctx, path); +} + +static int fusedav_rename(const char *from, const char *to, + unsigned int flags) { + (void)flags; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + return webdav_rename(ctx, from, to); +} + +static int fusedav_truncate(const char *path, off_t size, + struct fuse_file_info *fi) { + (void)fi; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + return webdav_truncate(ctx, path, size); +} + +static int fusedav_statfs(const char *path, struct statvfs *stbuf) { + (void)path; + + stbuf->f_bsize = 4096; + stbuf->f_frsize = 4096; + stbuf->f_blocks = 1000000000; + stbuf->f_bfree = 500000000; + stbuf->f_bavail = 500000000; + stbuf->f_files = 1000000; + stbuf->f_ffree = 500000; + stbuf->f_favail = 500000; + stbuf->f_fsid = 0; + stbuf->f_flag = 0; + stbuf->f_namemax = 255; + + return 0; +} + +static int fusedav_utimens(const char *path, const struct timespec tv[2], + struct fuse_file_info *fi) { + (void)path; + (void)tv; + (void)fi; + return 0; +} + +static int fusedav_access(const char *path, int mask) { + (void)mask; + + webdav_context_t *ctx = get_context(); + if (!ctx) return -EIO; + + if (path_is_root(path)) { + return 0; + } + + struct stat st; + return webdav_get_stat(ctx, path, &st); +} + +static void *fusedav_init(struct fuse_conn_info *conn, + struct fuse_config *cfg) { + (void)conn; + cfg->kernel_cache = 1; + cfg->auto_cache = 1; + cfg->entry_timeout = 30.0; + cfg->attr_timeout = 30.0; + cfg->negative_timeout = 5.0; + return NULL; +} + +static void fusedav_destroy(void *private_data) { + (void)private_data; + + webdav_context_t *ctx = get_context(); + if (ctx) { + cache_clear(ctx->metadata_cache); + cache_clear(ctx->dir_cache); + } +} + +struct fuse_operations fusedav_operations = { + .getattr = fusedav_getattr, + .readdir = fusedav_readdir, + .open = fusedav_open, + .create = fusedav_create, + .read = fusedav_read, + .write = fusedav_write, + .flush = fusedav_flush, + .fsync = fusedav_fsync, + .release = fusedav_release, + .mkdir = fusedav_mkdir, + .unlink = fusedav_unlink, + .rmdir = fusedav_rmdir, + .rename = fusedav_rename, + .truncate = fusedav_truncate, + .statfs = fusedav_statfs, + .utimens = fusedav_utimens, + .access = fusedav_access, + .init = fusedav_init, + .destroy = fusedav_destroy, +}; + +void operations_init(webdav_context_t *ctx) { + g_ctx = ctx; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..f57ffe2 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,403 @@ +/* retoor */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" +#include "cache.h" + +static const char *DAV_NS = "DAV:"; + +char *url_encode(const char *str) { + if (!str) return NULL; + + size_t len = strlen(str); + char *encoded = malloc(len * 3 + 1); + if (!encoded) return NULL; + + char *p = encoded; + for (size_t i = 0; i < len; i++) { + unsigned char c = (unsigned char)str[i]; + if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/') { + *p++ = c; + } else { + sprintf(p, "%%%02X", c); + p += 3; + } + } + *p = '\0'; + return encoded; +} + +char *url_decode(const char *str) { + if (!str) return NULL; + + size_t len = strlen(str); + char *decoded = malloc(len + 1); + if (!decoded) return NULL; + + char *p = decoded; + for (size_t i = 0; i < len; i++) { + if (str[i] == '%' && i + 2 < len) { + char hex[3] = {str[i + 1], str[i + 2], '\0'}; + *p++ = (char)strtol(hex, NULL, 16); + i += 2; + } else if (str[i] == '+') { + *p++ = ' '; + } else { + *p++ = str[i]; + } + } + *p = '\0'; + return decoded; +} + +char *path_join(const char *base, const char *path) { + if (!base || !path) return NULL; + + size_t base_len = strlen(base); + size_t path_len = strlen(path); + + while (base_len > 0 && base[base_len - 1] == '/') { + base_len--; + } + while (*path == '/') { + path++; + path_len--; + } + + char *result = malloc(base_len + 1 + path_len + 1); + if (!result) return NULL; + + memcpy(result, base, base_len); + result[base_len] = '/'; + memcpy(result + base_len + 1, path, path_len); + result[base_len + 1 + path_len] = '\0'; + + return result; +} + +char *path_parent(const char *path) { + if (!path) return NULL; + + size_t len = strlen(path); + while (len > 0 && path[len - 1] == '/') { + len--; + } + + while (len > 0 && path[len - 1] != '/') { + len--; + } + + while (len > 1 && path[len - 1] == '/') { + len--; + } + + if (len == 0) { + return strdup("/"); + } + + char *parent = malloc(len + 1); + if (!parent) return NULL; + + memcpy(parent, path, len); + parent[len] = '\0'; + return parent; +} + +char *path_basename(const char *path) { + if (!path) return NULL; + + size_t len = strlen(path); + while (len > 0 && path[len - 1] == '/') { + len--; + } + + size_t end = len; + while (len > 0 && path[len - 1] != '/') { + len--; + } + + size_t name_len = end - len; + if (name_len == 0) { + return strdup("/"); + } + + char *name = malloc(name_len + 1); + if (!name) return NULL; + + memcpy(name, path + len, name_len); + name[name_len] = '\0'; + return name; +} + +int path_is_root(const char *path) { + if (!path) return 0; + while (*path == '/') path++; + return *path == '\0'; +} + +int http_status_to_errno(long http_code) { + if (http_code >= 200 && http_code < 300) { + return 0; + } + + switch (http_code) { + case 400: return -EINVAL; + case 401: return -EACCES; + case 403: return -EACCES; + case 404: return -ENOENT; + case 405: return -ENOTSUP; + case 409: return -EEXIST; + case 412: return -ESTALE; + case 423: return -EBUSY; + case 507: return -ENOSPC; + default: + if (http_code >= 500) return -EIO; + return -EIO; + } +} + +static const char *MONTHS[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +time_t parse_http_date(const char *date_str) { + if (!date_str) return 0; + + struct tm tm = {0}; + + if (strptime(date_str, "%a, %d %b %Y %H:%M:%S", &tm) || + strptime(date_str, "%Y-%m-%dT%H:%M:%S", &tm)) { + return timegm(&tm); + } + + char month_str[4] = {0}; + int day, year, hour, min, sec; + + if (sscanf(date_str, "%*[^,], %d %3s %d %d:%d:%d", + &day, month_str, &year, &hour, &min, &sec) == 6) { + tm.tm_mday = day; + tm.tm_year = year - 1900; + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec; + + for (int i = 0; i < 12; i++) { + if (strcasecmp(month_str, MONTHS[i]) == 0) { + tm.tm_mon = i; + break; + } + } + return timegm(&tm); + } + + return 0; +} + +char *xml_get_text(xmlNodePtr node) { + if (!node) return NULL; + + xmlChar *content = xmlNodeGetContent(node); + if (!content) return NULL; + + char *result = strdup((char *)content); + xmlFree(content); + return result; +} + +int xml_is_collection(xmlNodePtr node) { + for (xmlNodePtr child = node->children; child; child = child->next) { + if (child->type == XML_ELEMENT_NODE) { + if (xmlStrcmp(child->name, (xmlChar *)"collection") == 0) { + return 1; + } + } + } + return 0; +} + +static xmlNodePtr find_child(xmlNodePtr parent, const char *name, const char *ns) { + for (xmlNodePtr child = parent->children; child; child = child->next) { + if (child->type != XML_ELEMENT_NODE) continue; + + if (xmlStrcmp(child->name, (xmlChar *)name) != 0) continue; + + if (ns) { + if (child->ns && xmlStrcmp(child->ns->href, (xmlChar *)ns) == 0) { + return child; + } + } else { + return child; + } + } + return NULL; +} + +static int parse_response_entry(xmlNodePtr response, + struct stat *st, char **entry_name) { + xmlNodePtr href = find_child(response, "href", DAV_NS); + if (!href) return -1; + + char *href_text = xml_get_text(href); + if (!href_text) return -1; + + char *decoded_href = url_decode(href_text); + free(href_text); + if (!decoded_href) return -1; + + char *name = path_basename(decoded_href); + free(decoded_href); + if (!name) return -1; + + if (entry_name) { + *entry_name = name; + } + + xmlNodePtr propstat = find_child(response, "propstat", DAV_NS); + if (!propstat) { + if (!entry_name) free(name); + return -1; + } + + xmlNodePtr prop = find_child(propstat, "prop", DAV_NS); + if (!prop) { + if (!entry_name) free(name); + return -1; + } + + memset(st, 0, sizeof(*st)); + st->st_uid = getuid(); + st->st_gid = getgid(); + st->st_nlink = 1; + + xmlNodePtr resourcetype = find_child(prop, "resourcetype", DAV_NS); + if (resourcetype && xml_is_collection(resourcetype)) { + st->st_mode = S_IFDIR | 0755; + st->st_nlink = 2; + } else { + st->st_mode = S_IFREG | 0644; + } + + xmlNodePtr contentlength = find_child(prop, "getcontentlength", DAV_NS); + if (contentlength) { + char *len_str = xml_get_text(contentlength); + if (len_str) { + st->st_size = (off_t)strtoll(len_str, NULL, 10); + free(len_str); + } + } + + xmlNodePtr lastmodified = find_child(prop, "getlastmodified", DAV_NS); + if (lastmodified) { + char *date_str = xml_get_text(lastmodified); + if (date_str) { + st->st_mtime = parse_http_date(date_str); + st->st_atime = st->st_mtime; + st->st_ctime = st->st_mtime; + free(date_str); + } + } + + if (st->st_mtime == 0) { + st->st_mtime = time(NULL); + st->st_atime = st->st_mtime; + st->st_ctime = st->st_mtime; + } + + st->st_blksize = 4096; + st->st_blocks = (st->st_size + 511) / 512; + + if (!entry_name) free(name); + return 0; +} + +int parse_propfind_response(const char *xml_data, size_t xml_len, + struct stat *st, dir_listing_t *listing) { + if (!xml_data || xml_len == 0) return -EINVAL; + + xmlDocPtr doc = xmlReadMemory(xml_data, (int)xml_len, NULL, NULL, + XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (!doc) return -EIO; + + xmlNodePtr root = xmlDocGetRootElement(doc); + if (!root) { + xmlFreeDoc(doc); + return -EIO; + } + + int count = 0; + for (xmlNodePtr node = root->children; node; node = node->next) { + if (node->type == XML_ELEMENT_NODE && + xmlStrcmp(node->name, (xmlChar *)"response") == 0) { + count++; + } + } + + if (count == 0) { + xmlFreeDoc(doc); + return -ENOENT; + } + + if (listing) { + listing->entries = calloc((size_t)count, sizeof(dir_entry_t)); + if (!listing->entries) { + xmlFreeDoc(doc); + return -ENOMEM; + } + listing->count = 0; + } + + int first = 1; + for (xmlNodePtr node = root->children; node; node = node->next) { + if (node->type != XML_ELEMENT_NODE || + xmlStrcmp(node->name, (xmlChar *)"response") != 0) { + continue; + } + + struct stat entry_st; + char *entry_name = NULL; + + if (parse_response_entry(node, &entry_st, &entry_name) != 0) { + continue; + } + + if (first && st) { + *st = entry_st; + first = 0; + free(entry_name); + continue; + } + first = 0; + + if (listing && entry_name) { + if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0 || + strlen(entry_name) == 0) { + free(entry_name); + continue; + } + + dir_entry_t *entry = &listing->entries[listing->count]; + entry->name = entry_name; + entry->is_directory = S_ISDIR(entry_st.st_mode); + entry->size = entry_st.st_size; + entry->mtime = entry_st.st_mtime; + listing->count++; + } else { + free(entry_name); + } + } + + xmlFreeDoc(doc); + return 0; +} diff --git a/src/webdav.c b/src/webdav.c new file mode 100644 index 0000000..6db0515 --- /dev/null +++ b/src/webdav.c @@ -0,0 +1,860 @@ +/* retoor */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "webdav.h" +#include "utils.h" +#include "config.h" + +typedef struct { + uint8_t *data; + size_t size; + size_t capacity; +} response_buffer_t; + +static const char *PROPFIND_BODY = + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + +static size_t write_callback(void *contents, size_t size, size_t nmemb, + void *userp) { + size_t total = size * nmemb; + response_buffer_t *buf = (response_buffer_t *)userp; + + if (buf->size + total + 1 > buf->capacity) { + size_t new_cap = buf->capacity * 2; + if (new_cap < buf->size + total + 1) { + new_cap = buf->size + total + 1024; + } + + uint8_t *new_data = realloc(buf->data, new_cap); + if (!new_data) return 0; + + buf->data = new_data; + buf->capacity = new_cap; + } + + memcpy(buf->data + buf->size, contents, total); + buf->size += total; + buf->data[buf->size] = '\0'; + + return total; +} + +static size_t read_callback(void *ptr, size_t size, size_t nmemb, + void *userp) { + response_buffer_t *buf = (response_buffer_t *)userp; + size_t total = size * nmemb; + size_t remaining = buf->capacity - buf->size; + + if (remaining == 0) return 0; + + size_t to_copy = (remaining < total) ? remaining : total; + memcpy(ptr, buf->data + buf->size, to_copy); + buf->size += to_copy; + + return to_copy; +} + +static void response_buffer_init(response_buffer_t *buf, size_t initial_cap) { + buf->data = malloc(initial_cap); + buf->size = 0; + buf->capacity = initial_cap; + if (buf->data) buf->data[0] = '\0'; +} + +static void response_buffer_free(response_buffer_t *buf) { + free(buf->data); + buf->data = NULL; + buf->size = 0; + buf->capacity = 0; +} + +static char *build_url(webdav_context_t *ctx, const char *path) { + char *encoded_path = url_encode(path); + if (!encoded_path) return NULL; + + char *url = path_join(ctx->webdav_url, encoded_path); + free(encoded_path); + return url; +} + +static void setup_curl_common(webdav_context_t *ctx, CURL *curl, + const char *url) { + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, ctx->request_timeout_sec); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, ctx->request_timeout_sec); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); + + if (ctx->debug) { + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + } + + if (ctx->username && ctx->password) { + char *auth = NULL; + if (asprintf(&auth, "%s:%s", ctx->username, ctx->password) > 0) { + curl_easy_setopt(curl, CURLOPT_USERPWD, auth); + free(auth); + } + curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + } +} + +int webdav_init(webdav_context_t *ctx, const config_t *cfg) { + if (!ctx || !cfg) return -EINVAL; + + memset(ctx, 0, sizeof(*ctx)); + + ctx->webdav_url = strdup(cfg->webdav_url); + if (cfg->username) ctx->username = strdup(cfg->username); + if (cfg->password) ctx->password = strdup(cfg->password); + ctx->cache_ttl_ms = cfg->cache_ttl_ms; + ctx->request_timeout_sec = cfg->request_timeout_sec; + ctx->debug = cfg->debug; + + if (!ctx->webdav_url) { + webdav_cleanup(ctx); + return -ENOMEM; + } + + if (pthread_mutex_init(&ctx->lock, NULL) != 0) { + webdav_cleanup(ctx); + return -ENOMEM; + } + + ctx->curl_handle = curl_easy_init(); + if (!ctx->curl_handle) { + webdav_cleanup(ctx); + return -ENOMEM; + } + + ctx->metadata_cache = cache_init(DEFAULT_MAX_CACHE_ENTRIES, cfg->cache_ttl_ms); + ctx->dir_cache = cache_init(DEFAULT_MAX_CACHE_ENTRIES, cfg->cache_ttl_ms); + + if (!ctx->metadata_cache || !ctx->dir_cache) { + webdav_cleanup(ctx); + return -ENOMEM; + } + + return 0; +} + +void webdav_cleanup(webdav_context_t *ctx) { + if (!ctx) return; + + if (ctx->curl_handle) { + curl_easy_cleanup(ctx->curl_handle); + ctx->curl_handle = NULL; + } + + if (ctx->metadata_cache) { + cache_destroy(ctx->metadata_cache); + ctx->metadata_cache = NULL; + } + + if (ctx->dir_cache) { + cache_destroy(ctx->dir_cache); + ctx->dir_cache = NULL; + } + + free(ctx->webdav_url); + free(ctx->username); + free(ctx->password); + + pthread_mutex_destroy(&ctx->lock); + memset(ctx, 0, sizeof(*ctx)); +} + +int webdav_get_stat(webdav_context_t *ctx, const char *path, struct stat *st) { + if (!ctx || !path || !st) return -EINVAL; + + if (cache_get_stat(ctx->metadata_cache, path, st) == 0) { + return 0; + } + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + response_buffer_t response; + response_buffer_init(&response, 4096); + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, PROPFIND_BODY); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Depth: 0"); + headers = curl_slist_append(headers, "Content-Type: application/xml"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(url); + + int result; + if (res != CURLE_OK) { + if (ctx->debug) { + fprintf(stderr, "CURL error: %s\n", curl_easy_strerror(res)); + } + result = -EIO; + } else if (http_code == 207 || http_code == 200) { + result = parse_propfind_response((char *)response.data, response.size, + st, NULL); + if (result == 0) { + cache_put_stat(ctx->metadata_cache, path, st); + } + } else { + if (ctx->debug) { + fprintf(stderr, "HTTP error: %ld\n", http_code); + } + result = http_status_to_errno(http_code); + } + + response_buffer_free(&response); + return result; +} + +int webdav_list_directory(webdav_context_t *ctx, const char *path, + dir_listing_t *listing) { + if (!ctx || !path || !listing) return -EINVAL; + + dir_listing_t *cached = NULL; + if (cache_get_dir(ctx->dir_cache, path, &cached) == 0) { + *listing = *cached; + free(cached); + return 0; + } + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + response_buffer_t response; + response_buffer_init(&response, 8192); + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, PROPFIND_BODY); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Depth: 1"); + headers = curl_slist_append(headers, "Content-Type: application/xml"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(url); + + int result; + if (res != CURLE_OK) { + result = -EIO; + } else if (http_code == 207 || http_code == 200) { + struct stat st; + result = parse_propfind_response((char *)response.data, response.size, + &st, listing); + if (result == 0) { + cache_put_dir(ctx->dir_cache, path, listing); + } + } else { + result = http_status_to_errno(http_code); + } + + response_buffer_free(&response); + return result; +} + +ssize_t webdav_read_file(webdav_context_t *ctx, const char *path, + off_t offset, size_t size, uint8_t *buffer) { + if (!ctx || !path || !buffer) return -EINVAL; + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + response_buffer_t response; + response_buffer_init(&response, size + 1); + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + char range_header[64]; + snprintf(range_header, sizeof(range_header), "Range: bytes=%lld-%lld", + (long long)offset, (long long)(offset + size - 1)); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, range_header); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(url); + + ssize_t result; + if (res != CURLE_OK) { + result = -EIO; + } else if (http_code == 206 || http_code == 200) { + size_t to_copy = (response.size < size) ? response.size : size; + memcpy(buffer, response.data, to_copy); + result = (ssize_t)to_copy; + } else { + result = http_status_to_errno(http_code); + } + + response_buffer_free(&response); + return result; +} + +ssize_t webdav_write_file(webdav_context_t *ctx, const char *path, + off_t offset, size_t size, const uint8_t *buffer) { + if (!ctx || !path || !buffer) return -EINVAL; + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + pthread_mutex_lock(&ctx->lock); + + uint8_t *full_content = NULL; + size_t full_size = 0; + + if (offset > 0) { + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + response_buffer_t response; + response_buffer_init(&response, 65536); + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + CURLcode res = curl_easy_perform(curl); + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + curl_easy_cleanup(curl); + + if (res == CURLE_OK && (http_code == 200 || http_code == 404)) { + full_size = (size_t)offset + size; + if (response.size > full_size) { + full_size = response.size; + } + + full_content = calloc(1, full_size); + if (!full_content) { + response_buffer_free(&response); + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + if (http_code == 200 && response.size > 0) { + memcpy(full_content, response.data, response.size); + } + + memcpy(full_content + offset, buffer, size); + } + + response_buffer_free(&response); + } else { + full_content = malloc(size); + if (!full_content) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + memcpy(full_content, buffer, size); + full_size = size; + } + + CURL *curl = curl_easy_init(); + if (!curl) { + free(full_content); + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)full_size); + + response_buffer_t upload_buf; + upload_buf.data = full_content; + upload_buf.size = 0; + upload_buf.capacity = full_size; + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_buf); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_easy_cleanup(curl); + free(full_content); + pthread_mutex_unlock(&ctx->lock); + free(url); + + cache_invalidate(ctx->metadata_cache, path); + char *parent = path_parent(path); + if (parent) { + cache_invalidate(ctx->dir_cache, parent); + free(parent); + } + + if (res != CURLE_OK) { + return -EIO; + } + + if (http_code == 200 || http_code == 201 || http_code == 204) { + return (ssize_t)size; + } + + return http_status_to_errno(http_code); +} + +int webdav_create_file(webdav_context_t *ctx, const char *path) { + if (!ctx || !path) return -EINVAL; + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)0); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(url); + + cache_invalidate(ctx->metadata_cache, path); + char *parent = path_parent(path); + if (parent) { + cache_invalidate(ctx->dir_cache, parent); + free(parent); + } + + if (res != CURLE_OK) { + return -EIO; + } + + if (http_code == 200 || http_code == 201 || http_code == 204) { + return 0; + } + + return http_status_to_errno(http_code); +} + +int webdav_mkdir(webdav_context_t *ctx, const char *path) { + if (!ctx || !path) return -EINVAL; + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + size_t len = strlen(url); + if (len > 0 && url[len - 1] != '/') { + char *new_url = realloc(url, len + 2); + if (!new_url) { + free(url); + return -ENOMEM; + } + url = new_url; + url[len] = '/'; + url[len + 1] = '\0'; + } + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "MKCOL"); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(url); + + cache_invalidate(ctx->metadata_cache, path); + char *parent = path_parent(path); + if (parent) { + cache_invalidate(ctx->dir_cache, parent); + free(parent); + } + + if (res != CURLE_OK) { + return -EIO; + } + + if (http_code == 201) { + return 0; + } + + if (http_code == 405) { + return -EEXIST; + } + + return http_status_to_errno(http_code); +} + +int webdav_delete(webdav_context_t *ctx, const char *path) { + if (!ctx || !path) return -EINVAL; + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(url); + + cache_invalidate(ctx->metadata_cache, path); + cache_invalidate_prefix(ctx->dir_cache, path); + char *parent = path_parent(path); + if (parent) { + cache_invalidate(ctx->dir_cache, parent); + free(parent); + } + + if (res != CURLE_OK) { + return -EIO; + } + + if (http_code == 200 || http_code == 204) { + return 0; + } + + return http_status_to_errno(http_code); +} + +int webdav_rename(webdav_context_t *ctx, const char *old_path, + const char *new_path) { + if (!ctx || !old_path || !new_path) return -EINVAL; + + char *src_url = build_url(ctx, old_path); + char *dst_url = build_url(ctx, new_path); + + if (!src_url || !dst_url) { + free(src_url); + free(dst_url); + return -ENOMEM; + } + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(src_url); + free(dst_url); + return -ENOMEM; + } + + setup_curl_common(ctx, curl, src_url); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "MOVE"); + + char *dest_header = NULL; + if (asprintf(&dest_header, "Destination: %s", dst_url) < 0) { + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(src_url); + free(dst_url); + return -ENOMEM; + } + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, dest_header); + headers = curl_slist_append(headers, "Overwrite: T"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + CURLcode res = curl_easy_perform(curl); + + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_slist_free_all(headers); + free(dest_header); + curl_easy_cleanup(curl); + pthread_mutex_unlock(&ctx->lock); + free(src_url); + free(dst_url); + + cache_invalidate(ctx->metadata_cache, old_path); + cache_invalidate(ctx->metadata_cache, new_path); + cache_invalidate_prefix(ctx->dir_cache, old_path); + + char *old_parent = path_parent(old_path); + char *new_parent = path_parent(new_path); + if (old_parent) { + cache_invalidate(ctx->dir_cache, old_parent); + free(old_parent); + } + if (new_parent) { + cache_invalidate(ctx->dir_cache, new_parent); + free(new_parent); + } + + if (res != CURLE_OK) { + return -EIO; + } + + if (http_code == 200 || http_code == 201 || http_code == 204) { + return 0; + } + + return http_status_to_errno(http_code); +} + +int webdav_truncate(webdav_context_t *ctx, const char *path, off_t size) { + if (!ctx || !path) return -EINVAL; + + if (size == 0) { + return webdav_create_file(ctx, path); + } + + char *url = build_url(ctx, path); + if (!url) return -ENOMEM; + + pthread_mutex_lock(&ctx->lock); + + CURL *curl = curl_easy_init(); + if (!curl) { + pthread_mutex_unlock(&ctx->lock); + free(url); + return -ENOMEM; + } + + response_buffer_t response; + response_buffer_init(&response, (size_t)size + 1); + + setup_curl_common(ctx, curl, url); + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + char range_header[64]; + snprintf(range_header, sizeof(range_header), "Range: bytes=0-%lld", + (long long)(size - 1)); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, range_header); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + CURLcode res = curl_easy_perform(curl); + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + + int result = 0; + if (res != CURLE_OK) { + result = -EIO; + } else if (http_code == 206 || http_code == 200) { + CURL *put_curl = curl_easy_init(); + if (!put_curl) { + result = -ENOMEM; + } else { + setup_curl_common(ctx, put_curl, url); + curl_easy_setopt(put_curl, CURLOPT_UPLOAD, 1L); + + size_t upload_size = (response.size < (size_t)size) ? + response.size : (size_t)size; + curl_easy_setopt(put_curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)upload_size); + + response_buffer_t upload_buf; + upload_buf.data = response.data; + upload_buf.size = 0; + upload_buf.capacity = upload_size; + + curl_easy_setopt(put_curl, CURLOPT_READFUNCTION, read_callback); + curl_easy_setopt(put_curl, CURLOPT_READDATA, &upload_buf); + + res = curl_easy_perform(put_curl); + curl_easy_getinfo(put_curl, CURLINFO_RESPONSE_CODE, &http_code); + curl_easy_cleanup(put_curl); + + if (res != CURLE_OK) { + result = -EIO; + } else if (http_code == 200 || http_code == 201 || + http_code == 204) { + result = 0; + } else { + result = http_status_to_errno(http_code); + } + } + } else { + result = http_status_to_errno(http_code); + } + + response_buffer_free(&response); + pthread_mutex_unlock(&ctx->lock); + free(url); + + cache_invalidate(ctx->metadata_cache, path); + + return result; +} + +file_handle_t *file_handle_create(const char *path) { + if (!path) return NULL; + + file_handle_t *fh = calloc(1, sizeof(file_handle_t)); + if (!fh) return NULL; + + fh->path = strdup(path); + if (!fh->path) { + free(fh); + return NULL; + } + + fh->write_buffer_size = DEFAULT_WRITE_BUFFER_SIZE; + fh->write_buffer = malloc(fh->write_buffer_size); + if (!fh->write_buffer) { + free(fh->path); + free(fh); + return NULL; + } + + fh->write_buffer_pos = 0; + fh->dirty = 0; + + return fh; +} + +void file_handle_destroy(file_handle_t *fh) { + if (!fh) return; + + free(fh->path); + free(fh->etag); + free(fh->write_buffer); + free(fh); +} + +int file_handle_flush(webdav_context_t *ctx, file_handle_t *fh) { + if (!ctx || !fh) return -EINVAL; + + if (!fh->dirty || fh->write_buffer_pos == 0) { + return 0; + } + + ssize_t written = webdav_write_file(ctx, fh->path, 0, + fh->write_buffer_pos, + fh->write_buffer); + + if (written < 0) { + return (int)written; + } + + fh->write_buffer_pos = 0; + fh->dirty = 0; + return 0; +} diff --git a/webdav/SmartSelect_20260103_165740_Chrome.jpg b/webdav/SmartSelect_20260103_165740_Chrome.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a0199900473393dace79fbdbabcf65cb8dc82c3 GIT binary patch literal 108181 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

AL<+V;4W%%#HTuoBD4e2B^5&DjB>DeVCEs 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%0Di`HGbH20rw+ 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 F{y+L`pS=J8 literal 0 HcmV?d00001 diff --git a/webdav/keys.txt b/webdav/keys.txt new file mode 100644 index 0000000..bcb066c --- /dev/null +++ b/webdav/keys.txt @@ -0,0 +1,24 @@ +export OPENAI_API_ADMIN_KEY="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" + +export OPENROUTER_API_KEY="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" + +export OPENAI_API_KEY="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" +export R_KEY="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" +export ANTHROPIC_API_KEY="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" +export PINECONE_API_KEY="pcsk_cmhgd_MHwBJk8XCcipoyXQdSGo2Rq56xZDTRKjYPbrvFzREeJgQLJed3g5uBoxTzRzGb7" +export GEMINI_API_KEY="AIzaSyCLJQuAzBCVKPgVKn4IsDXkOBPUjqH7dR0" +export TOGETHER_AI_API_KEY="daeb23017d865e8aa657643d6d2f11d69e099d3a5a1036534da28d7db6b47792" +export DEM_MOLODETZ_TOKEN="sk-5ea2bcf6e30c4a819f405963d7191c84" + +# Related keys/tokens from the file +export R__KEY="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" +export ANAKIN="APS-8GtkHpQVNqNYP6bJGU7PcAbPJJH4KEJ6" + +export OR_KEY="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" + +export EXA_API_KEY="d09b922b-7946-42f6-a95e-e421faa68663" +export ZAI_API_KEY=aaf5fb68732c40de9472d980b23054c9.eAJs7s74sh7VDm9O +# Related model configuration +export R_MODEL="gpt-4.1-mini" + +export EYE_API_KEY="none-of-your-business" diff --git a/webdav/tea/docker-compose.yaml~ b/webdav/tea/docker-compose.yaml~ new file mode 100644 index 0000000..6020179 --- /dev/null +++ b/webdav/tea/docker-compose.yaml~ @@ -0,0 +1,23 @@ +version: "3" + +networks: + gitea: + external: false + +services: + server: + image: gitea/gitea:1.22.4 + container_name: tea + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: always + networks: + - gitea + volumes: + - ./data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "127.0.0.1:8082:3000" + - "0.0.0.0:22:22"