/* * $Id: filecopy.c,v 0.70 2005/08/09 15:47:00 dankogai Exp $ */ #undef I_POLL #include #include "common/util.c" #ifdef _INC_PERL_XSUB_H static int setcopyerr(int err, char *filename, int line) { SV *OSerr; OSerr = perl_get_sv("MacOSX::File::CopyErr", 1); if (err){ sv_setpvf(OSerr, "err=%d,file=%s,line=%d", err, filename, line); }else{ sv_setiv(OSerr, 0); } return err; } #endif /* _INC_PERL_XSUB_H */ static UniCharCount Utf8toUni(UInt8 *src, UniChar *dst){ UInt32 utf32; UInt8 c1, c2, c3, c4; UniCharCount nchar = 0; for(; *src != '\0'; src++, nchar++){ if (*src < 0x80) { /* 1 byte */ utf32 = *src; }else if (*src < 0xE0){ /* 2 bytes */ c1 = *src++; c2 = *src; utf32 = ((c1 & 0x1F) << 6) | (c2 & 0x3F); }else if (*src < 0xF0){ /* 3 bytes */ c1 = *src++; c2 = *src++; c3 = *src; utf32 = ((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6)| (c3 & 0x3F); }else{ c1 = *src++; c2 = *src++; c3 = *src++; c4 = *src; utf32 = ((c1 & 0x07) << 16) | ((c2 & 0x3F) << 12)| ((c3 & 0x3F) << 6) | (c4 & 0x3F); } if (utf32 <= 0xffff){ *dst++ = (utf32 & 0xffff); }else{ /* ensurrogate */ *dst++ = ((utf32 - 0x10000) >> 10) + 0xD800; *dst++ = ((utf32 - 0x10000) & 0x3FF) + 0xDC00; nchar++; } } return nchar; } static OSErr newfile(char *path, FSRef *FSrefp, FSCatalogInfo *Catp){ FSRef parentFS; UniCharCount namelen; UniChar name[256]; Boolean isDir = 1; OSErr err; if (err = FSPathMakeRef(dirname(path), &parentFS, &isDir)){ return setcopyerr(err, __FILE__, __LINE__); } if ((namelen = Utf8toUni(colon2slash(basename(path)), name)) == 0){ return fnfErr; } /* Create the file with same finder info */ err = FSCreateFileUnicode(&parentFS, namelen, name, kFSCatInfoFinderInfo, Catp, FSrefp, NULL); if (err == paramErr){ /* Try reestablishing FSRef; file is created already */ err == FSPathMakeRef(path, FSrefp, NULL); } return setcopyerr(err, __FILE__, __LINE__); } #define MINCOPYBUFSIZE 4096 static UInt8 MinCopyBuf[MINCOPYBUFSIZE]; typedef struct{ UInt64 s; UInt8 *b; } copybuf ; static copybuf CopyBuf = { MINCOPYBUFSIZE, MinCopyBuf }; #ifdef FILECOPY_DEBUG #define fpf fprintf #else static void fpf(FILE *fp, ...){}; #endif static void freebuf() { if(CopyBuf.b != MinCopyBuf){ fpf(stderr, "free(CopyBuf.b = 0x%x)\n", CopyBuf.b); free(CopyBuf.b); CopyBuf.s = MINCOPYBUFSIZE; CopyBuf.b = MinCopyBuf; } } static UInt64 setbufsiz(UInt64 newsize){ UInt8 *newb; fpf(stderr, "Request %qd: Current %qd\n", newsize, CopyBuf.s); if (CopyBuf.s < newsize){ /* (re|m)alloc only when larger */ if (CopyBuf.b == MinCopyBuf){ /* first time */ if ((newb = (UInt8 *)malloc(newsize)) != NULL){ fpf(stderr, "malloc ok (0x%x)\n", newb); CopyBuf.b = newb; CopyBuf.s = newsize; }else{ fpf(stderr, "malloc failed! using MinCopyBuf\n"); CopyBuf.b = MinCopyBuf; CopyBuf.s = MINCOPYBUFSIZE; } }else{ if ((newb = (UInt8 *)realloc((UInt8 *)CopyBuf.b, newsize)) != NULL) { fpf(stderr, "realloc ok (0x%x)\n", newb); CopyBuf.b = newb; }else{ fpf(stderr, "remalloc failed! using old value.\n"); } } } fpf(stderr, "Buffer size == %qd\n", CopyBuf.s); return CopyBuf.s; } static OSErr copyfork(HFSUniStr255 *forkName, FSRef *src, FSRef *dst){ OSErr err, eof; SInt16 srcfork, dstfork; UInt32 bufsize; ByteCount nread; if (err = FSOpenFork(src, forkName->length, forkName->unicode, fsRdPerm, &srcfork)){ fpf(stderr, "Cannot open src. fork\n"); return setcopyerr(err, __FILE__, __LINE__); } if (err = FSOpenFork(dst, forkName->length, forkName->unicode, fsWrPerm, &dstfork)){ fpf(stderr, "Cannot open dst. fork\n"); FSCloseFork(srcfork); /* src fork is already open ! */ return setcopyerr(err, __FILE__, __LINE__); } while(1){ eof = FSReadFork(srcfork, fsAtMark, 0, CopyBuf.s, CopyBuf.b, &nread); if (err = FSWriteFork(dstfork, fsAtMark, 0, nread, CopyBuf.b, NULL)){ goto CLOSE; } if (eof){ goto CLOSE; } } CLOSE: FSCloseFork(srcfork); FSCloseFork(dstfork); return setcopyerr(err, __FILE__, __LINE__); } #define min(x, y) ((x) < y) ? (x) : (y) static OSErr filecopy(char *src, char *dst, UInt64 maxbufsize, int preserve){ OSErr err; FSCatalogInfo srcCat, dstCat; FSRef srcFS, dstFS; HFSUniStr255 forkName; UTCDateTime now; if (err = FSPathMakeRef(src, &srcFS, NULL)) { return err; } if (err = FSGetCatalogInfo(&srcFS, kFSCatInfoGettableInfo, &srcCat, NULL, NULL, NULL)) { return err; } bcopy(&srcCat, &dstCat, sizeof(FSCatalogInfo)); if (err = newfile(dst, &dstFS, &dstCat)){ fpf(stderr, "Cannot Create File %s\n", dst); return err; } if (srcCat.dataLogicalSize){ setbufsiz(min(srcCat.dataPhysicalSize, maxbufsize)); FSGetDataForkName(&forkName); if (err = copyfork(&forkName, &srcFS, &dstFS)) { return err; } } if (srcCat.rsrcLogicalSize){ setbufsiz(min(srcCat.rsrcPhysicalSize, maxbufsize)); FSGetResourceForkName(&forkName); if (err = copyfork(&forkName, &srcFS, &dstFS)) { return err; } } freebuf(); if (preserve){ err = FSSetCatalogInfo(&dstFS, kFSCatInfoSettableInfo, &srcCat); } return err; } /* static OSErr filemove(char *src, char *dst){ } */ #ifndef _INC_PERL_XSUB_H int main(int argc, char **argv){ OSErr err; int preserve = (argc > 3) ? 1 : 0; if (argc > 2){ err = filecopy(argv[1], argv[2], 0, preserve); fpf(stderr, "Err = %d, preserve = %d\n", err, preserve); } } #endif