1 /* 2 * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "PackagesDirectory.h" 8 9 #include <errno.h> 10 11 #include <fs/KPath.h> 12 #include <team.h> 13 #include <vfs.h> 14 15 #include "DebugSupport.h" 16 17 18 PackagesDirectory::PackagesDirectory() 19 : 20 fStateName(), 21 fPath(NULL), 22 fDirFD(-1), 23 fNodeRef(), 24 fHashNext(NULL) 25 { 26 } 27 28 29 PackagesDirectory::~PackagesDirectory() 30 { 31 if (fDirFD >= 0) 32 close(fDirFD); 33 34 free(fPath); 35 } 36 37 38 /*static*/ bool 39 PackagesDirectory::IsNewer(const PackagesDirectory* a, 40 const PackagesDirectory* b) 41 { 42 if (b->fStateName.IsEmpty()) 43 return false; 44 if (a->fStateName.IsEmpty()) 45 return true; 46 return strcmp(a->fStateName, b->fStateName) > 0; 47 } 48 49 50 status_t 51 PackagesDirectory::Init(const char* path, dev_t mountPointDeviceID, 52 ino_t mountPointNodeID, struct stat& _st) 53 { 54 // Open the directory. We want the path be interpreted depending on from 55 // where it came (kernel or userland), but we always want a FD in the 56 // kernel I/O context. There's no VFS service method to do that for us, 57 // so we need to do that ourselves. 58 bool calledFromKernel 59 = team_get_current_team_id() == team_get_kernel_team_id(); 60 // Not entirely correct, but good enough for now. The only 61 // alternative is to have that information passed in as well. 62 63 struct vnode* vnode; 64 status_t error; 65 if (path != NULL) { 66 error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode); 67 } else { 68 // No path given -- use the "packages" directory at our mount point. 69 error = vfs_entry_ref_to_vnode(mountPointDeviceID, mountPointNodeID, 70 "packages", &vnode); 71 } 72 if (error != B_OK) { 73 ERROR("Failed to open packages directory \"%s\"\n", strerror(error)); 74 RETURN_ERROR(error); 75 } 76 77 return _Init(vnode, _st); 78 } 79 80 81 status_t 82 PackagesDirectory::InitOldState(dev_t adminDirDeviceID, ino_t adminDirNodeID, 83 const char* stateName) 84 { 85 if (!fStateName.SetTo(stateName)) 86 RETURN_ERROR(B_NO_MEMORY); 87 88 struct vnode* vnode; 89 status_t error = vfs_entry_ref_to_vnode(adminDirDeviceID, adminDirNodeID, 90 stateName, &vnode); 91 if (error != B_OK) { 92 ERROR("Failed to open old state directory \"%s\"\n", strerror(error)); 93 RETURN_ERROR(error); 94 } 95 96 struct stat st; 97 return _Init(vnode, st); 98 } 99 100 101 status_t 102 PackagesDirectory::_Init(struct vnode* vnode, struct stat& _st) 103 { 104 fDirFD = vfs_open_vnode(vnode, O_RDONLY, true); 105 106 if (fDirFD < 0) { 107 ERROR("Failed to open packages directory \"%s\"\n", strerror(fDirFD)); 108 vfs_put_vnode(vnode); 109 RETURN_ERROR(fDirFD); 110 } 111 // Our vnode reference has been transferred to the FD. 112 113 // Is it a directory at all? 114 struct stat& st = _st; 115 if (fstat(fDirFD, &st) < 0) 116 RETURN_ERROR(errno); 117 118 fNodeRef.device = st.st_dev; 119 fNodeRef.node = st.st_ino; 120 121 // get a normalized path 122 KPath normalizedPath; 123 if (normalizedPath.InitCheck() != B_OK) 124 RETURN_ERROR(normalizedPath.InitCheck()); 125 126 char* normalizedPathBuffer = normalizedPath.LockBuffer(); 127 status_t error = vfs_entry_ref_to_path(fNodeRef.device, fNodeRef.node, NULL, 128 true, normalizedPathBuffer, normalizedPath.BufferSize()); 129 if (error != B_OK) 130 RETURN_ERROR(error); 131 132 fPath = strdup(normalizedPathBuffer); 133 if (fPath == NULL) 134 RETURN_ERROR(B_NO_MEMORY); 135 136 return B_OK; 137 } 138