- From ed7f138e1682b7da95d606125b81abf754653a0f Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 5 Apr 2025 16:43:13 +0200
- Subject: [PATCH 1/5] tests: lssparse -H does not print hole at offset 0 if
- more data exists
- lssparse -H does not print hole at offset 0 if more data exists.
- Fixes: https://cygwin.com/pipermail/cygwin/2025-April/257843.html
- Reported-by: Christian Franke <Christian.Franke@t-online.de>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/lssparse/lssparse.c | 10 ++++++----
- 1 file changed, 6 insertions(+), 4 deletions(-)
- diff --git a/tests/lssparse/lssparse.c b/tests/lssparse/lssparse.c
- index 4adb200..6fc269e 100644
- --- a/tests/lssparse/lssparse.c
- +++ b/tests/lssparse/lssparse.c
- @@ -2,7 +2,7 @@
- /*
- * MIT License
- *
- - * Copyright (c) 2011-2012 Roland Mainz <roland.mainz@nrubsig.org>
- + * Copyright (c) 2011-2025 Roland Mainz <roland.mainz@nrubsig.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- @@ -139,7 +139,8 @@ int main(int argc, char *argv[])
- * $ /cygdrive/c/Windows/system32/fsutil sparse queryrange ... #
- * output
- */
- - for (i=1 ;;) {
- +#define LSSPARSE_START_INDEX 1
- + for (i=LSSPARSE_START_INDEX ;;) {
- data_start = lseek(fd, offset, SEEK_DATA);
- if (data_start == -1)
- break;
- @@ -159,7 +160,8 @@ int main(int argc, char *argv[])
- }
- }
- - if (print_holes && (i == 0) && (data_start > 0)) {
- + if (print_holes &&
- + (i == LSSPARSE_START_INDEX) && (data_start > 0)) {
- (void)printf((pb == pb_hex)?
- "Hole range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
- "Hole range[%ld]: offset=%lld,\tlength=%lld\n",
- @@ -215,7 +217,7 @@ int main(int argc, char *argv[])
- (void)printf((pb == pb_hex)?
- "Hole range[%ld]: offset=0x%llx,\tlength=0x%llx\n":
- "Hole range[%ld]: offset=%lld,\tlength=%lld\n",
- - (long)0,
- + (long)LSSPARSE_START_INDEX,
- (long long)0LL,
- (long long)file_size);
- }
- --
- 2.45.1
- From 1b23534234fa58633bc96137220a9b9b32d4aa5f Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 5 Apr 2025 16:48:36 +0200
- Subject: [PATCH 2/5] tests: lssparse usage message should print all options in
- short form line
- lssparse usage message should print all options in short form line.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/lssparse/lssparse.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/tests/lssparse/lssparse.c b/tests/lssparse/lssparse.c
- index 6fc269e..399ac75 100644
- --- a/tests/lssparse/lssparse.c
- +++ b/tests/lssparse/lssparse.c
- @@ -42,7 +42,7 @@
- static
- void usage(const char *progname)
- {
- - (void)fprintf(stderr, "Usage: %s [-h] <sparse_file>\n"
- + (void)fprintf(stderr, "Usage: %s [-h] [-xdH] <sparse_file>\n"
- " -h: Display this help message\n"
- " -x: Print offsets in hexadecimal (base 16)\n"
- " -d: Print offsets in decimal (base 10)\n"
- --
- 2.45.1
- From 96fd0d99372b83f17835422a80f5f165c071d9c4 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 5 Apr 2025 17:08:50 +0200
- Subject: [PATCH 3/5] cygwin: Fix cygwinaccount2nfs4account error messages
- Fix cygwinaccount2nfs4account error messages
- Reported-by: Joshuah Hurst <joshhurst@gmail.com>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- .../cygwinaccount2nfs4account/cygwinaccount2nfs4account.ksh | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
- diff --git a/cygwin/utils/cygwinaccount2nfs4account/cygwinaccount2nfs4account.ksh b/cygwin/utils/cygwinaccount2nfs4account/cygwinaccount2nfs4account.ksh
- index 264b9c5..128e6d8 100644
- --- a/cygwin/utils/cygwinaccount2nfs4account/cygwinaccount2nfs4account.ksh
- +++ b/cygwin/utils/cygwinaccount2nfs4account/cygwinaccount2nfs4account.ksh
- @@ -406,7 +406,7 @@ function main
- # fixme: Need better text layout for $ cygwinaccount2nfs4account --man #
- typeset -r cygwinaccount2nfs4account_usage=$'+
- - [-?\n@(#)\$Id: cygwinaccount2nfs4account (Roland Mainz) 2025-03-19 \$\n]
- + [-?\n@(#)\$Id: cygwinaccount2nfs4account (Roland Mainz) 2025-04-05 \$\n]
- [-author?Roland Mainz <roland.mainz@nrubsig.org>]
- [+NAME?cygwinaccount2nfs4account - convert Cygwin user/group account
- info to Linux/UNIX NFSv4 server account data]
- @@ -455,12 +455,13 @@ function main
- done
- if [[ ! -v c.os ]] ; then
- - print -u2 -f $"%s: Require -O <operating-system>\n"
- + print -u2 -f $"%s: Require -O <operating-system>\n" "${progname}"
- return 1
- fi
- if [[ "${c.os}" != ~(Elr)(linux|solaris|illumos) ]] ; then
- print -u2 -f $"%s: Unsuppoted -O value %q, supported are 'linux', 'solaris', 'illumos'\n" \
- + "${progname}" \
- "${c.os}"
- return 1
- fi
- --
- 2.45.1
- From 56e4b20fdfee6100c3b3f511355854b466cede8e Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 5 Apr 2025 18:55:42 +0200
- Subject: [PATCH 4/5] cygwin,tests: Remove native "git clone" failure from bug
- list, fixed via |NFS41_DRIVER_HACK_DISABLE_FCB_ATTR_UPDATE_ON_OPEN|
- Remove native "git clone" failure from bug list, we worked around that
- issue via |NFS41_DRIVER_HACK_DISABLE_FCB_ATTR_UPDATE_ON_OPEN|
- (see commit "nfs41_build_features.h,sys: Add hack to avoid updating
- FCB attributes we open an already opened FCB")
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- cygwin/README.bintarball.txt | 20 --------------------
- tests/manual_testing.txt | 20 ++------------------
- 2 files changed, 2 insertions(+), 38 deletions(-)
- diff --git a/cygwin/README.bintarball.txt b/cygwin/README.bintarball.txt
- index 6a5c025..bfa378d 100644
- --- a/cygwin/README.bintarball.txt
- +++ b/cygwin/README.bintarball.txt
- @@ -609,26 +609,6 @@ $ mount -t drvfs '\0.49.202.230@2049\nfs4\bigdisk' /mnt/bigdisk
- Datei befindet. Versuchen Sie, die Datei woanders zu speichern.
- ---- snip ----
- -- Bug: Native Windows git (NOT cygwin /usr/bin/git) clone fails
- - like this:
- - # ---- snip ----
- - $ '/cygdrive/c/Program Files/Git/cmd/git' --version
- - git version 2.45.2.windows.1
- - $ '/cygdrive/c/Program Files/Git/cmd/git' clone https://github.com/kofemann/ms-nfs41-client.git
- - Cloning into 'ms-nfs41-client'...
- - remote: Enumerating objects: 6558, done.
- - remote: Counting objects: 100% (318/318), done.
- - remote: Compressing objects: 100% (172/172), done.
- - remote: Total 6558 (delta 191), reused 233 (delta 141), pack-reused 6240 (from 1)
- - Receiving objects: 100% (6558/6558), 2.43 MiB | 4.66 MiB/s, done.
- - fatal: premature end of pack file, 655 bytes missing
- - warning: die() called many times. Recursion error or racy threaded death!
- - fatal: fetch-pack: invalid index-pack output
- - # ---- snip ----
- - Workaround is to mount the NFS filesystem with the "writethru"
- - OR "nocache" option, e.g.
- - $ /sbin/nfs_mount -o rw,writethru 'j' derfwpc5131:/export/home/rmainz #
- -
- #
- # 12. Notes for troubleshooting && finding bugs/debugging:
- diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
- index 57c4861..d9291c0 100644
- --- a/tests/manual_testing.txt
- +++ b/tests/manual_testing.txt
- @@ -567,24 +567,8 @@ svn checkout https://svn.FreeBSD.org/base/head/share/man
- #
- # NATIVE Windows git clone (NOT Cygwin /usr/bin/git!)
- #
- -# Currently fails like this:
- -# ---- snip ----
- -# $ '/cygdrive/c/Program Files/Git/cmd/git' --version
- -# git version 2.45.2.windows.1
- -# $ '/cygdrive/c/Program Files/Git/cmd/git' clone https://github.com/kofemann/ms-nfs41-client.git
- -# Cloning into 'ms-nfs41-client'...
- -# remote: Enumerating objects: 6558, done.
- -# remote: Counting objects: 100% (318/318), done.
- -# remote: Compressing objects: 100% (172/172), done.
- -# remote: Total 6558 (delta 191), reused 233 (delta 141), pack-reused 6240 (from 1)
- -# Receiving objects: 100% (6558/6558), 2.43 MiB | 4.66 MiB/s, done.
- -# fatal: premature end of pack file, 655 bytes missing
- -# warning: die() called many times. Recursion error or racy threaded death!
- -# fatal: fetch-pack: invalid index-pack output
- -# ---- snip ----
- -# Workaround is to mount the NFS filesystem with the "writethru"
- -# OR "nocache" option, e.g.
- -# $ /sbin/nfs_mount -o rw,writethru 'j' derfwpc5131:/export/home/rmainz #
- +# This can fail with older Linux nfsd like Linux 5.10,
- +# but works with Linux 6.6.32-rt32 nfsd
- #
- # Test:
- '/cygdrive/c/Program Files/Git/cmd/git' clone https://github.com/kofemann/ms-nfs41-client.git
- --
- 2.45.1
- From 86d69fed7ca51432964392a2a963d21034f8b4d6 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 5 Apr 2025 19:49:14 +0200
- Subject: [PATCH 5/5] daemon,tests: Fix Nfs3Attr EA local uid/gid
- Nfs3Attr EA (probed via $ /bin/winfsinfo nfs3attr ... #) sometimes
- contains local uid=0/local gid=0 instead of the real local uid/gid.
- Fix is to always do the uid/gid lookup.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/open.c | 246 ++++++++++++++++++++++-----------------
- tests/manual_testing.txt | 15 +++
- 2 files changed, 155 insertions(+), 106 deletions(-)
- diff --git a/daemon/open.c b/daemon/open.c
- index 95d724a..d2629c0 100644
- --- a/daemon/open.c
- +++ b/daemon/open.c
- @@ -688,6 +688,134 @@ void symlink2ntpath(
- (int)*out_target_type));
- }
- +#ifdef NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES
- +static
- +void open_get_localuidgid(IN nfs41_daemon_globals *restrict nfs41dg,
- + IN nfs41_open_state *restrict state,
- + IN OUT nfs41_file_info *restrict info,
- + OUT DWORD *restrict owner_local_uid,
- + OUT DWORD *restrict owner_group_local_gid)
- +{
- + int status = 0;
- + char owner[NFS4_FATTR4_OWNER_LIMIT+1];
- + char owner_group[NFS4_FATTR4_OWNER_LIMIT+1];
- + uid_t map_uid = ~0UL;
- + gid_t map_gid = ~0UL;
- + char *at_ch; /* pointer to '@' */
- +
- +#if 1
- + EASSERT(info->attrmask.count >= 2);
- +
- + /* this should only happen for newly created files/dirs */
- + if ((info->attrmask.count < 2) ||
- + ((info->attrmask.arr[1] & FATTR4_WORD1_OWNER) == 0) ||
- + ((info->attrmask.arr[1] & FATTR4_WORD1_OWNER_GROUP) == 0)) {
- + bitmap4 og_attr_request;
- + nfs41_file_info og_info = { 0 };
- +
- + og_attr_request.count = 2;
- + og_attr_request.arr[0] = 0;
- + og_attr_request.arr[1] =
- + FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP;
- + og_info.owner = og_info.owner_buf;
- + og_info.owner_group = og_info.owner_group_buf;
- + status = nfs41_getattr(state->session, &state->file,
- + &og_attr_request, &og_info);
- + if (status) {
- + eprintf("open_get_localuidgid: nfs41_getattr('%s') "
- + "failed with %d\n",
- + state->path.path,
- + status);
- + *owner_local_uid = NFS_USER_NOBODY_UID;
- + *owner_group_local_gid = NFS_GROUP_NOGROUP_GID;
- + goto out;
- + }
- +
- + info->owner = info->owner_buf;
- + (void)strcpy(info->owner, og_info.owner);
- + info->attrmask.arr[1] |= FATTR4_WORD1_OWNER;
- + info->owner_group = info->owner_group_buf;
- + (void)strcpy(info->owner_group, og_info.owner_group);
- + info->attrmask.arr[1] |= FATTR4_WORD1_OWNER_GROUP;
- + }
- +#endif
- +
- + EASSERT((info->attrmask.arr[1] & FATTR4_WORD1_OWNER) != 0);
- + EASSERT((info->attrmask.arr[1] & FATTR4_WORD1_OWNER_GROUP) != 0);
- + EASSERT(info->owner != NULL);
- + EASSERT(info->owner_group != NULL);
- + EASSERT(info->owner == info->owner_buf);
- + EASSERT(info->owner_group == info->owner_group_buf);
- + EASSERT(strlen(info->owner) > 0);
- + EASSERT(strlen(info->owner_group) > 0);
- +
- + /* Make copies as we will modify them */
- + (void)strcpy(owner, info->owner);
- + (void)strcpy(owner_group, info->owner_group);
- +
- + /*
- + * Map owner to local uid
- + *
- + * |owner| can be numeric string ("1616"), plain username
- + * ("gisburn") or username@domain ("gisburn@sun.com")
- + */
- + /* stomp over '@' */
- + at_ch = strchr(owner, '@');
- + if (at_ch)
- + *at_ch = '\0';
- +
- + if (nfs41_idmap_name_to_uid(
- + nfs41dg->idmapper,
- + owner,
- + &map_uid) == 0) {
- + *owner_local_uid = map_uid;
- + }
- + else {
- + *owner_local_uid = NFS_USER_NOBODY_UID;
- + eprintf("open_get_localuidgid('%s'): "
- + "no username mapping for '%s', fake uid=%u\n",
- + state->path.path,
- + owner,
- + (unsigned int)*owner_local_uid);
- + }
- +
- + /*
- + * Map owner_group to local gid
- + *
- + * |owner_group| can be numeric string ("1616"), plain username
- + * ("gisgrp") or username@domain ("gisgrp@sun.com")
- + */
- + /* stomp over '@' */
- + at_ch = strchr(owner_group, '@');
- + if (at_ch)
- + *at_ch = '\0';
- +
- + if (nfs41_idmap_group_to_gid(
- + nfs41dg->idmapper,
- + owner_group,
- + &map_gid) == 0) {
- + *owner_group_local_gid = map_gid;
- + }
- + else {
- + *owner_group_local_gid = NFS_GROUP_NOGROUP_GID;
- + eprintf("open_get_localuidgid('%s'): "
- + "no group mapping for '%s', fake gid=%u\n",
- + state->path.path,
- + owner_group,
- + (unsigned int)*owner_group_local_gid);
- + }
- +
- +out:
- + DPRINTF(1,
- + ("open_get_localuidgid('%s'): "
- + "stat: owner=%u/'%s', owner_group=%u/'%s'\n",
- + state->path.path,
- + (unsigned int)*owner_local_uid, owner,
- + (unsigned int)*owner_group_local_gid,
- + owner_group));
- +}
- +#endif /* NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES */
- +
- static int handle_open(void *daemon_context, nfs41_upcall *upcall)
- {
- int status = 0;
- @@ -911,114 +1039,10 @@ static int handle_open(void *daemon_context, nfs41_upcall *upcall)
- args->mode = info.mode;
- EASSERT(bitmap_isset(&info.attrmask, 0, FATTR4_WORD0_CHANGE));
- args->changeattr = info.change;
- -
- -#ifdef NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES
- - char owner[NFS4_FATTR4_OWNER_LIMIT+1];
- - char owner_group[NFS4_FATTR4_OWNER_LIMIT+1];
- - uid_t map_uid = ~0UL;
- - gid_t map_gid = ~0UL;
- - char *at_ch; /* pointer to '@' */
- -
- -#if 1
- - /* this should only happen for newly created files/dirs */
- - if (((info.attrmask.arr[1] & FATTR4_WORD1_OWNER) == 0) ||
- - ((info.attrmask.arr[1] & FATTR4_WORD1_OWNER_GROUP) == 0)) {
- - bitmap4 og_attr_request;
- - nfs41_file_info og_info = { 0 };
- -
- - og_attr_request.count = 2;
- - og_attr_request.arr[0] = 0;
- - og_attr_request.arr[1] =
- - FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP;
- - og_info.owner = og_info.owner_buf;
- - og_info.owner_group = og_info.owner_group_buf;
- - status = nfs41_getattr(state->session, &state->file,
- - &og_attr_request, &og_info);
- - if (status) {
- - eprintf("get_stat_data: nfs41_getattr('%s') "
- - "failed with %d\n",
- - state->path.path,
- - status);
- - goto out_free_state;
- - }
- -
- - info.owner = info.owner_buf;
- - (void)strcpy(info.owner, og_info.owner);
- - info.attrmask.arr[1] |= FATTR4_WORD1_OWNER;
- - info.owner_group = info.owner_group_buf;
- - (void)strcpy(info.owner_group, og_info.owner_group);
- - info.attrmask.arr[1] |= FATTR4_WORD1_OWNER_GROUP;
- - }
- -#endif
- -
- - EASSERT((info.attrmask.arr[1] & FATTR4_WORD1_OWNER) != 0);
- - EASSERT((info.attrmask.arr[1] & FATTR4_WORD1_OWNER_GROUP) != 0);
- - EASSERT(info.owner != NULL);
- - EASSERT(info.owner_group != NULL);
- - EASSERT(info.owner == info.owner_buf);
- - EASSERT(info.owner_group == info.owner_group_buf);
- - EASSERT(strlen(info.owner) > 0);
- - EASSERT(strlen(info.owner_group) > 0);
- -
- - /* Make copies as we will modify them */
- - (void)strcpy(owner, info.owner);
- - (void)strcpy(owner_group, info.owner_group);
- -
- /*
- - * Map owner to local uid
- - *
- - * |owner| can be numeric string ("1616"), plain username
- - * ("gisburn") or username@domain ("gisburn@sun.com")
- + + |args->owner_local_uid| and |args->owner_group_local_gid|
- + * is set below
- */
- - /* stomp over '@' */
- - at_ch = strchr(owner, '@');
- - if (at_ch)
- - *at_ch = '\0';
- -
- - if (nfs41_idmap_name_to_uid(
- - nfs41dg->idmapper,
- - owner,
- - &map_uid) == 0) {
- - args->owner_local_uid = map_uid;
- - }
- - else {
- - args->owner_local_uid = NFS_USER_NOBODY_UID;
- - eprintf("get_stat_data('%s'): "
- - "no username mapping for '%s', fake uid=%d\n",
- - state->path.path,
- - owner, args->owner_local_uid);
- - }
- -
- - /*
- - * Map owner_group to local gid
- - *
- - * |owner_group| can be numeric string ("1616"), plain username
- - * ("gisgrp") or username@domain ("gisgrp@sun.com")
- - */
- - /* stomp over '@' */
- - at_ch = strchr(owner_group, '@');
- - if (at_ch)
- - *at_ch = '\0';
- -
- - if (nfs41_idmap_group_to_gid(
- - nfs41dg->idmapper,
- - owner_group,
- - &map_gid) == 0) {
- - args->owner_group_local_gid = map_gid;
- - }
- - else {
- - args->owner_group_local_gid = NFS_GROUP_NOGROUP_GID;
- - eprintf("get_stat_data('%s'): "
- - "no group mapping for '%s', fake gid=%d\n",
- - state->path.path,
- - owner_group, args->owner_group_local_gid);
- - }
- -
- - DPRINTF(1, ("handle_open('%s'): stat: owner=%u/'%s', owner_group=%u/'%s'\n",
- - state->path.path,
- - (unsigned int)args->owner_local_uid, owner,
- - (unsigned int)args->owner_group_local_gid, owner_group));
- -#endif /* NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES */
- } else {
- nfs41_file_info createattrs;
- uint32_t create = 0, createhowmode = 0, lookup_status = status;
- @@ -1167,6 +1191,16 @@ create_chgrp_out:
- }
- }
- +#ifdef NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES
- + if (status == 0) {
- + open_get_localuidgid(nfs41dg,
- + state,
- + &info,
- + &args->owner_local_uid,
- + &args->owner_group_local_gid);
- + }
- +#endif /* NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES */
- +
- #ifdef DEBUG_OPEN_SPARSE_FILES
- if ((status == 0) &&
- (info.type == NF4REG) &&
- diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
- index d9291c0..8f0fbdd 100644
- --- a/tests/manual_testing.txt
- +++ b/tests/manual_testing.txt
- @@ -196,6 +196,21 @@ $ rm -f d1 d2 d1.diff ; printf '1\n2\n' >d1 ; cp d1 d2 ; printf '3\n' >> d2 ; di
- The test should print "# test OK"
- +#
- +# Tests for Cycgwin/UWIN/SFU Nfs3Attr EA-based local uid/gid
- +#
- +# ToDO:
- +# - iterate over multiple groups via newgrp(1)/winsg(1)
- +# - iterate with bash/ksh93 (because it changes the pipeline process ordering)
- +#
- +
- +# create file, and the uid/gid fro Nfs3Attr EA must match /bin/id -u+/bin/id -g
- +# output should highlight uid=/gid= in colour
- +---- snip ----
- +ksh93 -c 'rm -f test1.txt ; command exec {n}>>test1.txt ; printf "fd=%d\n" $n ; printf "x" >&$n ; command exec {n}<&- ; /bin/winfsinfo nfs3attr test1.txt | egrep --colour "(uid=$(id -u)|gid=$(id -g))" ; true'
- +---- snip ----
- +
- +
- #
- # Test for native mklink && powershell New-Item -ItemType SymbolicLink
- #
- --
- 2.45.1
msnfs41client: Patches for lssparse fixes, Nfs3Attr EA fixes+misc, 2025-04-05
Posted by Anonymous on Sat 5th Apr 2025 19:01
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.