.
This commit is contained in:
commit
aae369b9c8
9 changed files with 334 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/build/
|
||||||
32
extension.c
Normal file
32
extension.c
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include <magic.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/byte.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
|
||||||
|
#include "pipeshare.h"
|
||||||
|
|
||||||
|
#define MAX(a,b) (a>b?a:b)
|
||||||
|
|
||||||
|
#define failmagic(...) do { \
|
||||||
|
carp(__VA_ARGS__,": ",magic_error(magic)); \
|
||||||
|
return 0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
int extension(int64 fd,char result[16])
|
||||||
|
{
|
||||||
|
magic_t magic=magic_open(MAGIC_EXTENSION);
|
||||||
|
if(!magic) failmagic("initialize libmagic");
|
||||||
|
if(magic_load(magic,NULL)<0) failmagic("load magic database");
|
||||||
|
const char *extensions=magic_descriptor(magic,fd);
|
||||||
|
if(!extensions) failmagic("get magic data");
|
||||||
|
|
||||||
|
size_t l=MAX(str_chr(extensions,'/'),16);
|
||||||
|
byte_copy(result,l,extensions);
|
||||||
|
result[l]=0;
|
||||||
|
magic_close(magic);
|
||||||
|
if(str_equal(result,"???"))
|
||||||
|
str_copy(result,"txt");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef failmagic
|
||||||
29
meson.build
Normal file
29
meson.build
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
project(
|
||||||
|
'pipeshare', 'c',
|
||||||
|
default_options: [
|
||||||
|
'c_std=c99',
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
deps = [
|
||||||
|
cc.find_library('libowfat'),
|
||||||
|
dependency('libmagic'),
|
||||||
|
]
|
||||||
|
|
||||||
|
executable('pipeshare', files(
|
||||||
|
'./pipeshare.c',
|
||||||
|
'./send_stdin.c',
|
||||||
|
'./extension.c',
|
||||||
|
), dependencies:deps, install:true)
|
||||||
|
|
||||||
|
executable('pipeshare-clean', files(
|
||||||
|
'./pipeshare-clean.c',
|
||||||
|
), dependencies:deps, install:true)
|
||||||
|
|
||||||
|
|
||||||
|
install_man([
|
||||||
|
'./pipeshare.1',
|
||||||
|
'./pipeshare-clean.1',
|
||||||
|
])
|
||||||
23
pipeshare-clean.1
Normal file
23
pipeshare-clean.1
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
.TH pipeshare 1
|
||||||
|
.SH NAME
|
||||||
|
pipeshare-clean \- remove old files
|
||||||
|
.SH SYNOPSIS
|
||||||
|
pipeshare-clean [-C dir]
|
||||||
|
.SH OPTIONS
|
||||||
|
\-C dir
|
||||||
|
chdir into dir at startup
|
||||||
|
.SH DESCRIPTION
|
||||||
|
if \-C is given, pipeshare-clean cd's into the specified
|
||||||
|
directory.
|
||||||
|
It then walks through all files that do not have a file
|
||||||
|
extension(i.e. do not contain a dot in their name) and for
|
||||||
|
each whose last chagne is older than 14 days, prompts the
|
||||||
|
user whether to delete it or not. If it is marked for
|
||||||
|
deletion, the file along with any other file starting with
|
||||||
|
the same prefix(id) are deleted.
|
||||||
|
.PP
|
||||||
|
The confirmation prompt is used to avoid accidental deletion
|
||||||
|
of files when pipeshare-clean is used from the wrong working
|
||||||
|
directory.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
pipeshare(1)
|
||||||
89
pipeshare-clean.c
Normal file
89
pipeshare-clean.c
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/array.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define dieusage() die(100,argv0," [-C dir]")
|
||||||
|
#define dienoarg(OPT) \
|
||||||
|
do { \
|
||||||
|
carp("missing argument for -"OPT); \
|
||||||
|
dieusage(); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static time_t now,expiration;
|
||||||
|
|
||||||
|
static int prompt_confirm(char *file)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
buffer_puts(buffer_1,"remove ");
|
||||||
|
buffer_puts(buffer_1,file);
|
||||||
|
buffer_putsflush(buffer_1,"? [y/N]");
|
||||||
|
if (read(0,&c,1)<=0) return 0;
|
||||||
|
return c=='y' || c=='Y';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete_shared(char *id)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
dir=opendir(".");
|
||||||
|
if (!dir) diesys(111,"opendir");
|
||||||
|
while ((ent=readdir(dir)))
|
||||||
|
if (str_start(ent->d_name,id))
|
||||||
|
unlink(ent->d_name);
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run(void)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
struct stat st;
|
||||||
|
dir=opendir(".");
|
||||||
|
if (!dir) diesys(111,"opendir");
|
||||||
|
while ((ent=readdir(dir))) {
|
||||||
|
if (str_chr(ent->d_name,'.')!=str_len(ent->d_name))
|
||||||
|
continue;
|
||||||
|
if (stat(ent->d_name,&st)<0)
|
||||||
|
diesys(111,"stat ",ent->d_name);
|
||||||
|
/* ignore alias */
|
||||||
|
if (now-st.st_mtime > expiration) {
|
||||||
|
if (!prompt_confirm(ent->d_name))
|
||||||
|
continue;
|
||||||
|
buffer_putsflush(buffer_1,"\n");
|
||||||
|
delete_shared(ent->d_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *dir=".";
|
||||||
|
errmsg_iam(*argv);
|
||||||
|
for (i=1;i<argc;i++) {
|
||||||
|
if (argv[i][0]!='-') break;
|
||||||
|
if (argv[i][1]=='-' && !argv[i][2]) break;
|
||||||
|
switch (argv[i][1]) {
|
||||||
|
case 'C':
|
||||||
|
if(!argv[++i]) dienoarg("C");
|
||||||
|
dir=argv[i];
|
||||||
|
break;
|
||||||
|
default: dieusage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc-=i; argv+=i;
|
||||||
|
|
||||||
|
if (chdir(dir)<0)
|
||||||
|
diesys(100,"chdir ",dir);
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
/* 14 days */
|
||||||
|
expiration = 14*60*60*24;
|
||||||
|
run();
|
||||||
|
}
|
||||||
24
pipeshare.1
Normal file
24
pipeshare.1
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
.TH pipeshare 1
|
||||||
|
.SH NAME
|
||||||
|
pipeshare \- share files
|
||||||
|
.SH SYNOPSIS
|
||||||
|
pipeshare [-C dir] < FILE
|
||||||
|
.SH OPTIONS
|
||||||
|
\-C dir
|
||||||
|
chdir into dir at startup
|
||||||
|
.SH DESCRIPTION
|
||||||
|
if \-C is given, pipeshare cd's into the specified
|
||||||
|
directory.
|
||||||
|
It chooses a unique filename in the directory(called the id)
|
||||||
|
and copys stdin into that files. Then it creates an
|
||||||
|
"alias"-file that reuses the same filename but with an added
|
||||||
|
extension. The extension is determined based on the MIME
|
||||||
|
type of the file.
|
||||||
|
.PP
|
||||||
|
To delete old files, pipeshare-clean(1) may be used.
|
||||||
|
.SH ENVIRONMENT
|
||||||
|
WWWBASE
|
||||||
|
base url to print. e.g. https://example.org will make
|
||||||
|
pipeshare print https://example.org/r4nd0m.txt
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
pipeshare-clean(1)
|
||||||
95
pipeshare.c
Normal file
95
pipeshare.c
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
#define _XOPEN_SOURCE 500
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
#include <libowfat/str.h>
|
||||||
|
#include <libowfat/buffer.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
|
#include "pipeshare.h"
|
||||||
|
|
||||||
|
#define dieusage() die(100,argv0," [-C dir]")
|
||||||
|
#define dienoarg(OPT) \
|
||||||
|
do { \
|
||||||
|
carp("missing argument for -"OPT); \
|
||||||
|
dieusage(); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static char *wwwbase=NULL;
|
||||||
|
|
||||||
|
static int mkaliasfile(char *id,char ext[16])
|
||||||
|
{
|
||||||
|
char *alias;
|
||||||
|
size_t l;
|
||||||
|
alias=alloca(str_len(id)+17);
|
||||||
|
l=str_copy(alias,id);
|
||||||
|
alias[l++]='.';
|
||||||
|
l+=str_copy(alias+l,ext);
|
||||||
|
alias[l]=0;
|
||||||
|
if(symlink(id,alias)<0) {
|
||||||
|
carpsys("symlink ",id," -> ",alias);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *dir=".";
|
||||||
|
char tmp[]="./XXXXXX";
|
||||||
|
int tmpfd;
|
||||||
|
char ext[16];
|
||||||
|
errmsg_iam(*argv);
|
||||||
|
for (i=1;i<argc;i++) {
|
||||||
|
if (argv[i][0]!='-') break;
|
||||||
|
if (argv[i][1]=='-' && !argv[i][2]) break;
|
||||||
|
switch (argv[i][1]) {
|
||||||
|
case 'C':
|
||||||
|
if (!argv[++i]) dienoarg("C");
|
||||||
|
dir=argv[i];
|
||||||
|
break;
|
||||||
|
default: dieusage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc-=i; argv+=i;
|
||||||
|
if (argc!=0) dieusage();
|
||||||
|
wwwbase=getenv("WWWBASE");
|
||||||
|
if (!wwwbase) die(100,"WWWBASE not set");
|
||||||
|
|
||||||
|
if (chdir(dir)<0)
|
||||||
|
diesys(111,"chdir ",dir);
|
||||||
|
|
||||||
|
tmpfd=mkstemp(tmp);
|
||||||
|
if(tmpfd<0) diesys(111, "mkstemp in ", argv[0]);
|
||||||
|
if(!io_fd(tmpfd)
|
||||||
|
||!io_fd(0)
|
||||||
|
) {
|
||||||
|
unlink(tmp);
|
||||||
|
diesys(111,"io_fd");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!send_stdin(tmpfd)) {
|
||||||
|
unlink(tmp);
|
||||||
|
die(111,"copy stdin to ",tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(tmpfd,0,SEEK_SET);
|
||||||
|
if(!extension(tmpfd,ext)) {
|
||||||
|
carp("determine extension");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mkaliasfile(tmp,ext)) {
|
||||||
|
unlink(tmp);
|
||||||
|
die(111,"create alias with extension");
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_puts(buffer_1,wwwbase);
|
||||||
|
buffer_puts(buffer_1,"/");
|
||||||
|
buffer_puts(buffer_1,basename(tmp));
|
||||||
|
buffer_puts(buffer_1,".");
|
||||||
|
buffer_puts(buffer_1,ext);
|
||||||
|
buffer_putsflush(buffer_1,"\n");
|
||||||
|
}
|
||||||
10
pipeshare.h
Normal file
10
pipeshare.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef PIPESHARE_H
|
||||||
|
#define PIPESHARE_H
|
||||||
|
|
||||||
|
#include <libowfat/io.h>
|
||||||
|
|
||||||
|
int send_stdin(int64 fd);
|
||||||
|
|
||||||
|
int extension(int64 fd,char result[16]);
|
||||||
|
|
||||||
|
#endif
|
||||||
31
send_stdin.c
Normal file
31
send_stdin.c
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include <libowfat/errmsg.h>
|
||||||
|
|
||||||
|
#include "pipeshare.h"
|
||||||
|
|
||||||
|
int send_stdin(int64 fd)
|
||||||
|
{
|
||||||
|
char buf[8192];
|
||||||
|
int r;
|
||||||
|
uint64 readpos=0,writepos=0;
|
||||||
|
int eof=0;
|
||||||
|
for(;;){
|
||||||
|
if(eof && writepos>=readpos)break;
|
||||||
|
if(!eof && readpos < sizeof buf) {
|
||||||
|
r=io_tryread(0,buf+readpos,(sizeof buf)-readpos);
|
||||||
|
if(r<=-2){carpsys("read stdin");return 0;}
|
||||||
|
if(r==0)eof=1;
|
||||||
|
if(r>0)readpos+=r;
|
||||||
|
}
|
||||||
|
if(writepos<readpos){
|
||||||
|
r=io_trywrite(fd,buf+writepos,readpos-writepos);
|
||||||
|
if(r<=-2){carpsys("write");return 0;}
|
||||||
|
if(r>0){
|
||||||
|
writepos+=r;
|
||||||
|
if(writepos==readpos)
|
||||||
|
readpos=writepos=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue