github.com/cyverse/go-irodsclient@v0.13.2/fs/fs_acl.go (about) 1 package fs 2 3 import ( 4 "fmt" 5 6 irods_fs "github.com/cyverse/go-irodsclient/irods/fs" 7 "github.com/cyverse/go-irodsclient/irods/types" 8 "github.com/cyverse/go-irodsclient/irods/util" 9 "golang.org/x/xerrors" 10 ) 11 12 // ListACLs returns ACLs 13 func (fs *FileSystem) ListACLs(path string) ([]*types.IRODSAccess, error) { 14 stat, err := fs.Stat(path) 15 if err != nil { 16 return nil, err 17 } 18 19 if stat.Type == DirectoryEntry { 20 return fs.ListDirACLs(path) 21 } else if stat.Type == FileEntry { 22 return fs.ListFileACLs(path) 23 } 24 25 return nil, xerrors.Errorf("unknown type - %s", stat.Type) 26 } 27 28 // ListACLsForEntries returns ACLs for entries in a collection 29 func (fs *FileSystem) ListACLsForEntries(path string) ([]*types.IRODSAccess, error) { 30 irodsPath := util.GetCorrectIRODSPath(path) 31 32 collectionEntry, err := fs.getCollection(irodsPath) 33 if err != nil { 34 return nil, err 35 } 36 37 collection := fs.getCollectionFromEntry(collectionEntry) 38 39 return fs.listACLsForEntries(collection) 40 } 41 42 // ListACLsWithGroupUsers returns ACLs 43 func (fs *FileSystem) ListACLsWithGroupUsers(path string) ([]*types.IRODSAccess, error) { 44 stat, err := fs.Stat(path) 45 if err != nil { 46 return nil, err 47 } 48 49 accesses := []*types.IRODSAccess{} 50 if stat.Type == DirectoryEntry { 51 accessList, err := fs.ListDirACLsWithGroupUsers(path) 52 if err != nil { 53 return nil, err 54 } 55 56 accesses = append(accesses, accessList...) 57 } else if stat.Type == FileEntry { 58 accessList, err := fs.ListFileACLsWithGroupUsers(path) 59 if err != nil { 60 return nil, err 61 } 62 63 accesses = append(accesses, accessList...) 64 } else { 65 return nil, xerrors.Errorf("unknown type '%s'", stat.Type) 66 } 67 68 return accesses, nil 69 } 70 71 // ListDirACLs returns ACLs of a directory 72 func (fs *FileSystem) ListDirACLs(path string) ([]*types.IRODSAccess, error) { 73 irodsPath := util.GetCorrectIRODSPath(path) 74 75 // check cache first 76 cachedAccesses := fs.cache.GetACLsCache(irodsPath) 77 if cachedAccesses != nil { 78 return cachedAccesses, nil 79 } 80 81 // otherwise, retrieve it and add it to cache 82 conn, err := fs.metaSession.AcquireConnection() 83 if err != nil { 84 return nil, err 85 } 86 defer fs.metaSession.ReturnConnection(conn) 87 88 accesses, err := irods_fs.ListCollectionAccesses(conn, irodsPath) 89 if err != nil { 90 return nil, err 91 } 92 93 // cache it 94 fs.cache.AddACLsCache(irodsPath, accesses) 95 96 return accesses, nil 97 } 98 99 // ListDirACLsWithGroupUsers returns ACLs of a directory 100 // CAUTION: this can fail if a group contains a lot of users 101 func (fs *FileSystem) ListDirACLsWithGroupUsers(path string) ([]*types.IRODSAccess, error) { 102 accesses, err := fs.ListDirACLs(path) 103 if err != nil { 104 return nil, err 105 } 106 107 newAccesses := []*types.IRODSAccess{} 108 newAccessesMap := map[string]*types.IRODSAccess{} 109 110 for _, access := range accesses { 111 if access.UserType == types.IRODSUserRodsGroup { 112 // retrieve all users in the group 113 users, err := fs.ListGroupUsers(access.UserName) 114 if err != nil { 115 return nil, err 116 } 117 118 for _, user := range users { 119 userAccess := &types.IRODSAccess{ 120 Path: access.Path, 121 UserName: user.Name, 122 UserZone: user.Zone, 123 UserType: user.Type, 124 AccessLevel: access.AccessLevel, 125 } 126 127 // remove duplicates 128 newAccessesMap[fmt.Sprintf("%s||%s", user.Name, access.AccessLevel)] = userAccess 129 } 130 } else { 131 newAccessesMap[fmt.Sprintf("%s||%s", access.UserName, access.AccessLevel)] = access 132 } 133 } 134 135 // convert map to array 136 for _, access := range newAccessesMap { 137 newAccesses = append(newAccesses, access) 138 } 139 140 return newAccesses, nil 141 } 142 143 // ListFileACLs returns ACLs of a file 144 func (fs *FileSystem) ListFileACLs(path string) ([]*types.IRODSAccess, error) { 145 irodsPath := util.GetCorrectIRODSPath(path) 146 147 // check cache first 148 cachedAccesses := fs.cache.GetACLsCache(irodsPath) 149 if cachedAccesses != nil { 150 return cachedAccesses, nil 151 } 152 153 // otherwise, retrieve it and add it to cache 154 conn, err := fs.metaSession.AcquireConnection() 155 if err != nil { 156 return nil, err 157 } 158 defer fs.metaSession.ReturnConnection(conn) 159 160 collectionEntry, err := fs.getCollection(util.GetIRODSPathDirname(irodsPath)) 161 if err != nil { 162 return nil, err 163 } 164 165 collection := fs.getCollectionFromEntry(collectionEntry) 166 167 accesses, err := irods_fs.ListDataObjectAccesses(conn, collection, util.GetIRODSPathFileName(irodsPath)) 168 if err != nil { 169 return nil, err 170 } 171 172 // cache it 173 fs.cache.AddACLsCache(irodsPath, accesses) 174 175 return accesses, nil 176 } 177 178 // ListFileACLsWithGroupUsers returns ACLs of a file 179 func (fs *FileSystem) ListFileACLsWithGroupUsers(path string) ([]*types.IRODSAccess, error) { 180 accesses, err := fs.ListFileACLs(path) 181 if err != nil { 182 return nil, err 183 } 184 185 newAccesses := []*types.IRODSAccess{} 186 newAccessesMap := map[string]*types.IRODSAccess{} 187 188 for _, access := range accesses { 189 if access.UserType == types.IRODSUserRodsGroup { 190 // retrieve all users in the group 191 users, err := fs.ListGroupUsers(access.UserName) 192 if err != nil { 193 return nil, err 194 } 195 196 for _, user := range users { 197 userAccess := &types.IRODSAccess{ 198 Path: access.Path, 199 UserName: user.Name, 200 UserZone: user.Zone, 201 UserType: user.Type, 202 AccessLevel: access.AccessLevel, 203 } 204 205 // remove duplicates 206 newAccessesMap[fmt.Sprintf("%s||%s", user.Name, access.AccessLevel)] = userAccess 207 } 208 } else { 209 newAccessesMap[fmt.Sprintf("%s||%s", access.UserName, access.AccessLevel)] = access 210 } 211 } 212 213 // convert map to array 214 for _, access := range newAccessesMap { 215 newAccesses = append(newAccesses, access) 216 } 217 218 return newAccesses, nil 219 } 220 221 // listACLsForEntries lists ACLs for entries in a collection 222 func (fs *FileSystem) listACLsForEntries(collection *types.IRODSCollection) ([]*types.IRODSAccess, error) { 223 // check cache first 224 cachedAccesses := []*types.IRODSAccess{} 225 useCached := false 226 227 cachedDirEntryPaths := fs.cache.GetDirCache(collection.Path) 228 if cachedDirEntryPaths != nil { 229 useCached = true 230 for _, cachedDirEntryPath := range cachedDirEntryPaths { 231 cachedAccess := fs.cache.GetACLsCache(cachedDirEntryPath) 232 if cachedAccess != nil { 233 cachedAccesses = append(cachedAccesses, cachedAccess...) 234 } else { 235 useCached = false 236 break 237 } 238 } 239 } 240 241 if useCached { 242 return cachedAccesses, nil 243 } 244 245 // otherwise, retrieve it and add it to cache 246 conn, err := fs.metaSession.AcquireConnection() 247 if err != nil { 248 return nil, err 249 } 250 defer fs.metaSession.ReturnConnection(conn) 251 252 // ListAccessesForSubCollections does not return Accesses for some files/dirs 253 // For these files/dirs, we compare accesses we obtained to the list of files/dirs in a dir 254 // and register an empty Access array to cache 255 dirEntryPathsToBeAdded := []string{} 256 if cachedDirEntryPaths != nil { 257 dirEntryPathsToBeAdded = append(dirEntryPathsToBeAdded, cachedDirEntryPaths...) 258 } else { 259 // otherwise, retrieve it and add it to cache 260 collections, err := irods_fs.ListSubCollections(conn, collection.Path) 261 if err != nil { 262 return nil, err 263 } 264 265 entries := []*Entry{} 266 267 for _, coll := range collections { 268 entry := fs.getEntryFromCollection(coll) 269 entries = append(entries, entry) 270 271 // cache it 272 fs.cache.RemoveNegativeEntryCache(entry.Path) 273 fs.cache.AddEntryCache(entry) 274 } 275 276 dataobjects, err := irods_fs.ListDataObjectsMasterReplica(conn, collection) 277 if err != nil { 278 return nil, err 279 } 280 281 for _, dataobject := range dataobjects { 282 if len(dataobject.Replicas) == 0 { 283 continue 284 } 285 286 entry := fs.getEntryFromDataObject(dataobject) 287 entries = append(entries, entry) 288 289 // cache it 290 fs.cache.RemoveNegativeEntryCache(entry.Path) 291 fs.cache.AddEntryCache(entry) 292 } 293 294 // cache dir entries 295 dirEntryPaths := []string{} 296 for _, entry := range entries { 297 dirEntryPaths = append(dirEntryPaths, entry.Path) 298 dirEntryPathsToBeAdded = append(dirEntryPathsToBeAdded, entry.Path) 299 } 300 fs.cache.AddDirCache(collection.Path, dirEntryPaths) 301 } 302 303 // list access 304 dirEntryPathsAdded := map[string]bool{} 305 306 collectionAccesses, err := irods_fs.ListAccessesForSubCollections(conn, collection.Path) 307 if err != nil { 308 return nil, err 309 } 310 311 accesses := []*types.IRODSAccess{} 312 313 accesses = append(accesses, collectionAccesses...) 314 315 // cache it 316 fs.cache.AddACLsCacheMulti(collectionAccesses) 317 318 dataobjectAccesses, err := irods_fs.ListAccessesForDataObjects(conn, collection) 319 if err != nil { 320 return nil, err 321 } 322 323 accesses = append(accesses, dataobjectAccesses...) 324 325 // cache it 326 fs.cache.AddACLsCacheMulti(dataobjectAccesses) 327 328 for _, acc := range accesses { 329 dirEntryPathsAdded[acc.Path] = true 330 } 331 332 // cache missing dir entries 333 for _, pathToBeAdded := range dirEntryPathsToBeAdded { 334 if _, ok := dirEntryPathsAdded[pathToBeAdded]; !ok { 335 // add empty one 336 fs.cache.AddACLsCache(pathToBeAdded, []*types.IRODSAccess{}) 337 dirEntryPathsAdded[pathToBeAdded] = true 338 } 339 } 340 341 return accesses, nil 342 }