Submitted By: Kelledin Date: 2004-03-06 Initial Package Version: 5.2.0 Upstream Status: Maintained separately Origin: http://acl.bestbits.at Description: This patch updates coreutils to properly support access control lists (ACLs) and extended attributes (EAs). This is a unified patch ported from the coreutils-5.1.2 patchset at acl.bestbits.at; note that the SELinux support from that patchset has been excluded (for now). diff -Naur coreutils-5.2.0/README coreutils-5.2.0-acl/README --- coreutils-5.2.0/README 2004-01-18 01:59:41.000000000 -0600 +++ coreutils-5.2.0-acl/README 2004-03-04 19:22:50.000000000 -0600 @@ -9,11 +9,11 @@ [ basename cat chgrp chmod chown chroot cksum comm cp csplit cut date dd df dir dircolors dirname du echo env expand expr factor false fmt fold - ginstall groups head hostid hostname id join kill link ln logname ls - md5sum mkdir mkfifo mknod mv nice nl nohup od paste pathchk pinky pr - printenv printf ptx pwd readlink rm rmdir seq sha1sum shred sleep sort - split stat stty su sum sync tac tail tee test touch tr true tsort tty - uname unexpand uniq unlink uptime users vdir wc who whoami yes + ginstall groups head id join kill link ln logname ls md5sum mkdir mkfifo + mknod mv nice nl nohup od paste pathchk pinky pr printenv printf ptx pwd + readlink rm rmdir seq sha1sum shred sleep sort split stat stty su sum + sync tac tail tee test touch tr true tsort tty uname unexpand uniq + unlink uptime users vdir wc who whoami yes See the file NEWS for a list of major changes in the current release. diff -Naur coreutils-5.2.0/config.hin coreutils-5.2.0-acl/config.hin --- coreutils-5.2.0/config.hin 2004-02-08 14:13:21.000000000 -0600 +++ coreutils-5.2.0-acl/config.hin 2004-03-04 19:26:42.000000000 -0600 @@ -96,6 +96,33 @@ /* Define to 1 if you have the `acl' function. */ #undef HAVE_ACL +/* Define to 1 if you have the `acl_delete_def_file' function. */ +#undef HAVE_ACL_DELETE_DEF_FILE + +/* Define to 1 if you have the `acl_entries' function. */ +#undef HAVE_ACL_ENTRIES + +/* Define to 1 if you have the `acl_extended_file' function. */ +#undef HAVE_ACL_EXTENDED_FILE + +/* Define to 1 if you have the `acl_free' function. */ +#undef HAVE_ACL_FREE + +/* Define to 1 if you have the `acl_from_text' function. */ +#undef HAVE_ACL_FROM_TEXT + +/* Define to 1 if you have the `acl_get_file' function. */ +#undef HAVE_ACL_GET_FILE + +/* Define to 1 if you have the header file. */ +#undef HAVE_ACL_LIBACL_H + +/* Define to 1 if you have the `acl_set_file' function. */ +#undef HAVE_ACL_SET_FILE + +/* Define to 1 if you have the `acl_to_text' function. */ +#undef HAVE_ACL_TO_TEXT + /* Define to 1 if you have the `alarm' function. */ #undef HAVE_ALARM @@ -112,6 +139,15 @@ /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT +/* Define to 1 if you have the `attr_copy_file' function. */ +#undef HAVE_ATTR_COPY_FILE + +/* Define to 1 if you have the header file. */ +#undef HAVE_ATTR_ERROR_CONTEXT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ATTR_LIBATTR_H + /* Define to 1 if you have the header file. */ #undef HAVE_BP_SYM_H @@ -404,9 +440,6 @@ /* Define to 1 if you have the `gethostbyname' function. */ #undef HAVE_GETHOSTBYNAME -/* Define to 1 if you have the `gethostid' function. */ -#undef HAVE_GETHOSTID - /* Define to 1 if you have the `gethostname' function. */ #undef HAVE_GETHOSTNAME @@ -1335,6 +1368,12 @@ . */ #undef UMAX4_3 +/* Define if you want access control list support. */ +#undef USE_ACL + +/* Define if you want extended attribute support. */ +#undef USE_XATTR + /* Version number of package */ #undef VERSION diff -Naur coreutils-5.2.0/doc/Makefile.in coreutils-5.2.0-acl/doc/Makefile.in --- coreutils-5.2.0/doc/Makefile.in 2004-02-08 14:12:49.000000000 -0600 +++ coreutils-5.2.0-acl/doc/Makefile.in 2004-03-04 19:24:21.000000000 -0600 @@ -128,11 +128,11 @@ $(top_srcdir)/m4/utimes-null.m4 $(top_srcdir)/m4/utimes.m4 \ $(top_srcdir)/m4/vasnprintf.m4 $(top_srcdir)/m4/vasprintf.m4 \ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ - $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xgetcwd.m4 \ - $(top_srcdir)/m4/xreadlink.m4 $(top_srcdir)/m4/xstrtod.m4 \ - $(top_srcdir)/m4/xstrtoimax.m4 $(top_srcdir)/m4/xstrtol.m4 \ - $(top_srcdir)/m4/xstrtoumax.m4 $(top_srcdir)/m4/yesno.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xattr.m4 \ + $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \ + $(top_srcdir)/m4/xstrtod.m4 $(top_srcdir)/m4/xstrtoimax.m4 \ + $(top_srcdir)/m4/xstrtol.m4 $(top_srcdir)/m4/xstrtoumax.m4 \ + $(top_srcdir)/m4/yesno.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs @@ -199,9 +199,11 @@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIB_ACL = @LIB_ACL@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ LIB_CRYPT = @LIB_CRYPT@ LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_XATTR = @LIB_XATTR@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ diff -Naur coreutils-5.2.0/doc/coreutils.texi coreutils-5.2.0-acl/doc/coreutils.texi --- coreutils-5.2.0/doc/coreutils.texi 2004-02-18 11:45:02.000000000 -0600 +++ coreutils-5.2.0-acl/doc/coreutils.texi 2004-03-04 19:22:50.000000000 -0600 @@ -58,8 +58,6 @@ * fold: (coreutils)fold invocation. Wrap long input lines. * groups: (coreutils)groups invocation. Print group names a user is in. * head: (coreutils)head invocation. Output the first part of files. -* hostid: (coreutils)hostid invocation. Print numeric host identifier. -* hostname: (coreutils)hostname invocation. Print or set system name. * id: (coreutils)id invocation. Print real/effective uid/gid. * install: (coreutils)install invocation. Copy and change attributes. * join: (coreutils)join invocation. Join lines on a common field. @@ -385,8 +383,6 @@ * date invocation:: Print or set system date and time * uname invocation:: Print system information -* hostname invocation:: Print or set system name -* hostid invocation:: Print numeric host identifier. @command{date}: Print or set system date and time @@ -6146,6 +6142,19 @@ directory in a different order). Equivalent to @option{-dpPR}. +@itemx @w{@kbd{--attributes}=@var{regex}} +@opindex --attributes +Preserve extended attributes whose names match the specified regular +expression. The default behavior or @command{cp} if no +@option{--attributes} option is given is to preserve all extended +attributes except file permissions. If @var{regex} is ``@samp{-}'', no +extended attributes are preserved. + +This option does not affect the preservation of discretionary file +permissions (i.e., file mode permission bits and access control lists). +To control the preservation of file permissions, the @option{-p} or +@option{--preserve=mode} options are used. + @item -b @itemx @w{@kbd{--backup}[=@var{method}]} @opindex -b @@ -6249,7 +6258,7 @@ @table @samp @itemx mode -Preserve the permission attributes. +Preserve the permission attributes, including access control lists. @itemx ownership Preserve the owner and group. On most modern systems, only the super-user may change the owner of a file, and regular users @@ -6265,7 +6274,6 @@ @itemx all Preserve all file attributes. Equivalent to specifying all of the above. -@c Mention ACLs here. @end table Using @option{--preserve} with no @var{attribute_list} is equivalent @@ -10778,8 +10786,6 @@ @menu * date invocation:: Print or set system date and time. * uname invocation:: Print system information. -* hostname invocation:: Print or set system name. -* hostid invocation:: Print numeric host identifier. @end menu @@ -11418,55 +11424,6 @@ @exitstatus -@node hostname invocation -@section @command{hostname}: Print or set system name - -@pindex hostname -@cindex setting the hostname -@cindex printing the hostname -@cindex system name, printing -@cindex appropriate privileges - -With no arguments, @command{hostname} prints the name of the current host -system. With one argument, it sets the current host name to the -specified string. You must have appropriate privileges to set the host -name. Synopsis: - -@example -hostname [@var{name}] -@end example - -The only options are @option{--help} and @option{--version}. @xref{Common -options}. - -@exitstatus - - -@node hostid invocation -@section @command{hostid}: Print numeric host identifier. - -@pindex hostid -@cindex printing the host identifier - -@command{hostid} prints the numeric identifier of the current host -in hexadecimal. This command accepts no arguments. -The only options are @option{--help} and @option{--version}. -@xref{Common options}. - -For example, here's what it prints on one system I use: - -@example -$ hostid -1bac013d -@end example - -On that system, the 32-bit quantity happens to be closely -related to the system's Internet address, but that isn't always -the case. - -@exitstatus - - @node Modified command invocation @chapter Modified command invocation diff -Naur coreutils-5.2.0/lib/Makefile.in coreutils-5.2.0-acl/lib/Makefile.in --- coreutils-5.2.0/lib/Makefile.in 2004-02-08 14:12:49.000000000 -0600 +++ coreutils-5.2.0-acl/lib/Makefile.in 2004-03-04 19:24:22.000000000 -0600 @@ -148,11 +148,11 @@ $(top_srcdir)/m4/utimes-null.m4 $(top_srcdir)/m4/utimes.m4 \ $(top_srcdir)/m4/vasnprintf.m4 $(top_srcdir)/m4/vasprintf.m4 \ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ - $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xgetcwd.m4 \ - $(top_srcdir)/m4/xreadlink.m4 $(top_srcdir)/m4/xstrtod.m4 \ - $(top_srcdir)/m4/xstrtoimax.m4 $(top_srcdir)/m4/xstrtol.m4 \ - $(top_srcdir)/m4/xstrtoumax.m4 $(top_srcdir)/m4/yesno.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xattr.m4 \ + $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \ + $(top_srcdir)/m4/xstrtod.m4 $(top_srcdir)/m4/xstrtoimax.m4 \ + $(top_srcdir)/m4/xstrtol.m4 $(top_srcdir)/m4/xstrtoumax.m4 \ + $(top_srcdir)/m4/yesno.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs @@ -331,9 +331,11 @@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIB_ACL = @LIB_ACL@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ LIB_CRYPT = @LIB_CRYPT@ LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_XATTR = @LIB_XATTR@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ diff -Naur coreutils-5.2.0/lib/acl.c coreutils-5.2.0-acl/lib/acl.c --- coreutils-5.2.0/lib/acl.c 2004-02-02 02:13:21.000000000 -0600 +++ coreutils-5.2.0-acl/lib/acl.c 2004-03-04 19:22:50.000000000 -0600 @@ -28,12 +28,28 @@ # define S_ISLNK(Mode) 0 #endif +#include "error.h" +#include "quote.h" #include "acl.h" +#ifdef HAVE_ACL_LIBACL_H +# include +#endif + #include #ifndef ENOSYS # define ENOSYS (-1) #endif +#ifndef ENOTSUP +# define ENOTSUP (-1) +#endif + +#if ENABLE_NLS +# include +# define _(Text) gettext (Text) +#else +# define _(Text) Text +#endif #ifndef MIN_ACL_ENTRIES # define MIN_ACL_ENTRIES 4 @@ -45,19 +61,198 @@ int file_has_acl (char const *path, struct stat const *pathstat) { - /* FIXME: This implementation should work on recent-enough versions - of HP-UX, Solaris, and Unixware, but it simply returns 0 with - POSIX 1003.1e (draft 17 -- abandoned), AIX, GNU/Linux, Irix, and - Tru64. Please see Samba's source/lib/sysacls.c file for - fix-related ideas. */ +#if USE_ACL && HAVE_ACL && defined GETACLCNT + /* This implementation should work on recent-enough versions of HP-UX, + Solaris, and Unixware. */ -#if HAVE_ACL && defined GETACLCNT if (! S_ISLNK (pathstat->st_mode)) { int n = acl (path, GETACLCNT, 0, NULL); return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n); } +#elif USE_ACL && HAVE_ACL_EXTENDED_FILE + /* Linux specific version. */ + + if (! S_ISLNK (pathstat->st_mode)) + { + int ret = acl_extended_file (path); + if (ret < 0) + return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1; + return ret; + } +#endif + + /* FIXME: Add support for POSIX 1003.1e (draft 17 -- abandoned), AIX, Irix, + and Tru64. Please see Samba's source/lib/sysacls.c file for fix-related + ideas. */ + + return 0; +} + +/* Copy the access control list of src_path to dst_path. Fall back to + src_st.st_mode if access control lists are not supported for either + file. */ +int +copy_acl (char const *src_path, char const *dst_path, mode_t mode) +{ +#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && \ + HAVE_ACL_FREE && HAVE_ACL_ENTRIES + /* Linux specific. Will work on all POSIX 1003.1e draft 17 (abandoned) + systems if the Linux specific acl_entries() function is substituted. */ + + acl_t acl = acl_get_file (src_path, ACL_TYPE_ACCESS); + if (acl == NULL) + { + if (errno == ENOSYS || errno == ENOTSUP) + return set_acl (dst_path, mode); + else + { + error (0, errno, "%s", quote (src_path)); + return -1; + } + } + + if (acl_set_file (dst_path, ACL_TYPE_ACCESS, acl)) + { + int saved_errno = errno; + + if (errno == ENOSYS || errno == ENOTSUP) + { + int n = acl_entries (acl); + + acl_free (acl); + if (n == 3) + { + if (chmod (dst_path, mode)) + saved_errno = errno; + else + return 0; + } + else + chmod (dst_path, mode); + } + else + { + acl_free (acl); + chmod (dst_path, mode); + } + error (0, saved_errno, _("preserving permissions for %s"), + quote (dst_path)); + return -1; + } + else + acl_free (acl); + + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) + { + /* We did not call chmod so far, so the special bits have not yet + been set. */ + + if (chmod (dst_path, mode)) + { + error (0, errno, _("preserving permissions for %s"), + quote (dst_path)); + return -1; + } + } + + if (S_ISDIR (mode)) + { + acl = acl_get_file (src_path, ACL_TYPE_DEFAULT); + if (acl == NULL) + { + error (0, errno, "%s", quote (src_path)); + return -1; + } + + if (acl_set_file (dst_path, ACL_TYPE_DEFAULT, acl)) + { + error (0, errno, _("preserving permissions for %s"), + quote (dst_path)); + acl_free(acl); + return -1; + } + else + acl_free(acl); + } + return 0; +#else + int ret = chmod (dst_path, mode); + if (ret) + error (0, errno, _("preserving permissions for %s"), quote (dst_path)); + return ret; #endif +} + +/* Set the access control list of path to the permissions defined by mode. */ +int +set_acl (char const *path, mode_t mode) +{ +#if USE_ACL && HAVE_ACL_FROM_TEXT && HAVE_ACL_SET_FILE && HAVE_ACL_FREE && \ + HAVE_ACL_DELETE_DEF_FILE + /* POSIX 1003.1e draft 17 (abandoned) specific version. */ + + char acl_text[] = "u::---,g::---,o::---"; + acl_t acl; + + if (mode & S_IRUSR) acl_text[ 3] = 'r'; + if (mode & S_IWUSR) acl_text[ 4] = 'w'; + if (mode & S_IXUSR) acl_text[ 5] = 'x'; + if (mode & S_IRGRP) acl_text[10] = 'r'; + if (mode & S_IWGRP) acl_text[11] = 'w'; + if (mode & S_IXGRP) acl_text[12] = 'x'; + if (mode & S_IROTH) acl_text[17] = 'r'; + if (mode & S_IWOTH) acl_text[18] = 'w'; + if (mode & S_IXOTH) acl_text[19] = 'x'; + acl = acl_from_text(acl_text); + if (!acl) + { + error (0, errno, "%s", quote (path)); + return -1; + } + + if (acl_set_file(path, ACL_TYPE_ACCESS, acl)) + { + int saved_errno = errno; + acl_free (acl); + + if (errno == ENOTSUP || errno == ENOSYS) + { + if (chmod (path, mode)) + saved_errno = errno; + else + return 0; + } + error (0, saved_errno, _("setting permissions for %s"), quote (path)); + return -1; + } + else + acl_free (acl); + + if (mode & (S_ISUID | S_ISGID | S_ISVTX)) + { + /* We did not call chmod so far, so the special bits have not yet + been set. */ + + if (chmod (path, mode)) + { + error (0, errno, _("preserving permissions for %s"), + quote (path)); + return -1; + } + } + + if (S_ISDIR (mode) && acl_delete_def_file (path)) + { + error (0, errno, _("setting permissions for %s"), quote (path)); + return -1; + } return 0; +#else + int ret = chmod (path, mode); + if (ret) + error (0, errno, _("setting permissions for %s"), quote (path)); + return ret; +#endif } diff -Naur coreutils-5.2.0/lib/acl.h coreutils-5.2.0-acl/lib/acl.h --- coreutils-5.2.0/lib/acl.h 2004-02-02 02:13:21.000000000 -0600 +++ coreutils-5.2.0-acl/lib/acl.h 2004-03-04 19:22:50.000000000 -0600 @@ -18,11 +18,13 @@ Written by Paul Eggert. */ -#if HAVE_SYS_ACL_H && HAVE_ACL +#if HAVE_SYS_ACL_H # include #endif -#if ! defined GETACLCNT && defined ACL_CNT +#if defined HAVE_ACL && ! defined GETACLCNT && defined ACL_CNT # define GETACLCNT ACL_CNT #endif int file_has_acl (char const *, struct stat const *); +int copy_acl(char const *, char const *, mode_t); +int set_acl(char const *, mode_t); diff -Naur coreutils-5.2.0/lib/linebuffer.h coreutils-5.2.0-acl/lib/linebuffer.h --- coreutils-5.2.0/lib/linebuffer.h 2003-06-18 01:58:01.000000000 -0500 +++ coreutils-5.2.0-acl/lib/linebuffer.h 2004-03-04 19:22:50.000000000 -0600 @@ -22,6 +22,11 @@ # include +/* Get mbstate_t. */ +# if HAVE_WCHAR_H +# include +# endif + /* A `struct linebuffer' holds a line of text. */ struct linebuffer @@ -29,6 +34,9 @@ size_t size; /* Allocated. */ size_t length; /* Used. */ char *buffer; +# if HAVE_WCHAR_H + mbstate_t state; +# endif }; /* Initialize linebuffer LINEBUFFER for use. */ diff -Naur coreutils-5.2.0/m4/Makefile.in coreutils-5.2.0-acl/m4/Makefile.in --- coreutils-5.2.0/m4/Makefile.in 2004-02-08 14:12:49.000000000 -0600 +++ coreutils-5.2.0-acl/m4/Makefile.in 2004-03-04 19:24:22.000000000 -0600 @@ -127,11 +127,11 @@ $(top_srcdir)/m4/utimes-null.m4 $(top_srcdir)/m4/utimes.m4 \ $(top_srcdir)/m4/vasnprintf.m4 $(top_srcdir)/m4/vasprintf.m4 \ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ - $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xgetcwd.m4 \ - $(top_srcdir)/m4/xreadlink.m4 $(top_srcdir)/m4/xstrtod.m4 \ - $(top_srcdir)/m4/xstrtoimax.m4 $(top_srcdir)/m4/xstrtol.m4 \ - $(top_srcdir)/m4/xstrtoumax.m4 $(top_srcdir)/m4/yesno.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xattr.m4 \ + $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \ + $(top_srcdir)/m4/xstrtod.m4 $(top_srcdir)/m4/xstrtoimax.m4 \ + $(top_srcdir)/m4/xstrtol.m4 $(top_srcdir)/m4/xstrtoumax.m4 \ + $(top_srcdir)/m4/yesno.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs @@ -184,9 +184,11 @@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIB_ACL = @LIB_ACL@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ LIB_CRYPT = @LIB_CRYPT@ LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_XATTR = @LIB_XATTR@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ diff -Naur coreutils-5.2.0/m4/acl.m4 coreutils-5.2.0-acl/m4/acl.m4 --- coreutils-5.2.0/m4/acl.m4 2004-02-02 02:13:57.000000000 -0600 +++ coreutils-5.2.0-acl/m4/acl.m4 2004-03-04 19:22:50.000000000 -0600 @@ -22,5 +22,22 @@ [ dnl Prerequisites of lib/acl.c. AC_CHECK_HEADERS(sys/acl.h) + if test "$ac_cv_header_sys_acl_h" = yes; then + use_acl=1 + else + use_acl=0 + fi + AC_DEFINE_UNQUOTED(USE_ACL, $use_acl, + [Define if you want access control list support.]) AC_CHECK_FUNCS(acl) + ac_save_LIBS="$LIBS" + AC_SEARCH_LIBS(acl_get_file, acl) + LIB_ACL=`echo "$LIBS" | \ + awk -- "{ print substr(\\$_, length(\"$ac_save_LIBS\")+1)}"` + AC_SUBST(LIB_ACL) + AC_CHECK_HEADERS(acl/libacl.h) + AC_CHECK_FUNCS(acl_get_file acl_set_file acl_free acl_to_text \ + acl_from_text acl_delete_def_file \ + acl_entries acl_extended_file) + LIBS="$ac_save_LIBS" ]) diff -Naur coreutils-5.2.0/m4/xattr.m4 coreutils-5.2.0-acl/m4/xattr.m4 --- coreutils-5.2.0/m4/xattr.m4 1969-12-31 18:00:00.000000000 -0600 +++ coreutils-5.2.0-acl/m4/xattr.m4 2004-03-04 19:22:50.000000000 -0600 @@ -0,0 +1,38 @@ +# xattr.m4 - check for Extended Attributes (Linux) + +# Copyright (C) 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +# Written by Andreas Gruenbacher. + +AC_DEFUN([AC_FUNC_XATTR], +[ + AC_CHECK_HEADERS(attr/error_context.h attr/libattr.h) + if test "$ac_cv_header_attr_libattr_h" = yes \ + && test "$ac_cv_header_attr_error_context_h" = yes; then + use_xattr=1 + else + use_xattr=0 + fi + AC_DEFINE_UNQUOTED(USE_XATTR, $use_xattr, + [Define if you want extended attribute support.]) + xattr_saved_LIBS=$LIBS + AC_SEARCH_LIBS(attr_copy_file, attr, + [test "$ac_cv_search_attr_copy_file" = "none required" || LIB_XATTR=$ac_cv_search_attr_copy_file]) + AC_SUBST(LIB_XATTR) + AC_CHECK_FUNCS(attr_copy_file) + LIBS=$xattr_saved_LIBS +]) diff -Naur coreutils-5.2.0/man/Makefile.am coreutils-5.2.0-acl/man/Makefile.am --- coreutils-5.2.0/man/Makefile.am 2004-01-23 09:54:23.000000000 -0600 +++ coreutils-5.2.0-acl/man/Makefile.am 2004-03-04 19:22:50.000000000 -0600 @@ -3,7 +3,7 @@ basename.1 cat.1 chgrp.1 chmod.1 chown.1 chroot.1 cksum.1 comm.1 \ cp.1 csplit.1 cut.1 date.1 dd.1 df.1 dir.1 dircolors.1 dirname.1 du.1 \ echo.1 env.1 expand.1 expr.1 factor.1 false.1 fmt.1 fold.1 groups.1 \ - head.1 hostid.1 hostname.1 id.1 install.1 join.1 kill.1 \ + head.1 id.1 install.1 join.1 kill.1 \ link.1 ln.1 logname.1 \ ls.1 md5sum.1 mkdir.1 mkfifo.1 mknod.1 mv.1 nice.1 nl.1 nohup.1 od.1 \ paste.1 pathchk.1 pinky.1 pr.1 printenv.1 printf.1 ptx.1 pwd.1 readlink.1 \ @@ -51,8 +51,6 @@ fold.1: $(common_dep) $(srcdir)/fold.x ../src/fold.c groups.1: $(common_dep) $(srcdir)/groups.x ../src/groups.sh head.1: $(common_dep) $(srcdir)/head.x ../src/head.c -hostid.1: $(common_dep) $(srcdir)/hostid.x ../src/hostid.c -hostname.1: $(common_dep) $(srcdir)/hostname.x ../src/hostname.c id.1: $(common_dep) $(srcdir)/id.x ../src/id.c install.1: $(common_dep) $(srcdir)/install.x ../src/install.c join.1: $(common_dep) $(srcdir)/join.x ../src/join.c diff -Naur coreutils-5.2.0/man/Makefile.in coreutils-5.2.0-acl/man/Makefile.in --- coreutils-5.2.0/man/Makefile.in 2004-02-08 14:12:50.000000000 -0600 +++ coreutils-5.2.0-acl/man/Makefile.in 2004-03-04 19:24:22.000000000 -0600 @@ -128,11 +128,11 @@ $(top_srcdir)/m4/utimes-null.m4 $(top_srcdir)/m4/utimes.m4 \ $(top_srcdir)/m4/vasnprintf.m4 $(top_srcdir)/m4/vasprintf.m4 \ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ - $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xgetcwd.m4 \ - $(top_srcdir)/m4/xreadlink.m4 $(top_srcdir)/m4/xstrtod.m4 \ - $(top_srcdir)/m4/xstrtoimax.m4 $(top_srcdir)/m4/xstrtol.m4 \ - $(top_srcdir)/m4/xstrtoumax.m4 $(top_srcdir)/m4/yesno.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xattr.m4 \ + $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \ + $(top_srcdir)/m4/xstrtod.m4 $(top_srcdir)/m4/xstrtoimax.m4 \ + $(top_srcdir)/m4/xstrtol.m4 $(top_srcdir)/m4/xstrtoumax.m4 \ + $(top_srcdir)/m4/yesno.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs @@ -189,9 +189,11 @@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIB_ACL = @LIB_ACL@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ LIB_CRYPT = @LIB_CRYPT@ LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_XATTR = @LIB_XATTR@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ @@ -266,7 +268,7 @@ basename.1 cat.1 chgrp.1 chmod.1 chown.1 chroot.1 cksum.1 comm.1 \ cp.1 csplit.1 cut.1 date.1 dd.1 df.1 dir.1 dircolors.1 dirname.1 du.1 \ echo.1 env.1 expand.1 expr.1 factor.1 false.1 fmt.1 fold.1 groups.1 \ - head.1 hostid.1 hostname.1 id.1 install.1 join.1 kill.1 \ + head.1 id.1 install.1 join.1 kill.1 \ link.1 ln.1 logname.1 \ ls.1 md5sum.1 mkdir.1 mkfifo.1 mknod.1 mv.1 nice.1 nl.1 nohup.1 od.1 \ paste.1 pathchk.1 pinky.1 pr.1 printenv.1 printf.1 ptx.1 pwd.1 readlink.1 \ @@ -532,8 +534,6 @@ fold.1: $(common_dep) $(srcdir)/fold.x ../src/fold.c groups.1: $(common_dep) $(srcdir)/groups.x ../src/groups.sh head.1: $(common_dep) $(srcdir)/head.x ../src/head.c -hostid.1: $(common_dep) $(srcdir)/hostid.x ../src/hostid.c -hostname.1: $(common_dep) $(srcdir)/hostname.x ../src/hostname.c id.1: $(common_dep) $(srcdir)/id.x ../src/id.c install.1: $(common_dep) $(srcdir)/install.x ../src/install.c join.1: $(common_dep) $(srcdir)/join.x ../src/join.c diff -Naur coreutils-5.2.0/src/Makefile.am coreutils-5.2.0-acl/src/Makefile.am --- coreutils-5.2.0/src/Makefile.am 2004-02-02 02:12:57.000000000 -0600 +++ coreutils-5.2.0-acl/src/Makefile.am 2004-03-04 19:22:50.000000000 -0600 @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -*-Makefile-*- -EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who +EXTRA_PROGRAMS = chroot df nice pinky stty su uname uptime users who bin_SCRIPTS = groups bin_PROGRAMS = [ chgrp chown chmod cp dd dircolors du \ @@ -9,7 +9,7 @@ cat cksum comm csplit cut expand fmt fold head join md5sum \ nl od paste pr ptx sha1sum sort split sum tac tail tr tsort unexpand uniq wc \ basename date dirname echo env expr factor false \ - hostname id kill logname pathchk printenv printf pwd seq sleep tee \ + id kill logname pathchk printenv printf pwd seq sleep tee \ test true tty whoami yes \ $(OPTIONAL_BIN_PROGS) $(DF_PROG) @@ -32,10 +32,13 @@ # replacement functions defined in libfetish.a. LDADD = ../lib/libfetish.a $(LIBINTL) ../lib/libfetish.a -dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) +ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) shred_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) +cp_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) +mv_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) +ginstall_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) ## If necessary, add -lm to resolve use of pow in lib/strtod.c. sort_LDADD = $(LDADD) $(POW_LIB) @@ -63,7 +66,8 @@ uptime_LDADD = $(LDADD) $(GETLOADAVG_LIBS) -su_LDADD = $(LDADD) $(LIB_CRYPT) +su_SOURCES = su.c getdef.c +su_LDADD = $(LDADD) $(LIB_CRYPT) -lpam -lpam_misc -ldl $(PROGRAMS): ../lib/libfetish.a diff -Naur coreutils-5.2.0/src/Makefile.in coreutils-5.2.0-acl/src/Makefile.in --- coreutils-5.2.0/src/Makefile.in 2004-02-10 02:11:58.000000000 -0600 +++ coreutils-5.2.0-acl/src/Makefile.in 2004-03-04 19:24:24.000000000 -0600 @@ -16,7 +16,7 @@ -SOURCES = $(__SOURCES) basename.c cat.c $(chgrp_SOURCES) chmod.c $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c $(ginstall_SOURCES) head.c hostid.c hostname.c id.c join.c kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c nohup.c od.c paste.c pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c readlink.c $(rm_SOURCES) rmdir.c seq.c setuidgid.c $(sha1sum_SOURCES) shred.c sleep.c sort.c split.c stat.c stty.c su.c sum.c sync.c tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c uname.c unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c yes.c +SOURCES = $(__SOURCES) basename.c cat.c $(chgrp_SOURCES) chmod.c $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) csplit.c cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c dirname.c du.c echo.c env.c expand.c expr.c factor.c false.c fmt.c fold.c $(ginstall_SOURCES) head.c id.c join.c kill.c link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) mkdir.c mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c nohup.c od.c paste.c pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c readlink.c $(rm_SOURCES) rmdir.c seq.c setuidgid.c $(sha1sum_SOURCES) shred.c sleep.c sort.c split.c stat.c stty.c $(su_SOURCES) sum.c sync.c tac.c tail.c tee.c test.c touch.c tr.c true.c tsort.c tty.c uname.c unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c yes.c srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -38,9 +38,9 @@ PRE_UNINSTALL = : POST_UNINSTALL = : host_triplet = @host@ -EXTRA_PROGRAMS = chroot$(EXEEXT) df$(EXEEXT) hostid$(EXEEXT) \ - nice$(EXEEXT) pinky$(EXEEXT) stty$(EXEEXT) su$(EXEEXT) \ - uname$(EXEEXT) uptime$(EXEEXT) users$(EXEEXT) who$(EXEEXT) +EXTRA_PROGRAMS = chroot$(EXEEXT) df$(EXEEXT) nice$(EXEEXT) \ + pinky$(EXEEXT) stty$(EXEEXT) su$(EXEEXT) uname$(EXEEXT) \ + uptime$(EXEEXT) users$(EXEEXT) who$(EXEEXT) bin_PROGRAMS = [$(EXEEXT) chgrp$(EXEEXT) chown$(EXEEXT) chmod$(EXEEXT) \ cp$(EXEEXT) dd$(EXEEXT) dircolors$(EXEEXT) du$(EXEEXT) \ ginstall$(EXEEXT) link$(EXEEXT) ln$(EXEEXT) dir$(EXEEXT) \ @@ -56,12 +56,11 @@ tail$(EXEEXT) tr$(EXEEXT) tsort$(EXEEXT) unexpand$(EXEEXT) \ uniq$(EXEEXT) wc$(EXEEXT) basename$(EXEEXT) date$(EXEEXT) \ dirname$(EXEEXT) echo$(EXEEXT) env$(EXEEXT) expr$(EXEEXT) \ - factor$(EXEEXT) false$(EXEEXT) hostname$(EXEEXT) id$(EXEEXT) \ - kill$(EXEEXT) logname$(EXEEXT) pathchk$(EXEEXT) \ - printenv$(EXEEXT) printf$(EXEEXT) pwd$(EXEEXT) seq$(EXEEXT) \ - sleep$(EXEEXT) tee$(EXEEXT) test$(EXEEXT) true$(EXEEXT) \ - tty$(EXEEXT) whoami$(EXEEXT) yes$(EXEEXT) $(am__EXEEXT_1) \ - $(am__EXEEXT_2) + factor$(EXEEXT) false$(EXEEXT) id$(EXEEXT) kill$(EXEEXT) \ + logname$(EXEEXT) pathchk$(EXEEXT) printenv$(EXEEXT) \ + printf$(EXEEXT) pwd$(EXEEXT) seq$(EXEEXT) sleep$(EXEEXT) \ + tee$(EXEEXT) test$(EXEEXT) true$(EXEEXT) tty$(EXEEXT) \ + whoami$(EXEEXT) yes$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) noinst_PROGRAMS = setuidgid$(EXEEXT) subdir = src DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ @@ -157,11 +156,11 @@ $(top_srcdir)/m4/utimes-null.m4 $(top_srcdir)/m4/utimes.m4 \ $(top_srcdir)/m4/vasnprintf.m4 $(top_srcdir)/m4/vasprintf.m4 \ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ - $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xgetcwd.m4 \ - $(top_srcdir)/m4/xreadlink.m4 $(top_srcdir)/m4/xstrtod.m4 \ - $(top_srcdir)/m4/xstrtoimax.m4 $(top_srcdir)/m4/xstrtol.m4 \ - $(top_srcdir)/m4/xstrtoumax.m4 $(top_srcdir)/m4/yesno.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xattr.m4 \ + $(top_srcdir)/m4/xgetcwd.m4 $(top_srcdir)/m4/xreadlink.m4 \ + $(top_srcdir)/m4/xstrtod.m4 $(top_srcdir)/m4/xstrtoimax.m4 \ + $(top_srcdir)/m4/xstrtol.m4 $(top_srcdir)/m4/xstrtoumax.m4 \ + $(top_srcdir)/m4/yesno.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs @@ -220,9 +219,10 @@ ../lib/libfetish.a am_cp_OBJECTS = cp.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) cp_OBJECTS = $(am_cp_OBJECTS) -cp_LDADD = $(LDADD) -cp_DEPENDENCIES = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ +am__DEPENDENCIES_2 = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ ../lib/libfetish.a +cp_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) csplit_SOURCES = csplit.c csplit_OBJECTS = csplit.$(OBJEXT) csplit_LDADD = $(LDADD) @@ -235,8 +235,6 @@ ../lib/libfetish.a date_SOURCES = date.c date_OBJECTS = date.$(OBJEXT) -am__DEPENDENCIES_2 = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ - ../lib/libfetish.a date_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) dd_SOURCES = dd.c dd_OBJECTS = dd.$(OBJEXT) @@ -250,7 +248,8 @@ ../lib/libfetish.a am_dir_OBJECTS = ls.$(OBJEXT) ls-dir.$(OBJEXT) dir_OBJECTS = $(am_dir_OBJECTS) -dir_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) +dir_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) dircolors_SOURCES = dircolors.c dircolors_OBJECTS = dircolors.$(OBJEXT) dircolors_LDADD = $(LDADD) @@ -307,24 +306,13 @@ am_ginstall_OBJECTS = install.$(OBJEXT) copy.$(OBJEXT) \ cp-hash.$(OBJEXT) ginstall_OBJECTS = $(am_ginstall_OBJECTS) -ginstall_LDADD = $(LDADD) -ginstall_DEPENDENCIES = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ - ../lib/libfetish.a +ginstall_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) head_SOURCES = head.c head_OBJECTS = head.$(OBJEXT) head_LDADD = $(LDADD) head_DEPENDENCIES = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ ../lib/libfetish.a -hostid_SOURCES = hostid.c -hostid_OBJECTS = hostid.$(OBJEXT) -hostid_LDADD = $(LDADD) -hostid_DEPENDENCIES = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ - ../lib/libfetish.a -hostname_SOURCES = hostname.c -hostname_OBJECTS = hostname.$(OBJEXT) -hostname_LDADD = $(LDADD) -hostname_DEPENDENCIES = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ - ../lib/libfetish.a id_SOURCES = id.c id_OBJECTS = id.$(OBJEXT) id_LDADD = $(LDADD) @@ -357,7 +345,8 @@ ../lib/libfetish.a am_ls_OBJECTS = ls.$(OBJEXT) ls-ls.$(OBJEXT) ls_OBJECTS = $(am_ls_OBJECTS) -ls_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) +ls_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) am_md5sum_OBJECTS = md5sum.$(OBJEXT) md5.$(OBJEXT) md5sum_OBJECTS = $(am_md5sum_OBJECTS) md5sum_LDADD = $(LDADD) @@ -381,9 +370,8 @@ am_mv_OBJECTS = mv.$(OBJEXT) copy.$(OBJEXT) cp-hash.$(OBJEXT) \ remove.$(OBJEXT) mv_OBJECTS = $(am_mv_OBJECTS) -mv_LDADD = $(LDADD) -mv_DEPENDENCIES = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ - ../lib/libfetish.a +mv_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) nice_SOURCES = nice.c nice_OBJECTS = nice.$(OBJEXT) nice_LDADD = $(LDADD) @@ -498,8 +486,8 @@ stty_LDADD = $(LDADD) stty_DEPENDENCIES = ../lib/libfetish.a $(am__DEPENDENCIES_1) \ ../lib/libfetish.a -su_SOURCES = su.c -su_OBJECTS = su.$(OBJEXT) +am_su_OBJECTS = su.$(OBJEXT) getdef.$(OBJEXT) +su_OBJECTS = $(am_su_OBJECTS) su_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) sum_SOURCES = sum.c sum_OBJECTS = sum.$(OBJEXT) @@ -584,7 +572,8 @@ ../lib/libfetish.a am_vdir_OBJECTS = ls.$(OBJEXT) ls-vdir.$(OBJEXT) vdir_OBJECTS = $(am_vdir_OBJECTS) -vdir_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) +vdir_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) wc_SOURCES = wc.c wc_OBJECTS = wc.$(OBJEXT) wc_LDADD = $(LDADD) @@ -624,40 +613,40 @@ @AMDEP_TRUE@ ./$(DEPDIR)/expand.Po ./$(DEPDIR)/expr.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/factor.Po ./$(DEPDIR)/false.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/fmt.Po ./$(DEPDIR)/fold.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/head.Po ./$(DEPDIR)/hostid.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/hostname.Po ./$(DEPDIR)/id.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/install.Po ./$(DEPDIR)/join.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/kill.Po ./$(DEPDIR)/lbracket.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/link.Po ./$(DEPDIR)/ln.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/logname.Po ./$(DEPDIR)/ls-dir.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ls-ls.Po ./$(DEPDIR)/ls-vdir.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/ls.Po ./$(DEPDIR)/md5.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/md5sum.Po ./$(DEPDIR)/mkdir.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/mkfifo.Po ./$(DEPDIR)/mknod.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/mv.Po ./$(DEPDIR)/nice.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/nl.Po ./$(DEPDIR)/nohup.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/od.Po ./$(DEPDIR)/paste.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/pathchk.Po ./$(DEPDIR)/pinky.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/pr.Po ./$(DEPDIR)/printenv.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/printf.Po ./$(DEPDIR)/ptx.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/pwd.Po ./$(DEPDIR)/readlink.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/remove.Po ./$(DEPDIR)/rm.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/rmdir.Po ./$(DEPDIR)/seq.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/setuidgid.Po ./$(DEPDIR)/sha1sum.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/shred.Po ./$(DEPDIR)/sleep.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/sort.Po ./$(DEPDIR)/split.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/stat.Po ./$(DEPDIR)/stty.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/su.Po ./$(DEPDIR)/sum.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/sync.Po ./$(DEPDIR)/tac.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/tail.Po ./$(DEPDIR)/tee.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/test.Po ./$(DEPDIR)/touch.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/tr.Po ./$(DEPDIR)/true.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/tsort.Po ./$(DEPDIR)/tty.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/uname.Po ./$(DEPDIR)/unexpand.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/uniq.Po ./$(DEPDIR)/unlink.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/uptime.Po ./$(DEPDIR)/users.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/wc.Po ./$(DEPDIR)/who.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/whoami.Po ./$(DEPDIR)/yes.Po +@AMDEP_TRUE@ ./$(DEPDIR)/getdef.Po ./$(DEPDIR)/head.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/id.Po ./$(DEPDIR)/install.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/join.Po ./$(DEPDIR)/kill.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/lbracket.Po ./$(DEPDIR)/link.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ln.Po ./$(DEPDIR)/logname.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ls-dir.Po ./$(DEPDIR)/ls-ls.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ls-vdir.Po ./$(DEPDIR)/ls.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/md5.Po ./$(DEPDIR)/md5sum.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/mkdir.Po ./$(DEPDIR)/mkfifo.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/mknod.Po ./$(DEPDIR)/mv.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/nice.Po ./$(DEPDIR)/nl.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/nohup.Po ./$(DEPDIR)/od.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/paste.Po ./$(DEPDIR)/pathchk.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/pinky.Po ./$(DEPDIR)/pr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/printenv.Po ./$(DEPDIR)/printf.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ptx.Po ./$(DEPDIR)/pwd.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/readlink.Po ./$(DEPDIR)/remove.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rm.Po ./$(DEPDIR)/rmdir.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/seq.Po ./$(DEPDIR)/setuidgid.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sha1sum.Po ./$(DEPDIR)/shred.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sleep.Po ./$(DEPDIR)/sort.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/split.Po ./$(DEPDIR)/stat.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/stty.Po ./$(DEPDIR)/su.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sum.Po ./$(DEPDIR)/sync.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/tac.Po ./$(DEPDIR)/tail.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/tee.Po ./$(DEPDIR)/test.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/touch.Po ./$(DEPDIR)/tr.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/true.Po ./$(DEPDIR)/tsort.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/tty.Po ./$(DEPDIR)/uname.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/unexpand.Po ./$(DEPDIR)/uniq.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/unlink.Po ./$(DEPDIR)/uptime.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/users.Po ./$(DEPDIR)/wc.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/who.Po ./$(DEPDIR)/whoami.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/yes.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -666,30 +655,30 @@ $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) \ csplit.c cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c \ dirname.c du.c echo.c env.c expand.c expr.c factor.c false.c \ - fmt.c fold.c $(ginstall_SOURCES) head.c hostid.c hostname.c \ - id.c join.c kill.c link.c ln.c logname.c $(ls_SOURCES) \ - $(md5sum_SOURCES) mkdir.c mkfifo.c mknod.c $(mv_SOURCES) \ - nice.c nl.c nohup.c od.c paste.c pathchk.c pinky.c pr.c \ - printenv.c printf.c ptx.c pwd.c readlink.c $(rm_SOURCES) \ - rmdir.c seq.c setuidgid.c $(sha1sum_SOURCES) shred.c sleep.c \ - sort.c split.c stat.c stty.c su.c sum.c sync.c tac.c tail.c \ - tee.c test.c touch.c tr.c true.c tsort.c tty.c uname.c \ - unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) \ - wc.c who.c whoami.c yes.c + fmt.c fold.c $(ginstall_SOURCES) head.c id.c join.c kill.c \ + link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) mkdir.c \ + mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c nohup.c od.c \ + paste.c pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c \ + readlink.c $(rm_SOURCES) rmdir.c seq.c setuidgid.c \ + $(sha1sum_SOURCES) shred.c sleep.c sort.c split.c stat.c \ + stty.c $(su_SOURCES) sum.c sync.c tac.c tail.c tee.c test.c \ + touch.c tr.c true.c tsort.c tty.c uname.c unexpand.c uniq.c \ + unlink.c uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c \ + yes.c DIST_SOURCES = $(__SOURCES) basename.c cat.c $(chgrp_SOURCES) chmod.c \ $(chown_SOURCES) chroot.c cksum.c comm.c $(cp_SOURCES) \ csplit.c cut.c date.c dd.c df.c $(dir_SOURCES) dircolors.c \ dirname.c du.c echo.c env.c expand.c expr.c factor.c false.c \ - fmt.c fold.c $(ginstall_SOURCES) head.c hostid.c hostname.c \ - id.c join.c kill.c link.c ln.c logname.c $(ls_SOURCES) \ - $(md5sum_SOURCES) mkdir.c mkfifo.c mknod.c $(mv_SOURCES) \ - nice.c nl.c nohup.c od.c paste.c pathchk.c pinky.c pr.c \ - printenv.c printf.c ptx.c pwd.c readlink.c $(rm_SOURCES) \ - rmdir.c seq.c setuidgid.c $(sha1sum_SOURCES) shred.c sleep.c \ - sort.c split.c stat.c stty.c su.c sum.c sync.c tac.c tail.c \ - tee.c test.c touch.c tr.c true.c tsort.c tty.c uname.c \ - unexpand.c uniq.c unlink.c uptime.c users.c $(vdir_SOURCES) \ - wc.c who.c whoami.c yes.c + fmt.c fold.c $(ginstall_SOURCES) head.c id.c join.c kill.c \ + link.c ln.c logname.c $(ls_SOURCES) $(md5sum_SOURCES) mkdir.c \ + mkfifo.c mknod.c $(mv_SOURCES) nice.c nl.c nohup.c od.c \ + paste.c pathchk.c pinky.c pr.c printenv.c printf.c ptx.c pwd.c \ + readlink.c $(rm_SOURCES) rmdir.c seq.c setuidgid.c \ + $(sha1sum_SOURCES) shred.c sleep.c sort.c split.c stat.c \ + stty.c $(su_SOURCES) sum.c sync.c tac.c tail.c tee.c test.c \ + touch.c tr.c true.c tsort.c tty.c uname.c unexpand.c uniq.c \ + unlink.c uptime.c users.c $(vdir_SOURCES) wc.c who.c whoami.c \ + yes.c HEADERS = $(noinst_HEADERS) ETAGS = etags CTAGS = ctags @@ -743,9 +732,11 @@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ +LIB_ACL = @LIB_ACL@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ LIB_CRYPT = @LIB_CRYPT@ LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_XATTR = @LIB_XATTR@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ @@ -834,10 +825,13 @@ # But libfetish.a must also follow $(LIBINTL), since libintl uses # replacement functions defined in libfetish.a. LDADD = ../lib/libfetish.a $(LIBINTL) ../lib/libfetish.a -dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) +ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) shred_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) +cp_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) +mv_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) +ginstall_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) sort_LDADD = $(LDADD) $(POW_LIB) # for clock_gettime @@ -861,7 +855,8 @@ sleep_LDADD = $(nanosec_libs) tail_LDADD = $(nanosec_libs) uptime_LDADD = $(LDADD) $(GETLOADAVG_LIBS) -su_LDADD = $(LDADD) $(LIB_CRYPT) +su_SOURCES = su.c getdef.c +su_LDADD = $(LDADD) $(LIB_CRYPT) -lpam -lpam_misc -ldl SUFFIXES = .sh installed_su = $(DESTDIR)$(bindir)/`echo su|sed '$(transform)'` setuid_root_mode = a=rx,u+s @@ -974,7 +969,7 @@ done clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) > /dev/null 2>&1 || /bin/rm -f $(bin_PROGRAMS) + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) installcheck-binPROGRAMS: $(bin_PROGRAMS) bad=0; pid=$$$$; list="$(bin_PROGRAMS)"; for p in $$list; do \ @@ -1080,12 +1075,6 @@ head$(EXEEXT): $(head_OBJECTS) $(head_DEPENDENCIES) @rm -f head$(EXEEXT) $(LINK) $(head_LDFLAGS) $(head_OBJECTS) $(head_LDADD) $(LIBS) -hostid$(EXEEXT): $(hostid_OBJECTS) $(hostid_DEPENDENCIES) - @rm -f hostid$(EXEEXT) - $(LINK) $(hostid_LDFLAGS) $(hostid_OBJECTS) $(hostid_LDADD) $(LIBS) -hostname$(EXEEXT): $(hostname_OBJECTS) $(hostname_DEPENDENCIES) - @rm -f hostname$(EXEEXT) - $(LINK) $(hostname_LDFLAGS) $(hostname_OBJECTS) $(hostname_LDADD) $(LIBS) id$(EXEEXT): $(id_OBJECTS) $(id_DEPENDENCIES) @rm -f id$(EXEEXT) $(LINK) $(id_LDFLAGS) $(id_OBJECTS) $(id_LDADD) $(LIBS) @@ -1331,9 +1320,8 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/false.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fold.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdef.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/head.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostid.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostname.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/install.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/join.Po@am__quote@ diff -Naur coreutils-5.2.0/src/copy.c coreutils-5.2.0-acl/src/copy.c --- coreutils-5.2.0/src/copy.c 2004-02-07 09:42:04.000000000 -0600 +++ coreutils-5.2.0-acl/src/copy.c 2004-03-04 19:22:50.000000000 -0600 @@ -41,6 +41,14 @@ #include "savedir.h" #include "utimens.h" #include "xreadlink.h" +#include "acl.h" + +#if USE_XATTR +# include "regex.h" +# include +# include +# include +#endif #define DO_CHOWN(Chown, File, New_uid, New_gid) \ (Chown (File, New_uid, New_gid) \ @@ -95,26 +103,6 @@ /* The invocation name of this program. */ extern char *program_name; -/* Encapsulate selection of the file mode to be applied to - new non-directories. */ - -static mode_t -get_dest_mode (const struct cp_options *option, mode_t mode) -{ - /* In some applications (e.g., install), use precisely the - specified mode. */ - if (option->set_mode) - return option->mode; - - /* Honor the umask for `cp', but not for `mv' or `cp -p'. - In addition, `cp' without -p must clear the set-user-ID and set-group-ID - bits. POSIX requires it do that when creating new files. */ - if (!option->move_mode && !option->preserve_mode) - mode &= (option->umask_kill & ~(S_ISUID | S_ISGID)); - - return mode; -} - /* FIXME: describe */ /* FIXME: rewrite this to use a hash table so we avoid the quadratic performance hit that's probably noticeable only on trees deeper @@ -132,6 +120,104 @@ return 0; } +#if USE_XATTR +static void +copy_attr_error (struct error_context *ctx, const char *fmt, ...) +{ + int err = errno; + va_list ap; + int len; + char *buffer; + + /* There is no error function that takes a va_list argument, + so we print the message in a buffer first. */ + + va_start (ap, fmt); + len = vsnprintf (NULL, 0, fmt, ap); + if (len > 0) + { + buffer = xmalloc (len + 1); + vsnprintf (buffer, len + 1, fmt, ap); + error (0, err, "%s", buffer); + free (buffer); + } + va_end (ap); +} + +static const char * +copy_attr_quote (struct error_context *ctx, const char *str) +{ + return xstrdup (quote (str)); +} + +static void +copy_attr_free (struct error_context *ctx, const char *str) +{ + free ((void *) str); +} + +struct copy_attr_context + { + struct error_context ctx; + const char *re_pattern; + struct re_pattern_buffer re_compiled; + } copy_attr_ctx = { + { copy_attr_error, + copy_attr_quote, + copy_attr_free } + }; + +static int +copy_attr_filter (const char *name, struct error_context *ctx) +{ + struct copy_attr_context *copy_ctx = (struct copy_attr_context *) ctx; + + return (attr_copy_check_permissions (name, ctx) + && copy_ctx->re_pattern != NULL + && re_search (©_ctx->re_compiled, name, strlen (name), 0, + strlen (name), NULL) >= 0); +} +#endif /* USE_XATTR */ + +static int +copy_extended_attributes (const char *src_path, const char *dst_path, + const struct cp_options *x) +{ +#if USE_XATTR + if (x->attr_pattern == NULL) + return 0; + + if (copy_attr_ctx.re_pattern != x->attr_pattern) + { + struct re_pattern_buffer *c = ©_attr_ctx.re_compiled; + size_t len = strlen (x->attr_pattern); + const char *err; + + free (c->fastmap); + free (c->buffer); + + copy_attr_ctx.re_pattern = x->attr_pattern; + c->allocated = 2 * len; + c->buffer = xmalloc (c->allocated); + c->fastmap = xmalloc (256); + c->translate = 0; + err = re_compile_pattern (x->attr_pattern, len, c); + if (err) + { + free (c->fastmap); + free (c->buffer); + copy_attr_ctx.re_pattern = NULL; + error (EXIT_FAILURE, 0, _("%s: invalid regular expression: %s"), + x->attr_pattern, err); + } + } + return attr_copy_file (src_path, dst_path, + copy_attr_filter, ©_attr_ctx.ctx); +#else /* USE_XATTR */ + return 0; +#endif /* USE_XATTR */ +} + /* Read the contents of the directory SRC_PATH_IN, and recursively copy the contents to DST_PATH_IN. NEW_DST is nonzero if DST_PATH_IN is a directory that was created previously in the @@ -813,12 +899,13 @@ struct stat dst_sb; mode_t src_mode; mode_t src_type; + mode_t dst_mode IF_LINT(= 0); + int dst_mode_valid = 0; char *earlier_file = NULL; char *dst_backup = NULL; int backup_succeeded = 0; int delayed_fail; int copied_as_regular = 0; - int ran_chown = 0; int preserve_metadata; if (x->move_mode && rename_succeeded) @@ -1317,15 +1404,36 @@ if (new_dst || !S_ISDIR (dst_sb.st_mode)) { - /* Create the new directory writable and searchable, so - we can create new entries in it. */ - - if (mkdir (dst_path, (src_mode & x->umask_kill) | S_IRWXU)) + if (mkdir (dst_path, src_mode)) { error (0, errno, _("cannot create directory %s"), quote (dst_path)); goto un_backup; } + /* We need search and write permissions to the new directory + for writing the directory's contents. Check if these + permissions are there. */ + + if (lstat (dst_path, &dst_sb)) + { + error (0, errno, _("cannot stat %s"), quote (dst_path)); + delayed_fail = 1; + } + else if ((dst_sb.st_mode & S_IRWXU) != S_IRWXU) + { + /* Make the new directory searchable and writable. The + original permissions will be restored later. */ + + dst_mode = dst_sb.st_mode; + dst_mode_valid = 1; + + if (chmod (dst_path, dst_mode | S_IRWXU)) + { + error (0, errno, _("setting permissions for %s"), + quote (dst_path)); + goto un_backup; + } + } /* Insert the created directory's inode and device numbers into the search structure, so that we can @@ -1410,15 +1518,14 @@ /* POSIX says the permission bits of the source file must be used as the 3rd argument in the open call, but that's not consistent with historical practice. */ - if (copy_reg (src_path, dst_path, x, - get_dest_mode (x, src_mode), &new_dst, &src_sb)) + if (copy_reg (src_path, dst_path, x, src_mode, &new_dst, &src_sb)) goto un_backup; } else #ifdef S_ISFIFO if (S_ISFIFO (src_type)) { - if (mkfifo (dst_path, get_dest_mode (x, src_mode))) + if (mkfifo (dst_path, src_mode)) { error (0, errno, _("cannot create fifo %s"), quote (dst_path)); goto un_backup; @@ -1429,7 +1536,7 @@ if (S_ISBLK (src_type) || S_ISCHR (src_type) || S_ISSOCK (src_type)) { - if (mknod (dst_path, get_dest_mode (x, src_mode), src_sb.st_rdev)) + if (mknod (dst_path, src_mode, src_sb.st_rdev)) { error (0, errno, _("cannot create special file %s"), quote (dst_path)); @@ -1542,7 +1649,8 @@ if (x->preserve_ownership && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) { - ran_chown = 1; + /* The chown() system call may clear the SUID and SGID bits, so we + may need to set them again later. */ if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid)) { error (0, errno, _("failed to preserve ownership for %s"), @@ -1569,20 +1677,30 @@ } #endif - /* Permissions of newly-created regular files were set upon `open' in - copy_reg. But don't return early if there were any special bits and - we had to run chown, because the chown must have reset those bits. */ - if ((new_dst && copied_as_regular) - && !(ran_chown && (src_mode & ~S_IRWXUGO))) - return delayed_fail; + if (copy_extended_attributes (src_path, dst_path, x)) + delayed_fail = 1; - if ((x->preserve_mode || new_dst) - && (x->copy_as_regular || S_ISREG (src_type) || S_ISDIR (src_type))) + if (x->preserve_mode || x->move_mode) + { + if (copy_acl (src_path, dst_path, src_mode) && x->require_preserve) + return 1; + } + else if (x->set_mode) + { + if (chmod (dst_path, x->mode)) + { + error (0, errno, _("preserving permissions for %s"), + quote (dst_path)); + if (x->require_preserve) + return 1; + } + } + else if (dst_mode_valid) { - if (chmod (dst_path, get_dest_mode (x, src_mode))) + if (chmod (dst_path, dst_mode)) { - error (0, errno, _("setting permissions for %s"), quote (dst_path)); - if (x->set_mode || x->require_preserve) + error (0, errno, _("setting permissions for %s"), quote(dst_path)); + if (x->require_preserve) return 1; } } diff -Naur coreutils-5.2.0/src/copy.h coreutils-5.2.0-acl/src/copy.h --- coreutils-5.2.0/src/copy.h 2004-02-07 10:00:59.000000000 -0600 +++ coreutils-5.2.0-acl/src/copy.h 2004-03-04 19:22:50.000000000 -0600 @@ -106,6 +106,10 @@ int preserve_mode; int preserve_timestamps; + /* Regular expression pattern that specifies which extended attributes to + copy. NULL stands for copying no extended attributes. */ + const char *attr_pattern; + /* Enabled for mv, and for cp by the --preserve=links option. If nonzero, attempt to preserve in the destination files any logical hard links between the source files. If used with cp's @@ -143,9 +147,6 @@ Create destination directories as usual. */ int symbolic_link; - /* The bits to preserve in created files' modes. */ - mode_t umask_kill; - /* If nonzero, do not copy a nondirectory that has an existing destination with the same or newer modification time. */ int update; diff -Naur coreutils-5.2.0/src/cp.c coreutils-5.2.0-acl/src/cp.c --- coreutils-5.2.0/src/cp.c 2004-02-07 09:55:09.000000000 -0600 +++ coreutils-5.2.0-acl/src/cp.c 2004-03-04 19:42:35.000000000 -0600 @@ -33,6 +33,7 @@ #include "path-concat.h" #include "quote.h" #include "utimens.h" +#include "acl.h" #define ASSIGN_BASENAME_STRDUPA(Dest, File_name) \ do \ @@ -58,7 +59,8 @@ need to be fixed after copying. */ struct dir_attr { - int is_new_dir; + mode_t mode; + int mode_valid; int slash_offset; struct dir_attr *next; }; @@ -75,7 +77,8 @@ SPARSE_OPTION, STRIP_TRAILING_SLASHES_OPTION, TARGET_DIRECTORY_OPTION, - UNLINK_DEST_BEFORE_OPENING + UNLINK_DEST_BEFORE_OPENING, + PRESERVE_XATTRS_OPTION }; /* Initial number of entries in each hash table entry's table of inodes. */ @@ -131,6 +134,7 @@ {"parents", no_argument, NULL, PARENTS_OPTION}, {"path", no_argument, NULL, PARENTS_OPTION}, /* Deprecated. */ {"preserve", optional_argument, NULL, PRESERVE_ATTRIBUTES_OPTION}, + {"attributes", required_argument, NULL, PRESERVE_XATTRS_OPTION}, {"recursive", no_argument, NULL, 'R'}, {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING}, {"reply", required_argument, NULL, REPLY_OPTION}, @@ -219,6 +223,13 @@ -v, --verbose explain what is being done\n\ -x, --one-file-system stay on this file system\n\ "), stdout); + fputs(_("\n\ + --attributes=regex preserve extended attributes whose name\n\ + matches the specified regular expression\n\ + (defaults to preserving all extended\n\ + attributes except file permissions;\n\ + regex=`-' preserves no extended attributes).\n\ +"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\ @@ -281,6 +292,7 @@ char *dst_path; /* A copy of CONST_DST_PATH we can change. */ char *src_path; /* The source name in `dst_path'. */ uid_t myeuid = geteuid (); + mode_t umask_kill = ~umask (0); ASSIGN_STRDUPA (dst_path, const_dst_path); src_path = dst_path + src_offset; @@ -333,9 +345,14 @@ } } - if (x->preserve_mode || p->is_new_dir) + if (x->preserve_mode) + { + if (copy_acl (src_path, dst_path, src_sb.st_mode)) + return 1; + } + else if (p->mode_valid) { - if (chmod (dst_path, src_sb.st_mode & x->umask_kill)) + if (chmod (dst_path, p->mode)) { error (0, errno, _("failed to preserve permissions for %s"), quote (dst_path)); @@ -353,8 +370,7 @@ SRC_OFFSET is the index in CONST_DIRPATH (which is a destination path) of the beginning of the source directory name. - Create any leading directories that don't already exist, - giving them permissions MODE. + Create any leading directories that don't already exist. If VERBOSE_FMT_STRING is nonzero, use it as a printf format string for printing a message after successfully making a directory. The format should take two string arguments: the names of the @@ -369,9 +385,9 @@ /* FIXME: find a way to synch this function with the one in lib/makepath.c. */ static int -make_path_private (const char *const_dirpath, int src_offset, int mode, +make_path_private (const char *const_dirpath, int src_offset, const char *verbose_fmt_string, struct dir_attr **attr_list, - int *new_dst, int (*xstat)()) + int *new_dst, struct cp_options const *x, int (*xstat)()) { struct stat stats; char *dirpath; /* A copy of CONST_DIRPATH we can change. */ @@ -411,14 +427,24 @@ *slash = '\0'; if ((*xstat) (dirpath, &stats)) { + mode_t src_mode; + /* This element of the path does not exist. We must set - *new_dst and new->is_new_dir inside this loop because, + *new_dst and new->mode inside this loop because, for example, in the command `cp --parents ../a/../b/c e_dir', make_path_private creates only e_dir/../a if ./b already exists. */ *new_dst = 1; - new->is_new_dir = 1; - if (mkdir (dirpath, mode)) + + if ((*xstat) (src, &stats)) + { + error (0, errno, _("failed to get attributes of %s"), + quote (src)); + return 1; + } + src_mode = stats.st_mode; + + if (mkdir (dirpath, src_mode)) { error (0, errno, _("cannot make directory %s"), quote (dirpath)); @@ -429,6 +455,42 @@ if (verbose_fmt_string != NULL) printf (verbose_fmt_string, src, dirpath); } + + /* We need search and write permissions to the new directory + for writing the directory's contents. Check if these + permissions are there. */ + + if (lstat (dirpath, &stats)) + { + error (0, errno, _("failed to get attributes of %s"), + quote (dirpath)); + return 1; + } + else + { + if (x->preserve_mode) { + new->mode = src_mode; + new->mode_valid = (src_mode != stats.st_mode); + } else { + new->mode = stats.st_mode; + new->mode_valid = 0; + } + + if ((stats.st_mode & S_IRWXU) != S_IRWXU) + { + /* Make the new directory searchable and writable. The + original permissions will be restored later. */ + + new->mode_valid = 1; + + if (chmod (dirpath, stats.st_mode | S_IRWXU)) + { + error (0, errno, _("setting permissions for %s"), + quote (dirpath)); + return 1; + } + } + } } else if (!S_ISDIR (stats.st_mode)) { @@ -438,7 +500,7 @@ } else { - new->is_new_dir = 0; + new->mode_valid = 0; *new_dst = 0; } *slash++ = '/'; @@ -593,11 +655,10 @@ leading directories. */ parent_exists = !make_path_private (dst_path, arg_in_concat - dst_path, - S_IRWXU, (x->verbose ? "%s -> %s\n" : NULL), - &attr_list, &new_dst, - xstat); + &attr_list, &new_dst, x, + xstat); } else { @@ -731,16 +792,12 @@ /* Not used. */ x->stdin_tty = 0; - /* Find out the current file creation mask, to knock the right bits - when using chmod. The creation mask is set to be liberal, so - that created directories can be written, even if it would not - have been allowed with the mask this process was started with. */ - x->umask_kill = ~ umask (0); - x->update = 0; x->verbose = 0; x->dest_info = NULL; x->src_info = NULL; + + x->attr_pattern = ""; /* all extended attributes */ } /* Given a string, ARG, containing a comma-separated list of arguments @@ -936,6 +993,13 @@ x.require_preserve = 1; break; + case PRESERVE_XATTRS_OPTION: + if (strcmp (optarg, "-") == 0) + x.attr_pattern = NULL; + else + x.attr_pattern = optarg; + break; + case PARENTS_OPTION: flag_path = 1; break; @@ -1011,9 +1075,6 @@ version_control_string) : none); - if (x.preserve_mode == 1) - x.umask_kill = ~ (mode_t) 0; - if (x.dereference == DEREF_UNDEFINED) { if (x.recursive) diff -Naur coreutils-5.2.0/src/cut.c coreutils-5.2.0-acl/src/cut.c --- coreutils-5.2.0/src/cut.c 2004-01-21 16:27:02.000000000 -0600 +++ coreutils-5.2.0-acl/src/cut.c 2004-03-04 19:22:50.000000000 -0600 @@ -29,6 +29,12 @@ #include #include #include + +/* Get mbstate_t, mbrtowc. */ +#if HAVE_WCHAR_H +# include +#endif + #include "system.h" #include "error.h" @@ -37,6 +43,18 @@ #include "quote.h" #include "xstrndup.h" +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC + installation; work around this configuration error. */ +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 +# undef MB_LEN_MAX +# define MB_LEN_MAX 16 +#endif + +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "cut" @@ -67,6 +85,52 @@ } \ while (0) +/* Refill the buffer BUF to get a multibyte character. */ +#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \ + do \ + { \ + if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) \ + { \ + memmove (BUF, BUFPOS, BUFLEN); \ + BUFLEN += fread (BUF + BUFLEN, 1, BUFSIZ, STREAM); \ + BUFPOS = BUF; \ + } \ + } \ + while (0) + +/* Get wide character on BUFPOS. BUFPOS is not included after that. + If byte sequence is not valid as a character, CONVFAIL is 1. Otherwise 0. */ +#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \ + do \ + { \ + mbstate_t state_bak; \ + \ + if (BUFLEN < 1) \ + { \ + WC = WEOF; \ + break; \ + } \ + \ + /* Get a wide character. */ \ + CONVFAIL = 0; \ + state_bak = STATE; \ + MBLENGTH = mbrtowc ((wchar_t *) &WC, BUFPOS, BUFLEN, &STATE); \ + \ + switch (MBLENGTH) \ + { \ + case (size_t) -1: \ + case (size_t) -2: \ + CONVFAIL++; \ + STATE = state_bak; \ + /* Fall througn. */ \ + \ + case 0: \ + MBLENGTH = 1; \ + break; \ + } \ + } \ + while (0) + struct range_pair { size_t lo; @@ -85,7 +149,7 @@ /* The number of bytes allocated for FIELD_1_BUFFER. */ static size_t field_1_bufsize; -/* The largest field or byte index used as an endpoint of a closed +/* The largest byte, character or field index used as an endpoint of a closed or degenerate range specification; this doesn't include the starting index of right-open-ended ranges. For example, with either range spec `2-5,9-', `2-3,5,9-' this variable would be set to 5. */ @@ -97,10 +161,11 @@ /* This is a bit vector. In byte mode, which bytes to output. + In character mode, which characters to output. In field mode, which DELIM-separated fields to output. - Both bytes and fields are numbered starting with 1, + Bytes, characters and fields are numbered starting with 1, so the zeroth bit of this array is unused. - A field or byte K has been selected if + A byte, character or field K has been selected if (K <= MAX_RANGE_ENDPOINT and is_printable_field(K)) || (EOL_RANGE_START > 0 && K >= EOL_RANGE_START). */ static unsigned char *printable_field; @@ -109,9 +174,12 @@ { undefined_mode, - /* Output characters that are in the given bytes. */ + /* Output bytes that are at the given positions. */ byte_mode, + /* Output characters that are at the given positions. */ + character_mode, + /* Output the given delimeter-separated fields. */ field_mode }; @@ -121,6 +189,13 @@ static enum operating_mode operating_mode; +/* If nonzero, when in byte mode, don't split multibyte characters. */ +static bool byte_mode_character_aware; + +/* If nonzero, the function for single byte locale is work + if this program runs on multibyte locale. */ +static bool force_singlebyte_mode; + /* If true do not output lines containing no delimeter characters. Otherwise, all such lines are printed. This option is valid only with field mode. */ @@ -128,6 +203,9 @@ /* The delimeter character for field mode. */ static unsigned char delim; +#if HAVE_WCHAR_H +static wchar_t wcdelim; +#endif /* True if the --output-delimiter=STRING option was specified. */ static bool output_delimiter_specified; @@ -199,7 +277,7 @@ -f, --fields=LIST output only these fields; also print any line\n\ that contains no delimiter character, unless\n\ the -s option is specified\n\ - -n (ignored)\n\ + -n with -b: don't split multibyte characters\n\ "), stdout); fputs (_("\ -s, --only-delimited do not print lines not containing delimiters\n\ @@ -327,7 +405,7 @@ in_digits = false; /* Starting a range. */ if (dash_found) - FATAL_ERROR (_("invalid byte or field list")); + FATAL_ERROR (_("invalid byte, character or field list")); dash_found = true; fieldstr++; @@ -352,14 +430,16 @@ if (value == 0) { /* `n-'. From `initial' to end of line. */ - eol_range_start = initial; + if (eol_range_start == 0 + || (eol_range_start != 0 && eol_range_start > initial)) + eol_range_start = initial; field_found = true; } else { /* `m-n' or `-n' (1-n). */ if (value < initial) - FATAL_ERROR (_("invalid byte or field list")); + FATAL_ERROR (_("invalid byte, character or field list")); /* Is there already a range going to end of line? */ if (eol_range_start != 0) @@ -434,6 +514,9 @@ if (operating_mode == byte_mode) error (0, 0, _("byte offset %s is too large"), quote (bad_num)); + else if (operating_mode == character_mode) + error (0, 0, + _("character offset %s is too large"), quote (bad_num)); else error (0, 0, _("field number %s is too large"), quote (bad_num)); @@ -445,7 +528,7 @@ fieldstr++; } else - FATAL_ERROR (_("invalid byte or field list")); + FATAL_ERROR (_("invalid byte, character or field list")); } max_range_endpoint = 0; @@ -549,6 +632,78 @@ } } +#if HAVE_MBRTOWC +/* This function is in use for the following case. + + 1. Read from the stream STREAM, printing to standard output any selected + characters. + + 2. Read from stream STREAM, printing to standard output any selected bytes, + without splitting multibyte characters. */ + +static void +cut_characters_or_cut_bytes_no_split (FILE *stream) +{ + int idx; /* number of bytes or characters in the line so far. */ + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ + char *bufpos; /* Next read position of BUF. */ + size_t buflen; /* The length of the byte sequence in buf. */ + wint_t wc; /* A gotten wide character. */ + size_t mblength; /* The byte size of a multibyte character which shows + as same character as WC. */ + mbstate_t state; /* State of the stream. */ + int convfail; /* 1, when conversion is failed. Otherwise 0. */ + /* Whether to begin printing delimiters between ranges for the current line. + Set after we've begun printing data corresponding to the first range. */ + bool print_delimiter; + + idx = 0; + buflen = 0; + bufpos = buf; + memset (&state, '\0', sizeof (mbstate_t)); + print_delimiter = false; + + while (1) + { + REFILL_BUFFER (buf, bufpos, buflen, stream); + + GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail); + + if (wc == WEOF) + { + if (idx > 0) + putchar ('\n'); + break; + } + else if (wc == L'\n') + { + putchar ('\n'); + idx = 0; + print_delimiter = false; + } + else + { + bool range_start; + bool *rs = output_delimiter_specified ? &range_start : NULL; + idx += (operating_mode == byte_mode) ? mblength : 1; + if (print_kth (idx, rs)) + { + if (rs && *rs && print_delimiter) + { + fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout); + } + print_delimiter = true; + fwrite (bufpos, mblength, sizeof (char), stdout); + } + } + + buflen -= mblength; + bufpos += mblength; + } +} +#endif + /* Read from stream STREAM, printing to standard output any selected fields. */ static void @@ -669,13 +824,192 @@ } } +#if HAVE_MBRTOWC +static void +cut_fields_mb (FILE *stream) +{ + int c; + unsigned int field_idx; + int found_any_selected_field; + int buffer_first_field; + int empty_input; + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ + char *bufpos; /* Next read position of BUF. */ + size_t buflen; /* The length of the byte sequence in buf. */ + wint_t wc; /* A gotten wide character. */ + size_t mblength; /* The byte size of a multibyte character which shows + as same character as WC. */ + mbstate_t state; /* State of the stream. */ + int convfail; /* 1, when conversion is failed. Otherwise 0. */ + + found_any_selected_field = 0; + field_idx = 1; + bufpos = buf; + buflen = 0; + memset (&state, '\0', sizeof (mbstate_t)); + + c = getc (stream); + empty_input = (c == EOF); + if (c != EOF) + ungetc (c, stream); + else + wc = WEOF; + + /* To support the semantics of the -s flag, we may have to buffer + all of the first field to determine whether it is `delimited.' + But that is unnecessary if all non-delimited lines must be printed + and the first field has been selected, or if non-delimited lines + must be suppressed and the first field has *not* been selected. + That is because a non-delimited line has exactly one field. */ + buffer_first_field = (suppress_non_delimited ^ !print_kth (1, NULL)); + + while (1) + { + if (field_idx == 1 && buffer_first_field) + { + int len = 0; + + while (1) + { + REFILL_BUFFER (buf, bufpos, buflen, stream); + + GET_NEXT_WC_FROM_BUFFER + (wc, bufpos, buflen, mblength, state, convfail); + + if (wc == WEOF) + break; + + field_1_buffer = xrealloc (field_1_buffer, len + mblength); + memcpy (field_1_buffer + len, bufpos, mblength); + len += mblength; + buflen -= mblength; + bufpos += mblength; + + if (!convfail && (wc == L'\n' || wc == wcdelim)) + break; + } + + if (wc == WEOF) + break; + + /* If the first field extends to the end of line (it is not + delimited) and we are printing all non-delimited lines, + print this one. */ + if (convfail || (!convfail && wc != wcdelim)) + { + if (suppress_non_delimited) + { + /* Empty. */ + } + else + { + fwrite (field_1_buffer, sizeof (char), len, stdout); + /* Make sure the output line is newline terminated. */ + if (convfail || (!convfail && wc != L'\n')) + putchar ('\n'); + } + continue; + } + + if (print_kth (1, NULL)) + { + /* Print the field, but not the trailing delimiter. */ + fwrite (field_1_buffer, sizeof (char), len - 1, stdout); + found_any_selected_field = 1; + } + ++field_idx; + } + + if (wc != WEOF) + { + if (print_kth (field_idx, NULL)) + { + if (found_any_selected_field) + { + fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout); + } + found_any_selected_field = 1; + } + + while (1) + { + REFILL_BUFFER (buf, bufpos, buflen, stream); + + GET_NEXT_WC_FROM_BUFFER + (wc, bufpos, buflen, mblength, state, convfail); + + if (wc == WEOF) + break; + else if (!convfail && (wc == wcdelim || wc == L'\n')) + { + buflen -= mblength; + bufpos += mblength; + break; + } + + if (print_kth (field_idx, NULL)) + fwrite (bufpos, mblength, 1, stdout); + + buflen -= mblength; + bufpos += mblength; + } + } + + if ((!convfail || wc == L'\n') && buflen < 1) + wc = WEOF; + + if (!convfail && wc == wcdelim) + ++field_idx; + else if (wc == WEOF || (!convfail && wc == L'\n')) + { + if (found_any_selected_field + || (!empty_input && !(suppress_non_delimited && field_idx == 1))) + putchar ('\n'); + if (wc == WEOF) + break; + field_idx = 1; + found_any_selected_field = 0; + } + } +} +#endif + static void cut_stream (FILE *stream) { - if (operating_mode == byte_mode) - cut_bytes (stream); +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1 && !force_singlebyte_mode) + { + switch (operating_mode) + { + case byte_mode: + if (byte_mode_character_aware) + cut_characters_or_cut_bytes_no_split (stream); + else + cut_bytes (stream); + break; + + case character_mode: + cut_characters_or_cut_bytes_no_split (stream); + break; + + case field_mode: + cut_fields_mb (stream); + break; + + default: + abort (); + } + } else - cut_fields (stream); +#endif + { + if (operating_mode == field_mode) + cut_fields (stream); + else + cut_bytes (stream); + } } /* Process file FILE to standard output. @@ -724,6 +1058,8 @@ int optc, exit_status = 0; bool delim_specified = false; char *spec_list_string IF_LINT(= NULL); + char mbdelim[MB_LEN_MAX + 1]; + size_t delimlen = 0; initialize_main (&argc, &argv); program_name = argv[0]; @@ -749,7 +1085,6 @@ break; case 'b': - case 'c': /* Build the byte list. */ if (operating_mode != undefined_mode) FATAL_ERROR (_("only one type of list may be specified")); @@ -757,6 +1092,14 @@ spec_list_string = optarg; break; + case 'c': + /* Build the character list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); + operating_mode = character_mode; + spec_list_string = optarg; + break; + case 'f': /* Build the field list. */ if (operating_mode != undefined_mode) @@ -768,10 +1111,35 @@ case 'd': /* New delimiter. */ /* Interpret -d '' to mean `use the NUL byte as the delimiter.' */ - if (optarg[0] != '\0' && optarg[1] != '\0') - FATAL_ERROR (_("the delimiter must be a single character")); - delim = optarg[0]; - delim_specified = true; +#if HAVE_MBRTOWC + { + if (MB_CUR_MAX > 1) + { + mbstate_t state; + + memset (&state, '\0', sizeof (mbstate_t)); + delimlen = mbrtowc (&wcdelim, optarg, strlen (optarg), &state); + + if (delimlen == (size_t) -1 || delimlen == (size_t) -2) + force_singlebyte_mode = true; + else + { + delimlen = (delimlen < 1) ? 1 : delimlen; + if (wcdelim != L'\0' && *(optarg + delimlen) != '\0') + FATAL_ERROR (_("the delimiter must be a single character")); + memcpy (mbdelim, optarg, delimlen); + } + } + + if (MB_CUR_MAX <= 1 || force_singlebyte_mode) +#endif + { + if (optarg[0] != '\0' && optarg[1] != '\0') + FATAL_ERROR (_("the delimiter must be a single character")); + delim = (unsigned char) optarg[0]; + } + delim_specified = true; + } break; case OUTPUT_DELIMITER_OPTION: @@ -784,6 +1152,7 @@ break; case 'n': + byte_mode_character_aware = true; break; case 's': @@ -802,7 +1171,7 @@ if (operating_mode == undefined_mode) FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); - if (delim != '\0' && operating_mode != field_mode) + if (delim_specified && operating_mode != field_mode) FATAL_ERROR (_("an input delimiter may be specified only\ when operating on fields")); @@ -829,15 +1198,34 @@ } if (!delim_specified) - delim = '\t'; + { + delim = '\t'; +#ifdef HAVE_MBRTOWC + wcdelim = L'\t'; + mbdelim[0] = '\t'; + mbdelim[1] = '\0'; + delimlen = 1; +#endif + } if (output_delimiter_string == NULL) { - static char dummy[2]; - dummy[0] = delim; - dummy[1] = '\0'; - output_delimiter_string = dummy; - output_delimiter_length = 1; +#ifdef HAVE_MBRTOWC + if (MB_CUR_MAX > 1 && !force_singlebyte_mode) + { + output_delimiter_string = xstrdup (mbdelim); + output_delimiter_length = delimlen; + } + + if (MB_CUR_MAX <= 1 || force_singlebyte_mode) +#endif + { + static char dummy[2]; + dummy[0] = delim; + dummy[1] = '\0'; + output_delimiter_string = dummy; + output_delimiter_length = 1; + } } if (optind == argc) diff -Naur coreutils-5.2.0/src/expand.c coreutils-5.2.0-acl/src/expand.c --- coreutils-5.2.0/src/expand.c 2004-01-21 16:27:02.000000000 -0600 +++ coreutils-5.2.0-acl/src/expand.c 2004-03-04 19:22:50.000000000 -0600 @@ -38,12 +38,29 @@ #include #include #include + +/* Get mbstate_t, mbrtowc, wcwidth. */ +#if HAVE_WCHAR_H +# include +#endif + #include "system.h" #include "error.h" #include "posixver.h" #include "quote.h" #include "xstrndup.h" +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC + installation; work around this configuration error. */ +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 +# define MB_LEN_MAX 16 +#endif + +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "expand" @@ -332,6 +349,7 @@ ++column; } } + else { if (convert) @@ -343,7 +361,8 @@ } else { - ++column; + if (!ISCNTRL (c)) + ++column; if (convert_entire_line == 0) convert = 0; } @@ -353,6 +372,146 @@ } } +#if HAVE_MBRTOWC +static void +expand_multibyte (void) +{ + FILE *fp; /* Input strem. */ + mbstate_t i_state; /* Current shift state of the input stream. */ + mbstate_t i_state_bak; /* Back up the I_STATE. */ + mbstate_t o_state; /* Current shift state of the output stream. */ + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ + char *bufpos; /* Next read position of BUF. */ + size_t buflen = 0; /* The length of the byte sequence in buf. */ + wchar_t wc; /* A gotten wide character. */ + size_t mblength; /* The byte size of a multibyte character + which shows as same character as WC. */ + int tab_index = 0; /* Index in `tab_list' of next tabstop. */ + int column = 0; /* Column on screen of the next char. */ + int next_tab_column; /* Column the next tab stop is on. */ + int convert = 1; /* If nonzero, perform translations. */ + + fp = next_file ((FILE *) NULL); + if (fp == NULL) + return; + + /* Binary I/O will preserve the original EOL style (DOS/Unix) of files. */ + SET_BINARY2 (fileno (fp), STDOUT_FILENO); + + memset (&o_state, '\0', sizeof (mbstate_t)); + memset (&i_state, '\0', sizeof (mbstate_t)); + + for (;;) + { + /* Refill the buffer BUF. */ + if (buflen < MB_LEN_MAX && !feof (fp) && !ferror (fp)) + { + memmove (buf, bufpos, buflen); + buflen += fread (buf + buflen, 1, BUFSIZ, fp); + bufpos = buf; + } + + /* No character is left in BUF. */ + if (buflen < 1) + { + fp = next_file (fp); + + if (fp == NULL) + break; /* No more files. */ + else + { + memset (&i_state, '\0', sizeof (mbstate_t)); + SET_BINARY2 (fileno (fp), STDOUT_FILENO); + continue; + } + } + + /* Get a wide character. */ + i_state_bak = i_state; + mblength = mbrtowc (&wc, bufpos, buflen, &i_state); + + switch (mblength) + { + case (size_t) -1: /* illegal byte sequence. */ + case (size_t) -2: + mblength = 1; + i_state = i_state_bak; + if (convert) + { + ++column; + if (convert_entire_line == 0) + convert = 0; + } + putchar (*bufpos); + break; + + case 0: /* null. */ + mblength = 1; + if (convert && convert_entire_line == 0) + convert = 0; + putchar ('\0'); + break; + + default: + if (wc == L'\n') /* LF. */ + { + tab_index = 0; + column = 0; + convert = 1; + putchar ('\n'); + } + else if (wc == L'\t' && convert) /* Tab. */ + { + if (tab_size == 0) + { + /* Do not let tab_index == first_free_tab; + stop when it is 1 less. */ + while (tab_index < first_free_tab - 1 + && column >= tab_list[tab_index]) + tab_index++; + next_tab_column = tab_list[tab_index]; + if (tab_index < first_free_tab - 1) + tab_index++; + if (column >= next_tab_column) + next_tab_column = column + 1; + } + else + next_tab_column = column + tab_size - column % tab_size; + + while (column < next_tab_column) + { + putchar (' '); + ++column; + } + } + else /* Others. */ + { + if (convert) + { + if (wc == L'\b') + { + if (column > 0) + --column; + } + else + { + int width; /* The width of WC. */ + + width = wcwidth (wc); + column += (width > 0) ? width : 0; + if (convert_entire_line == 0) + convert = 0; + } + } + fwrite (bufpos, 1, mblength, stdout); + } + } + buflen -= mblength; + bufpos += mblength; + } +} +#endif + int main (int argc, char **argv) { @@ -424,7 +583,12 @@ file_list = (optind < argc ? &argv[optind] : stdin_argv); - expand (); +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + expand_multibyte (); + else +#endif + expand (); if (have_read_stdin && fclose (stdin) == EOF) error (EXIT_FAILURE, errno, "-"); diff -Naur coreutils-5.2.0/src/fold.c coreutils-5.2.0-acl/src/fold.c --- coreutils-5.2.0/src/fold.c 2004-01-21 16:27:02.000000000 -0600 +++ coreutils-5.2.0-acl/src/fold.c 2004-03-04 19:22:50.000000000 -0600 @@ -23,24 +23,66 @@ #include #include +/* Get mbstate_t, mbrtowc, wcwidth. */ +#if HAVE_WCHAR_H +# include +#endif + +/* Get iswprint, iswblank, wcwidth. */ +#if HAVE_WCTYPE_H +# include +#endif + #include "system.h" #include "error.h" #include "posixver.h" #include "xstrtol.h" +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC + installation; work around this configuration error. */ +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 +# undef MB_LEN_MAX +# define MB_LEN_MAX 16 +#endif + +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "fold" #define AUTHORS "David MacKenzie" +#define FATAL_ERROR(Message) \ + do \ + { \ + error (0, 0, (Message)); \ + usage (2); \ + } \ + while (0) + +enum operating_mode +{ + /* Fold texts by columns that are at the given positions. */ + column_mode, + + /* Fold texts by bytes that are at the given positions. */ + byte_mode, + + /* Fold texts by characters that are at the given positions. */ + character_mode, +}; + /* The name this program was run with. */ char *program_name; /* If nonzero, try to break on whitespace. */ static bool break_spaces; -/* If nonzero, count bytes, not column positions. */ -static bool count_bytes; +/* The argument shows current mode. (Default: column_mode) */ +static enum operating_mode operating_mode; /* If nonzero, at least one of the files we read was standard input. */ static bool have_read_stdin; @@ -48,6 +90,7 @@ static struct option const longopts[] = { {"bytes", no_argument, NULL, 'b'}, + {"characters", no_argument, NULL, 'c'}, {"spaces", no_argument, NULL, 's'}, {"width", required_argument, NULL, 'w'}, {GETOPT_HELP_OPTION_DECL}, @@ -77,6 +120,7 @@ "), stdout); fputs (_("\ -b, --bytes count bytes rather than columns\n\ + -c, --characters count characters rather than columns\n\ -s, --spaces break at spaces\n\ -w, --width=WIDTH use WIDTH columns instead of 80\n\ "), stdout); @@ -94,7 +138,7 @@ static size_t adjust_column (size_t column, char c) { - if (!count_bytes) + if (operating_mode != byte_mode) { if (c == '\b') { @@ -113,14 +157,9 @@ return column; } -/* Fold file FILENAME, or standard input if FILENAME is "-", - to stdout, with maximum line length WIDTH. - Return 0 if successful, 1 if an error occurs. */ - static int -fold_file (char *filename, int width) +fold_text (FILE *istream, int width) { - FILE *istream; register int c; size_t column = 0; /* Screen column where next char will go. */ size_t offset_out = 0; /* Index in `line_out' for next char. */ @@ -128,20 +167,6 @@ static size_t allocated_out = 0; int saved_errno; - if (STREQ (filename, "-")) - { - istream = stdin; - have_read_stdin = true; - } - else - istream = fopen (filename, "r"); - - if (istream == NULL) - { - error (0, errno, "%s", filename); - return 1; - } - while ((c = getc (istream)) != EOF) { if (offset_out + 1 >= allocated_out) @@ -168,6 +193,15 @@ bool found_blank = false; size_t logical_end = offset_out; + /* If LINE_OUT has no wide character, + put a new wide character in LINE_OUT + if column is bigger than width. */ + if (offset_out == 0) + { + line_out[offset_out++] = c; + continue; + } + /* Look for the last blank. */ while (logical_end) { @@ -219,6 +253,222 @@ if (offset_out) fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + return saved_errno; +} + +#if HAVE_MBRTOWC +static int +fold_multibyte_text (FILE *istream, int width) +{ + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ + size_t buflen = 0; /* The length of the byte sequence in buf. */ + char *bufpos = buf; /* Next read position of BUF. */ + wint_t wc; /* A gotten wide character. */ + size_t mblength; /* The byte size of a multibyte character which shows + as same character as WC. */ + mbstate_t state, state_bak; /* State of the stream. */ + int convfail; /* 1, when conversion is failed. Otherwise 0. */ + + static char *line_out = NULL; + static size_t allocated_out = 0; + size_t offset_out = 0; /* Index in `line_out' for next char. */ + int saved_errno; + + int increment; + size_t column = 0; + + size_t last_blank_pos; + size_t last_blank_column; + int is_blank_seen; + int last_blank_increment; + int is_bs_following_last_blank; + size_t bs_following_last_blank_num; + int is_cr_after_last_blank; + +#define CLEAR_FLAGS \ + do \ + { \ + last_blank_pos = 0; \ + last_blank_column = 0; \ + is_blank_seen = 0; \ + is_bs_following_last_blank = 0; \ + bs_following_last_blank_num = 0; \ + is_cr_after_last_blank = 0; \ + } \ + while (0) + +#define START_NEW_LINE \ + do \ + { \ + putchar ('\n'); \ + column = 0; \ + offset_out = 0; \ + CLEAR_FLAGS; \ + } \ + while (0) + + CLEAR_FLAGS; + memset (&state, '\0', sizeof (mbstate_t)); + + for (;; bufpos += mblength, buflen -= mblength) + { + if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream)) + { + memmove (buf, bufpos, buflen); + buflen += fread (buf + buflen, sizeof (char), BUFSIZ, istream); + bufpos = buf; + } + + if (buflen < 1) + break; + + /* Get a wide character. */ + convfail = 0; + state_bak = state; + mblength = mbrtowc ((wchar_t *) &wc, bufpos, buflen, &state); + + switch (mblength) + { + case (size_t) -1: + case (size_t) -2: + convfail++; + state = state_bak; + /* Fall through. */ + + case 0: + mblength = 1; + break; + } + +rescan: + if (operating_mode == byte_mode) /* byte mode */ + increment = mblength; + else if (operating_mode == character_mode) /* character mode */ + increment = 1; + else /* column mode */ + { + if (convfail) + increment = 1; + else + { + switch (wc) + { + case L'\n': + if (offset_out > 0) + fwrite (line_out, sizeof (char), offset_out, stdout); + START_NEW_LINE; + continue; + + case L'\b': + increment = (column > 0) ? -1 : 0; + break; + + case L'\r': + increment = -1 * column; + break; + + case L'\t': + increment = 8 - column % 8; + break; + + default: + increment = wcwidth (wc); + increment = (increment < 0) ? 0 : increment; + } + } + } + + if (column + increment > width && break_spaces && last_blank_pos) + { + fwrite (line_out, sizeof (char), last_blank_pos, stdout); + putchar ('\n'); + + offset_out = offset_out - last_blank_pos; + column = column - last_blank_column + ((is_cr_after_last_blank) + ? last_blank_increment : bs_following_last_blank_num); + memmove (line_out, line_out + last_blank_pos, offset_out); + CLEAR_FLAGS; + goto rescan; + } + + if (column + increment > width && column != 0) + { + fwrite (line_out, sizeof (char), offset_out, stdout); + START_NEW_LINE; + goto rescan; + } + + if (allocated_out < offset_out + mblength) + { + allocated_out += 1024; + line_out = xrealloc (line_out, allocated_out); + } + + memcpy (line_out + offset_out, bufpos, mblength); + offset_out += mblength; + column += increment; + + if (is_blank_seen && !convfail && wc == L'\r') + is_cr_after_last_blank = 1; + + if (is_bs_following_last_blank && !convfail && wc == L'\b') + ++bs_following_last_blank_num; + else + is_bs_following_last_blank = 0; + + if (break_spaces && !convfail && iswctype (wc, wctype ("blank"))) + { + last_blank_pos = offset_out; + last_blank_column = column; + is_blank_seen = 1; + last_blank_increment = increment; + is_bs_following_last_blank = 1; + bs_following_last_blank_num = 0; + is_cr_after_last_blank = 0; + } + } + + saved_errno = errno; + + if (offset_out) + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + + return saved_errno; +} +#endif + +/* Fold file FILENAME, or standard input if FILENAME is "-", + to stdout, with maximum line length WIDTH. + Return 0 if successful, 1 if an error occurs. */ + +static int +fold_file (char *filename, int width) +{ + FILE *istream; + int saved_errno; + + if (STREQ (filename, "-")) + { + istream = stdin; + have_read_stdin = 1; + } + else + istream = fopen (filename, "r"); + + if (istream == NULL) + { + error (0, errno, "%s", filename); + return 1; + } + + /* Define how ISTREAM is being folded. */ +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + saved_errno = fold_multibyte_text (istream, width); + else +#endif + saved_errno = fold_text (istream, width); + if (ferror (istream)) { error (0, saved_errno, "%s", filename); @@ -251,7 +501,8 @@ atexit (close_stdout); - break_spaces = count_bytes = have_read_stdin = false; + operating_mode = column_mode; + break_spaces = have_read_stdin = false; /* Turn any numeric options into -w options. */ for (i = 1; i < argc; i++) @@ -278,7 +529,7 @@ } } - while ((optc = getopt_long (argc, argv, "bsw:", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "bcsw:", longopts, NULL)) != -1) { switch (optc) { @@ -286,7 +537,15 @@ break; case 'b': /* Count bytes rather than columns. */ - count_bytes = true; + if (operating_mode != column_mode) + FATAL_ERROR (_("only one way of folding may be specified")); + operating_mode = byte_mode; + break; + + case 'c': /* Count characters rather than columns. */ + if (operating_mode != column_mode) + FATAL_ERROR (_("only one way of folding may be specified")); + operating_mode = character_mode; break; case 's': /* Break at word boundaries. */ diff -Naur coreutils-5.2.0/src/getdef.c coreutils-5.2.0-acl/src/getdef.c --- coreutils-5.2.0/src/getdef.c 1969-12-31 18:00:00.000000000 -0600 +++ coreutils-5.2.0-acl/src/getdef.c 2004-03-04 19:22:50.000000000 -0600 @@ -0,0 +1,272 @@ +/* + * Copyright 1991 - 1994, Julianne Frances Haugh and Chip Rosenthal + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "getdef.h" + +/* + * A configuration item definition. + */ + +struct itemdef { + const char *name; /* name of the item */ + char *value; /* value given, or NULL if no value */ +}; + +/* + * This list *must* be sorted by the "name" member. + */ + +#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0])) +static struct itemdef def_table[] = { + { "FAILLOG_ENAB", "yes" }, + { "FAIL_DELAY", NULL }, + { "FTMP_FILE", NULL }, +}; + +#ifndef LOGINDEFS +#define LOGINDEFS "/etc/login.defs" +#endif + +static char def_fname[] = LOGINDEFS; /* login config defs file */ +static int def_loaded = 0; /* are defs already loaded? */ + +/* local function prototypes */ +static struct itemdef *def_find (const char *); +static void def_load (void); + +/* + * getdef_num - get numerical value from table of definitions + * + * Returns numeric value of specified item, else the "dflt" value if + * the item is not defined. Octal (leading "0") and hex (leading "0x") + * values are handled. + */ + +int +getdef_num(const char *item, int dflt) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + if ((d = def_find(item)) == NULL || d->value == NULL) + return dflt; + + return (int) strtol(d->value, (char **)NULL, 0); +} + +/* + * putdef_str - override the value read from /etc/login.defs + * (also used when loading the initial defaults) + */ + +int +putdef_str (const char *name, const char *value) +{ + struct itemdef *d; + char *cp; + + if (!def_loaded) + def_load (); + + /* + * Locate the slot to save the value. If this parameter + * is unknown then "def_find" will print an err message. + */ + if ((d = def_find (name)) == NULL) + return -1; + + /* + * Save off the value. + */ + if ((cp = strdup (value)) == NULL) + { + fprintf (stderr, "Could not allocate space for config info.\n"); + syslog (LOG_ERR, "could not allocate space for config info"); + return -1; + } + +#if 0 + /* We don't give the old value free, it could be our static + default */ + if (d->value) + free(d->value); +#endif + + d->value = cp; + return 0; +} + + +/* + * def_find - locate named item in table + * + * Search through a sorted table of configurable items to locate the + * specified configuration option. + */ + +static struct itemdef * +def_find (const char *name) +{ + int min, max, curr, n; + + /* + * Invariant - desired item in range [min:max]. + */ + + min = 0; + max = NUMDEFS-1; + + /* + * Binary search into the table. Relies on the items being + * sorted by name. + */ + + while (min <= max) + { + curr = (min+max)/2; + + if (! (n = strcmp(def_table[curr].name, name))) + return &def_table[curr]; + + if (n < 0) + min = curr+1; + else + max = curr-1; + } + +#if 0 + /* + * Item was never found. + */ + + fprintf (stderr, "configuration error - unknown item '%s' (notify administrator)\r\n", + name); + syslog (LOG_CRIT, "unknown configuration item `%s'", name); +#endif + return (struct itemdef *) NULL; +} + +/* + * def_load - load configuration table + * + * Loads the user-configured options from the default configuration file + */ + +static void +def_load(void) +{ + int i; + FILE *fp; + char buf[1024], *name, *value, *s; + + /* + * Open the configuration definitions file. + */ + if ((fp = fopen(def_fname, "r")) == NULL) { + syslog (LOG_CRIT, "cannot open login definitions %s [%m]", + def_fname); + return; + } + + /* + * Set the initialized flag. + * (do it early to prevent recursion in putdef_str()) + */ + ++def_loaded; + + /* + * Go through all of the lines in the file. + */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + + /* + * Trim trailing whitespace. + */ + for (i = strlen(buf)-1 ; i >= 0 ; --i) { + if (!isspace(buf[i])) + break; + } + buf[++i] = '\0'; + + /* + * Break the line into two fields. + */ + name = buf + strspn(buf, " \t"); /* first nonwhite */ + if (*name == '\0' || *name == '#') + continue; /* comment or empty */ + + s = name + strcspn(name, " \t"); /* end of field */ + if (*s == '\0') + continue; /* only 1 field?? */ + + *s++ = '\0'; + value = s + strspn(s, " \"\t"); /* next nonwhite */ + *(value + strcspn(value, "\"")) = '\0'; + + /* + * Store the value in def_table. + */ + putdef_str(name, value); + } + (void) fclose(fp); +} + +#if 0 +int +main(int argc, char **argv) +{ + int i; + char *cp; + struct itemdef *d; + + def_load (); + + for (i = 0 ; i < NUMDEFS ; ++i) { + if ((d = def_find(def_table[i].name)) == NULL) + printf("error - lookup '%s' failed\n", def_table[i].name); + else + printf("%4d %-24s %s\n", i+1, d->name, d->value); + } + for (i = 1;i < argc;i++) { + if ((cp = getdef_str (argv[1])) != NULL) + printf ("%s `%s'\n", argv[1], cp); + else + printf ("%s not found\n", argv[1]); + } + exit(0); +} +#endif diff -Naur coreutils-5.2.0/src/getdef.h coreutils-5.2.0-acl/src/getdef.h --- coreutils-5.2.0/src/getdef.h 1969-12-31 18:00:00.000000000 -0600 +++ coreutils-5.2.0-acl/src/getdef.h 2004-03-04 19:22:50.000000000 -0600 @@ -0,0 +1,11 @@ +#ifndef _GETDEF_H +#define _GETDEF_H + +/* getdef.c */ +extern int getdef_bool (const char *); +extern long getdef_long (const char *, long); +extern int getdef_num (const char *, int); +extern char *getdef_str (const char *); +extern int putdef_str (const char *, const char *); + +#endif /* _GETDEF_H */ diff -Naur coreutils-5.2.0/src/install.c coreutils-5.2.0-acl/src/install.c --- coreutils-5.2.0/src/install.c 2004-02-07 09:41:12.000000000 -0600 +++ coreutils-5.2.0-acl/src/install.c 2004-03-04 19:22:50.000000000 -0600 @@ -162,11 +162,12 @@ x->mode = S_IRUSR | S_IWUSR; x->stdin_tty = 0; - x->umask_kill = 0; x->update = 0; x->verbose = 0; x->dest_info = NULL; x->src_info = NULL; + + x->attr_pattern = NULL; /* no extended attributes */ } int @@ -531,7 +532,8 @@ while (pid != wait (&status)) /* Wait for kid to finish. */ /* Do nothing. */ ; if (status) - error (EXIT_FAILURE, 0, _("strip failed")); + /* Don't fail just because `strip' failed. */ + error (0, 0, _("strip failed")); break; } } diff -Naur coreutils-5.2.0/src/join.c coreutils-5.2.0-acl/src/join.c --- coreutils-5.2.0/src/join.c 2004-01-21 16:27:02.000000000 -0600 +++ coreutils-5.2.0-acl/src/join.c 2004-03-04 19:22:50.000000000 -0600 @@ -24,6 +24,16 @@ #include #include +/* Get mbstate_t, mbrtowc, mbrtowc, wcwidth. */ +#if HAVE_WCHAR_H +# include +#endif + +/* Get iswblank, towupper. */ +#if HAVE_WCTYPE_H +# include +#endif + #include "system.h" #include "error.h" #include "hard-locale.h" @@ -34,6 +44,11 @@ #include "xmemcoll.h" #include "xstrtol.h" +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "join" @@ -110,7 +125,10 @@ /* Tab character separating fields; if this is NUL fields are separated by any nonempty string of white space, otherwise by exactly one tab character. */ -static char tab; +static char *tab = NULL; + +/* The number of bytes used for tab. */ +static size_t tablen = 0; /* When using getopt_long_only, no long option can start with a character that is a short option. */ @@ -233,7 +251,7 @@ if (tab) { - unsigned char t = tab; + unsigned char t = tab[0]; char *sep; for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1) extract_field (line, ptr, sep - ptr); @@ -262,6 +280,133 @@ extract_field (line, ptr, lim - ptr); } +#if HAVE_MBRTOWC +static void +xfields_multibyte (struct line *line) +{ + int i; + char *ptr0 = line->buf.buffer; + char *ptr; + char *lim; + wchar_t wc = 0; + size_t mblength; + mbstate_t state, state_bak; + + memset (&state, 0, sizeof (mbstate_t)); + + ptr = ptr0; + lim = ptr0 + line->buf.length - 1; + + if (tab == NULL) + { + /* Skip leading blanks before the first field. */ + while (ptr < lim) + { + state_bak = state; + mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); + + if (mblength == (size_t) -1 || mblength == (size_t) -2) + { + mblength = 1; + state = state_bak; + break; + } + mblength = (mblength < 1) ? 1 : mblength; + + if (!iswblank (wc)) + break; + ptr += mblength; + } + } + + for (i = 0; ptr < lim; ++i) + { + if (tab != NULL) + { + char *beg = ptr; + while (ptr < lim) + { + state_bak = state; + mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); + + if (mblength == (size_t) -1 || mblength == (size_t) -2) + { + mblength = 1; + state = state_bak; + } + mblength = (mblength < 1) ? 1 : mblength; + + if (mblength == tablen && !memcmp (ptr, tab, mblength)) + break; + else + { + ptr += mblength; + continue; + } + } + + extract_field (line, beg, ptr - beg); + if (ptr < lim) + ptr += mblength; + } + else + { + char *beg = ptr; + while (ptr < lim) + { + state_bak = state; + mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); + + if (mblength == (size_t) -1 || mblength == (size_t) -2) + { + mblength = 1; + state = state_bak; + } + mblength = (mblength < 1) ? 1 : mblength; + + if (iswblank (wc)) + break; + else + { + ptr += mblength; + continue; + } + } + + extract_field (line, beg, ptr - beg); + if (ptr < lim) + ptr += mblength; + } + } + + if (ptr != ptr0) + { + mblength = mbrtowc (&wc, ptr - mblength, mblength, &state); + wc = (mbsinit (&state) && *(ptr - mblength) == '\0') ? L'\0' : wc; + if (tab != NULL) + { + if (mblength == (size_t) -1 || mblength == (size_t) -2) + mblength = 1; + + if (mblength == tablen && !memcmp (ptr - mblength, tab, mblength)) + /* Add one more (empty) field because the last character of + the line was a delimiter. */ + extract_field (line, NULL, 0); + } + else + { + if (mblength != (size_t) -1 && mblength != (size_t) -2) + { + if (iswblank (wc)) + /* Add one more (empty) field because the last character of + the line was a delimiter. */ + extract_field (line, NULL, 0); + } + } + } +} +#endif + /* Read a line from FP into LINE and split it into fields. Return true if successful. */ @@ -282,7 +427,13 @@ line->nfields_allocated = 0; line->nfields = 0; line->fields = NULL; - xfields (line); + +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + xfields_multibyte (line); + else +#endif + xfields (line); return true; } @@ -336,56 +487,115 @@ keycmp (struct line const *line1, struct line const *line2) { /* Start of field to compare in each file. */ - char *beg1; - char *beg2; - - size_t len1; - size_t len2; /* Length of fields to compare. */ + char *beg[2]; + char *copy[2]; + size_t len[2]; /* Length of fields to compare. */ int diff; + int i, j; if (join_field_1 < line1->nfields) { - beg1 = line1->fields[join_field_1].beg; - len1 = line1->fields[join_field_1].len; + beg[0] = line1->fields[join_field_1].beg; + len[0] = line1->fields[join_field_1].len; } else { - beg1 = NULL; - len1 = 0; + beg[0] = NULL; + len[0] = 0; } if (join_field_2 < line2->nfields) { - beg2 = line2->fields[join_field_2].beg; - len2 = line2->fields[join_field_2].len; + beg[1] = line2->fields[join_field_2].beg; + len[1] = line2->fields[join_field_2].len; } else { - beg2 = NULL; - len2 = 0; + beg[1] = NULL; + len[1] = 0; } - if (len1 == 0) - return len2 == 0 ? 0 : -1; - if (len2 == 0) + if (len[0] == 0) + return len[1] == 0 ? 0 : -1; + if (len[1] == 0) return 1; if (ignore_case) { - /* FIXME: ignore_case does not work with NLS (in particular, - with multibyte chars). */ - diff = memcasecmp (beg1, beg2, MIN (len1, len2)); +#ifdef HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + { + size_t mblength; + wchar_t wc, uwc; + mbstate_t state, state_bak; + + memset (&state, '\0', sizeof (mbstate_t)); + + for (i = 0; i < 2; i++) + { + copy[i] = alloca (len[i] + 1); + + for (j = 0; j < MIN (len[0], len[1]);) + { + state_bak = state; + mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state); + + switch (mblength) + { + case (size_t) -1: + case (size_t) -2: + state = state_bak; + /* Fall through */ + case 0: + mblength = 1; + break; + + default: + uwc = towupper (wc); + + if (uwc != wc) + { + mbstate_t state_wc; + + memset (&state_wc, '\0', sizeof (mbstate_t)); + wcrtomb (copy[i] + j, uwc, &state_wc); + } + else + memcpy (copy[i] + j, beg[i] + j, mblength); + } + j += mblength; + } + copy[i][j] = '\0'; + } + return xmemcoll (copy[0], len[0], copy[1], len[1]); + } +#endif + if (HAVE_SETLOCALE && hard_LC_COLLATE) + { + for (i = 0; i < 2; i++) + { + copy[i] = alloca (len[i] + 1); + + for (j = 0; j < MIN (len[0], len[1]); j++) + copy[i][j] = toupper (beg[i][j]); + + copy[i][j] = '\0'; + } + return xmemcoll (copy[0], len[0], copy[1], len[1]); + } + else + diff = memcasecmp (beg[0], beg[1], MIN (len[0], len[1])); } else { if (HAVE_SETLOCALE && hard_LC_COLLATE) - return xmemcoll (beg1, len1, beg2, len2); - diff = memcmp (beg1, beg2, MIN (len1, len2)); + return xmemcoll (beg[0], len[0], beg[1], len[1]); + diff = memcmp (beg[0], beg[1], MIN (len[0], len[1])); } if (diff) return diff; - return len1 < len2 ? -1 : len1 != len2; + return len[0] < len[1] ? -1 : len[0] != len[1]; } /* Print field N of LINE if it exists and is nonempty, otherwise @@ -414,7 +624,8 @@ prjoin (struct line const *line1, struct line const *line2) { const struct outlist *outlist; - char output_separator = tab ? tab : ' '; + char *output_separator = tab ? tab : " "; + size_t output_separator_len = tab ? tablen : 1; outlist = outlist_head.next; if (outlist) @@ -449,7 +660,7 @@ o = o->next; if (o == NULL) break; - putchar (output_separator); + fwrite (output_separator, 1, output_separator_len, stdout); } putchar ('\n'); } @@ -467,23 +678,23 @@ prfield (join_field_1, line1); for (i = 0; i < join_field_1 && i < line1->nfields; ++i) { - putchar (output_separator); + fwrite (output_separator, 1, output_separator_len, stdout); prfield (i, line1); } for (i = join_field_1 + 1; i < line1->nfields; ++i) { - putchar (output_separator); + fwrite (output_separator, 1, output_separator_len, stdout); prfield (i, line1); } for (i = 0; i < join_field_2 && i < line2->nfields; ++i) { - putchar (output_separator); + fwrite (output_separator, 1, output_separator_len, stdout); prfield (i, line2); } for (i = join_field_2 + 1; i < line2->nfields; ++i) { - putchar (output_separator); + fwrite (output_separator, 1, output_separator_len, stdout); prfield (i, line2); } putchar ('\n'); @@ -817,7 +1028,21 @@ break; case 't': - tab = *optarg; + tab = xstrdup (optarg); +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + { + mbstate_t state; + + memset (&state, 0, sizeof (mbstate_t)); + tablen = mbrtowc (NULL, optarg, strlen (optarg), &state); + if (tablen == (size_t) 0 + || tablen == (size_t) -1 || tablen == (size_t) -2) + tablen = 1; + } + else +#endif + tablen = 1; break; case 1: /* Non-option argument. */ diff -Naur coreutils-5.2.0/src/ls.c coreutils-5.2.0-acl/src/ls.c --- coreutils-5.2.0/src/ls.c 2004-02-01 13:31:00.000000000 -0600 +++ coreutils-5.2.0-acl/src/ls.c 2004-03-04 19:22:50.000000000 -0600 @@ -188,13 +188,13 @@ enum filetype filetype; -#if HAVE_ACL +#if USE_ACL /* For long listings, true if the file has an access control list. */ bool have_acl; #endif }; -#if HAVE_ACL +#if USE_ACL # define FILE_HAS_ACL(F) ((F)->have_acl) #else # define FILE_HAS_ACL(F) 0 @@ -2403,7 +2403,7 @@ return 0; } -#if HAVE_ACL +#if USE_ACL if (format == long_format) { int n = file_has_acl (path, &f->stat); diff -Naur coreutils-5.2.0/src/mv.c coreutils-5.2.0-acl/src/mv.c --- coreutils-5.2.0/src/mv.c 2004-02-07 09:41:02.000000000 -0600 +++ coreutils-5.2.0-acl/src/mv.c 2004-03-04 19:22:50.000000000 -0600 @@ -132,16 +132,12 @@ x->mode = 0; x->stdin_tty = isatty (STDIN_FILENO); - /* Find out the current file creation mask, to knock the right bits - when using chmod. The creation mask is set to be liberal, so - that created directories can be written, even if it would not - have been allowed with the mask this process was started with. */ - x->umask_kill = ~ umask (0); - x->update = 0; x->verbose = 0; x->dest_info = NULL; x->src_info = NULL; + + x->attr_pattern = ""; /* all extended attributes */ } /* If PATH is an existing directory, return nonzero, else 0. */ diff -Naur coreutils-5.2.0/src/pr.c coreutils-5.2.0-acl/src/pr.c --- coreutils-5.2.0/src/pr.c 2004-01-21 16:27:02.000000000 -0600 +++ coreutils-5.2.0-acl/src/pr.c 2004-03-04 19:22:50.000000000 -0600 @@ -314,12 +314,50 @@ #include #include #include + +/* Get MB_LEN_MAX. */ +#include +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC + installation; work around this configuration error. */ +#if !defined MB_LEN_MAX || MB_LEN_MAX == 1 +# define MB_LEN_MAX 16 +#endif + +/* Get MB_CUR_MAX. */ +#include + +/* Solaris 2.5 has a bug: must be included before . */ +/* Get mbstate_t, mbrtowc(), wcwidth(). */ +#if HAVE_WCHAR_H +# include +#endif + +/* Get iswprint(). -- for wcwidth(). */ +#if HAVE_WCTYPE_H +# include +#endif +#if !defined iswprint && !HAVE_ISWPRINT +# define iswprint(wc) 1 +#endif + #include "system.h" #include "error.h" #include "mbswidth.h" #include "posixver.h" #include "xstrtol.h" +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HAVE_MBRTOWC && defined mbstate_t +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + +#ifndef HAVE_DECL_WCWIDTH +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_WCWIDTH +extern int wcwidth (); +#endif + /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "pr" @@ -411,8 +449,21 @@ typedef struct COLUMN COLUMN; #define NULLCOL (COLUMN *)0 + +/* Funtion pointers to switch functions for single byte locale or for + multibyte locale. If multibyte functions do not exist in your sysytem, + these pointers always point the function for single byte locale. */ +static void (*print_char) (int c); +static int (*char_to_clump) (int c); + +/* Functions for single byte locale. */ +static void print_char_single (int c); +static int char_to_clump_single (int c); + +/* Functions for multibyte locale. */ +static void print_char_multi (int c); +static int char_to_clump_multi (int c); -static int char_to_clump (int c); static int read_line (COLUMN *p); static int print_page (void); static int print_stored (COLUMN *p); @@ -422,6 +473,7 @@ static void pad_across_to (int position); static void add_line_number (COLUMN *p); static void getoptarg (char *arg, char switch_char, char *character, + int *character_length, int *character_width, int *number); void usage (int status); static void print_files (int number_of_files, char **av); @@ -436,7 +488,6 @@ static void pad_down (int lines); static void read_rest_of_line (COLUMN *p); static void skip_read (COLUMN *p, int column_number); -static void print_char (int c); static void cleanup (void); static void first_last_page (char *pages); static void print_sep_string (void); @@ -452,7 +503,7 @@ we store the leftmost columns contiguously in buff. To print a line from buff, get the index of the first character from line_vector[i], and print up to line_vector[i + 1]. */ -static char *buff; +static unsigned char *buff; /* Index of the position in buff where the next character will be stored. */ @@ -556,7 +607,7 @@ static int untabify_input = FALSE; /* (-e) The input tab character. */ -static char input_tab_char = '\t'; +static char input_tab_char[MB_LEN_MAX] = "\t"; /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ... where the leftmost column is 1. */ @@ -566,7 +617,10 @@ static int tabify_output = FALSE; /* (-i) The output tab character. */ -static char output_tab_char = '\t'; +static char output_tab_char[MB_LEN_MAX] = "\t"; + +/* (-i) The byte length of output tab character. */ +static int output_tab_char_length = 1; /* (-i) The width of the output tab. */ static int chars_per_output_tab = 8; @@ -640,7 +694,13 @@ static int numbered_lines = FALSE; /* (-n) Character which follows each line number. */ -static char number_separator = '\t'; +static char number_separator[MB_LEN_MAX] = "\t"; + +/* (-n) The byte length of the character which follows each line number. */ +static int number_separator_length = 1; + +/* (-n) The character width of the character which follows each line number. */ +static int number_separator_width = 0; /* (-n) line counting starts with 1st line of input file (not with 1st line of 1st page printed). */ @@ -693,6 +753,7 @@ -a|COLUMN|-m is a `space' and with the -J option a `tab'. */ static char *col_sep_string = ""; static int col_sep_length = 0; +static int col_sep_width = 0; static char *column_separator = " "; static char *line_separator = "\t"; @@ -842,6 +903,13 @@ col_sep_length = (int) strlen (optarg_S); col_sep_string = xmalloc (col_sep_length + 1); strcpy (col_sep_string, optarg_S); + +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + col_sep_width = mbswidth (col_sep_string, 0); + else +#endif + col_sep_width = col_sep_length; } int @@ -866,6 +934,21 @@ atexit (close_stdout); +/* Define which functions are used, the ones for single byte locale or the ones + for multibyte locale. */ +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) + { + print_char = print_char_multi; + char_to_clump = char_to_clump_multi; + } + else +#endif + { + print_char = print_char_single; + char_to_clump = char_to_clump_single; + } + n_files = 0; file_names = (argc > 1 ? xmalloc ((argc - 1) * sizeof (char *)) @@ -943,8 +1026,12 @@ break; case 'e': if (optarg) - getoptarg (optarg, 'e', &input_tab_char, - &chars_per_input_tab); + { + int dummy_length, dummy_width; + + getoptarg (optarg, 'e', input_tab_char, &dummy_length, + &dummy_width, &chars_per_input_tab); + } /* Could check tab width > 0. */ untabify_input = TRUE; break; @@ -957,8 +1044,12 @@ break; case 'i': if (optarg) - getoptarg (optarg, 'i', &output_tab_char, - &chars_per_output_tab); + { + int dummy_width; + + getoptarg (optarg, 'i', output_tab_char, &output_tab_char_length, + &dummy_width, &chars_per_output_tab); + } /* Could check tab width > 0. */ tabify_output = TRUE; break; @@ -985,8 +1076,8 @@ case 'n': numbered_lines = TRUE; if (optarg) - getoptarg (optarg, 'n', &number_separator, - &chars_per_number); + getoptarg (optarg, 'n', number_separator, &number_separator_length, + &number_separator_width, &chars_per_number); break; case 'N': skip_count = FALSE; @@ -1025,7 +1116,7 @@ old_s = FALSE; /* Reset an additional input of -s, -S dominates -s */ col_sep_string = ""; - col_sep_length = 0; + col_sep_length = col_sep_width = 0; use_col_separator = TRUE; if (optarg) separator_string (optarg); @@ -1173,10 +1264,45 @@ a number. */ static void -getoptarg (char *arg, char switch_char, char *character, int *number) +getoptarg (char *arg, char switch_char, char *character, int *character_length, + int *character_width, int *number) { if (!ISDIGIT (*arg)) - *character = *arg++; + { +#ifdef HAVE_MBRTOWC + if (MB_CUR_MAX > 1) /* for multibyte locale. */ + { + wchar_t wc; + size_t mblength; + int width; + mbstate_t state = {'\0'}; + + mblength = mbrtowc (&wc, arg, strlen (arg), &state); + + if (mblength == (size_t) -1 || mblength == (size_t) -2) + { + *character_length = 1; + *character_width = 1; + } + else + { + *character_length = (mblength < 1) ? 1 : mblength; + width = wcwidth (wc); + *character_width = (width < 0) ? 0 : width; + } + + strncpy (character, arg, *character_length); + arg += *character_length; + } + else /* for single byte locale. */ +#endif + { + *character = *arg++; + *character_length = 1; + *character_width = 1; + } + } + if (*arg) { long int tmp_long; @@ -1241,7 +1367,7 @@ else col_sep_string = column_separator; - col_sep_length = 1; + col_sep_length = col_sep_width = 1; use_col_separator = TRUE; } /* It's rather pointless to define a TAB separator with column @@ -1273,11 +1399,11 @@ TAB_WIDTH (chars_per_input_tab, chars_per_number); */ /* Estimate chars_per_text without any margin and keep it constant. */ - if (number_separator == '\t') + if (number_separator[0] == '\t') number_width = chars_per_number + TAB_WIDTH (chars_per_default_tab, chars_per_number); else - number_width = chars_per_number + 1; + number_width = chars_per_number + number_separator_width; /* The number is part of the column width unless we are printing files in parallel. */ @@ -1292,7 +1418,7 @@ } chars_per_column = (chars_per_line - chars_used_by_number - - (columns - 1) * col_sep_length) / columns; + (columns - 1) * col_sep_width) / columns; if (chars_per_column < 1) error (EXIT_FAILURE, 0, _("page width too narrow")); @@ -1421,7 +1547,7 @@ /* Enlarge p->start_position of first column to use the same form of padding_not_printed with all columns. */ - h = h + col_sep_length; + h = h + col_sep_width; /* This loop takes care of all but the rightmost column. */ @@ -1455,7 +1581,7 @@ } else { - h = h_next + col_sep_length; + h = h_next + col_sep_width; h_next = h + chars_per_column; } } @@ -1739,9 +1865,9 @@ align_column (COLUMN *p) { padding_not_printed = p->start_position; - if (padding_not_printed - col_sep_length > 0) + if (padding_not_printed - col_sep_width > 0) { - pad_across_to (padding_not_printed - col_sep_length); + pad_across_to (padding_not_printed - col_sep_width); padding_not_printed = ANYWHERE; } @@ -2015,13 +2141,13 @@ /* May be too generous. */ buff = x2nrealloc (buff, &buff_allocated, sizeof *buff); } - buff[buff_current++] = (char) c; + buff[buff_current++] = (unsigned char) c; } static void add_line_number (COLUMN *p) { - int i; + int i, j; char *s; int left_cut; @@ -2044,22 +2170,24 @@ /* Tabification is assumed for multiple columns, also for n-separators, but `default n-separator = TAB' hasn't been given priority over equal column_width also specified by POSIX. */ - if (number_separator == '\t') + if (number_separator[0] == '\t') { i = number_width - chars_per_number; while (i-- > 0) (p->char_func) ((int) ' '); } else - (p->char_func) ((int) number_separator); + for (j = 0; j < number_separator_length; j++) + (p->char_func) ((int) number_separator[j]); } else /* To comply with POSIX, we avoid any expansion of default TAB separator with a single column output. No column_width requirement has to be considered. */ { - (p->char_func) ((int) number_separator); - if (number_separator == '\t') + for (j = 0; j < number_separator_length; j++) + (p->char_func) ((int) number_separator[j]); + if (number_separator[0] == '\t') output_position = POS_AFTER_TAB (chars_per_output_tab, output_position); } @@ -2219,7 +2347,7 @@ while (goal - h_old > 1 && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) { - putchar (output_tab_char); + fwrite (output_tab_char, 1, output_tab_char_length, stdout); h_old = h_new; } while (++h_old <= goal) @@ -2239,6 +2367,7 @@ { char *s; int l = col_sep_length; + int not_space_flag; s = col_sep_string; @@ -2252,6 +2381,7 @@ { for (; separators_not_printed > 0; --separators_not_printed) { + not_space_flag = 0; while (l-- > 0) { /* 3 types of sep_strings: spaces only, spaces and chars, @@ -2265,12 +2395,15 @@ } else { + not_space_flag = 1; if (spaces_not_printed > 0) print_white_space (); putchar (*s++); - ++output_position; } } + if (not_space_flag) + output_position += col_sep_width; + /* sep_string ends with some spaces */ if (spaces_not_printed > 0) print_white_space (); @@ -2297,8 +2430,9 @@ a nonspace is encountered, call print_white_space() to print the required number of tabs and spaces. */ + static void -print_char (int c) +print_char_single (int c) { if (tabify_output) { @@ -2322,6 +2456,74 @@ putchar (c); } +#ifdef HAVE_MBRTOWC +static void +print_char_multi (int c) +{ + static size_t mbc_pos = 0; + static unsigned char mbc[MB_LEN_MAX] = {'\0'}; + static mbstate_t state = {'\0'}; + mbstate_t state_bak; + wchar_t wc; + size_t mblength; + int width; + + if (tabify_output) + { + state_bak = state; + mbc[mbc_pos++] = (unsigned char) c; + mblength = mbrtowc (&wc, mbc, mbc_pos, &state); + + while (mbc_pos > 0) + { + switch (mblength) + { + case (size_t) -2: + state = state_bak; + return; + + case (size_t) -1: + state = state_bak; + ++output_position; + putchar (mbc[0]); + memmove (mbc, mbc + 1, MB_CUR_MAX - 1); + --mbc_pos; + break; + + case 0: + mblength = 1; + + default: + if (wc == L' ') + { + memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); + --mbc_pos; + ++spaces_not_printed; + return; + } + else if (spaces_not_printed > 0) + print_white_space (); + + /* Nonprintables are assumed to have width 0, except L'\b'. */ + if ((width = wcwidth (wc)) < 1) + { + if (wc == L'\b') + --output_position; + } + else + output_position += width; + + fwrite (mbc, 1, mblength, stdout); + memmove (mbc, mbc + mblength, MB_CUR_MAX - mblength); + mbc_pos -= mblength; + } + } + return; + } + putchar (c); +} +#endif + /* Skip to page PAGE before printing. PAGE may be larger than total number of pages. */ @@ -2496,9 +2698,9 @@ align_empty_cols = FALSE; } - if (padding_not_printed - col_sep_length > 0) + if (padding_not_printed - col_sep_width > 0) { - pad_across_to (padding_not_printed - col_sep_length); + pad_across_to (padding_not_printed - col_sep_width); padding_not_printed = ANYWHERE; } @@ -2599,9 +2801,9 @@ } } - if (padding_not_printed - col_sep_length > 0) + if (padding_not_printed - col_sep_width > 0) { - pad_across_to (padding_not_printed - col_sep_length); + pad_across_to (padding_not_printed - col_sep_width); padding_not_printed = ANYWHERE; } @@ -2614,8 +2816,8 @@ if (spaces_not_printed == 0) { output_position = p->start_position + end_vector[line]; - if (p->start_position - col_sep_length == chars_per_margin) - output_position -= col_sep_length; + if (p->start_position - col_sep_width == chars_per_margin) + output_position -= col_sep_width; } return TRUE; @@ -2633,8 +2835,9 @@ characters in clump_buff. (e.g, the width of '\b' is -1, while the number of characters is 1.) */ + static int -char_to_clump (int c) +char_to_clump_single (int c) { register int *s = clump_buff; register int i; @@ -2643,10 +2846,10 @@ int chars; int chars_per_c = 8; - if (c == input_tab_char) + if (c == input_tab_char[0]) chars_per_c = chars_per_input_tab; - if (c == input_tab_char || c == '\t') + if (c == input_tab_char[0] || c == '\t') { width = TAB_WIDTH (chars_per_c, input_position); @@ -2717,6 +2920,154 @@ return chars; } +#ifdef HAVE_MBRTOWC +static int +char_to_clump_multi (int c) +{ + static size_t mbc_pos = 0; + static unsigned char mbc[MB_LEN_MAX] = {'\0'}; + static mbstate_t state = {'\0'}; + mbstate_t state_bak; + wchar_t wc; + size_t mblength; + int wc_width; + register int *s = clump_buff; + register int i, j; + char esc_buff[4]; + int width; + int chars; + int chars_per_c = 8; + + state_bak = state; + mbc[mbc_pos++] = (unsigned char) c; + mblength = mbrtowc (&wc, mbc, mbc_pos, &state); + + width = 0; + chars = 0; + while (mbc_pos > 0) + { + switch (mblength) + { + case (size_t) -2: + state = state_bak; + return 0; + + case (size_t) -1: + state = state_bak; + mblength = 1; + + if (use_esc_sequence || use_cntrl_prefix) + { + width = +4; + chars = +4; + *s++ = '\\'; + sprintf (esc_buff, "%03o", mbc[0]); + for (i = 0; i <= 2; ++i) + *s++ = (int) esc_buff[i]; + } + else + { +