| 1186 | } |
| 1187 | |
| 1188 | int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode) |
| 1189 | { |
| 1190 | STRUCT_STAT fst, xst; |
| 1191 | dev_t rdev; |
| 1192 | mode_t mode, fmode; |
| 1193 | |
| 1194 | if (dry_run) |
| 1195 | return 0; |
| 1196 | |
| 1197 | if (read_only || list_only) { |
| 1198 | rsyserr(FERROR_XFER, EROFS, "failed to write xattr %s for %s", |
| 1199 | XSTAT_ATTR, full_fname(fname)); |
| 1200 | return -1; |
| 1201 | } |
| 1202 | |
| 1203 | if (x_lstat(fname, &fst, &xst) < 0) { |
| 1204 | rsyserr(FERROR_XFER, errno, "failed to re-stat %s", |
| 1205 | full_fname(fname)); |
| 1206 | return -1; |
| 1207 | } |
| 1208 | |
| 1209 | fst.st_mode &= (_S_IFMT | CHMOD_BITS); |
| 1210 | fmode = new_mode & (_S_IFMT | CHMOD_BITS); |
| 1211 | |
| 1212 | if (IS_DEVICE(fmode)) { |
| 1213 | uint32 *devp = F_RDEV_P(file); |
| 1214 | rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); |
| 1215 | } else |
| 1216 | rdev = 0; |
| 1217 | |
| 1218 | /* Dump the special permissions and enable full owner access. */ |
| 1219 | mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS) |
| 1220 | | (S_ISDIR(fst.st_mode) ? 0700 : 0600); |
| 1221 | if (fst.st_mode != mode) |
| 1222 | do_chmod_at(fname, mode); |
| 1223 | if (!IS_DEVICE(fst.st_mode)) |
| 1224 | fst.st_rdev = 0; /* just in case */ |
| 1225 | |
| 1226 | if (mode == fmode && fst.st_rdev == rdev |
| 1227 | && fst.st_uid == F_OWNER(file) && fst.st_gid == F_GROUP(file)) { |
| 1228 | /* xst.st_mode will be 0 if there's no current stat xattr */ |
| 1229 | if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) { |
| 1230 | rsyserr(FERROR_XFER, errno, |
| 1231 | "delete of stat xattr failed for %s", |
| 1232 | full_fname(fname)); |
| 1233 | return -1; |
| 1234 | } |
| 1235 | return 0; |
| 1236 | } |
| 1237 | |
| 1238 | if (xst.st_mode != fmode || xst.st_rdev != rdev |
| 1239 | || xst.st_uid != F_OWNER(file) || xst.st_gid != F_GROUP(file)) { |
| 1240 | char buf[256]; |
| 1241 | int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u", |
| 1242 | to_wire_mode(fmode), |
| 1243 | (int)major(rdev), (int)minor(rdev), |
| 1244 | F_OWNER(file), F_GROUP(file)); |
| 1245 | if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) { |
no test coverage detected