 Day 9 let's make a file. This will be the first time we'll write to our file system So that will be very exciting So I've made this little make.s Program all it does is it tries to create a file using a new XSCB make that turns into The BDOS create file system call and this will create and open a new file So if you make Who it currently bails out with unimplemented? create file will create a directory entry for the file that you specify and Set set it in the open state so that you can then use it to write data We're not writing any data. So it will just get a empty directory entry So let's find In our BDOS we want Create file. We are going to have to implement nearly all of these But most of them are trivial So These are going to be unimplemented These are unimplemented this one is not unimplemented this is that should actually be direct console IO That allows you to do things like poll for pending keys I'm sorry. No, it doesn't console status here does that direct IO Actually, yeah direct IO Is direct console IO it provides a direct interface to the BIOS so it bypasses anything that the BDOS might be doing in fact our implementation here doesn't do that. So Get version just returns this constant value Close file. We're going to be working on Not quite next next but one Delete yeah, right sequential we're going to have to do eventually Rename. Yeah, get login bitmap just returns 16 bit value ditto Haven't done anything in this yet Turn the 16 bit value this one will be interesting this This looks up a value in the BIOS storage and returns it. That's not complicated These are just simple wrappers around read sequential and write sequential What they do is they seek to a certain position specified with an absolute number of records Read sequential and write sequential have all the same information in them They just stored weirdly in the FCB. So that's not tricky not complicated compute file size scans the directory it looks for the largest extent number and Uses that to compute the total number of records in the file This is used to convert a sequential position into a random access position That's pretty straightforward. That one doesn't do anything and This one is kind of special This one will write a random record to a new allocation block and Fill all the other records in that allocation block with zeros So, yeah, it is actually in CPM 2.2 despite the fact there's a gap in the numbering system So what we're gonna do is this is actually going to be part of open file I'm gonna put this here Creates a file entry File set carry for error Thinking about the Z80 Okay, so make who cannot open file. It's returned an error good So what this does? Let's find the BDOS Make here we go So what this does is it's going to look for an empty directory entry Find one copy the user's FCB into the dear end flush it to disk and That's it really We don't need to worry about a lot of these things so that you know, for example The user extent is not relevant because we know it's going to be zero. This is a new file The record count is going to be zero because this is a new file, etc, etc So the main thing we need to do is to Create a directory entry ensure that we update The number of directory entries and Make sure there isn't a matching file now weirdly If the file exists already the default action is to return to the command prompt at IE do a soft reboot Which makes no sense whatsoever I have written CPM codes that tries to create files and like you have to try and open it first to make sure that the file doesn't exist So that you can return a reasonable error message, but Anyway We're going to Initialize the FCB we want to check to see if the drive is right protected so this is calling this function called check write and This is doing a hard error which will abort the program Don't think we've done any of those This is calling an error handler routine so we're actually going to Here this looks like it's a table which you can patch I do not actually recall any of this from the error message So yes, this the standard error handling it'll print a message Wait for the user to press a key and then do a soft boot Which isn't that awful? I suppose Okay, so check This right ball. This is what the directory handling. So this would go and drive management so Drive Check disk disk writeable, and we'll just put an RTS there for now. I think create file Yeah, so we now want to search for a Deleted directory entry and to do that We are going to Call find first But we want to set the drive byte in the FCB to e5 to tell find first we're looking for empty directory entries This will overwrite the existing drive, but that's okay because we know that the It's been processed here We know that what's in there is the user code and we have the user code handy so we don't need to save it This is pushing it on to the stack in the 8080 code So we call find first If Carrie is clear We've got one so we now want to copy the contents of the user's FCB into the directory buffer We want to make sure the allocation part is The allocation part of the FCB is all zeroed That's kind of important as we have no disk blocks allocated so We're going to So this is going to be a simple loop where we just copy a byte Current dear end come away. Yep to compare that with The allocation buffer so that's just going to be Current record actually no we're going to do AL plus 16 So we are going to update the current user to the right value we are going to ensure that The These four fields are all zero. We know the s2 has been zeroed because that happens in New user FCB, but the others are not zeroed so Actually, we're going to do this further up here So we can save a tiny tiny amount of code Okay, now I can't remember what I actually called that Routine it's in find. No, it's not it's in login Check no not check dear pause. Here we go update CDR max Have I done this Right actually, I think actually I think not So we don't want to clear the metadata Because we're relying on the user Doing that the user has to clear those spikes for the routine to work properly and that's in the Specification But we do have to We do have to do this bit Because we want to leave the file. We want to leave the FCB opened We do want to clear the allocation area in the FCB So we're going to do that here So we start at here So that means that we don't have to do this here because We can just copy the whole thing out of the FCB and it should be valid So I think that's everything we need apart from one Terribly important thing. What's this set? Set foof. Okay. That's the that's the s2 byte There is one terribly important thing we want to do which is we need to write that sector back to the disk now we could Just not do that Set this bit to zero. This means that when the file gets closed by the user program then this should end up being written back, but that would be dead confusing because Firstly the close code would have to handle the case where there wasn't a matching dear end for the FCB and Also, if the user tries to create another file Because this is always going to find the first file We'll end up trying to put two files in the same directory entry and that ain't gonna work So how do we Read From the disk well Read dear entry is the code that's actually doing the work and this is pre incremented that means that this as correctly set the Sector number and DMA and so on so Hopefully all we need to do is just call write sector and it should work Okay, but we haven't actually implemented this This is luckily very easy code and this becomes by us right we're going to Bring that out Set current sector like this. Okay So let's see if it works then so make Nord cannot open file Did I remember to clear the carry make Lord cannot open file Okay, I am gonna guess that find first here is booked so let's Stick a jump star there Fire up the debugger and see what happens break One C 2 9 break point in break one C 2 9 reset continue Okay, so set the drive bite of the Dear end of the day the FCB which is at 2188. So there is our directory entry With a E5 at the beginning What we're looking at here actually is makes P blog So there is the command line afterwards, which is nice so Should be in find first now Should there be an LDA zero? Ah We need to tell it how many bytes of directory entry we want to compare so for deleted files That's a one. I've forgotten that that act that calculation normally happens in the public entry point so let's Oops, what's that? I'm scanning a big document. So if you may be able to hear machine noises occasionally and It's not a very good scanner We were going to Did I save that I Did not save that okay So we are going to restart and try that again. So we are here So we set the count Home to drive reset the directory position Read a directory entry Check to see if we're at the end of the directory. We are not Did the user want to see deleted files? Yes, so we skip the CDR max test do We are now going to do the comparison So we check the first byte. It's not a question mark This we are not looking at byte 13. We're not looking at the extent byte So we're here Compare the two characters. This should be a zero. It's a zero That's not a zero Right, that's because the first directory entry is a file. Okay, so I Think we've got four files in our directory. Okay, actually, I think I'm just going to continue and The program thought it worked. Let's do a dir and that does not look like it's worked That looks like it's corrupted our disk So let's take a look at what it did Well, it has written a directory entry It's got a user code of zero Everything here looks fine So why did dir not work? This is the first directory entry which is on a It's in the second record so Possibly something with the logic there has gone wrong. They know what's happened It's printing one file Because in the during the login process when we scan the bit scan the directory we compute CDR max We're incorrectly calculating it based on the position in the directory buffer. So we look at the first record Well, let me look at the second record and We see that There's a maximum value of one here. This is one directory entry We go down go through the rest and then when we do the directory scan Because CDR max is one we only return one file Right thing do yeah, so this is This is That's not that's it. This should be correct current dear end is the Is a counter So Wait, what's this doing? Move on to the next dear end Directory pause should be the the count of directory entries Current dear end is a pointer So the maximum directory entry in the file. This should be Directory pause and and Yeah, directory pause is a two byte value. So this Facts throughout all this code. This should be current dear end Directory pause Okay, right, let's try that couldn't open CCP. Well That'll be because this isn't working and Calculate the offset in the get the sector number Load the sector And take the directory buffer and we add What on earth is this doing? This is calculating Directory buffer plus Things if we've gone through here, I think it's expecting directory pause to be the shifted Now these things is faking a to be the shifted directory pause But if we've gone through here and loaded a new sector then that will be corrupted So I think that needs to be LD zero to indicate that the shifted the directory pause is going to be zero Which we know it will be because we're at the beginning of a new sector so it Yeah, open CCP So I'm willing to bet this is because this code is doing something wrong. Have I misunderstood how my own code works? So we read a directory entry We increment directory pause the directory pause is pointing at the directory entry. We just read Are we resetting? the CDR max value in the dph I am not actually sure we Much code if carry set return three bytes. So that is the same as A jump to exit I don't think that will help no Okay, let's put a breakpoint in here because I bet this is what is causing things to go wrong bugger One EC zero Okay, so we are reading directory pause which is zero at this point because We've just read one directory entry the first one and there's incremented the directory pointer from invalid minus one to zero And our dph is at five C4 and it's all zeros Okay So we do the two byte Comparison wait What this code is bollocks We want to you see this compare instruction is going to discard the result of the previous compare instruction That should be a sbc. So this is going to do a two byte comparison By basically subtracting directory pause and dph if dph is greater than or equal to Directory pause and I'm great. I think this wants to be a carry clear due to the way we've done this so we're subtracting This is done. This is dph minus directory pause so a is Directory pause if directory pause is greater than or equal to dph carry set. Okay, then update CDR max So compare Tracked Carry is set because we haven't updated CDR max yet So we now set CDR max and we go around again this time directory pause should be One which it is so Okay, and again and again and again and Again, so this looks like it correctly set CDR max oh oh Is the find next code here correct the directory still looks valid 1d9e Okay, so we should have done the login which means that CDR max should be set up correctly so CDR max still at 5c4 and I believe it's These two bytes indicating four You see this is actually doing a compare an SBC, but I bet that this comparison is wrong Yes, it is wrong. That's inverted. How did this ever work in the first place? so compare Current drent that should be directory pause Okay, 2obf is The directory pause which is currently Zero Yes, we've read one directory entry. So it's gone from minus one to zero So zero is less than CDR max. So we do not brunch Right, and now it loads the CCP and if we go to dir One two three four five and Good, I think that works So if I can type Fnaud and it's empty I can dump Fnaud and it's empty It's not really a lot else I can do with it So I think we're creating files Let's make some more. So if I do make Baz Okay, let's try and Make another Fnaud that shouldn't have worked and it's created two Fnauds Why did that? Oh, I know why it's because this search we did for empty dirrents has in fact Ignored the filename. So I think we're going to have to do another call to find first in fact, we don't want to load that with 15 and Want to use a symbolic number for this? so If carry is clear I if we did manage to read the file Then set carry and exit and I think we want to put that Here Because we're about to start tinkering with the FCB make Fnaud cannot open file That's correct. I want this one right. I change this file so it rebuilt the disk image Make Fnaud Fnaud cannot create file good Okay, I think that's working so what is next? Well First I have to feed the scanner Okay scanner is fed and scanning The document it's it's scanning a huge document with lots of pages and unfortunately the page feeder Oh, it feeds pages in all right. It just tends to Jumble them on the way out So once this is done, I'm going to have to put like 150 pages back into order Ah Anyway, that's a different problem. I think we now want to try and write to the file first I'm going to make me a new Helper Because we're about to have to start allocating disk blocks so let's make a Program that Dumps the allocation bitmap of the disk To the console now There is a call for this which is get allocation bitmap So we're going to put a Pointer here And we're going to have an index the allocation the allocation bitmap can contain More than 256 entries, but we know this disk is smaller than that and this is a hacky debug tool. So How does it work a return address of allocation map return address? Of the current allocation bitmap In h l okay So Get allocation bitmap sda bitmap plus zero sda in bitmap plus one So we are now going to Say repeat We are going to Load the byte index Get one of the allocation bytes Stick it in value You know what I was going to try and print it as weird as like x's and dashes but I can't be bothered. So Let's just print it as hex Which honestly is almost as easy to read. So we're going to copy this uh Print an 8-bit hex number And stick that in here So this is going to be print hex number print a space increment index Load index is it 32 which is I know is the number of bytes In my bitmap. No, I don't know that And 30 do will do fine Until it's equal Print a new line and exit Space is undefined. So there is our new program bitmap Unimplemented right that's because we didn't if we haven't implemented get allocation bitmap Which goes Here and this is going to This goes under drive management Does it no it goes under Login directory management I need to rename that banner location bitmap Say Incidentally I've had occasional comments about how clicky my keyboard is You'll be pleased to know that I have acquired a new clicky keyboard that is even clickier And it feels so nice to use. I'm probably going to end up using it as a daily driver Just not at work because I'm not allowed Where did we put the bitmap update bitmap status is doing it get bitmap location Is getting the location to the bitmap Bitmap address is in variable called bitmap Allocation bitmap from the dph. Okay. Well, that's easy Okay, so boot it bitmap Right There is that bitmap Okay, ignore the trailing garbage because we are dumping too many bytes, but we see that The first eight blocks are Allocated that's Not right Is it I think that is right, you know Because we now have lots of files. I was thinking we would just see the directory But our file system is Contains actual data So a block is Uh, how big is a block? 1k so that's 400. So we've got two blocks for the directory Uh, we've got a file We got Another file this looks like No, this is the ccp this one. It's c00 more files See there's actually quite a lot of ways to space because the allocation block is a kilobyte And most of our files are smaller than that There's a text file here we go. Uh, so p By 400 is eight. All right, that's correct. We have correctly computed the bitmap So let's go down to Make try and create the file. This is going to be it's fcb Right sequential Okay, we haven't done that one yet But we haven't imported it So now we want to Create our right sequential Right Add another library function So why are we importing get instead? Or we don't All clear So we now we are now calling right sequential in our program So We call make snored And we get unimplemented because we haven't done right sequential yet So We go to here entry right Sequential I'm sure it's spelt more or less correctly. So read sequential is this junk of code Early versions of cpm only had read sequential and write sequential if you wanted to do uh Random access Then the user would tinker with the fcb directly I'm actually not Tirely sure why they ended up putting the random access stuff in the bedoss Okay, now a lot of this code is going to be exactly the same so We're going to move some of this stuff out So this is going to be Get sequential Sector number Which is going to be all of this down to here Sector number Okay, this is going to fail because We don't have eoff yet. So if The disk block value is zero then Exit with the error code in a So here If carry is set we exit with error actually actually This can only ever return This can only ever fail like that. So Okay, so this should still work. We are reading sequentially So we are now going to copy All of this so if the Current record is equal to the record count the extent is full until we need to go and find another one So we get the allocation block We get the sector If Carry is set we're going to have to allocate a block A new one so Actually, we're not going to do it there Hmm, we did this comparison here because it's much easier to test to see if x and a are equal By writing them to memory. I think it's the only way but really We want to Do it Here So to do that we're going to do Change this way around to say there's two code paths one for big disks and one for small disks But This side of things is Harder So we actually want to All the two values together now, we can't do that there because you've put something onto the stack Uh, I think we're going to have to do this the hard way so So we all the two together if the value is zero we exit Uh, we have not set x at this point However, this code will do it We could safely reload the byte from y because we know they're both zero So now we want to Load them both again so ta to x decrement y And in fact that's better code so we can get rid of this code So read sequential. This is going to be We put that comparison there Let's make sure that still works It looks like it works Yep, good So in write sequential It essentially becomes this code So we are going to need to allocate a block number. Where is our block management code? Bitmap that'll be Here somewhere Given a block number and 10 plus zero and a block state isn't a sets it Okay, so allocate a new block from the bitmap allocate block That's going to be a procedure. I'm sure so We want to Work through the bitmap until we find a byte with a empty block in it and then we know that Okay, it's one bit per block therefore even if it's a big disk And we know that the block the bitmap must be less than 250 Do we know it's less than 256? No big disks can have more than 256 blocks So this is actually going to want to be a actual pointer arithmetic great so We're essentially going to want to load a byte Compare it with ff If it's not ff then this means that that byte must have empty blocks in it Otherwise, we're going to want to increment the pointer If roll over in 10 plus one We're also going to want to compare against the end of the bitmap So we can either compute the end of the The bitmap and then compare our pointer or we can use a counter So let's just use a counter That's the wrong field So the dp a here we go We want to know the We want to know the size of the Allocation bitmap That's not actually there that's in That's in the dpb Well, if we haven't actually I haven't created the macrofe a definition for this If I haven't created a definition for this then dp Ah, I'm copying it. That's what I'm doing. Yeah, here we go So, uh, so Wait Does the dpb contain the address of the Other that contain the length of the allocation bitmap. I am not sure it does So the dph contains directory Allocation vector Address of the allocation that's the dpb it does Not contain The address of the allocation vector. So in fact, we are going to need to Sorry does not contain the length of the allocation vector So we are going to need to CDR max is Wrong We are going to want to Load the We're going to need to compute how long it is from the uh Blocks on disk value Okay, no, we're not going to do that. We're going to do something else Because The reason it's going to be slower, but honestly, that's not important. So we copy the We take a copy of the number of blocks on disk and this is going to be our count Nope, I'm changing my mind again Our count is going to work up from zero Okay If if the block number is zero This is really really annoying Uh Rather than do this the cheap and easy way. I'm going to do this the slow and small way So This is block number We then Given the block number and temp zero return Rotated block status in a so We are going to Get bitmap status now. Unfortunately, this is going to overwrite Temp zero. Why did we do it like that? Because get bitmap location Read from temp zero and update the pointer Get bitmap Because this code Is using temp two and temp three for something else Okay So Okay, so we get the bitmap status into a And now we want to increment the block number If it rolls over Increment the high byte So then we can have a until zero That means the block is free Which means We can load the block number Into a x and return it um We don't have it's more important to be small than fast for all this stuff because even though it's a nasty O1 on Algorithm for finding the new block even on a really slow 8-bit machine The amount of time taken to find a block is insignificant compared to the amount of time taken to Actually write it to disk so This is going to be find unused Find unused block Into x a we now want to allocate it This is going to kind of change my mind about this again so Given a block number and temp zero and a single bit status in a So we are going to Block is now allocated update and Read the block number and return it Okay, so our Write code which is here We've allocated the block. We now want to Set it in the fcb Set the current block number in the fcb 2 x a set fcb block um So again, this is going to be using Temporaries block index Y Are we a big disk? So that's dx So we are going to load the low byte store the high byte door otherwise There is only the low byte simplify like this Okay, so I think this may actually do something so make Baz Hang on before we do that bitmap ff oo make baz Bitmap It did not allocate A bit. I was expecting that to be eight zero So let's get out the debugger and find out why Wait, what? We are calling write sequential That's very strange. Why is that not? going into write sequential There are no places where we can actually produce an error so I'm going to have to put our breakpoint here Foo Okay, now at least it breaks two two one seven Foo, okay So that did something weird. Let's try that one again. Shall we? Make foo kind of Make bar, okay That's better So we should have gone from We're now in xfcb Wait a minute. Wait a minute No, that's right. That's right. Um, I'm actually going to change this. I'm going to put uh Put our breakpoint here just to keep me sane So I don't have to step through the xfcb stuff Okay Break Debugger two two nine seven So we now go through the bidos here Right, we should now be in write sequential here, so We convert the user fcb We load the current record Which is zero We load the record. Oh, that's not right Ah, I know what's happening We are Uh We're treating this as end of file where we shouldn't be okay. That makes much more sense So we don't want to test against record count, but we do want to check for a Uh extent full error Because then we want to allocate a new extent and we haven't done that yet Okay, so this is going to get to the block Um Move the fcb onto the next record for next time Uh if cr is greater than record count update rc a record count is Current record is in a so compare with Param y so A is the current records if current record is greater than or equal to record count carry set Uh, we also want to We are going to want to mark the fcb as being modified and we do that by clearing that top bit of the s two Flag Which is this stuff here So we want to do that here fcb is modified And we want to do it Here Now notice that if we're writing to an existing block We don't necessarily modify the fcb. So we don't have to Clear the flag Okay, so make Floor okay bitmap four zero four zero Really still four zero. That's the wrong bit So this looks like it's uh This looks like it has actually calculated. It's it's found the right bit And then has set the wrong one. I know this because the next time through Yeah, because we've incremented it here So we actually want to do this here Break if zero Then do the increment. So then this has to become a loop end loop We were incrementing the bit block number after we did the test Yeah, and you notice that the bitmap has been reset. This is because we haven't written our fcb back eight zero good make C zero right it is allocating blocks correctly good so We are now correctly I think we are now correctly writing to Uh the file So that will This needs to go back to code Okay So make for lord bitmap Okay, so these should have written One records worth of stuff We haven't updated the directory But we should have actually written the data. So if I close this And we look at the image file We go down to the end we see In the right place a records worth of queues. That's this data here So there is one more thing we want to do One quite big thing we want to do Which is we go back to our application And we close the file now in cpm's close call is Uh badly named Because it doesn't actually close the file You use you can still write to the file after it's been closed That's not a problem because it doesn't change anything in the fcb other than to mark it as uh That it hasn't it doesn't need flushing again Uh what it does do is it syncs the fcb to disk So this is the point where any of your um New allocated blocks get written to the directory so that the next time the bitmap is read It'll see them This is actually pretty cunning It means that the file system ends up Being consistent in the extent of crashes If your program terminates without closing the file or rather without flushing the file syncing it to disk Then any blocks that have been allocated into that extent Will be uh Lost uh the data will have been written to disk but The directory entry won't have been updated to point at them This does the whole ordered write thing in a tiny amount of logic Uh, it means that the data gets flushed to disk before the metadata gets flushed to disk So that your metadata should always be correct uh The one place where this breaks down is if you change extents like if you seek between 16k boundaries We need to flush the current directory to disk So that we can load the the directory entry for the new extent Uh, so basically if you're writing to a big file you get periodic flushers As you seek around in the disk And the final changes only get flushed when you call close It's a fairly elegant system. Uh, yeah, we're gonna need to want to Add an xfcb function Now that's going to so this will go here Okay Close So we want prepare we want bidos file Okay So now when we run our program Make foo Unimplemented we haven't done close yet. So we find the n vector table Close file File open file create file close a file Flush the fcb to disk Okay So how does this work? Well As usual we want to convert the user fcb And as usual we want to go look at the original Uh implementation Now we have no idea where the Um Where the directory entry on disk actually is so we're going to have to search it So the first thing we're going to want to do is as usual Check that the disk is writable and it will fail with an error a hard error if it's not Check that this fcb has actually Changed it's an s2 If The value we just read is negative than the top bit is set And we can just return We now want to Find the Directory entry so to do this We are going to Stent we want to do a directory scan And we're looking for All The bytes Because we need something that matches Uh ex and s2 but not record count So s2 plus 1 find first if There's an error Then We do actually want to Fail Here What does it do? So if uh if it can't find it then this means that Yeah, it's just an error If the directory entry can't be found this means the user changed disks where they shouldn't There is a mechanism for testing if disks get changed By check summing the directory which we haven't implemented Okay, but at this point uh Directory entry has been updated to point at the drent We want to update the disk map Now I would have thought that you would just copy the fcb But why is this doing Such complicated code weird update the entry from the From the fcb so we want to update the Uh the record count for a start So load sd a Uh Because that's the only thing that needs copying we now want to Run through the merge algorithm Excuse me. I suppose the reason for doing this is that it's possible to have The same file open more than once That seems like a bad idea to be honest Okay, that's Yeah, I don't quite understand that but this is a big Chunk of complicated code. So I assume it's necessary Also, I am not sure that find first Uh Okay. Yeah, it does set carry if no files were found Does it Let me just double check that because that might explain why opening invalid files produces weird results No more files Does indeed set carry So I'm going to actually merge fcb into drent If there's an error exit That this is going to be fairly fairly small amount of code. So So that can just be branch if carry set to exit set exit and exit now We We do want to mark the Mark the fcb as modified fcb is not modified Okay So we need to do merge fcb into drent And we're going to put that down in the rest of our stupid internal logic They bitmap for drent Bitmap status blah blah blah Where's our Where's the code that actually Looks at The allocation block I can't remember but we were using it in right sequential We have set fcb block up here in read sequential. Well, that doesn't make any sense, but uh We want this code to be recently We want this code to be Located near each other. Okay All right now once the current block number e this is So are we a big disc? Yes That means that Our blocks are two mites. So we are going to load the fcb block number Compare it with the drent block number If they are Hmm Actually, I'm going to do the algorithm for the small disc first because that's going to be easier So and that will let me decide how it's actually supposed to work so uh If the fcb block number is zero then We don't have anything to do No, actually we do we want to we want to update the fcb from the drent in this case if the If the drent block Is zero Update it from the fcb otherwise Compare them If they are not equal Then this means that we have two files open. We've both tried to allocate different blocks for sorry. We have the file open twice and uh There is a conflict at which point we just give up so Merge error We just Fail Go on to the next one and keep going until we hit The end of the allocation map. Okay So that's our algorithm So now we have to do this For 16 bit values rm comma y And we are going to have to increment y again so that Let's actually put some new lines in to split things up a bit So that uh, we're consistent in the position of y Between the two branches of that if okay, so now Current drent comma y Hang on a second if fcb is yep. Okay. I have I flipped both sides of the But the arrow and the order so fcb goes to drent y is low so So now y is pointing at the low byte We want to compare the two do param first increment y comma y And then it's the same error code So in fact we can Like so and then increment y so it points at the next item Check for the end and terminate with success Okay not very I mean the algorithm is is simple enough, but I'm not particularly convinced by my implementation of it so Make Baz So we hang 1 d2 c d e f We're here. So are we a big disc? No, we're doing this version Get the fcb block number. So this will be the one that we've just allocated Nope, that's not a correct block number. So our fcb is at 2 4 2 f And there is indeed a block number there, but we have set the wrong value There is a break at 1 d2 c Okay, get the block number 9 So somehow we managed to write back that Uh that block 8 is in use interesting. I wonder how that happened Anyway Um Is it zero? No Get the drent block. Is it zero? Yes therefore Copy into the drent are they different No, they're not which is a good thing because we've just copied one to the other Go around to the next one get the fcb block number. Is it zero? Yes, it is So we copy from the drent, but that's going to be zero as well, but this is harmless because they're the same Copy in the other direction. This is also going to go through And go around again. So let's just Finish that Edit So we can see that blue here does indeed have A block allocated to it. So there's bars. I don't know why So we see that there are in fact two blocks on disk Both of which are identical, but that's okay. I can dump that And we get 128 bytes of cues these shorter far names Okay, I think this is working The file system image will be extended by the moss operating system as needed I just need to make sure it's size the file is sized correctly I just need to make sure that the Disk definition is correct to make it actually fit on a floppy disk Cool, I think this is working. So we don't have any of the extent management stuff yet So when we reach the end of an extent we want to move to the next one We can't have files bigger than 16k, but I believe it is working. Let's Using make dfs to create a disk Image, okay, boot that from a real disk You see the pause as we get to here. That's because it's reading the next directory sector So I can make a file Oh interesting Right. I know what happened there. So what's happened is it's is uh It's tried to make the cpmfs file bigger So we've we've been dumped back to moss, but it can't Does xx work? Yeah So Uh This is a moss command that shows the names of the files Load address execution address length and start sector Dfs, which is what this is all based on doesn't support fragmented files So it can't make cpmfs any bigger Because the bdos file is In the way so if I kill this off and Change the order in which I add the files Like so Then I run it We see that uh bdos is below cpmfs cpmfs and the sector number. So I run that We should be able to extend the file. Indeed we can And there is our queue excellent Right, we can read and write files Just more files So that is really nice progress Uh, where's my vector table? We need to implement Uh the one The calls here that that we actually wanted to implement So that's going to be one Two three Four five six Seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen Yeah, there's still quite a lot of calls, but Most of the actual logic the hard stuff is done Uh the next bit Is going to be extent management uh, so Here and in fact All this is going to want to do Is to close the current extent to make sure it's been flushed Increment the extent pointer And Uh Open the file again So this is not going to be a lot of code and it's going to be the same code for both read and write Then of course we have to fix all the bugs Okay, so I am going to stop here for now because it's just Because I want to go and have lunch and my scan has finished So that is That's very pleasing. Okay next time extents