| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/clientctx.h |
| Date: | 2025-11-09 02:35:23 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 21 | 21 | 100.0% |
| Branches: | 5 | 6 | 83.3% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM File System. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef CVMFS_CLIENTCTX_H_ | ||
| 6 | #define CVMFS_CLIENTCTX_H_ | ||
| 7 | |||
| 8 | #include <pthread.h> | ||
| 9 | #include <unistd.h> | ||
| 10 | |||
| 11 | #include <cassert> | ||
| 12 | #include <vector> | ||
| 13 | |||
| 14 | class InterruptCue; | ||
| 15 | |||
| 16 | /** | ||
| 17 | * A client context associates a file system call with the uid, gid, and pid | ||
| 18 | * of the calling process and an InterruptCue of the file system request. | ||
| 19 | * For the library, the calling process is just the current process and | ||
| 20 | * user, the InterruptCue is the default one. | ||
| 21 | * For the Fuse module, the uid and gid are provided by fuse, the pid | ||
| 22 | * can be figured out from the system. The InterruptCue is the FuseInterruptCue | ||
| 23 | * defined in cvmfs.cc. A client context is used to download files with the | ||
| 24 | * credentials of the caller and to interrupt a download if the file system | ||
| 25 | * request got canceled. | ||
| 26 | * | ||
| 27 | * A ClientCtx encapulates thread-local storage. It can be set somewhere at the | ||
| 28 | * beginning of a file system call and used anywhere during the processing of | ||
| 29 | * the call. It is a singleton. | ||
| 30 | */ | ||
| 31 | class ClientCtx { | ||
| 32 | public: | ||
| 33 | struct ThreadLocalStorage { | ||
| 34 | 193 | ThreadLocalStorage(uid_t u, gid_t g, pid_t p, InterruptCue *ic) | |
| 35 | 193 | : uid(u), gid(g), pid(p), interrupt_cue(ic), is_set(true) { } | |
| 36 | uid_t uid; | ||
| 37 | gid_t gid; | ||
| 38 | pid_t pid; | ||
| 39 | InterruptCue *interrupt_cue; ///< A non-owning pointer | ||
| 40 | bool is_set; ///< either not yet set or deliberately unset | ||
| 41 | }; | ||
| 42 | |||
| 43 | static ClientCtx *GetInstance(); | ||
| 44 | static void CleanupInstance(); | ||
| 45 | ~ClientCtx(); | ||
| 46 | |||
| 47 | void Set(uid_t uid, gid_t gid, pid_t pid, InterruptCue *ic); | ||
| 48 | void Unset(); | ||
| 49 | void Get(uid_t *uid, gid_t *gid, pid_t *pid, InterruptCue **ic); | ||
| 50 | bool IsSet(); | ||
| 51 | |||
| 52 | private: | ||
| 53 | static ClientCtx *instance_; | ||
| 54 | static void TlsDestructor(void *data); | ||
| 55 | |||
| 56 | ClientCtx(); | ||
| 57 | |||
| 58 | pthread_key_t thread_local_storage_; | ||
| 59 | pthread_mutex_t *lock_tls_blocks_; | ||
| 60 | std::vector<ThreadLocalStorage *> tls_blocks_; | ||
| 61 | }; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * RAII form of the ClientCtx. On construction, automatically sets the context | ||
| 65 | * via the constructor; on destruction, restores to the previous values. | ||
| 66 | * | ||
| 67 | * Meant to be allocated on the stack. | ||
| 68 | */ | ||
| 69 | class ClientCtxGuard { | ||
| 70 | public: | ||
| 71 | 654 | ClientCtxGuard(uid_t uid, gid_t gid, pid_t pid, InterruptCue *ic) | |
| 72 | 654 | : set_on_construction_(false) | |
| 73 | 654 | , old_uid_(-1) | |
| 74 | 654 | , old_gid_(-1) | |
| 75 | 654 | , old_pid_(-1) | |
| 76 | 654 | , old_interrupt_cue_(NULL) { | |
| 77 | // Implementation guarantees old_ctx is not null. | ||
| 78 | 654 | ClientCtx *old_ctx = ClientCtx::GetInstance(); | |
| 79 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 654 times.
|
654 | assert(old_ctx); |
| 80 |
2/2✓ Branch 1 taken 29 times.
✓ Branch 2 taken 625 times.
|
654 | if (old_ctx->IsSet()) { |
| 81 | 29 | set_on_construction_ = true; | |
| 82 | 29 | old_ctx->Get(&old_uid_, &old_gid_, &old_pid_, &old_interrupt_cue_); | |
| 83 | } | ||
| 84 | 654 | old_ctx->Set(uid, gid, pid, ic); | |
| 85 | 654 | } | |
| 86 | |||
| 87 | 654 | ~ClientCtxGuard() { | |
| 88 | 654 | ClientCtx *ctx = ClientCtx::GetInstance(); | |
| 89 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 625 times.
|
654 | if (set_on_construction_) { |
| 90 | 29 | ctx->Set(old_uid_, old_gid_, old_pid_, old_interrupt_cue_); | |
| 91 | } else { | ||
| 92 | 625 | ctx->Unset(); | |
| 93 | } | ||
| 94 | 654 | } | |
| 95 | |||
| 96 | private: | ||
| 97 | bool set_on_construction_; | ||
| 98 | uid_t old_uid_; | ||
| 99 | gid_t old_gid_; | ||
| 100 | pid_t old_pid_; | ||
| 101 | InterruptCue *old_interrupt_cue_; | ||
| 102 | }; | ||
| 103 | |||
| 104 | #endif // CVMFS_CLIENTCTX_H_ | ||
| 105 |