X-Git-Url: http://git.rot13.org/?p=perl-fuse.git;a=blobdiff_plain;f=Fuse.xs;h=5be011a40445884ec9d9427c501adfee3e650481;hp=fb73a12794c0dac95e3534e397231e57d9fad634;hb=8ac7788ce64454586f49f896f3bfe9dcecb6cfca;hpb=4de2d39279b7cfcab70112b0986ee554a0c859ee diff --git a/Fuse.xs b/Fuse.xs index fb73a12..5be011a 100755 --- a/Fuse.xs +++ b/Fuse.xs @@ -5,13 +5,45 @@ #include -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if (defined(__FreeBSD__) && __FreeBSD__ < 10) || defined(__NetBSD__) # define XATTR_CREATE 1 # define XATTR_REPLACE 2 #else # include #endif +#if defined(__linux__) +# define STAT_NSEC(st, st_xtim) ((st)->st_xtim.tv_nsec) +#else +# define STAT_NSEC(st, st_xtim) ((st)->st_xtim##espec.tv_nsec) +#endif + +/* Implement a macro to handle multiple formats (integer, float, and array + * containing seconds and nanoseconds). */ +#define PULL_TIME(st, st_xtim, svp) \ +{ \ + SV *sv = svp; \ + if (SvROK(sv)) { \ + AV *av = (AV *)SvRV(sv); \ + if (SvTYPE((SV *)av) != SVt_PVAV) { \ + Perl_croak_nocontext("Reference was not array ref"); \ + } \ + if (av_len(av) != 1) { \ + Perl_croak_nocontext("Array of incorrect dimension"); \ + } \ + (st)->st_xtim##e = SvIV(*(av_fetch(av, 0, FALSE))); \ + STAT_NSEC(st, st_xtim) = SvIV(*(av_fetch(av, 1, FALSE))); \ + } \ + else if (SvNOK(sv) || SvIOK(sv)) { \ + double tm = SvNV(sv); \ + (st)->st_xtim##e = (int)tm; \ + STAT_NSEC(st, st_xtim) = (tm - (int)tm) * 1000000000; \ + } \ + else { \ + Perl_croak_nocontext("Invalid data type passed"); \ + } \ +} + /* Determine if threads support should be included */ #ifdef USE_ITHREADS # ifdef I_PTHREAD @@ -33,16 +65,9 @@ #define MY_CXT_KEY "Fuse::_guts" XS_VERSION #if FUSE_VERSION >= 28 -# define N_CALLBACKS 40 -/* # define N_CALLBACKS 41 */ -#elif FUSE_VERSION >= 26 -# define N_CALLBACKS 38 -#elif FUSE_VERSION >= 25 -# define N_CALLBACKS 35 -#elif FUSE_VERSION >= 23 -# define N_CALLBACKS 31 +# define N_CALLBACKS 41 #else -# define N_CALLBACKS 25 +# define N_CALLBACKS 38 #endif typedef struct { @@ -55,6 +80,7 @@ typedef struct { #ifdef USE_ITHREADS perl_mutex mutex; #endif + int utimens_as_array; } my_cxt_t; START_MY_CXT; @@ -130,8 +156,10 @@ void S_fh_store_handle(pTHX_ pMY_CXT_ struct fuse_file_info *fi, SV *sv) { SvSHARE(sv); } #endif - MAGIC *mg = (SvTYPE(sv) == SVt_PVMG) ? mg_find(sv, PERL_MAGIC_shared_scalar) : NULL; - fi->fh = mg ? PTR2IV(mg->mg_ptr) : PTR2IV(sv); + /* This seems to be screwing things up... */ + // MAGIC *mg = (SvTYPE(sv) == SVt_PVMG) ? mg_find(sv, PERL_MAGIC_shared_scalar) : NULL; + // fi->fh = mg ? PTR2IV(mg->mg_ptr) : PTR2IV(sv); + fi->fh = PTR2IV(sv); if(hv_store_ent(MY_CXT.handles, FH_KEY(fi), SvREFCNT_inc(sv), 0) == NULL) { SvREFCNT_dec(sv); } @@ -161,9 +189,9 @@ int _PLfuse_getattr(const char *file, struct stat *result) { } else { result->st_blocks = POPi; result->st_blksize = POPi; - result->st_ctime = POPi; - result->st_mtime = POPi; - result->st_atime = POPi; + PULL_TIME(result, st_ctim, POPs); + PULL_TIME(result, st_mtim, POPs); + PULL_TIME(result, st_atim, POPs); result->st_size = POPn; // we pop double here to support files larger than 4Gb (long limit) result->st_rdev = POPi; result->st_gid = POPi; @@ -507,11 +535,9 @@ int _PLfuse_open (const char *file, struct fuse_file_info *fi) { */ fi->fh = 0; /* Ensure it starts with 0 - important if they don't set it */ fihash = newHV(); -#if FUSE_VERSION >= 24 (void) hv_store(fihash, "direct_io", 9, newSViv(fi->direct_io), 0); (void) hv_store(fihash, "keep_cache", 10, newSViv(fi->keep_cache), 0); -#endif -#if FUSE_VERSION >= 29 +#if FUSE_VERSION >= 28 (void) hv_store(fihash, "nonseekable", 11, newSViv(fi->nonseekable), 0); #endif XPUSHs(sv_2mortal(newRV_noinc((SV*) fihash))); @@ -532,14 +558,12 @@ int _PLfuse_open (const char *file, struct fuse_file_info *fi) { if (rv == 0) { /* Success, so copy the file handle which they returned */ -#if FUSE_VERSION >= 24 SV **svp; if ((svp = hv_fetch(fihash, "direct_io", 9, 0)) != NULL) fi->direct_io = SvIV(*svp); if ((svp = hv_fetch(fihash, "keep_cache", 10, 0)) != NULL) fi->keep_cache = SvIV(*svp); -#endif -#if FUSE_VERSION >= 29 +#if FUSE_VERSION >= 28 if ((svp = hv_fetch(fihash, "nonseekable", 11, 0)) != NULL) fi->nonseekable = SvIV(*svp); #endif @@ -908,7 +932,6 @@ int _PLfuse_removexattr (const char *file, const char *name) { return rv; } -#if FUSE_VERSION >= 23 int _PLfuse_opendir(const char *file, struct fuse_file_info *fi) { int rv; FUSE_CONTEXT_PRE; @@ -996,9 +1019,9 @@ int _PLfuse_readdir(const char *file, void *dirh, fuse_fill_dir_t dirfil, st.st_gid = SvIV(*(av_fetch(av2, 5, FALSE))); st.st_rdev = SvIV(*(av_fetch(av2, 6, FALSE))); st.st_size = SvNV(*(av_fetch(av2, 7, FALSE))); - st.st_atime = SvIV(*(av_fetch(av2, 8, FALSE))); - st.st_mtime = SvIV(*(av_fetch(av2, 9, FALSE))); - st.st_ctime = SvIV(*(av_fetch(av2, 10, FALSE))); + PULL_TIME(&st, st_atim, *(av_fetch(av2, 8, FALSE))); + PULL_TIME(&st, st_mtim, *(av_fetch(av2, 9, FALSE))); + PULL_TIME(&st, st_ctim, *(av_fetch(av2, 10, FALSE))); st.st_blksize = SvIV(*(av_fetch(av2, 11, FALSE))); st.st_blocks = SvIV(*(av_fetch(av2, 12, FALSE))); st_filled = 1; @@ -1078,11 +1101,7 @@ int _PLfuse_fsyncdir(const char *file, int datasync, return rv; } -#if FUSE_VERSION >= 26 void *_PLfuse_init(struct fuse_conn_info *fc) -#else /* FUSE_VERSION < 26 */ -void *_PLfuse_init(void) -#endif /* FUSE_VERSION >= 26 */ { void *rv = NULL; int prv; @@ -1127,9 +1146,7 @@ void _PLfuse_destroy(void *private_data) { DEBUGf("init end\n"); FUSE_CONTEXT_POST; } -#endif /* FUSE_VERSION >= 23 */ -#if FUSE_VERSION >= 25 int _PLfuse_access(const char *file, int mask) { int rv; FUSE_CONTEXT_PRE; @@ -1169,7 +1186,7 @@ int _PLfuse_create(const char *file, mode_t mode, struct fuse_file_info *fi) { fihash = newHV(); (void) hv_store(fihash, "direct_io", 9, newSViv(fi->direct_io), 0); (void) hv_store(fihash, "keep_cache", 10, newSViv(fi->keep_cache), 0); -#if FUSE_VERSION >= 29 +#if FUSE_VERSION >= 28 (void) hv_store(fihash, "nonseekable", 11, newSViv(fi->nonseekable), 0); #endif XPUSHs(sv_2mortal(newRV_noinc((SV*) fihash))); @@ -1195,7 +1212,7 @@ int _PLfuse_create(const char *file, mode_t mode, struct fuse_file_info *fi) { fi->direct_io = SvIV(*svp); if ((svp = hv_fetch(fihash, "keep_cache", 10, 0)) != NULL) fi->keep_cache = SvIV(*svp); -#if FUSE_VERSION >= 29 +#if FUSE_VERSION >= 28 if ((svp = hv_fetch(fihash, "nonseekable", 11, 0)) != NULL) fi->nonseekable = SvIV(*svp); #endif @@ -1264,9 +1281,9 @@ int _PLfuse_fgetattr(const char *file, struct stat *result, } else { result->st_blocks = POPi; result->st_blksize = POPi; - result->st_ctime = POPi; - result->st_mtime = POPi; - result->st_atime = POPi; + PULL_TIME(result, st_ctim, POPs); + PULL_TIME(result, st_mtim, POPs); + PULL_TIME(result, st_atim, POPs); result->st_size = POPn; // we pop double here to support files larger than 4Gb (long limit) result->st_rdev = POPi; result->st_gid = POPi; @@ -1284,9 +1301,7 @@ int _PLfuse_fgetattr(const char *file, struct stat *result, FUSE_CONTEXT_POST; return rv; } -#endif /* FUSE_VERSION >= 25 */ -#if FUSE_VERSION >= 26 int _PLfuse_lock(const char *file, struct fuse_file_info *fi, int cmd, struct flock *lockinfo) { int rv; @@ -1364,8 +1379,30 @@ int _PLfuse_utimens(const char *file, const struct timespec tv[2]) { SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,0))); - XPUSHs(tv ? sv_2mortal(newSVnv(tv[0].tv_sec + (tv[0].tv_nsec / 1000000000.0))) : &PL_sv_undef); - XPUSHs(tv ? sv_2mortal(newSVnv(tv[1].tv_sec + (tv[1].tv_nsec / 1000000000.0))) : &PL_sv_undef); + if (MY_CXT.utimens_as_array) { + /* Pushing timespecs as 2-element arrays (if tv is present). */ + AV *av; + if (tv) { + av = newAV(); + av_push(av, newSViv(tv[0].tv_sec)); + av_push(av, newSViv(tv[0].tv_nsec)); + XPUSHs(sv_2mortal(newRV_noinc((SV *)av))); + av = newAV(); + av_push(av, newSViv(tv[1].tv_sec)); + av_push(av, newSViv(tv[1].tv_nsec)); + XPUSHs(sv_2mortal(newRV_noinc((SV *)av))); + } + else { + XPUSHs(&PL_sv_undef); + XPUSHs(&PL_sv_undef); + } + + } + else { + /* Pushing timespecs as floating point (double) values. */ + XPUSHs(tv ? sv_2mortal(newSVnv(tv[0].tv_sec + (tv[0].tv_nsec / 1000000000.0))) : &PL_sv_undef); + XPUSHs(tv ? sv_2mortal(newSVnv(tv[1].tv_sec + (tv[1].tv_nsec / 1000000000.0))) : &PL_sv_undef); + } PUTBACK; rv = call_sv(MY_CXT.callback[36],G_SCALAR); SPAGAIN; @@ -1417,22 +1454,24 @@ int _PLfuse_bmap(const char *file, size_t blocksize, uint64_t *idx) { FUSE_CONTEXT_POST; return rv; } -#endif /* FUSE_VERSION >= 26 */ #if FUSE_VERSION >= 28 int _PLfuse_ioctl(const char *file, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data) { int rv; + SV *sv = NULL; FUSE_CONTEXT_PRE; DEBUGf("ioctl begin\n"); ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(file,0))); - XPUSHs(sv_2mortal(newSViv(cmd))); - XPUSHs(sv_2mortal(newSViv((uintptr_t)arg))); + /* I don't know why cmd is a signed int in the first place; + * casting as unsigned so stupid tricks don't have to be done on + * the perl side */ + XPUSHs(sv_2mortal(newSVuv((unsigned int)cmd))); XPUSHs(sv_2mortal(newSViv(flags))); - if (_IOC_DIR(cmd) & _IOC_READ) + if (_IOC_DIR(cmd) & _IOC_WRITE) XPUSHs(sv_2mortal(newSVpvn(data, _IOC_SIZE(cmd)))); else XPUSHs(&PL_sv_undef); @@ -1440,12 +1479,18 @@ int _PLfuse_ioctl(const char *file, int cmd, void *arg, PUTBACK; rv = call_sv(MY_CXT.callback[39],G_ARRAY); SPAGAIN; - if (_IOC_DIR(cmd) & _IOC_WRITE) { - if (rv == 2) { - SV *sv = POPs; + if ((_IOC_DIR(cmd) & _IOC_READ) && (rv == 2)) { + sv = POPs; + rv--; + } + + if (rv > 0) + rv = POPi; + + if ((_IOC_DIR(cmd) & _IOC_READ) && !rv) { + if (sv) { size_t len; char *rdata = SvPV(sv, len); - rv--; if (len > _IOC_SIZE(cmd)) { fprintf(stderr, "ioctl(): returned data was too large for data area\n"); @@ -1457,12 +1502,10 @@ int _PLfuse_ioctl(const char *file, int cmd, void *arg, } } else { - fprintf(stderr, "ioctl(): ioctl was a write op, but no data was returned from call?\n"); + fprintf(stderr, "ioctl(): ioctl was a read op, but no data was returned from call?\n"); rv = -EFAULT; } } - if (rv > 0) - rv = POPi; FREETMPS; LEAVE; PUTBACK; @@ -1471,12 +1514,42 @@ int _PLfuse_ioctl(const char *file, int cmd, void *arg, return rv; } -#if 0 int _PLfuse_poll(const char *file, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp) { - + int rv; + SV *sv = NULL; + FUSE_CONTEXT_PRE; + DEBUGf("poll begin\n"); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(file,0))); + if (ph) { + /* Still gotta figure out how to do this right... */ + sv = newSViv(PTR2IV(ph)); + SvREADONLY_on(sv); + SvSHARE(sv); + XPUSHs(sv); + } + else + XPUSHs(&PL_sv_undef); + XPUSHs(sv_2mortal(newSViv(*reventsp))); + XPUSHs(FH_GETHANDLE(fi)); + PUTBACK; + rv = call_sv(MY_CXT.callback[40],G_ARRAY); + SPAGAIN; + if (rv > 1) { + *reventsp = POPi; + rv--; + } + rv = (rv ? POPi : 0); + FREETMPS; + LEAVE; + PUTBACK; + DEBUGf("poll end: %i\n", rv); + FUSE_CONTEXT_POST; + return rv; } -#endif #endif /* FUSE_VERSION >= 28 */ struct fuse_operations _available_ops = { @@ -1505,30 +1578,22 @@ setxattr: _PLfuse_setxattr, getxattr: _PLfuse_getxattr, listxattr: _PLfuse_listxattr, removexattr: _PLfuse_removexattr, -#if FUSE_VERSION >= 23 opendir: _PLfuse_opendir, readdir: _PLfuse_readdir, releasedir: _PLfuse_releasedir, fsyncdir: _PLfuse_fsyncdir, init: _PLfuse_init, destroy: _PLfuse_destroy, -#endif /* FUSE_VERSION >= 23 */ -#if FUSE_VERSION >= 25 access: _PLfuse_access, create: _PLfuse_create, ftruncate: _PLfuse_ftruncate, fgetattr: _PLfuse_fgetattr, -#endif /* FUSE_VERSION >= 25 */ -#if FUSE_VERSION >= 26 lock: _PLfuse_lock, utimens: _PLfuse_utimens, bmap: _PLfuse_bmap, -#endif /* FUSE_VERSION >= 26 */ #if FUSE_VERSION >= 28 ioctl: _PLfuse_ioctl, -#if 0 poll: _PLfuse_poll, -#endif #endif /* FUSE_VERSION >= 28 */ }; @@ -1613,7 +1678,6 @@ fuse_version() OUTPUT: RETVAL -#ifndef __FreeBSD__ SV * XATTR_CREATE() CODE: @@ -1628,8 +1692,6 @@ XATTR_REPLACE() OUTPUT: RETVAL -#endif - void perl_fuse_main(...) PREINIT: @@ -1641,7 +1703,7 @@ perl_fuse_main(...) struct fuse_chan *fc; dMY_CXT; INIT: - if(items != N_CALLBACKS + 5) { + if(items != N_CALLBACKS + 6) { fprintf(stderr,"Perl<->C inconsistency or internal error\n"); XSRETURN_UNDEF; } @@ -1667,8 +1729,9 @@ perl_fuse_main(...) #if FUSE_VERSION >= 28 fops.flag_nullpath_ok = SvIV(ST(4)); #endif /* FUSE_VERSION >= 28 */ + MY_CXT.utimens_as_array = SvIV(ST(5)); for(i=0;i= 28 + +void +pollhandle_destroy(...) + PREINIT: + struct fuse_pollhandle *ph; + INIT: + if (items != 1) { + fprintf(stderr, "No pollhandle passed?\n"); + XSRETURN_UNDEF; + } + CODE: + ph = INT2PTR(struct fuse_pollhandle*, SvIV(ST(0))); + fuse_pollhandle_destroy(ph); + +int +notify_poll(...) + PREINIT: + struct fuse_pollhandle *ph; + INIT: + if (items != 1) { + fprintf(stderr, "No pollhandle passed?\n"); + XSRETURN_UNDEF; + } + CODE: + ph = INT2PTR(struct fuse_pollhandle*, SvIV(ST(0))); + RETVAL = fuse_notify_poll(ph); + OUTPUT: + RETVAL + +#endif