diff -cr cvs-1.11.5/config.h.in cvs-1.11.5+fp/config.h.in *** cvs-1.11.5/config.h.in Thu Jan 16 16:41:43 2003 --- cvs-1.11.5+fp/config.h.in Mon Mar 17 18:17:35 2003 *************** *** 10,15 **** --- 10,18 ---- /* Define if you want CVS to be able to be a remote repository client. */ #undef CLIENT_SUPPORT + /* Define to use preserve permissions (both full and file_perms). */ + #undef PRESERVE_PERMISSIONS_SUPPORT + /* Define to 1 if the `closedir' function returns void instead of `int'. */ #undef CLOSEDIR_VOID *************** *** 440,445 **** --- 443,456 ---- which is interpreted as an octal number. */ #undef UMASK_DFLT + /* + * The default file mode for files that are in the repository but don't have + * a 'permissions' node -- usually when preserve_file_perms is turned on + * on a pre-existing repository. + */ + #undef FILE_MODE_DFLT + + /* Define if setmode is required when writing binary data to stdout. */ #undef USE_SETMODE_STDOUT diff -cr cvs-1.11.5/configure cvs-1.11.5+fp/configure *** cvs-1.11.5/configure Thu Jan 16 16:36:48 2003 --- cvs-1.11.5+fp/configure Mon Mar 17 18:17:35 2003 *************** *** 9199,9204 **** --- 9199,9224 ---- + # Check whether --with-filemode or --without-filemode was given. + if test "${with_filemode+set}" = set; then + withval="$with_filemode" + + fi; + + if test -z "$with_filemode" || test yes = "$with_filemode"; then + with_filemode=0600 + elif test no = "$with_filemode"; then + with_filemode=000 + fi + + + cat >>confdefs.h <<_ACEOF + #define FILE_MODE_DFLT $with_filemode + _ACEOF + + + + # Check whether --with-cvs-admin-group or --without-cvs-admin-group was given. if test "${with_cvs_admin_group+set}" = set; then withval="$with_cvs_admin_group" *************** *** 9476,9481 **** --- 9496,9505 ---- fi # enable_server + cat >> confdefs.h <<\_ACEOF + #define PRESERVE_PERMISSIONS_SUPPORT 1 + _ACEOF + # Check whether --enable-encryption or --disable-encryption was given. if test "${enable_encryption+set}" = set; then enableval="$enable_encryption" diff -cr cvs-1.11.5/configure.in cvs-1.11.5+fp/configure.in *** cvs-1.11.5/configure.in Thu Jan 16 15:16:56 2003 --- cvs-1.11.5+fp/configure.in Mon Mar 17 18:14:19 2003 *************** *** 519,524 **** --- 519,550 ---- dnl dnl + dnl Get default file mode + dnl + + AC_ARG_WITH( + [filemode], + AC_HELP_STRING( + [--with-filemode], + [Set the file mode CVS will use when restoring preserve file permissions on a file that did not have that information saved (default 0600)])) + + if test -z "$with_filemode" || test yes = "$with_filemode"; then + with_filemode=0600 + elif test no = "$with_filemode"; then + with_filemode=000 + fi + + AC_DEFINE_UNQUOTED( + [FILE_MODE_DFLT], [$with_filemode], + [The default file mode for files that are in the repository but don't have + a 'permissions' node -- usually when preserve_file_perms is turned on + on a pre-existing repository.]) + + dnl + dnl Done setting default file mode + dnl + + dnl dnl Set CVS Administrator Group dnl AC_ARG_WITH( *************** *** 740,745 **** --- 766,777 ---- fi # enable_server + dnl For the moment we will assume that all systems which have + dnl the unixyness to run configure are unixy enough to do the + dnl PreservePermissions stuff.  I have this sinking feeling that + dnl things won't be that simple, before long. + AC_DEFINE(PRESERVE_PERMISSIONS_SUPPORT) + dnl dnl Use --enable-encryption to turn on encryption support, but ignore this dnl option unless either client or server is enabled. diff -cr cvs-1.11.5/src/checkin.c cvs-1.11.5+fp/src/checkin.c *** cvs-1.11.5/src/checkin.c Sun Feb 22 14:46:46 1998 --- cvs-1.11.5+fp/src/checkin.c Mon Mar 17 14:50:36 2003 *************** *** 78,84 **** call RCS_checkout here, compare the resulting files using xcmp, and rename if necessary. I think this should be fixed in RCS_cmp_file. */ ! if ((! preserve_perms && options != NULL && (strcmp (options, "-ko") == 0 || strcmp (options, "-kb") == 0)) --- 78,84 ---- call RCS_checkout here, compare the resulting files using xcmp, and rename if necessary. I think this should be fixed in RCS_cmp_file. */ ! if ((! preserve_perms && ! preserve_file_perms && options != NULL && (strcmp (options, "-ko") == 0 || strcmp (options, "-kb") == 0)) diff -cr cvs-1.11.5/src/client.c cvs-1.11.5+fp/src/client.c *** cvs-1.11.5/src/client.c Thu Jan 16 10:10:55 2003 --- cvs-1.11.5+fp/src/client.c Mon Mar 17 15:02:45 2003 *************** *** 131,136 **** --- 131,137 ---- static void handle_e PROTO((char *, int)); static void handle_f PROTO((char *, int)); static void handle_notified PROTO((char *, int)); + static void handle_preserve_permissions PROTO((char *, int)); static size_t try_read_from_server PROTO ((char *, size_t)); *************** *** 288,312 **** mode_t mode; #endif /* __STDC__ */ { ! char buf[18], u[4], g[4], o[4]; int i; i = 0; if (mode & S_IRUSR) u[i++] = 'r'; if (mode & S_IWUSR) u[i++] = 'w'; if (mode & S_IXUSR) u[i++] = 'x'; u[i] = '\0'; i = 0; if (mode & S_IRGRP) g[i++] = 'r'; if (mode & S_IWGRP) g[i++] = 'w'; if (mode & S_IXGRP) g[i++] = 'x'; g[i] = '\0'; i = 0; if (mode & S_IROTH) o[i++] = 'r'; if (mode & S_IWOTH) o[i++] = 'w'; if (mode & S_IXOTH) o[i++] = 'x'; o[i] = '\0'; sprintf(buf, "u=%s,g=%s,o=%s", u, g, o); --- 289,316 ---- mode_t mode; #endif /* __STDC__ */ { ! char buf[21], u[5], g[5], o[5]; int i; i = 0; if (mode & S_IRUSR) u[i++] = 'r'; if (mode & S_IWUSR) u[i++] = 'w'; if (mode & S_IXUSR) u[i++] = 'x'; + if (mode & S_ISUID) u[i++] = 's'; u[i] = '\0'; i = 0; if (mode & S_IRGRP) g[i++] = 'r'; if (mode & S_IWGRP) g[i++] = 'w'; if (mode & S_IXGRP) g[i++] = 'x'; + if (mode & S_ISGID) g[i++] = 's'; g[i] = '\0'; i = 0; if (mode & S_IROTH) o[i++] = 'r'; if (mode & S_IWOTH) o[i++] = 'w'; if (mode & S_IXOTH) o[i++] = 'x'; + if (mode & S_ISVTX) o[i++] = 's'; o[i] = '\0'; sprintf(buf, "u=%s,g=%s,o=%s", u, g, o); *************** *** 371,377 **** { if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') { ! int can_read = 0, can_write = 0, can_execute = 0; char *q = p + 2; while (*q != ',' && *q != '\0') { --- 375,381 ---- { if ((p[0] == 'u' || p[0] == 'g' || p[0] == 'o') && p[1] == '=') { ! int can_read = 0, can_write = 0, can_execute = 0, is_sticky = 0; char *q = p + 2; while (*q != ',' && *q != '\0') { *************** *** 381,386 **** --- 385,392 ---- can_write = 1; else if (*q == 'x') can_execute = 1; + else if (*q == 's') + is_sticky = 1; ++q; } if (p[0] == 'u') *************** *** 391,396 **** --- 397,404 ---- mode |= S_IWUSR; if (can_execute) mode |= S_IXUSR; + if (is_sticky) + mode |= S_ISUID; } else if (p[0] == 'g') { *************** *** 400,405 **** --- 408,415 ---- mode |= S_IWGRP; if (can_execute) mode |= S_IXGRP; + if (is_sticky) + mode |= S_ISGID; } else if (p[0] == 'o') { *************** *** 409,414 **** --- 419,426 ---- mode |= S_IWOTH; if (can_execute) mode |= S_IXOTH; + if (is_sticky) + mode |= S_ISVTX; } } /* Skip to the next field. */ *************** *** 418,424 **** ++p; } ! if (respect_umask) { oumask = umask (0); (void) umask (oumask); --- 430,436 ---- ++p; } ! if ((! preserve_file_perms) && respect_umask) { oumask = umask (0); (void) umask (oumask); *************** *** 3159,3164 **** --- 3171,3195 ---- } + /* Get the PreservePermissions setting from the server -- assume + this is the exact string as found in the config file (although + it may not be at the moment) */ + + static void + handle_preserve_permissions (args, len) + char *args; + int len; + { + /* if (strcmp(args, "yes") == 0) + preserve_perms = 1; /* Don't handle 'yes' for now -- client support has not been developed and it will most likely cause problems */ + + if (strcmp(args, "file_perms") == 0) + preserve_file_perms = 1; + + return; + } + + static void handle_m (args, len) char *args; *************** *** 3421,3426 **** --- 3452,3460 ---- RSP_LINE("E", handle_e, response_type_normal, rs_essential), RSP_LINE("F", handle_f, response_type_normal, rs_optional), RSP_LINE("MT", handle_mt, response_type_normal, rs_optional), + RSP_LINE("PreservePermissions", handle_preserve_permissions, + response_type_normal, + rs_optional), /* Possibly should be response_type_error. */ RSP_LINE(NULL, NULL, response_type_normal, rs_essential) *************** *** 4611,4616 **** --- 4645,4661 ---- } } + /* Get PreservePermissions from the server. */ + + if (supported_request ("sendme-PreservePermissions")) + { + int err; + send_to_server ("sendme-PreservePermissions\012", 0); + err = get_server_responses (); + if (err != 0) + error (err, 0, "error reading from server"); + } + /* Find out about server-side cvswrappers. An extra network turnaround for cvs import seems to be unavoidable, unless we want to add some kind of client-side place to configure which diff -cr cvs-1.11.5/src/cvs.h cvs-1.11.5+fp/src/cvs.h *** cvs-1.11.5/src/cvs.h Sat Dec 28 13:01:30 2002 --- cvs-1.11.5+fp/src/cvs.h Mon Mar 17 15:04:04 2003 *************** *** 761,766 **** --- 761,768 ---- /* TODO: can the finfo argument to special_file_mismatch be changed? -twp */ int special_file_mismatch PROTO ((struct file_info *finfo, char *rev1, char *rev2)); + int special_file_mismatch_file_perms_only PROTO ((struct file_info *finfo, + char *rev1, char *rev2)); /* CVSADM_BASEREV stuff, from entries.c. */ extern char *base_get PROTO ((struct file_info *)); diff -cr cvs-1.11.5/src/error.c cvs-1.11.5+fp/src/error.c *** cvs-1.11.5/src/error.c Fri Dec 15 15:15:03 2000 --- cvs-1.11.5+fp/src/error.c Tue Mar 18 11:55:48 2003 *************** *** 159,164 **** --- 159,169 ---- sprintf (buf, "%d", num); cvs_outerr (buf, strlen (buf)); break; + case 'o': + num = va_arg (args, int); + sprintf (buf, "%o", num); + cvs_outerr (buf, strlen (buf)); + break; case 'l': if (q[2] == 'd') { diff -cr cvs-1.11.5/src/filesubr.c cvs-1.11.5+fp/src/filesubr.c *** cvs-1.11.5/src/filesubr.c Tue Sep 24 16:47:09 2002 --- cvs-1.11.5+fp/src/filesubr.c Mon Mar 17 15:04:56 2003 *************** *** 353,359 **** struct stat sb; mode_t mode, oumask; ! if (preserve_perms) return; if (stat (fname, &sb) < 0) --- 353,359 ---- struct stat sb; mode_t mode, oumask; ! if (preserve_perms || preserve_file_perms) return; if (stat (fname, &sb) < 0) diff -cr cvs-1.11.5/src/import.c cvs-1.11.5+fp/src/import.c *** cvs-1.11.5/src/import.c Tue Sep 24 16:47:09 2002 --- cvs-1.11.5+fp/src/import.c Mon Mar 17 15:08:27 2003 *************** *** 1248,1253 **** --- 1248,1258 ---- } } } + else if (preserve_file_perms) { + if (fprintf (fprcs, "permissions\t%o;\012", + sb.st_mode & 07777) < 0) + goto write_error; + } #endif if (add_vbranch != NULL) *************** *** 1304,1309 **** --- 1309,1320 ---- userfile); } } + } + else if (preserve_file_perms) { + if (fprintf (fprcs, "permissions\t%o;\012", + sb.st_mode & 07777) < 0) + goto write_error; + } #endif diff -cr cvs-1.11.5/src/mkmodules.c cvs-1.11.5+fp/src/mkmodules.c *** cvs-1.11.5/src/mkmodules.c Fri Sep 7 10:22:39 2001 --- cvs-1.11.5+fp/src/mkmodules.c Mon Mar 17 15:09:56 2003 *************** *** 287,293 **** "\n", #ifdef PRESERVE_PERMISSIONS_SUPPORT "# Set `PreservePermissions' to `yes' to save file status information\n", ! "# in the repository.\n", "#PreservePermissions=no\n", "\n", #endif --- 287,294 ---- "\n", #ifdef PRESERVE_PERMISSIONS_SUPPORT "# Set `PreservePermissions' to `yes' to save file status information\n", ! "# in the repository. Set it to 'file_perms' to just save file\n", ! "# permissions\n", "#PreservePermissions=no\n", "\n", #endif diff -cr cvs-1.11.5/src/no_diff.c cvs-1.11.5+fp/src/no_diff.c *** cvs-1.11.5/src/no_diff.c Sat Aug 15 10:05:57 1998 --- cvs-1.11.5+fp/src/no_diff.c Mon Mar 17 15:10:29 2003 *************** *** 41,46 **** --- 41,48 ---- information also means that the files should be considered different. */ if (preserve_perms && special_file_mismatch (finfo, vers->vn_user, NULL)) return 1; + if (preserve_file_perms && special_file_mismatch_file_perms_only (finfo, vers->vn_user, NULL)) + return 1; #endif if (vers->entdata && vers->entdata->options) diff -cr cvs-1.11.5/src/parseinfo.c cvs-1.11.5+fp/src/parseinfo.c *** cvs-1.11.5/src/parseinfo.c Fri Dec 6 14:09:26 2002 --- cvs-1.11.5+fp/src/parseinfo.c Mon Mar 17 15:25:45 2003 *************** *** 353,358 **** --- 353,361 ---- warning: this CVS does not support PreservePermissions"); #endif } + else if (strcmp(p, "file_perms") == 0) { + preserve_file_perms = 1; + } else { error (0, 0, "unrecognized value '%s' for PreservePermissions", diff -cr cvs-1.11.5/src/rcs.c cvs-1.11.5+fp/src/rcs.c *** cvs-1.11.5/src/rcs.c Thu Jan 16 10:10:55 2003 --- cvs-1.11.5+fp/src/rcs.c Mon Mar 17 15:29:11 2003 *************** *** 25,30 **** --- 25,31 ---- #endif int preserve_perms = 0; + int preserve_file_perms = 0; /* The RCS -k options, and a set of enums that must match the array. These come first so that we can use enum kflag in function *************** *** 4368,4373 **** --- 4369,4392 ---- workfile, info->data); } } + else if (preserve_file_perms) + { + RCSVers *vers; + Node *info; + + vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); + if (vp == NULL) + error (1, 0, "internal error: no revision information for %s", + rev == NULL ? rcs->head : rev); + vers = (RCSVers *) vp->data; + + info = findnode (vers->other_delta, "permissions"); + if (info != NULL) + { + change_rcs_mode = 1; + rcs_mode = (mode_t) strtoul (info->data, NULL, 8); + } + } #endif if (expand != KFLAG_O && expand != KFLAG_B) *************** *** 4684,4689 **** --- 4703,4730 ---- return (RCSVers *) p->data; } + mode_t + RCS_get_perms (rcs, rev) + RCSNode *rcs; + char *rev; + { + RCSVers *vers; + Node *info; + Node *vp = NULL; + + vp = findnode (rcs->versions, rev == NULL ? rcs->head : rev); + if (vp == NULL) + error (1, 0, "internal error: no revision information for %s", + rev == NULL ? rcs->head : rev); + vers = (RCSVers *) vp->data; + + info = findnode (vers->other_delta, "permissions"); + if (info != NULL) + return (mode_t) strtoul (info->data, NULL, 8); + + return (mode_t) FILE_MODE_DFLT; + } + /* Revision number string, R, must contain a `.'. Return a newly-malloc'd copy of the prefix of R up to but not including the final `.'. */ *************** *** 5072,5077 **** --- 5113,5135 ---- delta->hardlinks = list_linked_files_on_disk (workfile); } } + else if (preserve_file_perms) + { + Node *np; + struct stat sb; + char buf[64]; /* static buffer should be safe: see usage. -twp */ + + delta->other_delta = getlist(); + + if (CVS_LSTAT (workfile, &sb) < 0) + error (1, 1, "cannot lstat %s", workfile); + + (void) sprintf (buf, "%o", sb.st_mode & 07777); + np = getnode(); + np->key = xstrdup ("permissions"); + np->data = xstrdup (buf); + addnode (delta->other_delta, np); + } #endif /* Create a new deltatext node. */ diff -cr cvs-1.11.5/src/rcs.h cvs-1.11.5+fp/src/rcs.h *** cvs-1.11.5/src/rcs.h Fri Mar 30 17:10:36 2001 --- cvs-1.11.5+fp/src/rcs.h Mon Mar 17 15:29:44 2003 *************** *** 243,248 **** --- 243,249 ---- char *make_file_label PROTO ((char *, char *, RCSNode *)); extern int preserve_perms; + extern int preserve_file_perms; /* From import.c. */ extern int add_rcs_file PROTO ((char *, char *, char *, char *, char *, diff -cr cvs-1.11.5/src/server.c cvs-1.11.5+fp/src/server.c *** cvs-1.11.5/src/server.c Thu Jan 16 10:10:55 2003 --- cvs-1.11.5+fp/src/server.c Mon Mar 17 16:30:41 2003 *************** *** 4489,4494 **** --- 4489,4515 ---- } + /* Tell the client about PreservePermissions options set in CVSROOT/config. + Currently, rather than reading the exact string from the config file, + we regenerate the string based on the variables we know are PreservePermission's + related. Ideally we would save the PreservePermissions string when we read + it the first time, then pass that as is to the client. */ + static void + serve_preserve_permissions (arg) + char *arg; + { + buf_output0 (buf_to_net, "PreservePermissions "); + buf_output0 (buf_to_net, (preserve_perms ? "yes" : (preserve_file_perms ? "file_perms" : "no"))); + buf_output0 (buf_to_net, "\012"); + + buf_output0 (buf_to_net, "ok\012"); + + /* The client is waiting for us, so we better send the data now. */ + buf_flush (buf_to_net, 1); + } + + + static void serve_ignore (arg) char *arg; *************** *** 4811,4816 **** --- 4832,4838 ---- REQ_LINE("annotate", serve_annotate, 0), REQ_LINE("rannotate", serve_rannotate, 0), REQ_LINE("noop", serve_noop, RQ_ROOTLESS), + REQ_LINE("sendme-PreservePermissions", serve_preserve_permissions, 0), REQ_LINE("version", serve_version, RQ_ROOTLESS), REQ_LINE(NULL, NULL, 0) diff -cr cvs-1.11.5/src/update.c cvs-1.11.5+fp/src/update.c *** cvs-1.11.5/src/update.c Sat Dec 28 13:01:30 2002 --- cvs-1.11.5+fp/src/update.c Mon Mar 17 15:52:00 2003 *************** *** 1396,1402 **** if (stat (vers_ts->srcfile->path, &sb) < 0) error (1, errno, "cannot stat %s", vers_ts->srcfile->path); ! mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH); } if (cvswrite --- 1396,1405 ---- if (stat (vers_ts->srcfile->path, &sb) < 0) error (1, errno, "cannot stat %s", vers_ts->srcfile->path); ! if (preserve_file_perms) ! mode = RCS_get_perms(vers_ts->srcfile, vers_ts->vn_rcs); ! else ! mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH); } if (cvswrite *************** *** 1405,1411 **** { if (revbuf == NULL) xchmod (finfo->file, 1); ! else { /* We know that we are the server here, so although xchmod checks umask, we don't bother. */ --- 1408,1414 ---- { if (revbuf == NULL) xchmod (finfo->file, 1); ! else if (! preserve_file_perms) /* don't mess with the mode if preserve_file_perms is set */ { /* We know that we are the server here, so although xchmod checks umask, we don't bother. */ *************** *** 1828,1835 **** if (CVS_STAT (vers_ts->srcfile->path, file_info) < 0) error (1, errno, "could not stat %s", vers_ts->srcfile->path); if (chmod (finfo->file, ! file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH)) ! < 0) error (0, errno, "cannot change mode of file %s", finfo->file); if (cvswrite && !fileattr_get (finfo->file, "_watched")) --- 1831,1842 ---- if (CVS_STAT (vers_ts->srcfile->path, file_info) < 0) error (1, errno, "could not stat %s", vers_ts->srcfile->path); if (chmod (finfo->file, ! (preserve_file_perms ? ! RCS_get_perms(vers_ts->srcfile, vers_ts->vn_rcs) ! : ! file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) ! )) ! < 0) error (0, errno, "cannot change mode of file %s", finfo->file); if (cvswrite && !fileattr_get (finfo->file, "_watched")) *************** *** 2890,2899 **** if (check_modes && (rev1_mode & 07777) != (rev2_mode & 07777)) { ! error (0, 0, "%s: permission mismatch between %s and %s", finfo->file, ! (rev1 == NULL ? "working file" : rev1), ! (rev2 == NULL ? "working file" : rev2)); result = 1; } --- 2897,2906 ---- if (check_modes && (rev1_mode & 07777) != (rev2_mode & 07777)) { ! error (0, 0, "%s: permission mismatch between %s (0%o) and %s (0%o)", finfo->file, ! (rev1 == NULL ? "working file" : rev1), (rev1_mode & 07777), ! (rev2 == NULL ? "working file" : rev2), (rev2_mode & 07777)); result = 1; } *************** *** 2945,2950 **** --- 2952,3107 ---- } int + special_file_mismatch_file_perms_only (finfo, rev1, rev2) + struct file_info *finfo; + char *rev1; + char *rev2; + { + #ifdef PRESERVE_PERMISSIONS_SUPPORT + struct stat sb; + RCSVers *vp; + Node *n; + uid_t rev1_uid, rev2_uid; + gid_t rev1_gid, rev2_gid; + mode_t rev1_mode, rev2_mode; + unsigned long dev_long; + dev_t rev1_dev, rev2_dev; + char *rev1_symlink = NULL; + char *rev2_symlink = NULL; + List *rev1_hardlinks; + List *rev2_hardlinks; + int check_uids, check_gids, check_modes; + int result; + + /* If we don't care about special file info, then + don't report a mismatch in any case. */ + if (!preserve_file_perms) + return 0; + + /* When special_file_mismatch is called from No_Difference, the + RCS file has been only partially parsed. We must read the + delta tree in order to compare special file info recorded in + the delta nodes. (I think this is safe. -twp) */ + if (finfo->rcs->flags & PARTIAL) + RCS_reparsercsfile (finfo->rcs, NULL, NULL); + + check_modes = 1; + + /* Obtain file information for REV1. If this is null, then stat + finfo->file and use that info. */ + /* If a revision does not know anything about its status, + then presumably it doesn't matter, and indicates no conflict. */ + + if (rev1 == NULL) + { + if (islink (finfo->file)) + rev1_symlink = xreadlink (finfo->file); + else + { + if (CVS_LSTAT (finfo->file, &sb) < 0) + error (1, errno, "could not get file information for %s", + finfo->file); + rev1_mode = sb.st_mode; + } + } + else + { + n = findnode (finfo->rcs->versions, rev1); + vp = (RCSVers *) n->data; + + n = findnode (vp->other_delta, "symlink"); + if (n != NULL) + rev1_symlink = xstrdup (n->data); + else + { + n = findnode (vp->other_delta, "permissions"); + if (n == NULL || n->data == NULL || *n->data == '\0') + rev1_mode = FILE_MODE_DFLT; + else + rev1_mode = strtoul (n->data, NULL, 8); + } + } + + /* Obtain file information for REV2. */ + if (rev2 == NULL) + { + if (islink (finfo->file)) + rev2_symlink = xreadlink (finfo->file); + else + { + if (CVS_LSTAT (finfo->file, &sb) < 0) + error (1, errno, "could not get file information for %s", + finfo->file); + rev2_mode = sb.st_mode; + } + } + else + { + n = findnode (finfo->rcs->versions, rev2); + vp = (RCSVers *) n->data; + + n = findnode (vp->other_delta, "symlink"); + if (n != NULL) + rev2_symlink = xstrdup (n->data); + else + { + n = findnode (vp->other_delta, "permissions"); + if (n == NULL) + check_modes = 0; /* don't care */ + else + rev2_mode = strtoul (n->data, NULL, 8); + } + } + + /* Check the user/group ownerships and file permissions, printing + an error for each mismatch found. Return 0 if all characteristics + matched, and 1 otherwise. */ + + result = 0; + + /* Compare symlinks first, since symlinks are simpler (don't have + any other characteristics). */ + /* if (rev1_symlink != NULL && rev2_symlink == NULL) + { + error (0, 0, "%s is a symbolic link", + (rev1 == NULL ? "working file" : rev1)); + result = 1; + } + else if (rev1_symlink == NULL && rev2_symlink != NULL) + { + error (0, 0, "%s is a symbolic link", + (rev2 == NULL ? "working file" : rev2)); + result = 1; + } + else if (rev1_symlink != NULL) + */ if (rev1_symlink != NULL) + result = (strcmp (rev1_symlink, rev2_symlink) == 0); + else + { + /* Compare permissions. */ + if (check_modes && + (rev1_mode & 07777) != (rev2_mode & 07777)) + { + error (0, 0, "%s: permission mismatch between %s (0%o) and %s (0%o)", + finfo->file, + (rev1 == NULL ? "working file" : rev1), (rev1_mode & 07777), + (rev2 == NULL ? "working file" : rev2), (rev2_mode & 07777)); + result = 1; + } + } + + if (rev1_symlink != NULL) + free (rev1_symlink); + if (rev2_symlink != NULL) + free (rev2_symlink); + + return result; + #else + return 0; + #endif + } + + int joining () { return (join_rev1 != NULL);