aboutsummaryrefslogtreecommitdiff
path: root/copy
diff options
context:
space:
mode:
Diffstat (limited to 'copy')
-rw-r--r--copy/Makefile58
-rw-r--r--copy/copy-help.pd15
-rw-r--r--copy/copy.c205
3 files changed, 278 insertions, 0 deletions
diff --git a/copy/Makefile b/copy/Makefile
new file mode 100644
index 0000000..0600286
--- /dev/null
+++ b/copy/Makefile
@@ -0,0 +1,58 @@
+NAME=copy
+CSYM=copy
+
+LIBDIR=/usr/local/lib
+PDDIR=$(LIBDIR)/pd
+INSTALLPATH=$(PDDIR)/extra/
+
+current: pd_darwin
+
+
+# ----------------------- Linux -----------------------
+
+pd_linux: $(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -ggdb -DPD -O3 -fPIC -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+# Debug
+#LINUXCFLAGS = -ggdb -g -DPD -O0 -fPIC -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXINCLUDE = -I/usr/include -I./include -I../../../pd/src
+
+.c.pd_linux:
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -c $(NAME).c
+ ld --export-dynamic -shared -o $(NAME).pd_linux $(NAME).o -lc
+ strip --strip-unneeded $(NAME).pd_linux
+ rm -f *.o
+
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: $(NAME).pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -O3 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch -L/usr/local/lib/
+
+DARWININCLUDE = $(LINUXINCLUDE)
+
+.c.pd_darwin:
+ $(CC) $(DARWINCFLAGS) $(DARWININCLUDE) -c $(NAME).c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $(NAME).pd_darwin $(NAME).o
+ rm -f *.o
+
+# ----------------------- Generic -----------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
+
+install:
+ cp copy.pd_linux $(INSTALLPATH)
+ install -d $(PDDIR)/doc/5.reference/copy/
+ install -m 644 doc/help-* $(PDDIR)/doc/5.reference/
diff --git a/copy/copy-help.pd b/copy/copy-help.pd
new file mode 100644
index 0000000..cef5b57
--- /dev/null
+++ b/copy/copy-help.pd
@@ -0,0 +1,15 @@
+#N canvas 470 62 398 308 10;
+#X obj 46 119 copy;
+#X obj 46 154 sel 0 1;
+#X msg 65 179 set copied;
+#X msg 46 209 set failed;
+#X symbolatom 46 250 10 0 0 0 - - -, f 10;
+#X msg 46 62 list /source/path /destination/path;
+#X text 42 21 [copy] copy file from source path to destination path
+;
+#X connect 0 0 1 0;
+#X connect 1 0 3 0;
+#X connect 1 1 2 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 5 0 0 0;
diff --git a/copy/copy.c b/copy/copy.c
new file mode 100644
index 0000000..d943aaa
--- /dev/null
+++ b/copy/copy.c
@@ -0,0 +1,205 @@
+/* copy - copy a file from one path to another preserving permissions
+ *
+ * Author: Jamie Bullock <jamie@jamiebullock.com>
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org/>
+ */
+
+#include "m_pd.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef __APPLE__
+#define O_BINARY 0
+#endif
+
+#define CONSOLE_PREFIX "[copy]: "
+
+typedef struct _copy
+{
+ t_object x_obj;
+ t_outlet *outlet;
+}
+t_copy;
+
+t_class *copy_class;
+
+int copy(const char *source, const char *target);
+
+void *copy_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_copy *x = (t_copy *)pd_new(copy_class);
+ x->outlet = outlet_new(&x->x_obj, &s_float);
+ post(CONSOLE_PREFIX "copy file from source path to destination path");
+ return (void *)x;
+}
+
+void copy_list(t_copy *x, t_symbol *s, int ac, t_atom *av)
+{
+ char source[MAXPDSTRING];
+ char target[MAXPDSTRING];
+
+ if(ac != 2 || (av[0].a_type != A_SYMBOL && av[1].a_type != A_SYMBOL))
+ {
+ pd_error(x, "expected a list containing <source path> <destination path>");
+ }
+
+ atom_string(&av[0], source, MAXPDSTRING);
+ atom_string(&av[1], target, MAXPDSTRING);
+
+ int rv = copy(source, target);
+ rv++;
+
+ if(rv)
+ {
+ post(CONSOLE_PREFIX "%s successfully copied to %s", source, target);
+ }
+
+ outlet_float(x->outlet, (t_float)rv);
+}
+
+void copy_setup(void)
+{
+ copy_class = class_new(gensym("copy"),
+ (t_newmethod)copy_new,
+ 0, sizeof(t_copy), 0,
+ A_GIMME, 0);
+ class_addlist(copy_class, copy_list);
+}
+
+void block(int fd, int event)
+{
+ struct pollfd topoll;
+ topoll.fd = fd;
+ topoll.events = event;
+ poll(&topoll, 1, -1);
+ // no need to check errors - if the stream is bust then the
+ // next read/write will tell us
+}
+
+int copy_data_buffer(int fdin, int fdout, void *buf, size_t bufsize)
+{
+ for(;;)
+ {
+ void *pos;
+ // read data to buffer
+ ssize_t bytestowrite = read(fdin, buf, bufsize);
+ if (bytestowrite == 0) break; // end of input
+ if (bytestowrite == -1)
+ {
+ if (errno == EINTR) continue; // signal handled
+ if (errno == EAGAIN)
+ {
+ block(fdin, POLLIN);
+ continue;
+ }
+ return -1;
+ }
+
+ // write data from buffer
+ pos = buf;
+ while (bytestowrite > 0)
+ {
+ ssize_t bytes_written = write(fdout, pos, bytestowrite);
+ if (bytes_written == -1)
+ {
+ if (errno == EINTR) continue;
+ if (errno == EAGAIN)
+ {
+ block(fdout, POLLOUT);
+ continue;
+ }
+ return -1;
+ }
+ bytestowrite -= bytes_written;
+ pos += bytes_written;
+ }
+ }
+ return 0;
+}
+
+#ifndef FILECOPY_BUFFER_SIZE
+#define FILECOPY_BUFFER_SIZE (64*1024)
+#endif
+
+int copy_data(int fdin, int fdout)
+{
+ for (size_t bufsize = FILECOPY_BUFFER_SIZE; bufsize >= 256; bufsize /= 2)
+ {
+ void *buffer = malloc(bufsize);
+ if (buffer != NULL)
+ {
+ int result = copy_data_buffer(fdin, fdout, buffer, bufsize);
+ free(buffer);
+ return result;
+ }
+ }
+
+ return -1;
+}
+
+int copy(const char *source, const char *target)
+{
+ struct stat info;
+
+ int fdin = open(source, O_RDONLY|O_BINARY, 0);
+ if (fdin == -1)
+ {
+ error(CONSOLE_PREFIX "invalid input");
+ return -1;
+ }
+
+ int rv = fstat(fdin, &info);
+
+ if(rv == -1)
+ {
+ error(CONSOLE_PREFIX "stat failed\n");
+ return -1;
+ }
+
+ int fdout = open(target, O_WRONLY|O_BINARY|O_CREAT|O_TRUNC, info.st_mode);
+ if (fdout == -1)
+ {
+ error(CONSOLE_PREFIX "invalid output\n");
+ close(fdin);
+ return -1;
+ }
+
+ rv = copy_data(fdin, fdout);
+
+ if (rv == -1)
+ {
+ error(CONSOLE_PREFIX "copy failed\n");
+ }
+
+ return 0;
+}