1 /* 2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 ** Distributed under the terms of the OpenBeOS License. 4 */ 5 6 7 #include "Directory.h" 8 #include "Volume.h" 9 #include "File.h" 10 11 #include <StorageDefs.h> 12 #include <util/kernel_cpp.h> 13 14 #include <string.h> 15 #include <unistd.h> 16 #include <stdint.h> 17 #include <stdio.h> 18 19 //#define TRACE(x) dprintf x 20 #define TRACE(x) do {} while (0) 21 22 namespace FATFS { 23 24 struct dir_entry { 25 void *Buffer() const { return (void *)fName; }; 26 const char *BaseName() const { return fName; }; 27 const char *Extension() const { return fExt; }; 28 uint8 Flags() const { return fFlags; }; 29 uint32 Cluster(int32 fatBits) const; 30 uint32 Size() const { return B_LENDIAN_TO_HOST_INT32(fSize); }; 31 bool IsFile() const; 32 bool IsDir() const; 33 char fName[8]; 34 char fExt[3]; 35 uint8 fFlags; 36 uint8 fReserved1; 37 uint8 fCreateTime10ms; 38 uint16 fCreateTime; 39 uint16 fCreateDate; 40 uint16 fAccessDate; 41 uint16 fClusterMSB; 42 uint16 fModifiedTime; 43 uint16 fModifiedDate; 44 uint16 fClusterLSB; 45 uint32 fSize; 46 } _PACKED; 47 48 49 uint32 50 dir_entry::Cluster(int32 fatBits) const 51 { 52 uint32 c = B_LENDIAN_TO_HOST_INT16(fClusterLSB); 53 if (fatBits == 32) 54 c += ((uint32)B_LENDIAN_TO_HOST_INT16(fClusterMSB) << 16); 55 return c; 56 } 57 58 bool 59 dir_entry::IsFile() const 60 { 61 return ((Flags() & (FAT_VOLUME|FAT_SUBDIR)) == 0); 62 } 63 64 65 bool 66 dir_entry::IsDir() const 67 { 68 return ((Flags() & (FAT_VOLUME|FAT_SUBDIR)) == FAT_SUBDIR); 69 } 70 71 72 struct dir_cookie { 73 int32 index; 74 struct dir_entry entry; 75 off_t Offset() const { return index * sizeof(struct dir_entry); } 76 }; 77 78 79 Directory::Directory(Volume &volume, uint32 cluster, const char *name) 80 : 81 fVolume(volume), 82 fStream(volume, cluster, UINT32_MAX, name) 83 { 84 TRACE(("FASFS::Directory::(, %lu, %s)\n", cluster, name)); 85 } 86 87 88 Directory::~Directory() 89 { 90 TRACE(("FASFS::Directory::~()\n")); 91 } 92 93 94 status_t 95 Directory::InitCheck() 96 { 97 status_t err; 98 err = fStream.InitCheck(); 99 if (err < B_OK) 100 return err; 101 return B_OK; 102 } 103 104 105 status_t 106 Directory::Open(void **_cookie, int mode) 107 { 108 TRACE(("FASFS::Directory::%s(, %d)\n", __FUNCTION__, mode)); 109 _inherited::Open(_cookie, mode); 110 111 struct dir_cookie *c = new struct dir_cookie; 112 if (c == NULL) 113 return B_NO_MEMORY; 114 115 c->index = -1; 116 117 *_cookie = (void *)c; 118 return B_OK; 119 } 120 121 122 status_t 123 Directory::Close(void *cookie) 124 { 125 TRACE(("FASFS::Directory::%s()\n", __FUNCTION__)); 126 _inherited::Close(cookie); 127 128 delete (struct dir_cookie *)cookie; 129 return B_OK; 130 } 131 132 133 Node * 134 Directory::Lookup(const char *name, bool traverseLinks) 135 { 136 TRACE(("FASFS::Directory::%s('%s', %d)\n", __FUNCTION__, name, traverseLinks)); 137 if (!strcmp(name, ".")) { 138 Acquire(); 139 return this; 140 } 141 char *dot = strchr(name, '.'); 142 int baselen = strlen(name); 143 if (baselen > FATFS_BASENAME_LENGTH) // !? 144 return NULL; 145 char *ext = NULL; 146 int extlen = 0; 147 if (dot) { 148 baselen = dot - name; 149 ext = dot + 1; 150 if (strlen(ext) > FATFS_EXTNAME_LENGTH) // !? 151 return NULL; 152 extlen = strlen(ext); 153 } 154 155 status_t err; 156 struct dir_cookie cookie; 157 struct dir_cookie *c = &cookie; 158 c->index = -1; 159 160 do { 161 err = GetNextEntry(c); 162 if (err < B_OK) 163 return NULL; 164 TRACE(("FASFS::Directory::%s: %s <> '%8.8s.%3.3s'\n", __FUNCTION__, 165 name, c->entry.BaseName(), c->entry.Extension())); 166 int i; 167 for (i = 0; i < FATFS_BASENAME_LENGTH; i++) 168 if (c->entry.BaseName()[i] == ' ') 169 break; 170 int nlen = MIN(i,FATFS_BASENAME_LENGTH); 171 for (i = 0; i < FATFS_EXTNAME_LENGTH; i++) 172 if (c->entry.Extension()[i] == ' ') 173 break; 174 int elen = MIN(i,FATFS_EXTNAME_LENGTH); 175 if (nlen != baselen) 176 continue; 177 if (elen != extlen) 178 continue; 179 if (strncasecmp(name, c->entry.BaseName(), nlen)) 180 continue; 181 if (strncasecmp(ext, c->entry.Extension(), elen)) 182 continue; 183 TRACE(("GOT IT!\n")); 184 break; 185 } while (true); 186 187 if (c->entry.IsFile()) { 188 TRACE(("IS FILE\n")); 189 return new File(fVolume, c->entry.Cluster(fVolume.FatBits()), 190 c->entry.Size(), name); 191 } 192 if (c->entry.IsDir()) { 193 TRACE(("IS DIR\n")); 194 return new Directory(fVolume, c->entry.Cluster(fVolume.FatBits()), 195 name); 196 } 197 return NULL; 198 } 199 200 201 status_t 202 Directory::GetNextEntry(void *cookie, char *name, size_t size) 203 { 204 TRACE(("FASFS::Directory::%s()\n", __FUNCTION__)); 205 struct dir_cookie *c = (struct dir_cookie *)cookie; 206 status_t err; 207 208 err = GetNextEntry(cookie); 209 if (err < B_OK) 210 return err; 211 212 strlcpy(name, c->entry.fName, MIN(size, FATFS_BASENAME_LENGTH)); 213 strlcpy(name, ".", size); 214 strlcpy(name, c->entry.fExt, MIN(size, FATFS_EXTNAME_LENGTH)); 215 return B_OK; 216 } 217 218 219 status_t 220 Directory::GetNextNode(void *cookie, Node **_node) 221 { 222 return B_ERROR; 223 } 224 225 226 status_t 227 Directory::Rewind(void *cookie) 228 { 229 TRACE(("FASFS::Directory::%s()\n", __FUNCTION__)); 230 struct dir_cookie *c = (struct dir_cookie *)cookie; 231 c->index = -1; 232 233 return B_OK; 234 } 235 236 237 bool 238 Directory::IsEmpty() 239 { 240 TRACE(("FASFS::Directory::%s()\n", __FUNCTION__)); 241 struct dir_cookie cookie; 242 struct dir_cookie *c = &cookie; 243 c->index = -1; 244 if (GetNextEntry(c) == B_OK) 245 return false; 246 return true; 247 } 248 249 250 status_t 251 Directory::GetName(char *name, size_t size) const 252 { 253 TRACE(("FASFS::Directory::%s()\n", __FUNCTION__)); 254 if (this == fVolume.Root()) 255 return fVolume.GetName(name, size); 256 return fStream.GetName(name, size); 257 } 258 259 260 ino_t 261 Directory::Inode() const 262 { 263 TRACE(("FASFS::Directory::%s()\n", __FUNCTION__)); 264 return fStream.FirstCluster() << 16; 265 } 266 267 status_t 268 Directory::GetNextEntry(void *cookie, uint8 mask, uint8 match) 269 { 270 TRACE(("FASFS::Directory::%s(, %02x, %02x)\n", __FUNCTION__, mask, match)); 271 struct dir_cookie *c = (struct dir_cookie *)cookie; 272 273 do { 274 c->index++; 275 size_t len = sizeof(c->entry); 276 if (fStream.ReadAt(c->Offset(), (uint8 *)&c->entry, &len) < B_OK) 277 return B_ENTRY_NOT_FOUND; 278 TRACE(("FASFS::Directory::%s: got one entry\n", __FUNCTION__)); 279 if ((uint8)c->entry.fName[0] == 0x00) // last one 280 return B_ENTRY_NOT_FOUND; 281 if ((uint8)c->entry.fName[0] == 0xe5) // deleted 282 continue; 283 if (c->entry.Flags() == 0x0f) // LFN entry 284 continue; 285 if (c->entry.Flags() & (FAT_VOLUME|FAT_SUBDIR) == FAT_VOLUME) { 286 // TODO handle Volume name (set fVolume's name) 287 continue; 288 } 289 TRACE(("FASFS::Directory::%s: checking '%8.8s.%3.3s', %02x\n", __FUNCTION__, 290 c->entry.BaseName(), c->entry.Extension(), c->entry.Flags())); 291 if ((c->entry.Flags() & mask) == match) 292 break; 293 } while (true); 294 TRACE(("FATFS::Directory::%s: '%8.8s.%3.3s'\n", __FUNCTION__, 295 c->entry.BaseName(), c->entry.Extension())); 296 return B_OK; 297 } 298 299 } // namespace FATFS 300