int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags) { int (*libc_fchmodat)(int dirfd, const char *pathname, mode_t mode, int flags); *(void **)(&libc_fchmodat) = dlsym(RTLD_NEXT, "fchmodat"); if(dlerror()) { errno = EPERM; return -1; } return (*libc_fchmodat)(dirfd, pathname, fix_mode(mode), flags); }
int fchmod(int fd, mode_t mode) { int (*libc_fchmod)(int fd, mode_t mode); *(void **)(&libc_fchmod) = dlsym(RTLD_NEXT, "fchmod"); if(dlerror()) { errno = EPERM; return -1; } return (*libc_fchmod)(fd, fix_mode(mode)); }
int chmod(const char *path, mode_t mode) { int (*libc_chmod)(const char *path, mode_t mode); *(void **)(&libc_chmod) = dlsym(RTLD_NEXT, "chmod"); if(dlerror()) { errno = EPERM; return -1; } return (*libc_chmod)(path, fix_mode(mode)); }
static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) { int err = 0; struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct iattr lower_ia; inode = dentry->d_inode; /* * Check if user has permission to change inode. We don't check if * this user can change the lower inode: that should happen when * calling notify_change on the lower inode. */ err = inode_change_ok(inode, ia); if (err) goto out_err; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); /* fix warpfs file owner and permission. cannot change them. */ ia->ia_uid = AID_ROOT; ia->ia_gid = AID_SDCARD_RW; fix_mode(ia->ia_mode); /* prepare our own lower struct iattr (with the lower file) */ memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file); lower_ia.ia_uid = AID_MEDIA_RW; lower_ia.ia_gid = AID_MEDIA_RW; fix_mode(lower_ia.ia_mode); /* * If shrinking, first truncate upper level to cancel writing dirty * pages beyond the new eof; and also if its' maxbytes is more * limiting (fail with -EFBIG before making any change to the lower * level). There is no need to vmtruncate the upper level * afterwards in the other cases: we fsstack_copy_inode_size from * the lower level. */ if (ia->ia_valid & ATTR_SIZE) { err = inode_newsize_ok(inode, ia->ia_size); if (err) goto out; truncate_setsize(inode, ia->ia_size); } /* for FAT emulation */ /* * mode change is for clearing setuid/setgid bits. Allow lower fs * to interpret this in its own way. */ if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) lower_ia.ia_valid &= ~ATTR_MODE; /* notify the (possibly copied-up) lower inode */ /* * Note: we use lower_dentry->d_inode, because lower_inode may be * unlinked (no inode->i_sb and i_ino==0. This happens if someone * tries to open(), unlink(), then ftruncate() a file. */ mutex_lock(&lower_dentry->d_inode->i_mutex); err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */ mutex_unlock(&lower_dentry->d_inode->i_mutex); if (err) goto out; /* get attributes from the lower inode */ fsstack_copy_attr_all(inode, lower_inode); fix_fat_permission(inode); /* * Not running fsstack_copy_inode_size(inode, lower_inode), because * VFS should update our inode size, and notify_change on * lower_inode should update its size. */ out: sdcardfs_put_lower_path(dentry, &lower_path); out_err: return err; }
static void clone (char* s_path, char* d_path, int sroot_flag, int level) { struct stat src_stat_buf; struct stat dst_stat_buf; int dir_already_exists = 0; const char* intype = "file"; if (lstat (s_path, &src_stat_buf) == -1) { if (!quiet_flag) { fprintf (stderr, "%s: error: can't get status of %s: %s\n", pname, s_path, sys_errlist[errno]); fprintf (stderr, "%s: input entity %s will be ignored\n", pname, s_path); } return; } if (sccs_flag && sroot_flag && S_ISLNK (src_stat_buf.st_mode)) { /* If root of the source path is a symbolic link and SCCS cloning is enabled, clone the target of the link */ if (stat(s_path, &src_stat_buf) == -1) { if (!quiet_flag) { fprintf (stderr, "%s: error: can't get status of %s: %s\n", pname, s_path, sys_errlist[errno]); fprintf (stderr, "%s: input entity %s will be ignored\n", pname, s_path); } return; } } if (IS_DIR (src_stat_buf)) intype = "directory"; if (access (d_path, 0)) { if (errno != ENOENT) { if (!quiet_flag) { fprintf (stderr, "%s: error: can't check accessability of %s: %s\n", pname, d_path, sys_errlist[errno]); fprintf (stderr, "%s: input %s %s will be ignored\n", pname, intype, s_path); } return; } } else { const char* outtype = "file"; if (lstat (d_path, &dst_stat_buf) == -1) { if (!quiet_flag) { fprintf (stderr, "%s: error: unable to get status of %s: %s\n" , pname, d_path, sys_errlist[errno]); fprintf (stderr, "%s: input %s %s will be ignored\n", pname, intype, s_path); } return; } if (IS_DIR (dst_stat_buf)) outtype = "directory"; if (IS_DIR (src_stat_buf) && IS_DIR (dst_stat_buf)) { dir_already_exists = -1; /* Have to make sure that we have full access to the output directory (at least temporarily). */ chmod (d_path, (dst_stat_buf.st_mode & 07777) | 0700); if (access (d_path, R_OK | W_OK | X_OK) != 0) { if (!quiet_flag) { fprintf (stderr, "%s: error: too few permissions for existing directory %s\n", pname, d_path); fprintf (stderr, "%s: input directory %s will be ignored\n", pname, s_path); } return; } } else { if (force_flag) { if (remove_item (s_path, d_path)) return; } else { if (!quiet_flag) { fprintf (stderr, "%s: error: output %s already exists: %s\n", pname, outtype, d_path); fprintf (stderr, "%s: input %s %s will be ignored\n", pname, intype, s_path); } return; } } } switch (src_stat_buf.st_mode & S_IFMT) { case S_IFDIR: /* Clone a directory */ if (!dir_already_exists) { /* Don't let others sneak in. Only we can write the new directory (for now). */ if (mkdir (d_path, 0700)) { if (!quiet_flag) { fprintf (stderr, "%s: error: can't create output directory %s: %s\n", pname, d_path, sys_errlist[errno]); fprintf (stderr, "%s: input directory %s will be ignored\n", pname, s_path); } return; } if (verbose_flag) fprintf (stderr, "%s: created new output directory: %s\n", pname, d_path); } clone_dir(s_path, d_path, level); /* By default, output directories which existed before this program was executed are reset back to their original permissions (when we are done adding things to them). For output directories which are actually created by this program however, these have their permissions set so that they are essentially the same as the permissions for their corresponding input directories, except that the owner is given full permissions. */ if (dir_already_exists) fix_mode (dst_stat_buf.st_mode & 07777, d_path); else fix_mode ((src_stat_buf.st_mode & 07777) | 0700, d_path); break; #ifndef USG case S_IFLNK: /* Clone a symbolic link */ if (!sccs_flag) clone_symbolic_link (s_path, d_path); break; #endif default: /* Clone a normal file */ if (sccs_flag) break; #ifndef USG if (symlink_flag) mk_symbolic_link(s_path, d_path, level); else #endif if (copy_flag) copy_file(s_path, d_path); else mk_hard_link(s_path, d_path); break; } /* switch */ }
static void copy_file (char *s_path, char *d_path) { int input, output; struct stat src_stat_buf; if (lstat (s_path, &src_stat_buf) == -1) { if (!quiet_flag) { fprintf (stderr, "%s: error: can't get status of %s: %s\n", pname, s_path, sys_errlist[errno]); fprintf (stderr, "%s: input entity %s will be ignored\n", pname, s_path); } return; } if ((input = open (s_path, O_RDONLY, 0)) == -1) { if (!quiet_flag) { fprintf (stderr, "%s: error: can't open input file %s: %s\n", pname, d_path, sys_errlist[errno]); fprintf (stderr, "%s: input file %s will be ignored\n", pname, s_path); } return; } if ((output = open (d_path, O_CREAT | O_WRONLY, src_stat_buf.st_mode & 07777)) == -1) { if (!quiet_flag) { fprintf (stderr, "%s: error: can't create output file %s: %s\n", pname, d_path, sys_errlist[errno]); fprintf (stderr, "%s: input file %s will be ignored\n", pname, s_path); } return; } for (;;) { int rlen, wlen; char block_buf[BLKDEV_IOSIZE]; if ((rlen = read (input, block_buf, BLKDEV_IOSIZE)) == -1) { if (!quiet_flag) { fprintf (stderr, "%s: error: bad read from input file %s: %s\n", pname, s_path, sys_errlist[errno]); fprintf (stderr, "%s: input file %s was not fully copied\n", pname, s_path); } break; } if (rlen == 0) break; if ((wlen = write (output, block_buf, rlen)) == -1 || wlen != rlen) { if (!quiet_flag) { fprintf (stderr, "%s: error: bad write to output file %s: %s\n", pname, s_path, sys_errlist[errno]); fprintf (stderr, "%s: input file %s not fully copied\n", pname, s_path); } break; } } close (output); close (input); fix_mode (src_stat_buf.st_mode & 07777, d_path); if (verbose_flag) fprintf (stderr, "%s: created file copy %s = %s\n", pname, d_path, s_path); }