diff --git a/fakeroot/.md5sum b/fakeroot/.md5sum index 5a4314257..dcb0f9789 100644 --- a/fakeroot/.md5sum +++ b/fakeroot/.md5sum @@ -1 +1,2 @@ -edfc56b315c8ccfba4049d4158db38dc fakeroot_1.6.4.tar.gz +f252ff4580b0bebba40cef328b02ec40 fakeroot-atfuncs.patch +8912fe0f58cd26ea16873ac1acd0b9f4 fakeroot_1.6.5.tar.gz diff --git a/fakeroot/Pkgfile b/fakeroot/Pkgfile index f13b229d6..a72d14222 100644 --- a/fakeroot/Pkgfile +++ b/fakeroot/Pkgfile @@ -3,12 +3,15 @@ # Maintainer: Jürgen Daubert, juergen dot daubert at t-online dot de name=fakeroot -version=1.6.4 +version=1.6.5 release=1 -source=(http://ftp.debian.org/debian/pool/main/f/$name/${name}_$version.tar.gz) +source=(http://ftp.debian.org/debian/pool/main/f/$name/${name}_$version.tar.gz \ + fakeroot-atfuncs.patch) build () { cd $name-$version + patch -p1 -i $SRC/fakeroot-atfuncs.patch + autoconf ./configure --prefix=/usr \ --mandir=/usr/man make diff --git a/fakeroot/fakeroot-atfuncs.patch b/fakeroot/fakeroot-atfuncs.patch new file mode 100644 index 000000000..890850da1 --- /dev/null +++ b/fakeroot/fakeroot-atfuncs.patch @@ -0,0 +1,593 @@ +Ref: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=402688 + +diff -Nru fakeroot-1.6.5.orig/config.h.in fakeroot-1.6.5/config.h.in +--- fakeroot-1.6.5.orig/config.h.in 2007-03-23 15:16:09.357845554 +0100 ++++ fakeroot-1.6.5/config.h.in 2007-03-23 15:31:20.711930341 +0100 +@@ -19,12 +19,21 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_ENDIAN_H + ++/* Define to 1 if you have the `fchmodat' function. */ ++#undef HAVE_FCHMODAT ++ ++/* Define to 1 if you have the `fchownat' function. */ ++#undef HAVE_FCHOWNAT ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_FCNTL_H + + /* Define to 1 if you have the header file. */ + #undef HAVE_FEATURES_H + ++/* Define to 1 if you have the `fstatat' function. */ ++#undef HAVE_FSTATAT ++ + /* Define to 1 if you have the `getresgid' function. */ + #undef HAVE_GETRESGID + +@@ -49,12 +58,24 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_MEMORY_H + ++/* Define to 1 if you have the `mkdirat' function. */ ++#undef HAVE_MKDIRAT ++ ++/* Define to 1 if you have the `mknodat' function. */ ++#undef HAVE_MKNODAT ++ + /* Define to 1 if you have the header file, and it defines `DIR'. */ + #undef HAVE_NDIR_H + ++/* Define to 1 if you have the `openat' function. */ ++#undef HAVE_OPENAT ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_PTHREAD_H + ++/* Define to 1 if you have the `renameat' function. */ ++#undef HAVE_RENAMEAT ++ + /* have the semun union */ + #undef HAVE_SEMUN_DEF + +@@ -114,6 +135,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_UNISTD_H + ++/* Define to 1 if you have the `unlinkat' function. */ ++#undef HAVE_UNLINKAT ++ + /* second argument of initgroups */ + #undef INITGROUPS_SECOND_ARG + +@@ -185,6 +209,11 @@ + #define TMP_FSTAT __astat + #define NEXT_FSTAT_NOARG next___astat + ++#define WRAP_FSTATAT_QUOTE __astatat ++#define WRAP_FSTATAT __astatat ++#define TMP_FSTATAT __astatat ++#define NEXT_FSTATAT_NOARG next___astatat ++ + #define WRAP_STAT64_QUOTE __astat64 + #define WRAP_STAT64 __astat64 + #define TMP_STAT64 __astat64 +@@ -200,11 +229,24 @@ + #define TMP_FSTAT64 __astat64 + #define NEXT_FSTAT64_NOARG next___astat64 + ++#define WRAP_FSTATAT64_QUOTE __astatat64 ++#define WRAP_FSTATAT64 __astatat64 ++#define TMP_FSTATAT64 __astatat64 ++#define NEXT_FSTATAT64_NOARG next___astatat64 ++ + #define WRAP_MKNOD_QUOTE __amknod + #define WRAP_MKNOD __amknod + #define TMP_MKNOD __amknod + #define NEXT_MKNOD_NOARG next___amknod + ++#define WRAP_MKNODAT_QUOTE __amknodat ++#define WRAP_MKNODAT __amknodat ++#define TMP_MKNODAT __amknodat ++#define NEXT_MKNODAT_NOARG next___amknodat ++ ++ ++/* fifth argument of __xmknodat */ ++#undef XMKNODAT_FIFTH_ARG + + /* fourth argument of __xmknod */ + #undef XMKNOD_FRTH_ARG +diff -Nru fakeroot-1.6.5.orig/configure.ac fakeroot-1.6.5/configure.ac +--- fakeroot-1.6.5.orig/configure.ac 2007-03-23 15:16:09.357845554 +0100 ++++ fakeroot-1.6.5/configure.ac 2007-03-23 15:31:20.711930341 +0100 +@@ -144,6 +144,33 @@ + + ]) + ++dnl Possibly this should only be done if we actually have mknodat ++dnl on the system. Nothing breaks by running the test itself though. ++AH_TEMPLATE([XMKNODAT_FIFTH_ARG], [fifth argument of __xmknodat]) ++dnl glibc uses `* dev' as fifth argument of __xmknodat. ++dnl Although the test below should probably be more general ++dnl (not just __xmknodat, but also mknod etc), at the moment this ++dnl seems enough, as probably glibc is the only that does this. ++AC_MSG_CHECKING([for type of arg of __xmknodat]) ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ++ #include ++ #include ++ #include ++ #include ++ ]], [[ ++ int __xmknodat ( int ver, ++ inf dirfd, ++ const char *pathname , ++ mode_t mode , dev_t dev); ++ ]])],[ ++ AC_DEFINE(XMKNODAT_FIFTH_ARG,) ++ AC_MSG_RESULT([no extra *]) ++ ],[ ++ AC_DEFINE(XMKNODAT_FIFTH_ARG,[*]) ++ AC_MSG_RESULT([needs *]) ++ ++ ]) ++ + AH_TEMPLATE([INITGROUPS_SECOND_ARG], [second argument of initgroups]) + dnl FreeBSD 4.7 uses int instead of gid_t + AC_MSG_CHECKING([for type of arg of initgroups]) +@@ -234,6 +261,8 @@ + ]) + done + ++AC_CHECK_FUNCS(fchmodat fchownat fstatat mkdirat mknodat openat renameat unlinkat) ++ + dnl find out how stat() etc are called. On linux systems, we really + dnl need to wrap (IIRC): + dnl Linux : __xstat +@@ -243,7 +272,7 @@ + + :>fakerootconfig.h.tmp + +-for SEARCH in %stat f%stat l%stat %stat64 f%stat64 l%stat64 %mknod; do ++for SEARCH in %stat f%stat l%stat f%statat %stat64 f%stat64 l%stat64 f%statat64 %mknod %mknodat; do + FUNC=`echo $SEARCH|sed -e 's/.*%//'` + PRE=`echo $SEARCH|sed -e 's/%.*//'` + FOUND= +@@ -271,6 +300,12 @@ + fi + if test "${FUNC}" = "mknod"; then + DEF_END=",d" ++ elif test "${FUNC}" = "mknodat"; then ++ DEF_END=",d,e" ++ elif test "${FUNC}" = "statat"; then ++ DEF_END=",d,e" ++ elif test "${FUNC}" = "statat64"; then ++ DEF_END=",d,e" + else + DEF_END="" + fi +@@ -389,6 +424,11 @@ + #define TMP_FSTAT __astat + #define NEXT_FSTAT_NOARG next___astat + ++#define WRAP_FSTATAT_QUOTE __astatat ++#define WRAP_FSTATAT __astatat ++#define TMP_FSTATAT __astatat ++#define NEXT_FSTATAT_NOARG next___astatat ++ + #define WRAP_STAT64_QUOTE __astat64 + #define WRAP_STAT64 __astat64 + #define TMP_STAT64 __astat64 +@@ -404,10 +444,20 @@ + #define TMP_FSTAT64 __astat64 + #define NEXT_FSTAT64_NOARG next___astat64 + ++#define WRAP_FSTATAT64_QUOTE __astatat64 ++#define WRAP_FSTATAT64 __astatat64 ++#define TMP_FSTATAT64 __astatat64 ++#define NEXT_FSTATAT64_NOARG next___astatat64 ++ + #define WRAP_MKNOD_QUOTE __amknod + #define WRAP_MKNOD __amknod + #define TMP_MKNOD __amknod + #define NEXT_MKNOD_NOARG next___amknod ++ ++#define WRAP_MKNODAT_QUOTE __amknodat ++#define WRAP_MKNODAT __amknodat ++#define TMP_MKNODAT __amknodat ++#define NEXT_MKNODAT_NOARG next___amknodat + ]) + dnl kludge end + +diff -Nru fakeroot-1.6.5.orig/libfakeroot.c fakeroot-1.6.5/libfakeroot.c +--- fakeroot-1.6.5.orig/libfakeroot.c 2007-03-23 15:16:09.357845554 +0100 ++++ fakeroot-1.6.5/libfakeroot.c 2007-03-23 15:31:20.721930057 +0100 +@@ -548,6 +548,27 @@ + return 0; + } + ++#ifdef HAVE_FSTATAT ++int WRAP_FSTATAT FSTATAT_ARG(int ver, ++ int dir_fd, ++ const char *path, ++ struct stat *st, ++ int flags){ ++ ++ ++ int r; ++ ++ r=NEXT_FSTATAT(ver, dir_fd, path, st, flags); ++ if(r) ++ return -1; ++#ifndef STUPID_ALPHA_HACK ++ send_get_stat(st); ++#else ++ send_get_stat(st,ver); ++#endif ++ return 0; ++} ++#endif /* HAVE_FSTATAT */ + + #ifdef STAT64_SUPPORT + +@@ -605,7 +626,29 @@ + return 0; + } + ++#ifdef HAVE_FSTATAT ++int WRAP_FSTATAT64 FSTATAT64_ARG(int ver, ++ int dir_fd, ++ const char *path, ++ struct stat64 *st, ++ int flags){ ++ ++ ++ int r; ++ ++ r=NEXT_FSTATAT64(ver, dir_fd, path, st, flags); ++ if(r) ++ return -1; ++#ifndef STUPID_ALPHA_HACK ++ send_get_stat64(st); ++#else ++ send_get_stat64(st,ver); + #endif ++ return 0; ++} ++#endif /* HAVE_FSTATAT */ ++ ++#endif /* STAT64_SUPPORT */ + + + +@@ -724,6 +767,54 @@ + return r; + } + ++ ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_FCHOWNAT ++int fchownat(int dir_fd, const char *path, uid_t owner, gid_t group, int flags) { ++ int r; ++ /* If AT_SYMLINK_NOFOLLOW is set in the fchownat call it should ++ be when we stat it. */ ++#ifdef STAT64_SUPPORT ++ struct stat64 st; ++ r=NEXT_FSTATAT64(_STAT_VER, dir_fd, path, &st, (flags & AT_SYMLINK_NOFOLLOW)); ++#else ++ struct stat st; ++ r=NEXT_FSTATAT(_STAT_VER, dir_fd, path, &st, (flags & AT_SYMLINK_NOFOLLOW)); ++#endif ++ ++ if(r) ++ return(r); ++ ++ st.st_uid=owner; ++ st.st_gid=group; ++#ifdef STAT64_SUPPORT ++#ifndef STUPID_ALPHA_HACK ++ send_stat64(&st,chown_func); ++#else ++ send_stat64(&st,chown_func, _STAT_VER); ++#endif ++#else ++#ifndef STUPID_ALPHA_HACK ++ send_stat(&st,chown_func); ++#else ++ send_stat(&st,chown_func, _STAT_VER); ++#endif ++#endif /* STAT64_SUPPORT */ ++ ++ if(!dont_try_chown()) ++ r=next_fchownat(dir_fd,path,owner,group,flags); ++ else ++ r=0; ++ ++ if(r&&(errno==EPERM)) ++ r=0; ++ ++ return r; ++} ++#endif /* HAVE_FCHOWNAT */ ++#endif /* HAVE_FSTATAT */ ++ ++ + int chmod(const char *path, mode_t mode){ + INT_STRUCT_STAT st; + int r; +@@ -786,6 +877,40 @@ + return r; + } + ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_FCHMODAT ++int fchmodat(int dir_fd, const char *path, mode_t mode, int flags) { ++/* (int fd, mode_t mode){*/ ++ int r; ++ struct stat st; ++ ++ /* If AT_SYMLINK_NOFOLLOW is set in the fchownat call it should ++ be when we stat it. */ ++ r=NEXT_FSTATAT(_STAT_VER, dir_fd, path, &st, flags & AT_SYMLINK_NOFOLLOW); ++ ++ if(r) ++ return(r); ++ ++ st.st_mode=(mode&ALLPERMS)|(st.st_mode&~ALLPERMS); ++#ifndef STUPID_ALPHA_HACK ++ send_stat(&st,chmod_func); ++#else ++ send_stat(&st,chmod_func, _STAT_VER); ++#endif ++ ++ /* see chmod() for comment */ ++ mode |= 0600; ++ if(S_ISDIR(st.st_mode)) ++ mode |= 0100; ++ ++ r=next_fchmodat(dir_fd, path, mode, flags); ++ if(r&&(errno==EPERM)) ++ r=0; ++ return r; ++} ++#endif /* HAVE_FCHMODAT */ ++#endif /* HAVE_FSTATAT */ ++ + int WRAP_MKNOD MKNOD_ARG(int ver UNUSED, + const char *pathname, + mode_t mode, dev_t XMKNOD_FRTH_ARG dev) +@@ -825,6 +950,54 @@ + return 0; + } + ++ ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_MKNODAT ++int WRAP_MKNODAT MKNODAT_ARG(int ver UNUSED, ++ int dir_fd, ++ const char *pathname, ++ mode_t mode, dev_t XMKNODAT_FIFTH_ARG dev) ++{ ++ struct stat st; ++ mode_t old_mask=umask(022); ++ int fd,r; ++ ++ umask(old_mask); ++ ++ /*Don't bother to mknod the file, that probably doesn't work. ++ just create it as normal file, and leave the permissions ++ to the fakemode.*/ ++ ++ fd=openat(dir_fd, pathname, O_WRONLY|O_CREAT|O_TRUNC, 00644); ++ ++ if(fd==-1) ++ return -1; ++ ++ close(fd); ++ /* get the inode, to communicate with faked */ ++ ++ /* The only known flag is AT_SYMLINK_NOFOLLOW and ++ we don't want that here. */ ++ r=NEXT_FSTATAT(_STAT_VER, dir_fd, pathname, &st, 0); ++ ++ if(r) ++ return -1; ++ ++ st.st_mode= mode & ~old_mask; ++ st.st_rdev= XMKNODAT_FIFTH_ARG dev; ++ ++#ifndef STUPID_ALPHA_HACK ++ send_stat(&st,mknod_func); ++#else ++ send_stat(&st,mknod_func, _STAT_VER); ++#endif ++ ++ return 0; ++} ++#endif /* HAVE_MKNODAT */ ++#endif /* HAVE_FSTATAT */ ++ ++ + int mkdir(const char *path, mode_t mode){ + INT_STRUCT_STAT st; + int r; +@@ -857,6 +1030,42 @@ + return 0; + } + ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_MKDIRAT ++int mkdirat(int dir_fd, const char *path, mode_t mode){ ++ struct stat st; ++ int r; ++ mode_t old_mask=umask(022); ++ ++ umask(old_mask); ++ ++ ++ /* we need to tell the fake deamon the real mode. In order ++ to communicate with faked we need a struct stat, so we now ++ do a stat of the new directory (just for the inode/dev) */ ++ ++ r=next_mkdirat(dir_fd, path, mode|0700); ++ /* mode|0700: see comment in the chown() function above */ ++ if(r) ++ return -1; ++ r=NEXT_FSTATAT(_STAT_VER, dir_fd, path, &st, 0); ++ ++ if(r) ++ return -1; ++ ++ st.st_mode=(mode&~old_mask&ALLPERMS)|(st.st_mode&~ALLPERMS)|S_IFDIR; ++ ++#ifndef STUPID_ALPHA_HACK ++ send_stat(&st, chmod_func); ++#else ++ send_stat(&st, chmod_func, _STAT_VER); ++#endif ++ ++ return 0; ++} ++#endif /* HAVE_MKDIRAT */ ++#endif /* HAVE_FSTATAT */ ++ + /* + The remove funtions: unlink, rmdir, rename. + These functions can all remove inodes from the system. +@@ -895,6 +1104,40 @@ + return 0; + } + ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_UNLINKAT ++int unlinkat(int dir_fd, const char *pathname, int flags){ ++ int r; ++#ifdef STAT64_SUPPORT ++ struct stat64 st; ++ r=NEXT_FSTATAT64(_STAT_VER, dir_fd, pathname, &st, (flags&~AT_REMOVEDIR) | AT_SYMLINK_NOFOLLOW); ++#else ++ struct stat st; ++ r=NEXT_FSTATAT(_STAT_VER, dir_fd, pathname, &st, (flags&~AT_REMOVEDIR) | AT_SYMLINK_NOFOLLOW); ++#endif ++ if(r) ++ return -1; ++ ++ r=next_unlinkat(dir_fd, pathname, flags); ++ ++ if(r) ++ return -1; ++ ++#ifdef STAT64_SUPPORT ++#ifndef STUPID_ALPHA_HACK ++ send_stat64(&st, unlink_func); ++#else ++ send_stat64(&st, unlink_func, _STAT_VER); ++#endif ++#else ++ send_stat(&st, unlink_func); ++#endif ++ ++ return 0; ++} ++#endif /* HAVE_UNLINKAT */ ++#endif /* HAVE_FSTATAT */ ++ + /* + See the `remove funtions:' comments above for more info on + these remove function wrappers. +@@ -976,6 +1219,37 @@ + return 0; + } + ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_RENAMEAT ++int renameat(int olddir_fd, const char *oldpath, ++ int newdir_fd, const char *newpath){ ++ int r,s; ++ struct stat st; ++ ++ /* If newpath points to an existing file, that file will be ++ unlinked. Make sure we tell the faked daemon about this! */ ++ ++ /* we need the st_new struct in order to inform faked about the ++ (possible) unlink of the file */ ++ ++ r=NEXT_FSTATAT(_STAT_VER, newdir_fd, newpath, &st, AT_SYMLINK_NOFOLLOW); ++ ++ s=next_renameat(olddir_fd, oldpath, newdir_fd, newpath); ++ if(s) ++ return -1; ++ if(!r) ++#ifndef STUPID_ALPHA_HACK ++ send_stat(&st,unlink_func); ++#else ++ send_stat(&st,unlink_func, _STAT_VER); ++#endif ++ ++ return 0; ++} ++#endif /* HAVE_RENAMEAT */ ++#endif /* HAVE_FSTATAT */ ++ ++ + #ifdef FAKEROOT_FAKENET + pid_t fork(void) + { +diff -Nru fakeroot-1.6.5.orig/wrapfunc.inp fakeroot-1.6.5/wrapfunc.inp +--- fakeroot-1.6.5.orig/wrapfunc.inp 2007-03-23 15:16:09.357845554 +0100 ++++ fakeroot-1.6.5/wrapfunc.inp 2007-03-23 15:31:20.721930057 +0100 +@@ -22,15 +22,27 @@ + WRAP_LSTAT;int;LSTAT_ARG(int ver, const char *file_name, struct stat *buf);LSTAT_ARG(ver, file_name, buf);LSTAT + WRAP_STAT;int;STAT_ARG(int ver, const char *file_name, struct stat *buf);STAT_ARG(ver, file_name, buf);STAT + WRAP_FSTAT;int;FSTAT_ARG(int ver, int fd, struct stat *buf);FSTAT_ARG(ver, fd, buf);FSTAT ++#ifdef HAVE_FSTATAT ++WRAP_FSTATAT;int;FSTATAT_ARG(int ver, int dir_fd, const char *path, struct stat *buf, int flags);FSTATAT_ARG(ver, dir_fd, path, buf, flags);FSTATAT ++#endif /* HAVE_FSTATAT */ + + #ifdef STAT64_SUPPORT + WRAP_LSTAT64;int;LSTAT64_ARG(int ver, const char *file_name, struct stat64 *buf);LSTAT64_ARG(ver, file_name, buf);LSTAT64 + WRAP_STAT64;int;STAT64_ARG(int ver, const char *file_name, struct stat64 *buf);STAT64_ARG(ver, file_name, buf);STAT64 + WRAP_FSTAT64;int;FSTAT64_ARG(int ver, int fd, struct stat64 *buf);FSTAT64_ARG(ver, fd, buf);FSTAT64 +-#endif ++#ifdef HAVE_FSTATAT ++WRAP_FSTATAT64;int;FSTATAT64_ARG(int ver, int dir_fd, const char *path, struct stat64 *buf, int flags);FSTATAT64_ARG(ver, dir_fd, path, buf, flags);FSTATAT64 ++#endif /* HAVE_FSTATAT */ ++#endif /* STAT64_SUPPORT */ + + WRAP_MKNOD;int;MKNOD_ARG(int ver, const char *pathname, mode_t mode, dev_t XMKNOD_FRTH_ARG dev);MKNOD_ARG(ver, pathname, mode, dev);MKNOD + ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_MKNODAT ++WRAP_MKNODAT;int;MKNODAT_ARG(int ver, int dir_fd, const char *pathname, mode_t mode, dev_t dev);MKNODAT_ARG(ver, dir_fd, pathname, mode, dev);MKNODAT ++#endif /* HAVE_MKNODAT */ ++#endif /* HAVE_FSTATAT */ ++ + /*opendir;DIR *;(const char *name);(name)*/ + /*closedir;int;(DIR *dir);(dir)*/ + /*readdir;struct dirent *;(DIR *dir);(dir)*/ +@@ -89,3 +101,26 @@ + #endif /* HAVE_SETFSGID */ + initgroups;int;(const char *user, INITGROUPS_SECOND_ARG group);(user, group) + setgroups;int;(SETGROUPS_SIZE_TYPE size, const gid_t *list);(size, list) ++ ++#ifdef HAVE_FSTATAT ++#ifdef HAVE_FCHMODAT ++fchmodat;int;(int dir_fd, const char *path, mode_t mode, int flags);(dir_fd, path, mode, flags) ++#endif /* HAVE_FCHMODAT */ ++#ifdef HAVE_FCHOWNAT ++fchownat;int;(int dir_fd, const char *path, uid_t owner, gid_t group, int flags);(dir_fd, path, owner, group, flags) ++#endif /* HAVE_FCHOWNAT */ ++#ifdef HAVE_MKDIRAT ++mkdirat;int;(int dir_fd, const char *pathname, mode_t mode);(dir_fd, pathname, mode) ++#endif /* HAVE_MKDIRAT */ ++#ifdef HAVE_OPENAT ++openat;int;(int dir_fd, const char *pathname, int flags);(dir_fd, pathname, flags) ++#endif /* HAVE_OPENAT */ ++#ifdef HAVE_RENAMEAT ++renameat;int;(int olddir_fd, const char *oldpath, int newdir_fd, const char *newpath);(olddir_fd, oldpath, newdir_fd, newpath) ++#endif /* HAVE_RENAMEAT */ ++#ifdef HAVE_UNLINKAT ++unlinkat;int;(int dir_fd, const char *pathname, int flags);(dir_fd, pathname, flags) ++#endif /* HAVE_UNLINKAT */ ++#endif /* HAVE_FSTATAT */ ++ ++