bool TPath::HasAccess(const TCred &cred, enum Access mask) const { struct stat st; int mode; if (!cred.Uid && !access(c_str(), mask & TPath::RWX)) return true; if (stat(c_str(), &st)) { if (!(mask & TPath::P) || errno != ENOENT) return false; TPath dir = DirName(); while (stat(dir.c_str(), &st)) { if (errno != ENOENT) return false; if (dir.Path.size() <= 1) return false; dir = dir.DirName(); } } if ((mask & TPath::U) && cred.Uid == st.st_uid) return true; if (cred.Uid == st.st_uid) mode = st.st_mode >> 6; else if (cred.IsMemberOf(st.st_gid))
TError TNamespaceFd::Open(TPath path) { Close(); Fd = open(path.c_str(), O_RDONLY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC); if (Fd < 0) return TError(EError::Unknown, errno, "Cannot open " + path.ToString()); return TError::Success(); }
TError TMount::Find(TPath path, const TPath mounts) { path = path.NormalPath(); auto device = path.GetDev(); if (!device) return TError(EError::Unknown, "device not found: " + path.ToString() + ")"); FILE* f = setmntent(mounts.c_str(), "r"); if (!f) return TError(EError::Unknown, errno, "setmntent(" + mounts.ToString() + ")"); struct mntent* m, mntbuf; TScopedMem buf(4096); TError error(EError::Unknown, "mountpoint not found: " + path.ToString() + ")"); while ((m = getmntent_r(f, &mntbuf, (char *)buf.GetData(), buf.GetSize()))) { TPath source(m->mnt_fsname); TPath target(m->mnt_dir); if (target.InnerPath(path).IsEmpty() || source.GetBlockDev() != device) continue; Source = source; Target = target; Type = m->mnt_type; Data.clear(); error = SplitString(m->mnt_opts, ',', Data); break; } endmntent(f); return error; }
TError TMount::Snapshot(std::vector<std::shared_ptr<TMount>> &result, const TPath mounts) { FILE* f = setmntent(mounts.c_str(), "r"); if (!f) return TError(EError::Unknown, errno, "setmntent(" + mounts.ToString() + ")"); struct mntent* m, mntbuf; TScopedMem buf(4096); while ((m = getmntent_r(f, &mntbuf, (char *)buf.GetData(), buf.GetSize()))) { vector<string> flags; TError error = SplitString(m->mnt_opts, ',', flags); if (error) { endmntent(f); return error; } result.push_back(std::make_shared<TMount>(m->mnt_fsname, m->mnt_dir, m->mnt_type, flags)); } endmntent(f); return TError::Success(); }
TError SetupLoopDevice(TPath image, int &dev) { static std::mutex BigLoopLock; int control_fd, image_fd, loop_nr, loop_fd; struct loop_info64 info; std::string loop; int retry = 10; TError error; image_fd = open(image.c_str(), O_RDWR | O_CLOEXEC); if (image_fd < 0) { error = TError(EError::Unknown, errno, "open(" + image.ToString() + ")"); goto err_image; } control_fd = open("/dev/loop-control", O_RDWR | O_CLOEXEC); if (control_fd < 0) { error = TError(EError::Unknown, errno, "open(/dev/loop-control)"); goto err_control; } BigLoopLock.lock(); again: loop_nr = ioctl(control_fd, LOOP_CTL_GET_FREE); if (loop_nr < 0) { error = TError(EError::Unknown, errno, "ioctl(LOOP_CTL_GET_FREE)"); goto err_get_free; } loop = "/dev/loop" + std::to_string(loop_nr); loop_fd = open(loop.c_str(), O_RDWR | O_CLOEXEC); if (loop_fd < 0) { error = TError(EError::Unknown, errno, "open(" + loop + ")"); goto err_loop_open; } if (ioctl(loop_fd, LOOP_SET_FD, image_fd) < 0) { error = TError(EError::Unknown, errno, "ioctl(LOOP_SET_FD)"); if (errno == EBUSY) { if (!ioctl(loop_fd, LOOP_GET_STATUS64, &info) || errno == ENXIO) { if (--retry > 0) { close(loop_fd); goto again; } } } goto err_set_fd; } memset(&info, 0, sizeof(info)); strncpy((char *)info.lo_file_name, image.c_str(), LO_NAME_SIZE); if (ioctl(loop_fd, LOOP_SET_STATUS64, &info) < 0) { error = TError(EError::Unknown, errno, "ioctl(LOOP_SET_STATUS64)"); ioctl(loop_fd, LOOP_CLR_FD, 0); goto err_set_status; } dev = loop_nr; error = TError::Success(); err_set_status: err_set_fd: close(loop_fd); err_loop_open: err_get_free: BigLoopLock.unlock(); close(control_fd); err_control: close(image_fd); err_image: return error; }
TError TMount::Remount(TPath path, unsigned long flags) { if (mount(NULL, path.c_str(), NULL, flags, NULL)) return TError(EError::Unknown, errno, "mount(NULL, " + path.ToString() + ", NULL, " + std::to_string(flags) + ", NULL)"); return TError::Success(); }