1 //---------------------------------------------------------------------- 2 // This software is part of the Haiku distribution and is covered 3 // by the MIT license. 4 // 5 // Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net 6 //--------------------------------------------------------------------- 7 #include "Icb.h" 8 9 #include "time.h" 10 11 #include "AllocationDescriptorList.h" 12 #include "Utils.h" 13 #include "Volume.h" 14 15 16 status_t 17 DirectoryIterator::GetNextEntry(char *name, uint32 *length, ino_t *id) 18 { 19 if (!id || !name || !length) 20 return B_BAD_VALUE; 21 22 TRACE(("DirectoryIterator::GetNextEntry: name = %s, length = %ld, " 23 "id = %p, position = %Ld, parent length = %Ld\n", name, *length, id, 24 fPosition, Parent()->Length())); 25 26 status_t status = B_OK; 27 if (fAtBeginning) { 28 TRACE(("DirectoryIterator::GetNextEntry: .\n")); 29 sprintf(name, "."); 30 *length = 2; 31 *id = Parent()->Id(); 32 fAtBeginning = false; 33 } else { 34 if (uint64(fPosition) >= Parent()->Length()) 35 return B_ENTRY_NOT_FOUND; 36 37 uint8 data[kMaxFileIdSize]; 38 file_id_descriptor *entry = (file_id_descriptor *)data; 39 40 uint32 block = 0; 41 off_t offset = fPosition; 42 43 size_t entryLength = kMaxFileIdSize; 44 // First read in the static portion of the file id descriptor, 45 // then, based on the information therein, read in the variable 46 // length tail portion as well. 47 status = Parent()->Read(offset, entry, &entryLength, &block); 48 if (!status && entryLength >= sizeof(file_id_descriptor) 49 && entry->tag().init_check(block) == B_OK) { 50 PDUMP(entry); 51 offset += entry->total_length(); 52 53 if (entry->is_parent()) { 54 TRACE(("DirectoryIterator::GetNextEntry: ..\n")); 55 sprintf(name, ".."); 56 *length = 3; 57 } else { 58 UdfString string(entry->id(), entry->id_length()); 59 TRACE(("DirectoryIterator::GetNextEntry: UfdString id == `%s', " 60 "length = %lu\n", string.Utf8(), string.Utf8Length())); 61 DUMP(entry->icb()); 62 sprintf(name, "%s", string.Utf8()); 63 *length = string.Utf8Length(); 64 } 65 *id = to_vnode_id(entry->icb()); 66 } 67 68 if (!status) 69 fPosition = offset; 70 } 71 72 return status; 73 } 74 75 76 /* \brief Rewinds the iterator to point to the first entry in the directory. */ 77 void 78 DirectoryIterator::Rewind() 79 { 80 fAtBeginning = true; 81 fPosition = 0; 82 } 83 84 85 // #pragma - Private methods 86 87 88 DirectoryIterator::DirectoryIterator(Icb *parent) 89 : 90 fAtBeginning(true), 91 fParent(parent), 92 fPosition(0) 93 { 94 } 95 96 Icb::Icb(Volume *volume, long_address address) 97 : 98 fVolume(volume), 99 fData(volume), 100 fInitStatus(B_NO_INIT), 101 fId(to_vnode_id(address)), 102 fFileEntry(&fData), 103 fExtendedEntry(&fData) 104 { 105 TRACE(("Icb::Icb: volume = %p, address(block = %ld, partition = %d, " 106 "length = %ld)\n", volume, address.block(), address.partition(), 107 address.length())); 108 109 if (volume == NULL) 110 fInitStatus = B_BAD_VALUE; 111 112 off_t block; 113 status_t status = fVolume->MapBlock(address, &block); 114 if (!status) { 115 icb_header *header = (icb_header *)fData.SetTo(block); 116 if (header->tag().id() == TAGID_FILE_ENTRY) { 117 file_icb_entry *entry = (file_icb_entry *)header; 118 PDUMP(entry); 119 (void)entry; // warning death 120 } else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) { 121 extended_file_icb_entry *entry = (extended_file_icb_entry *)header; 122 PDUMP(entry); 123 (void)entry; // warning death 124 } else { 125 PDUMP(header); 126 } 127 status = header->tag().init_check(address.block()); 128 } 129 130 fInitStatus = status; 131 TRACE(("Icb::Icb: status = 0x%lx, `%s'\n", status, strerror(status))); 132 } 133 134 135 status_t 136 Icb::GetDirectoryIterator(DirectoryIterator **iterator) 137 { 138 status_t error = iterator ? B_OK : B_BAD_VALUE; 139 140 if (!error) { 141 *iterator = new(std::nothrow) DirectoryIterator(this); 142 if (*iterator) 143 fIteratorList.Add(*iterator); 144 else 145 error = B_NO_MEMORY; 146 } 147 148 return error; 149 } 150 151 152 status_t 153 Icb::InitCheck() 154 { 155 return fInitStatus; 156 } 157 158 159 time_t 160 Icb::AccessTime() 161 { 162 return make_time(_FileEntry()->access_date_and_time()); 163 } 164 165 166 time_t 167 Icb::ModificationTime() 168 { 169 return make_time(_FileEntry()->modification_date_and_time()); 170 } 171 172 173 status_t 174 Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block) 175 { 176 TRACE(("Icb::Read: pos = %Ld, buffer = %p, length = (%p)->%ld\n", 177 pos, buffer, length, (length ? *length : 0))); 178 179 if (!buffer || !length || pos < 0) 180 return B_BAD_VALUE; 181 182 if (uint64(pos) >= Length()) { 183 *length = 0; 184 return B_OK; 185 } 186 187 switch (_IcbTag().descriptor_flags()) { 188 case ICB_DESCRIPTOR_TYPE_SHORT: { 189 TRACE(("Icb::Read: descriptor type -> short\n")); 190 AllocationDescriptorList<ShortDescriptorAccessor> list(this, ShortDescriptorAccessor(0)); 191 RETURN(_Read(list, pos, buffer, length, block)); 192 break; 193 } 194 195 case ICB_DESCRIPTOR_TYPE_LONG: { 196 TRACE(("Icb::Read: descriptor type -> long\n")); 197 AllocationDescriptorList<LongDescriptorAccessor> list(this); 198 RETURN(_Read(list, pos, buffer, length, block)); 199 break; 200 } 201 202 case ICB_DESCRIPTOR_TYPE_EXTENDED: { 203 TRACE(("Icb::Read: descriptor type -> extended\n")); 204 // AllocationDescriptorList<ExtendedDescriptorAccessor> list(this, ExtendedDescriptorAccessor(0)); 205 // RETURN(_Read(list, pos, buffer, length, block)); 206 RETURN(B_ERROR); 207 break; 208 } 209 210 case ICB_DESCRIPTOR_TYPE_EMBEDDED: { 211 TRACE(("Icb::Read: descriptor type: embedded\n")); 212 RETURN(B_ERROR); 213 break; 214 } 215 216 default: 217 TRACE(("Icb::Read: invalid icb descriptor flags! (flags = %d)\n", 218 _IcbTag().descriptor_flags())); 219 RETURN(B_BAD_VALUE); 220 break; 221 } 222 } 223 224 225 status_t 226 Icb::Find(const char *filename, ino_t *id) 227 { 228 TRACE(("Icb::Find: filename = `%s', id = %p\n", filename, id)); 229 230 if (!filename || !id) 231 RETURN(B_BAD_VALUE); 232 233 DirectoryIterator *i; 234 status_t status = GetDirectoryIterator(&i); 235 if (status != B_OK) 236 return status; 237 238 ino_t entryId; 239 uint32 length = B_FILE_NAME_LENGTH; 240 char name[B_FILE_NAME_LENGTH]; 241 242 bool foundIt = false; 243 while (i->GetNextEntry(name, &length, &entryId) == B_OK) { 244 if (strcmp(filename, name) == 0) { 245 foundIt = true; 246 break; 247 } 248 } 249 250 if (foundIt) 251 *id = entryId; 252 else 253 status = B_ENTRY_NOT_FOUND; 254 255 return status; 256 } 257