print push print off string asis include 'common.equ.src' ;------------------------------------------ ; ; Equates from procedure ; ;------------------------------------------ CallStringToText equ 1 ;conditional code for JudgeName, 14-Apr-91 DAL AllowLCPeriods equ 0 ;conditional code allowing blanks in names, 7-Aug-91 DAL ;(0 = no blanks allowed, 12-Aug-91 GAB) debug_on equ 00 ;00 = debug off, <>0 = debug on word equ 02 ;two bytes for a word blk_size equ 512 ;standard size of a prodos block delimiter equ $3A ;pathname delimiter = ":" min_send_cnt equ $21 ;If read < 33 bytes use local routine vcr_main equ vcr_dev+2 vol_reserved equ $0000 ;8 bytes of reserved field from disk vol_mod equ vol_reserved+2 ;volume mod date vol_create equ vol_reserved+8 ;create date/time from header vol_version equ vol_create+4 ;version of OS that created file vol_min_version equ vol_version+1 ;minimum version of OS that can access vol_access equ vol_min_version+1 ;access for a file vol_entry_len equ vol_access+1 ;entry length of each entry vol_entries equ vol_entry_len+1 ;number of entries per block vol_file_count equ vol_entries+1 ;number of files in volume directory vol_bitmap_addr equ vol_file_count+2 ;starting block of bitmap vol_total_blks equ vol_bitmap_addr+2 ;total number of blocks on disk num_bitmap_blks equ vol_total_blks+2 ;total number of bitmap blocks end_bitmap equ num_bitmap_blks+2 ;1st byte that starts all zeros avail_bitmap equ end_bitmap+2 ;1st bitmap block(rel) with free space curr_bitmap equ avail_bitmap+2 ;current bitmap(rel) block in memory bitmap_dirty equ curr_bitmap+2 ;0 = bitmap clean, <> 0 = bitmap dirty free_blocks equ bitmap_dirty+2 ;Free blocks on volume,$FFFF = unknown vol_damaged equ free_blocks+2 ;stops writing to bad disk if <> 00 dirty_file_cnt equ vol_damaged+2 ;number of files that are open for writing and are dirty bitmap_start equ dirty_file_cnt+4+vcr_main pro_vcr_size equ bitmap_start+$200 bitmap_mod equ $FFFF bitmap_unknown equ $FFFF vcr_entry_length equ $000F fcr_res_num equ $0000 ;resource number of this file fcr_storage equ fcr_res_num+2 ;real storage type on disk fcr_entry_type equ fcr_storage+2 ;storage type from directory entry fcr_file_id equ fcr_entry_type+2 ;used to ID duplicate files fcr_file_type equ fcr_file_id+2 ;file type fcr_key_blk equ fcr_file_Type+1 ;key block of the file fcr_blks_used equ fcr_key_blk+2 ;number of blocks used fcr_eof equ fcr_blks_used+2 ;current end of file fcr_create equ fcr_eof+3 ;create date/time ProDOS fcr_vers equ fcr_create+4 ;version of o/s that made file fcr_min_vers equ fcr_vers+1 ;min version of o/s allowed fcr_disk_acc equ fcr_min_vers+1 ;file access fcr_aux_type equ fcr_disk_acc+1 ;aux type for this file fcr_modified equ fcr_aux_type+2 ;modified date of file fcr_header_ptr equ fcr_modified+4 ;key block of dir owner fcr_status equ fcr_header_ptr+2 ;offset: current status of file gde_entry_num equ fcr_status+2 ;current entry for Get_Dir_Entry gde_offset equ gde_entry_num+2 ;current offset to entry gde_curr_blk equ gde_offset+2 ;current directory block loaded gde_tot_files equ gde_curr_blk+2 ;total files in directory fcr_curr_mark equ gde_tot_files+2 ;current file mark fcr_blks_alloc equ fcr_curr_mark+4 ;current number of blks alloc fcr_curr_eof equ fcr_blks_alloc+2 ;current end of file fcr_parent equ fcr_curr_eof+4 ;block number of directory block fcr_entry_offs equ fcr_parent+2 ;index to entry within parent block data_blk_num equ fcr_entry_offs+2 ;block number of current data block index_blk_num equ data_blk_num+2 ;block number of current index block master_blk_num equ index_blk_num+2 ;block number of master index block clr_global_clean equ $7FFF ;clear the global clean bit set_global_clean equ $8000 ;set the file clean in the FCR set_access_res equ $4000 ;set the resource fork bit in the FCR ClrAllButAccess equ $3FFF ;clear the resource bit from access word. fcr_fst_ptr equ fcr_access+2 fcr_io_start equ master_blk_num+2+fcr_fst_ptr fcr_data_size equ fcr_io_start+$200 fcr_index_size equ fcr_io_start+$400 fcr_master_size equ fcr_io_start+$600 my_pblk_ptr equ fst_start my_vcr_ptr equ my_pblk_ptr+4 prodos_vcr_ptr equ my_vcr_ptr+4 my_fcr_ptr equ prodos_vcr_ptr+4 pro_fcr_ptr equ my_fcr_ptr+4 gbuf_ptr equ pro_fcr_ptr+4 temp_ptr equ gbuf_ptr+4 temp2_ptr equ temp_ptr+4 temp3_ptr equ temp2_ptr+4 temp4_ptr equ temp3_ptr+4 temp5_ptr equ temp4_ptr+4 math_temp equ temp5_ptr+4 data_ptr equ math_temp+4 index_ptr equ data_ptr+4 master_ptr equ index_ptr+4 bitmap equ master_ptr+4 users_buf_ptr equ bitmap+4 sparse_ptr equ users_buf_ptr+4 newline_ptr equ sparse_ptr+4 pro_id equ $0001 ;identifies prodos fst prodos_version equ $0005 ;current version of the PRODOS. path1_mask equ $4000 ;used to determine if path1 is avail. path2_mask equ $0040 ;used to determine if path2 is avail. carry equ $01 ;used to set the carry overflow equ $40 ;used to set the overflow flag in_cache equ $8002 user_cache_val equ $0001 class_mask equ $E000 disk_protect equ $0004 ;bit to see if disk is protected max_base equ $0003 pcount1 equ 1 pcount2 equ 2 pcount3 equ 3 pcount4 equ 4 pcount5 equ 5 pcount6 equ 6 pcount7 equ 7 pcount8 equ 8 pcount9 equ 9 write_call equ $13 read_enabled equ $0001 ;1=Read Enabled write_enabled equ $0002 ;1=Write Enabled backup_enabled equ $0020 ;1=Needs to be backed up rename_enabled equ $0040 ;1=Rename allowed destroy_enabled equ $0080 ;1=Destroy is enabled read_access equ $01 write_access equ $02 invis_bit equ $04 read_write_acc equ $03 seedling_type equ $0010 ;$0000000 < EOF < $0000201 sapling_type equ $0020 ;$0000200 < EOF < $0020001 tree_type equ $0030 ;$0020000 < EOF < $1000000 pascal_area equ $0040 ;Area set aside for Pascal resource_type equ $0050 ;Special type for resource files purge_dir equ $0060 ;directory that contains pugred files subdir_type equ $00D0 ;Subdirectory subdir_header equ $00E0 ;First entry in sudbirectory volume_header equ $00F0 ;First entry in the volume directory vol_dir_start equ $0002 ;start of the volume directory bitmap_strt_blk equ $0006 ;start of the volume bitmap entry_length equ $0027 entries_per_block equ $000D parent_index equ $0027 par_entry_num equ $0029 res_header equ 08 ;number of bytes in a header res_map_size equ 382 ;size of map for info call purge_index equ $0019 ;index to flag indicating purge files. purgable_index equ $0029 ;index to total blocks purge_flag equ $00FE purge_verify equ $0004 header_file_cnt equ $0025 ;number of files in a directory backup_on equ $20 backup_off equ $DF file_type_index equ $10 ;look at page 168 (ProDOS 8 manual) key_blk_index equ $11 ;index into disk entry blks_used_index equ $13 eof_index equ $15 create_index equ $18 version_index equ $1C min_version equ $1D access_index equ $1E aux_type_index equ $1F last_mod_index equ $21 header_ptr_index equ $25 no_root equ $8000 ;indicates root level name is invalid no_dup equ $4000 ;indicates duplicates are not valid root_only equ $2000 ;allow only the root level in pathname vol_mod_offset equ $16 ;offset to the volume mod date field vol_acc_offset equ $22 ;offset to the volume access field dir_file_type equ $0F tool_locator equ $E10000 misc_tools equ $0003 read_time_hex equ $000D ;read the clock via misc_tools set_time_stamp equ $0001 get_time_stamp equ set_time_stamp+$8000 set_upper_case equ $0002 get_upper_case equ set_upper_case+$8000 debugger_cmnd equ $0002 debugger_status equ debugger_cmnd+$8000 file_dirty equ $8000 ;ora masks to active field data_active equ $4000 index_active equ $2000 master_active equ $1000 file_clean equ $7FFF ;and masks to deactivate field data_inactive equ $BFFB index_inactive equ $DFFD master_inactive equ $EFFE dirEntry_dirty equ $0008 dirEntry_clean equ ÅdirEntry_dirty ;'Å' is the assembler's one's complement operator data_dirty equ $0004 data_clean equ $FFFB index_dirty equ $0002 index_clean equ $FFFD master_dirty equ $0001 master_clean equ $FFFE hfs_id equ $0006 ;HFS FST ID ashare_id equ $000D ;AppleShare FST ID finfo_type equ 1 ;HFS FInfo entry type xfinfo_type equ 2 ;HFS xFInfo entry type ;------------------------------------------ ; ; Equates from procedure data ; ;------------------------------------------ drvr_bytes equ $1A ;start at byte $1A and $1B path_used equ $0100 vcr_used equ $0200 fcr_used equ $0400 io_used equ $0800 clr_io_used equ $F7FF flush_1st equ $1000 damage equ $2000 max_class1 equ $0020 max_class2 equ $0040 max_class3 equ $0060 max_class4 equ $0080 max_class5 equ $00A0 max_class6 equ $00C0 max_class7 equ $00E0 max_pcnt1 equ 1+1 max_pcnt2 equ 2+1 max_pcnt3 equ 3+1 max_pcnt4 equ 4+1 max_pcnt5 equ 5+1 max_pcnt6 equ 6+1 max_pcnt7 equ 7+1 max_pcnt8 equ 8+1 max_pcnt9 equ 9+1 max_pcnt10 equ 10+1 max_pcnt11 equ 11+1 max_pcnt12 equ 12+1 max_pcnt13 equ 13+1 max_pcnt14 equ 14+1 max_pcnt15 equ 15+1 max_pcnt16 equ 16+1 max_pcnt17 equ 17+1 do_dirty equ $4000 ;----------------------------------------------- ; ; Forward addresses and entries ; ;----------------------------------------------- ENTRY abs_to_rel ENTRY activate_vcr ENTRY add_free_blk ENTRY add_index ENTRY appl_call ENTRY bitmap_changed ENTRY bitmap_corrupt ENTRY build_path ENTRY build_the_fcr ENTRY build_vcr ENTRY calc_curr_mark ENTRY change_path ENTRY check_base ENTRY check_dup ENTRY check_vcr_first ENTRY chk_allocation ENTRY chk_vol_syntax ENTRY clear_backup ENTRY clear_index ENTRY close ENTRY clr_fcr_status ENTRY clr_to_boundary ENTRY cmd_error ENTRY cmd_tbl ENTRY create ENTRY damaged_message IF debug_on<>0 THEN ENTRY debugger ENDIF ENTRY dec_blk_count ENTRY deferred_flush ENTRY destroy ENTRY dev_with_mount ENTRY device_call ENTRY dow_convert ENTRY end_read_write ENTRY entry_to_gstr ENTRY eof_to_blks ENTRY erase_disk ENTRY fast_read ENTRY fill_io_buf ENTRY find_file ENTRY find_resource ENTRY find_volume ENTRY flush ENTRY flush_blocks ENTRY flush_data_blk ENTRY flush_file ENTRY flush_index ENTRY force_bitmap ENTRY format_disk ENTRY fst_specific ENTRY get_bit_block ENTRY get_data_num ENTRY get_dev_num ENTRY get_dir_entry ENTRY get_eof ENTRY get_file_info ENTRY get_index_blk ENTRY get_mark ENTRY get_next_fcr ENTRY get_time ENTRY get_write_blk ENTRY id_disk ENTRY issue_mount ENTRY judge_name ENTRY kill_bitmap ENTRY load_data ENTRY load_index ENTRY make_entry_num ENTRY mount_volume ENTRY move_dir_entry ENTRY move_vol_entry ENTRY num_seq_blks ENTRY open ENTRY range_error ENTRY read ENTRY read_block ENTRY read_with_cache ENTRY reset_vcr ENTRY sapling_seed ENTRY save_curr_mark ENTRY send_partial ENTRY send_sparse_blk ENTRY send_time ENTRY set_eof ENTRY set_fcr_status ENTRY set_file_info ENTRY set_mark ENTRY set_user_cache ENTRY setup_bitmap_ptr ENTRY setup_curr_eof ENTRY setup_curr_mark ENTRY setup_io_buf ENTRY setup_io_ptrs ENTRY setup_my_fcr ENTRY setup_my_vcr ENTRY setup_name ENTRY setup_vol_mesg ENTRY show_damage ENTRY shutdown ENTRY slug_ripple ENTRY standard_req ENTRY startup ENTRY sub_free_blk ENTRY sys_remove_vol ENTRY sys_tbl ENTRY system_call ENTRY tree_sapling ENTRY update_key_blk ENTRY update_mark_eof ENTRY vol_to_buffer ENTRY volume ENTRY write ENTRY write_block ENTRY Chk_Dirty_Flag ENTRY dirty_flags print pop ;====================================================================== ; ;ProDOS File System Translator for GS/OS ; ;Created: Feb 25, 1987 ;Modified: Mar 16, 1988 ;Author: Rob Turner ; ; ;Copyright Apple Computer Inc. 1987-92 ALL RIGHTS RESERVED ; ;====================================================================== PRINT GEN msb off longa on longi on ;equates for the read call. pblk_12_ref equ $0000 ;index to the reference number pblk_12_buf equ pblk_12_ref+2 ;index to user's buffer pointer pblk_12_req equ pblk_12_buf+4 ;index to request count pblk_12_tran equ pblk_12_req+4 ;index to transfer count pblk_12_cache equ pblk_12_tran+4 ;index to user provided cache priority max_read_pcnt equ $0005 ;equates used by open pblk_10_access equ $000A pblk_10_ftype equ pblk_10_access+2 pblk_10_aux equ pblk_10_ftype+2 pblk_10_storage equ pblk_10_aux+4 pblk_10_eof equ pblk_10_storage+2 pblk_10_num_res equ pblk_10_eof+4 pblk_10_create equ pblk_10_num_res+2 pblk_10_mod equ pblk_10_create+8 pblk_10_blks equ pblk_10_mod+8 pblk_10_map equ pblk_10_blks+4 ;equates used by set_mark pblk_16_base equ $0002 pblk_16_disp equ pblk_16_base+2 ;equates used by get_mark pblk_17_pos equ $0002 ;equates used by get_eof pblk_19_eof equ $0002 ;equates used by send_info pblk_s_access equ $0000 pblk_s_ftype equ pblk_s_access+2 pblk_s_aux equ pblk_s_ftype+2 pblk_s_storage equ pblk_s_aux+4 pblk_s_create equ pblk_s_storage+2 pblk_s_mod equ pblk_s_create+8 pblk_s_opt equ pblk_s_mod+8 pblk_s_eof equ pblk_s_opt+4 pblk_s_blks equ pblk_s_eof+4 pblk_s_res_eof equ pblk_s_blks+4 pblk_s_res_blk equ pblk_s_res_eof+4 ;equates used by volume pblk_08_vol equ $0004 pblk_08_tot equ pblk_08_vol+4 pblk_08_free equ pblk_08_tot+4 pblk_08_id equ pblk_08_free+4 pblk_08_size equ pblk_08_id+2 pblk_08_purge equ pblk_08_size+2 ;equates used by set_file_info pblk_05_accs equ $0004 pblk_05_ftype equ pblk_05_accs+2 pblk_05_aux equ pblk_05_ftype+2 pblk_05_create equ pblk_05_aux+6 pblk_05_mod equ pblk_05_create+8 pblk_05_opt equ pblk_05_mod+8 ;equates used by get_file_info pblk_06_map equ $0028 ;equates used by set_eof pblk_18_odisp equ $0002 pblk_18_base equ $0002 pblk_18_disp equ pblk_18_base+2 ;equates used by create pblk_01_accs equ $0004 pblk_01_ftype equ pblk_01_accs+2 pblk_01_aux equ pblk_01_ftype+2 pblk_01_stype equ pblk_01_aux+4 pblk_01_eof1 equ pblk_01_stype+2 pblk_01_eof2 equ pblk_01_eof1+4 pblk_01_old_time equ $000E ;equates used by get dir entry pblk_1c_extend equ $0002 pblk_1c_disp equ $0002 pblk_1c_name equ pblk_1c_disp+2 pblk_1c_entry equ pblk_1c_name+4 pblk_1c_ftype equ pblk_1c_entry+2 pblk_1c_eof equ pblk_1c_ftype+2 pblk_1c_blks equ pblk_1c_eof+4 pblk_1c_create equ pblk_1c_blks+4 pblk_1c_mod equ pblk_1c_create+8 pblk_1c_access equ pblk_1c_mod+8 pblk_1c_aux equ pblk_1c_access+2 pblk_1c_id equ pblk_1c_aux+4 pblk_1c_opt equ pblk_1c_id+2 pblk_1c_res_eof equ pblk_1c_opt+4 pblk_1c_res_blks equ pblk_1c_res_eof+4 gde_max_base equ $0002 bad_file_format equ $004a ;equates used by judge_name 1/22/91 CAE pblk_07_ntype equ $0002 pblk_07_syntax equ pblk_07_ntype+2 pblk_07_max_len equ pblk_07_syntax+4 pblk_07_name equ pblk_07_max_len+2 pblk_07_nflags equ pblk_07_name+4 ;equates used by change_path 5-Dec-91 MSD pblk_04_src equ $0000 ; (long) source pathname pblk_04_dest equ $0004 ; (long) destination pathname pblk_04_flags equ $0008 ; (word) $8000 = assume source is duplicate volume ; Revisions have been moved to the file "pro.fst.revisions" in the ProDOS project ; by Monte Benaresh on 6/21/90 ;====================================================================== ;Below is the FST header definition used by GS/OS at boot time ;====================================================================== EXPORT fst_header fst_header PROC EXPORT code_start code_start DC.B 'FST ' ;Says I'm a FST DC.L appl_call ;Process a normal application call DC.L system_call ;Process a FST system call DC.W Pro_ID ;My ID number (ProDOS) Export fst_attr fst_attr DC.W $3003 ;(Uppercase pathnames if enabled), formattable, strip high bit. DC.W $0402 ;Version 4.02 final DC.W 512 ;block size DC.L $10000 ;Max Blocks (32 meg) DC.L $0007 ;Min Blocks DC.L $01000000 ;max file size DC.L $0000 ;reserved DC.B 6 DC.B 'ProDOS' string pascal IF debug_on<>0 THEN DC.B 'ProDOS FST w/Debugger v04.02' ELSE DC.B 'ProDOS FST v04.02' ENDIF DC.W 0000 ;reserved field dc.b 'ProDOS FST written by Rob Turner. V4.02' string asis ENDP ;====================================================================== ;Below is the main entry point for ALL standard operating system calls. ; ;Input: X = Call number * 2 ; Y = Class number * 2 ; A = undefined longa on longi on EXPORT appl_call appl_call PROC import max_call import write_occurred import write_dev_num import cp_device_flag import fake_name_str import error_priority phk ;setup our bank register plb rep #$30 cpx #max_call+1 ;check command number bcs cmd_error jmp (cmd_tbl-2,x) ;call the function EXPORT cmd_error cmd_error lda #bad_system_call EXPORT error_exit error_exit sec EXPORT main_exit main_exit IMPORT flags ; If we're reporting an error, then check cp_device_flag to see if we were ; renaming a duplicate volume. If so, we built a vcr with a fake name. Since we ; got an error at some point in the process, we need to find the vcr with the fake ; name and release it if it still exists. 1/22/91 CAE pha ;save the error code php ;save error flag bcc @cont ;branch if no error lda cp_device_flag ;did we build a vcr with a fake name? bpl @cont ;no - so no need to clean up ldx #fake_name_str ;get pointer to fake name string ldy #^fake_name_str lda #0000 ;search by name jsl find_vcr bcs @cont ;didn't find the vcr so we're ok jsl deref ;dereference vcr pointer stx 0 THEN phx ;save X and Y please phy pha php jsr debugger plp pla ply plx ENDIF jml sys_exit ENDP ;====================================================================== ;Below is the main entry point for ALL FST system calls ; ;Input: X = Call number * 2 ; Y = Class number * 2 ; A = undefined EXPORT system_call system_call PROC import max_sys phk ;setup our bank register plb cpx #max_sys+1 ;maximum system calls bcs sys_err jmp (sys_tbl-2,x) ;call system routine sys_err ; lda #bad_system_call rtl ;return error to Jim and Mike ENDP IF debug_on<>0 THEN include 'debugger' ENDIF ;====================================================================== ;Below are my dispatch tables for application and system calls EXPORT dispatch_tables dispatch_tables PROC EXPORT cmd_tbl cmd_tbl DC.W create ;create a file call DC.W destroy ;delete a file DC.W cmd_error DC.W change_path ;rename or move a file or subdir DC.W set_file_info ;alter directory info on a file DC.W get_file_info ;return directory info on a file DC.W judge_name ;judge a name DC.W volume ;return information on a volume DC.W cmd_error ;we don't handle 'Set_Prefix' DC.W cmd_error ;we also don't handle 'Get_Prefix' DC.W clear_backup ;clear the backup bit on a file DC.W cmd_error ;RESERVED DC.W cmd_error ;RESERVED DC.W cmd_error ;RESERVED DC.W cmd_error DC.W open ;open a file or subdirectory DC.W cmd_error ;we don't handle newline DC.W read ;read 'n' bytes from a file DC.W write ;write 'n' bytes to a file DC.W close ;close a file or subdirectoy DC.W flush ;flush a file(s) DC.W set_mark ;set a file marker DC.W get_mark ;return file marker DC.W set_eof ;change EOF of a file DC.W get_eof ;return EOF of a file DC.W cmd_error ;system call DC.W cmd_error ;system call DC.W get_dir_entry ;return a entry from a directory DC.W cmd_error ;RESERVED DC.W cmd_error ;RESERVED DC.W cmd_error ;RESERVED DC.W get_dev_num ;Get_Dev_Num DC.W cmd_error ;GS/OS handles 'Get_Last_Dev' DC.W read_block ;read Block only in ProDOS fst DC.W write_block ;write Block only in ProDOS fst DC.W format_disk ;format media and build directory DC.W erase_disk ;build directory structure DC.W cmd_error ;reserved DC.W cmd_error ;get name DC.W cmd_error ;get boot vol DC.W cmd_error ;quit DC.W cmd_error ;get version DC.W cmd_error ;get fst info DC.W cmd_error ;device info DC.W cmd_error ;device status DC.W cmd_error ;device control DC.W cmd_error ;device read DC.W cmd_error ;device write DC.W cmd_error ;alloc int DC.W cmd_error ;dealloc int DC.W fst_specific ;FST Specific EXPORT end_tbl end_tbl EXPORT Max_call:EQU Max_call equ end_tbl-cmd_tbl ;Last valid call I support EXPORT sys_tbl sys_tbl DC.W startup ;set ready for work DC.W shutdown ;get ready to quit DC.W sys_remove_vol ;remove local data from VCR DC.W deferred_flush ;flush deferred blocks. EXPORT max_sys:equ max_sys equ *-sys_tbl ENDP ; ; 22-Jan-92 MSD: Moved all non-zero items in the data to the start of ; the proc so that all of the zero bytes would be contiguous. This ; should help the FST sparsify itself (and reduce disk space). ; ;====================================================================== ;below are virtual pointers returned by GS/OS. Init these to zero ;on startup EXPORT data data PROC Export dummy_name dummy_name dc.b 'cant.find.me' ;used to calculate the latest mod date dc.w 00 EXPORT time_stamp_opt time_stamp_opt DC.W 02 ;0 = files ; ;1 = files + subdirs ; ;2 = files + subdirs + subdirs to root ; EXPORT dir_offset_tbl dir_offset_tbl DC.W $0004 ;offsets to directory entries within DC.W $002b ;a directory block DC.W $0052 DC.W $0079 DC.W $00A0 DC.W $00C7 DC.W $00EE DC.W $0115 DC.W $013C DC.W $0163 DC.W $018A DC.W $01B1 DC.W $01D8 export fake_name_str fake_name_str DC.W 3 ;fake name string for VCR DC.B $C DC.B $A DC.B $E DC.B $00 export syntax_str syntax_str DC.B end_text-start_text start_text DC.B 'ProDOS names must begin with a letter. ' DC.B 'They may be up to 15 characters long and may contain ' DC.B 'letters, digits' if AllowLCPeriods then ;added 7-Aug-91 DAL DC.B ', spaces' endif ;end 7-Aug-91 DAL DC.B ' and periods.' end_text EXPORT format_header format_header ; DC.W $0000 ;backword link is nill DC.W $0003 ;forward link to block three EXPORT new_vol_name new_vol_name DC.B 00 ;length plus storage type DS.B 15 ;fifteen bytes for the name DS.B 2 ;eight bytes reserved Export new_vol_mod new_vol_mod ds.b 4 ;four byte for the Mod time ds.b 2 ;2 bytes for the case bits EXPORT new_vol_date new_vol_date DS.B 4 ;create date for the volume DC.B prodos_version DC.B 00 ;minimum version (back to SOS 1.0) DC.B $C3 ;access DC.B $27 ;entry length (39) DC.B $0D ;entries per block (13) DC.W $0000 ;file count is nill DC.W $0006 ;bitmap pointer EXPORT new_tot_blks new_tot_blks DC.W $0000 ;total number of blocks on the volume EXPORT control_list control_list ;partion string DC.W $0E ;length increased by 2 7/26/90, see below DC.B 'Apple_PRODOS' dc.b 0,0 ;terminator nulls added 7/26/90 for compatibility with ;Macintosh-side FSM, by Matt Gulick, Monte Benaresh Export key_blk_changed key_blk_changed dc.w 00 ;used by set EOF to indicate that the file changed structure ;====================================================================== ;below is the startup tables for each call. The table contains the ;following data: ; ; 1) Max PCount for the call ; 2) Max Class for the call ; 3) Pathnames used by call ; 4) volume control record used ; 5) file control record used. ; 6) io buffer used (data_ptr,Index_ptr,master_ptr) ; 7) flush file before call ; 8) damaged disk protect ; 9) Check Dirty Flag. ; ; |9|8|7|6|5|4|3| 2 | 1 | ; _|_|_|_|_|_|_|_|_____|_________| ; | | | | | | | | | | | | | | | | | ; |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| ; | | | ; 1 6 0 8 0 0 EXPORT start_tbl start_tbl DC.W max_pcnt7+max_class1+path_used+damage ;Create DC.W max_pcnt1+max_class1+path_used+damage ;Destroy DC.W 0000 DC.W max_pcnt3+max_class1+path_used+damage ;ChangePath ; set max pCount=3 (5-Dec-91 MSD) DC.W max_pcnt12+max_class1+path_used+damage ;SetFileInfo DC.W max_pcnt12+max_class1+path_used ;GetFileInfo DC.W max_pcnt6+max_class1 ;JudgeName DC.W max_pcnt6+max_class1 ;Volume DC.W 0000 DC.W 0000 DC.W max_pcnt1+max_class1+path_used+damage ;ClearBackup DC.W 0000 DC.W 0000 DC.W 0000 DC.W 0000 DC.W max_pcnt15+max_class1+path_used ;Open DC.W 0000 DC.W max_pcnt5+max_class1+vcr_used+fcr_used+io_used ;Read DC.W max_pcnt5+max_class1+vcr_used+fcr_used+io_used+damage+do_dirty ;Write DC.W max_pcnt1+max_class1+vcr_used+fcr_used+io_used ;Close DC.W max_pcnt2+max_class1+vcr_used+fcr_used+io_used+damage ;Flush DC.W max_pcnt4+max_class1+vcr_used+fcr_used+io_used ;SetMark DC.W max_pcnt2+max_class1+fcr_used ;GetMark DC.W max_pcnt3+max_class1+vcr_used+fcr_used+flush_1st+io_used+damage+do_dirty ;SetEof DC.W max_pcnt2+max_class1+fcr_used ;GetEof DC.W 0000 DC.W 0000 DC.W max_pcnt17+max_class1+vcr_used+fcr_used+io_used ;GetDirEntry DC.W 0000 DC.W 0000 DC.W 0000 DC.W max_pcnt2+max_class1+path_used ;GetDevNum DC.W 0000 DC.W 0000 ;ReadBlock DC.W 0000 ;WriteBlock DC.W max_pcnt6+max_class1+path_used ;Format DC.W max_pcnt6+max_class1+path_used ;Erase EXPORT gbuf_addr gbuf_addr DC.L 0 ;pointer to general I/O buffer EXPORT virtual virtual DC.L 0 ;pointer to virtual memory after ; ;a call to 'Get_Segment' EXPORT virtual2 virtual2 DC.L 00 ;====================================================================== ;data storage used EXPORT hours hours DC.W 00 EXPORT minutes minutes DC.W 00 EXPORT year year DC.W 00 EXPORT month month DC.W 00 EXPORT day day DC.W 00 EXPORT day_of_week day_of_week DC.W 00 EXPORT pro_time pro_time DC.L 00 Export write_occurred write_occurred dc.w 00 ;IF non-zero on exit then a write occurred Export write_dev_num ;device number that was written too write_dev_num dc.w 00 Export curr_mod_date curr_mod_date dc.l 00 Export case_bits ;case bits for the last pathname case_bits dc.w 00 Export case_bit_pattern case_bit_pattern dc.w 00 EXPORT src_dev_num src_dev_num DC.W 00 ;used by change path EXPORT src_start_blk src_start_blk DC.W 00 ;'' EXPORT src_dir_blk src_dir_blk DC.W 00 ;'' EXPORT src_offset src_offset DC.W 00 EXPORT slug_block slug_block DC.W 00 ;for slug ripple 'to root time stamp' EXPORT slug_offset slug_offset DC.W 00 EXPORT close_flag close_flag DC.W 00 ;used to determine if we should call ; ;slug_ripple from flush_file ; EXPORT src_slug_blk src_slug_blk DC.W 00 ;used by change_path EXPORT src_slug_offset src_slug_offset DC.W 00 EXPORT dest_slug_blk dest_slug_blk DC.W 00 EXPORT dest_slug_offset dest_slug_offset DC.W 00 EXPORT dest_dev_num dest_dev_num DC.W 00 ;used by change path EXPORT dest_start_blk dest_start_blk DC.W 00 ;'' EXPORT dest_dir_blk dest_dir_blk DC.W 00 ;'' EXPORT dest_offset dest_offset DC.W 00 EXPORT vol_rename_flag vol_rename_flag DC.W 00 ;'' EXPORT direct_page direct_page DS.B $4C ;used when we must mount a volume EXPORT my_direct my_direct DS.B $78 ;'' EXPORT world_flag world_flag DC.W 00 ;detect re-entrent code EXPORT def_dir_page def_dir_page DS.B $4C ;used when we flush deferred blocks EXPORT def_my_direct def_my_direct DS.B $78 ;'' EXPORT def_vol_name def_vol_name DS.B 20 EXPORT alloc_chk_flag alloc_chk_flag DC.W 00 ;used by write routine EXPORT seq_write_start seq_write_start DC.L 00 ;pointer used by write routine EXPORT seq_write_cnt seq_write_cnt DC.W 00 ;sequential block counter EXPORT seq_write_blk seq_write_blk DC.W 00 ;starting block for sequential write EXPORT path_searched path_searched DC.W 00 ;set by find file. ; EXPORT last_blk last_blk DC.W 0 ;used by find_file to verify ; ;directory structure ; ; EXPORT search_flag search_flag DC.W 00 ;flag used by process path ; ; bit 15 = volume name not allowed ; ; bit 14 = search for new entry ; ; bit 13 = volume only allowed ; EXPORT dir_start_blk dir_start_blk DC.W 00 ;starting block of a directory EXPORT dir_last_blk dir_last_blk DC.W 00 ;last block read by find file EXPORT free_dir_blk free_dir_blk DC.W 00 ;1st dir block with a free entry EXPORT free_dir_offset free_dir_offset DC.W 00 ;offset to free entry in dir block EXPORT searching_free searching_free DC.W 00 ;flag that is used by Find_File EXPORT blks_used1 blks_used1 DC.W 00 ;blks needed for data fork. (create) EXPORT blks_used2 blks_used2 DC.W 00 ;blks needed for res. fork. (create) EXPORT blocks_needed blocks_needed DC.W 00 ;total blocks needed for files. (create) EXPORT data_storage data_storage DC.W 00 ;storage type for data fork EXPORT res_storage res_storage DC.W 00 ;storage type for resource fork EXPORT res_tot_blks res_tot_blks DC.W 00 ;used by create EXPORT res_key_blk res_key_blk DC.W 00 ;'' EXPORT some_free some_free DC.W 00 ;used by find_free_blks EXPORT volume_name volume_name DS.B 20 ;holds the volume name of an input str EXPORT gstring gstring DS.B 20 ;holds gstrings EXPORT search_length search_length DC.W 00 ;used by 'find_file' routine EXPORT search_name search_name DS.B 17 EXPORT fcr_wanted fcr_wanted DC.W 00 ;used by check_dup routine EXPORT key_block key_block DC.W 00 ;used by check_dup routine EXPORT find_this_entry find_this_entry DC.W 00 ;used by get dir entry EXPORT entry_sto_type entry_sto_type DC.W 00 EXPORT storage_type storage_type DC.W 00 ;used by open EXPORT alloc_entry alloc_entry DC.B 00 ;used to give entry name a length word EXPORT one_entry one_entry DS.B 40 ;holds one directory entry EXPORT files_key_block files_key_block DC.W 00 ;used by open EXPORT hold_path_ptr hold_path_ptr DC.W 00 EXPORT data_eof data_eof DC.L 00 ;used by create EXPORT res_eof res_eof DC.L 00 ;used by create EXPORT tree_key_blk tree_key_blk DC.W 00 ;used by create EXPORT tree_blks tree_blks DC.W 00 ;used by create EXPORT parent_blk parent_blk DC.W 00 ;used by the open routine EXPORT entry_offset entry_offset DC.W 00 ;used by the open routine EXPORT num_of_res num_of_res DC.W 00 ;used by open EXPORT newline_len newline_len DC.W 00 EXPORT newline_mask newline_mask DC.W 00 EXPORT newline_char newline_char DC.W 00 EXPORT base base DC.W 00 ;used with calls that have base param EXPORT displacement displacement DC.L 00 ;used with calls that have displacement EXPORT purge_addr purge_addr DC.W 00 ;block address of purgable files EXPORT new_last new_last DC.W 00 ;used to cut back eof (SET_EOF) EXPORT bitmap_blks bitmap_blks DC.W 00 ;used to calc_free_blks EXPORT last_bitmap last_bitmap DC.W 00 ;'' '' EXPORT first_free first_free DC.W 00 ;'' '' EXPORT bits bits DC.W 00 ;used to count bits in calc_free_blks EXPORT alloc_count alloc_count DC.W 00 ;used by find_free_blks EXPORT alloc_start alloc_start DC.W 00 ;'' EXPORT byte_offset byte_offset DC.W 00 ;'' EXPORT mark_changed mark_changed DC.W 00 ;used by fill_io_buf (setmark=EOF case) EXPORT user_cache user_cache DC.W 00 ;default cache value for file reads EXPORT create_time create_time DC.L 00 ;used by set_file_info EXPORT mod_time mod_time DC.L 00 ;used by set_file_info EXPORT first_free_bm first_free_bm DC.W 00 EXPORT index_blks index_blks DC.W 00 ;number of indexes needed for tree files EXPORT data_indexes data_indexes DC.W 00 ;used by create EXPORT res_indexes res_indexes DC.W 00 ;used by create. EXPORT entries_blk_num entries_blk_num DC.W 00 EXPORT files_examined files_examined DC.W 00 EXPORT files_in_dir files_in_dir DC.W 00 EXPORT pcount pcount DC.W 00 EXPORT resource_num resource_num DC.W 00 EXPORT access access DC.W 00 EXPORT and_mask and_mask DC.W 00 EXPORT curr_mark curr_mark DC.L 00 EXPORT curr_eof curr_eof DC.L 00 EXPORT tran_cnt tran_cnt DC.L 00 EXPORT user_req_cnt user_req_cnt DC.L 00 EXPORT entries_checked entries_checked DC.W 00 EXPORT chars_checked chars_checked DC.W 00 EXPORT name_length name_length DC.W 00 EXPORT flush_entry flush_entry dc.w 00 ;allows us to flush only the I/O buffer EXPORT Users_access users_access dc.w 00 ;used during the open call Export dirty_flags ;flags at the beginning of the call dirty_flags dc.w 00 Export flush_flags flush_flags dc.w 00 ;used by the flush routines export chk_dirty_flag ;flag used to indicate that the call can cause dirty blocks chk_dirty_flag dc.w 00 export dirty_cnt_changed dirty_cnt_changed dc.w 00 ;indicates that we have changed the dirty_cnt once export new_eof new_eof dc.l 00 ;used by set EOF export cp_device_flag cp_device_flag DC.W 00 ;1 = ChangePath using device name, else 0 export cp_flags ;Added 5-Dec-91 MSD cp_flags DC.W 00 ;$8000 = assume source is duplicate volume export cp_to_child ; non-zero if ChangePath trying to move an item cp_to_child dc.w 00 ; into its own child (i.e. :A:B to :A:B:C). export hfs_flag hfs_flag DC.W 00 ;1 = we have HFS Finder Info, else 0 export hfs_finfo hfs_finfo DS.B 32 ;storage area for HFS Finder Info export error_priority error_priority DC.W 00 ;storage for error priority ;====================================================================== ;Data used by Format and Erase disk calls EXPORT format_ctrl format_ctrl DC.W 00 ;length of control list EXPORT status_list status_list DC.W 00 ;status code EXPORT return_blks return_blks DC.L 00000 ;number of blocks on device EXPORT entries_offset entries_offset dc.w 00 ;offset to directory entry export gde_temp gde_temp dc.w 00 ; temp used by GetDirEntry ;driver save area EXPORT drvr_save drvr_save DS.B $1b ;save room for direct page ;equates used by 'setup_params' EXPORT class class DC.W 00 EXPORT max_pcount max_pcount DC.W 00 EXPORT flags flags DC.W 00 *** added 28-Feb-92 DAL ; ; Used by chk_disk_protect to save the first 512 bytes of GBUF ; export chk_protect_gbuf chk_protect_gbuf ds.b 512 *** end 28-Feb-92 DAL ENDP expand_record Record expand_flag dc.w 00 expand_file dc.w 00 ;used to indicate we are extending a file expand_storage dc.w 00 ;storage type of the data fork on extension expand_key_blk dc.w 00 expand_blks_used dc.w 00 expand_eof dc.l 00 endr ;========================================================================== ; Prodos universal boot loader. This is the second stage boot ; for all apple manufactured Apple II disk drives. ; It is located at block zero (0) of a ProDOS formatted disk(ette). ; Support for Apple /// has been removed to save space. ; ;Rev History: ; ;Jan 12, 1988 By Rob Turner ; ; Removed Apple /// (SOS) support and converted source to APW ; ;Jun 02, 1988 By Rob Turner ; ; Changed the boot code to handle a sparse ProDOS file. ; ;========================================================================== boot_code_start proc endp msb off longa off longi off MACHINE M6502 EXPORT boot_code boot_code PROC temporg $000800 dcmd equ $42 ;disk command (=1 for read) unit equ $43 ;(16*slot)+(128*(drive-1)) buff equ $44 ;ram address blok equ $46 ;disk address dent equ $48 ;device call entry address. idxl equ $4a ;pointer to low page of index block idxh equ $4c ;pointer to high page of index block idxp equ $4e ;index byte pointer. iobuff equ $60 ; the following are for disk ii only: dbuf equ $26 slotz equ $2b oddbits equ $3c sector equ $3d trktmp equ $40 track equ $41 prior equ $50 trkn equ $51 rtrycnt equ $52 curtrk equ $53 trkcnt equ $54 * q6l equ $c08c motoron equ $c089 motoroff equ $c088 phaseoff equ $c080 nbuf1 equ $300 dnib equ $2d6 * directory dependent stuff... clrscrn equ $fc58 scrn equ $5b1 ;5ae dostyp equ $ff sosid equ $c00 entlen equ sosid+$23 kernel equ $2000 zzstart equ $09F2 rd1 equ $09F2 rd1a equ $09F7 mod1 equ $0008 chg1 equ $FFF4 rd2 equ $09FB rd3 equ $0A05 mod2 equ $001E chg2 equ $FFD7 mod3 equ $0024 rdhd0 equ $0A15 chg3 equ $FFD1 rdhd1 equ $0A17 rdhd2 equ $0A19 rdhd3 equ $0A1B rdhd4 equ $0A23 mod4 equ $003F chg4 equ $FFB6 mod5 equ $0045 chg5a equ $0A38 mod6 equ $0047 chg6 equ $FFB4 rddt1 equ $0A3A rddt1a equ $0A3C rddt2 equ $0A3E rddt3 equ $0A4E rddt4 equ $0A50 rdchk equ $0A5F mod7 equ $0076 chg7 equ $FFAC nxttwo equ $0A6B twobit equ $0A6D zzzend equ $0A7F chg5 equ $004B goseek equ $0A83 ;========================================================================== ;Main Entry Point For Booting Apple II Computer. ;========================================================================== xboot DC.B $01 ;(prodos boot id) entry sec ;(apple iii enters xboot 'ora $38') bcs entry1 ;branch if not apple iii native mode. jmp booterr ;Apple /// Boot. entry1 sei ;disable interupts so we can boot on the IIGS with debugger stx unit ;save unit number. cmp #$03 ;for disk ii. php ;save result, it may be irrelevent. txa ;find out if disk ii. and #$70 ;strip drive # if any. lsr a lsr a ;get slot address. lsr a lsr a ora #$c0 sta dent+1 ldy #$ff ;look at last byte. sty dent plp ;restore carry (if disk ii & sect 0&2 read carry set). iny ;make y=0 lda (dent),y ;get device entry addr. bne ndsk2 ;branch if not disk ii (16 sector). bcs isdsk2 ;branch if it is disk ii, but block 0 read. lda #3 ;make rom read only sector 2 sta xboot ;to complete block 0 inc sector ;(was = 1) lda dent+1 ;do rts to re-enter rom. pha lda #$5b pha rts ;go read sector 2 into $900. isdsk2 sta trktmp ;make sure previous track =0 sta dent ;and dent points at beginning of slot ldy #$5e ;move code from card to ram mvboot lda (dent),y sta zzstart-$5e,y iny cpy #$eb ;have we moved enough? bne mvboot ldx #6 ;now modify code to handle errors. modboot ldy mods,x lda chgs,x sta zzstart,y lda endcode,x sta zzzend,x dex bpl modboot lda #>d2io ;reset device entry sta dent+1 ; to point at disk ii routines. lda #|<-------- Y Register --------->| ; | | | ; |<--high Byte-->|<--low Byte-->|<--high Byte-->|<--low Byte-->| ; _______________________________________________________________ ; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ; | year | month | day |0 0 0| hour |0 0| minute | ; |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| ; ; ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: all register ; get_time (Subroutine that reads time) ; hours,minutes (data words) ; year,month,day ; longa on longi on EXPORT pack_time pack_time PROC stz pro_time stz pro_time+2 jsr get_time ;read the time from tool set ;We call this entry point if the time parameters are setup and need ;only to be convert to the ProDOS format. EXPORT convert_time convert_time lda day sta pro_time ;save the day in prodos format lda month asl a asl a asl a asl a asl a ;shift to correct position ora pro_time ;month is now happy sta pro_time lda year ; 27-Jan-92 MSD: Years outside the range 1940..2039 will be converted ; to "unknown" (i.e. all zeroes). cmp #40 ; less than 1940? blt @bad_year cmp #140 ; 2040 or greater? bge @bad_year cmp #100 ; 2000..2039? blt @got_year ; no, so leave as is sbc #100 ; convert 2000..2039 to 0..39 @got_year ; End 27-Jan-92 MSD xba asl a ;shift year to upper 7 bits ora pro_time sta pro_time tax ;return in X register too lda minutes sta pro_time+2 lda hours xba ora pro_time+2 sta pro_time+2 tay ;return in Y register clc ; 27-Jan-92 MSD: valid date/time rts @bad_year ; year was bad, set date/time ldx #0 ; to "unknown" (all zeroes). txy stx pro_time sty pro_time+2 sec ; 27-Jan-92 MSD: invalid date/time rts ENDP ;====================================================================== ;unpack_time: This routine will unpack a prodos time into a GS/OS time. ; ;Input: A = undefined ; ;Format of time: ; ; |<-------- X Register --------->|<-------- Y Register --------->| ; | | | ; |<--high Byte-->|<--low Byte-->|<--high Byte-->|<--low Byte-->| ; _______________________________________________________________ ; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ; | year | month | day |x x x| hour |x x| minute | ; |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| ; ; P = nvmxdizc ; ..000..0 ; b = k ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; hours (Times are all hex format) ; minutes ; year ; month ; day ; day_of_week ; ;Uses: all register ; dow_convert (Subroutine) ; longa on longi on EXPORT unpack_time unpack_time PROC stx pro_time sty pro_time+2 ;Init time to zero (unknown) jsr zero_date txa ora pro_time+2 beq end_unpack lda pro_time and #$001F ;isolate day sta day cmp #32 ;valid days are 01 to 31 bcs zero_date ;sorry bud you get unknown tay ;save for DOW convert txa ;get year/month/day again (X is still valid here) lsr a lsr a lsr a lsr a lsr a and #$000F ;isolate month sta month cmp #13 ;is the month 13 or >? bcs zero_date tax lda pro_time xba lsr a and #$007F ;isolate the year cmp #40 ;year = 40-99? bcs @store_it ;yes, must be 1940-1999 adc #100 ;else must be 2000-2039, adjust @store_it sta year jsr dow_convert ;go ahead and calculate the day of week sta day_of_week lda pro_time+2 and #$003F ;isolate minutes sta minutes cmp #60 bcs zero_date lda pro_time+2 xba and #$001F ;isolate hours sta hours cmp #24 bcc end_unpack zero_date ;indicate that the date is unknown stz hours stz minutes stz year stz month stz day stz day_of_week end_unpack rts ENDP ;====================================================================== ;DOW_Convert:This routine convert Month,Day,Year into day of week ; ;Input: A = Year ; X = Month ; Y = Day ; P = saved ; b = k ; ;Output: A = day of week ; X = undefined ; Y = undefined ; P = restored ; b = k ; ;Uses: all register ; local temps ; longa off longi off EXPORT dow_convert dow_convert PROC php sep #$30 phy tay ;Figure the number of leap years since 1900 lsr a lsr a sta dow_temp ;If it's a leap year and it's Jan or Feb subtract 1 from the total tya ;get the year back and #%00000011 bne stim015 cpx #03 bcs stim015 dey ;add the number of leap years elapsed, the year, a constant for the ;month, and the day stim015 clc tya ;get the year again adc dow_temp ;# of leap years since 1900 adc wkmon-1,x adc 1,s ply ;clean the stack ;Now mod the result by seven, but exit in the range [1..7] sec stim016 ; sbc #07 cmp #08 bcs stim016 plp ;restore mode rts dow_temp DC.B 0 wkmon DC.B $08,$0B,$0B,$07,$09,$0C,$07,$0A,$0D,$08,$0B,$0D ENDP ;====================================================================== ;get_time: This routine will read the time from the GS Clock. ; ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..0 ; b = k ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; hours,minutes ; year,month,day ;all are setup with the time ; day_of_week ; ;uses: Misc tools ;(Gets hex time) ; ;====================================================================== longa on longi on EXPORT get_time get_time PROC lda #0000 ;setup default time to zero pha ;minutes,seconds result pha ;year,hour results pha ;month,day results pha ;weekday,null results ldx #(read_time_hex*$100)+misc_tools jsl tool_locator longa off sep #$20 pla ;disregard seconds pla sta minutes pla sta hours pla sta year pla bcs no_inc1 inc a no_inc1 sta day ;convert 0 to 30 -> 1 to 31 pla bcs no_inc2 inc a no_inc2 sta month ;convert 0 to 11 -> 1 to 12 pla ;null field pla sta day_of_week longa on rep #$30 rts ENDP ;============================================================================ ; ;Calc_Bit: This routine will convert a 16 bit block number into ; the correct index into the bitmap block, the correct pattern ; to indicate which bit it is, and which relative block in the ; bitmap contains the bit ; ;Input: X = Block number to convert ; m = 0 ; x = 0 ; b = k ; ;Output: A = Bit Pattern (Which bit that needs to be changed) ; Y = Byte offset into bitmap block that contains bit ; X = Relative Block number of the bitmap that contains the bit ; Carry Clr ; All other flags undefined ; ;Uses: Local Table ; All registers ; EXPORT calc_bit calc_bit PROC txa ;X=Block number and #$0007 ;isolate bit index tay lda bit_table,y ;get the bit pattern and #$00FF ;table is a byte table pha txa ;now isolate byte index and #$0FF8 lsr a lsr a lsr a tay ;Y=Offset into bitmap block jsr abs_to_rel ;absolute to relative block number pla ;A=Bit pattern rts EXPORT abs_to_rel abs_to_rel clc txa ;now isolate relative block number and #$F000 rol a rol a rol a rol a rol a tax ;X=Relative block number in bitmap rts bit_table DC.B $80,$40,$20,$10,$08,$04,$02,$01 ENDP ;============================================================================ ;Alloc_block This routine will allocate a block in the bitmap. ; If the block is not in memory then it will load it. ; ;Input: X = Block number that you want to allocate ; m = 0 ; x = 0 ; b = k ; prodos_vcr_ptr ; ;Output: carry clr = no error ; carry set = could not allocate ; A = error code if carry set ; 01 = User would not mount the volume ; all flags undefined ; ;Uses: All Registers ; Calc_bit (Subroutine) ; Get_Bit_block (Subroutine) ; bitmap_changed (Subroutine) ; EXPORT alloc_block alloc_block PROC jsr calc_bit ;calculate bit(A),byte(Y),block(X) pha phy jsr get_bit_block ;load the correct block if needed ply pla tax ;save mask bcs done ;could not load block from disk and [bitmap],y ;is the block already allocated? beq bitmap_corrupt ;the bitmap is in bad shape, sorry. txa ;restore the AND mask eor #$FFFF ;we need to flip the patterns and [Bitmap],y ;clear the correct bit sta [bitmap],y jsr bitmap_changed ;update bitmap flags jsr sub_free_blk ;adjust free block count done rts EXPORT bitmap_corrupt bitmap_corrupt ;we get here if the bitmap is corrupt lda #damaged_bitmap sec rts ;return the error EXPORT sub_free_blk sub_free_blk ldy #free_blocks lda [prodos_vcr_ptr],y inc a beq who_knows dec a ;$FFFF = major problem dec a sta [prodos_vcr_ptr],y who_knows clc rts ENDP ;============================================================================ ;DeAlloc_block This routine will deallocate a block in the bitmap. ; If the bitmap block is not in memory then it will load it. ; The routine will also update the free block count if needed ; ;Input: X = Block number that you want to deallocate ; m = 0 ; x = 0 ; b = k ; prodos_vcr_ptr (must be setup) ; my_vcr_ptr (must be setup) ; ;Output: carry clr = no error ; carry set = could not allocate ; A = error code if carry set ; 01 = User would not mount the volume ; all flags undefined ; ;Uses: All Registers ; Calc_bit (Subroutine) ; Get_Bit_block (Subroutine) ; EXPORT dealloc_block dealloc_block PROC jsr calc_bit ;calculate bit(A),byte(Y),block(X) phx pha phy jsr get_bit_block ;load the correct block if needed ply pla plx bcs done ;could not load block from disk pha ;save the mask please and [bitmap],y ;is the block already deallocated? beq no_prob ;the block is currently allocated pla ;fix the stack bra bitmap_corrupt ;return the error please no_prob ; pla ;restore the mask please ora [bitmap],y ;set the correct bit sta [bitmap],y ;We have just deallocated some blocks so lets make sure the first bitmap block ;that contains available space is correct for the current VCR ldy #avail_bitmap txa ;relative block number cmp [prodos_vcr_ptr],y ; ; 2/3/90 Mensch, Hauser,Benaresh ; ; Rob says that avail_bitmap should *ALWAYS* be equal to the lowest bitmap ; block that has space in it. So, the branch that was a BEQ should really be ; a BCS (BGE) this way, so it will work right. ; bge go_changed ;the relative block num is the same ;If we freed up a block in a previously full bitmap then lets update the VCR sta [prodos_vcr_ptr],y go_changed jsr add_free_blk EXPORT bitmap_changed bitmap_changed clc ;========================================================================== ;This routine will mark the current bitmap block dirty. NOTE: This routine ;must not change the state of the carry. ldy #bitmap_dirty lda #bitmap_mod ;bitmap modified sta [prodos_vcr_ptr],y done rts ;========================================================================== ;This routine will add one to the free block count for a volume. If the ;number of free blocks is unknown then the routine will just exit. EXPORT add_free_blk add_free_blk ldy #free_blocks lda [prodos_vcr_ptr],y inc a ;$FFFF = free block count unknown beq end_free ;free block count is not known sta [prodos_vcr_ptr],y end_free rts ENDP ;========================================================================== ;get_bit_block: This routine will load in the correct bitmap block from ; disk. If the correct block is already loaded then the ; routine will just exit. ; ;Input: A = undefined ; X = relative block number to load ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; prodos_vcr_ptr (must be setup correctly) ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; bitmap (points to bitmap buffer) ; drvr_buf_ptr (same as bitmap) ; ;Uses: All registers ; device_call ; drvr_call_num ; longa on longi on EXPORT get_bit_block get_bit_block PROC phx ;save the block number jsr setup_bitmap_ptr stx drvr_buf_ptr stx bitmap sty drvr_buf_ptr+2 sty bitmap+2 pla ;retore relative block number sta math_temp ldy #curr_bitmap cmp [prodos_vcr_ptr],y beq good_exit pha ;force dirty bitmap block back to disk if needed. jsr force_bitmap ;force the bitmap to disk bcc flushed plx rts flushed ;If we get here we have to calculate the right block to read into memory pla clc ldy #vol_bitmap_addr adc [prodos_vcr_ptr],y sta drvr_blk_num jsr read_with_cache bcc read_ok jsr kill_bitmap sec rts ;return the error read_ok ;Now we need to update the current bitmap ldy #curr_bitmap lda math_temp sta [prodos_vcr_ptr],y good_exit clc rts ENDP ;========================================================================== ;calc_free_blks This routine will calculate the number of blocks that are ; free on a volume. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; prodos_vcr_ptr (must be setup correctly) ; drvr_dev_num (must be setup up) ; ;Output: A = error code if carry set otherwise total blocks free ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; device_call ; I/O buffer ; longa on longi on EXPORT calc_free_blks calc_free_blks PROC ;before we start going to disk lets see if we already know the number of ;free blocks. IF free_blocks = $FFFF then free blocks are unknown. ldy #free_blocks lda [prodos_vcr_ptr],y inc a beq go_figure ;we need to calculate it dec a ;A = total blocks clc rts go_figure jsr force_bitmap ;flush the bitmap if needed ;setup the buffer pointer to the general I/O buffer provided by GS/OS shell stz first_free_bm ;indicate that we do not know free cnt ;First lets see if there is already a bitmap buffer allocated. If so ;lets use it as our I/O buffer. jsr setup_bitmap_ptr stx drvr_buf_ptr sty drvr_buf_ptr+2 ;read 512 bytes from the disk. jsr standard_req ;go do a run on the bitmap calculating the number of blocks free stz math_temp ;counts the free blocks ldy #vol_bitmap_addr lda [prodos_vcr_ptr],y sta drvr_blk_num ;starting block number of bitmap ldy #num_bitmap_blks lda [prodos_vcr_ptr],y sta bitmap_blks ;number of blocks in the bitmap ldy #end_bitmap ;first byte that should be all zeros lda [prodos_vcr_ptr],y sta last_bitmap ldy #avail_bitmap lda [prodos_vcr_ptr],y inc a beq block_loop dec a tay ;save start clc adc drvr_blk_num ;adjust the starting block number sta drvr_blk_num phy sec lda bitmap_blks ;number of blocks to scan sbc 1,s ;subtract start block number sta bitmap_blks pla block_loop jsr read_with_cache ;read in a block bcc read_ok jsr kill_bitmap sec rts ;we should not get any errors bad_bitmap lda #damaged_bitmap sec rts read_ok ;update the current bitmap in memory field. sec ldy #vol_bitmap_addr lda drvr_blk_num sbc [prodos_vcr_ptr],y ldy #curr_bitmap sta [prodos_vcr_ptr],y ;if this is the last block of the bitmap then verify ending with zeros. dec bitmap_blks bne not_last ldy last_bitmap ;starting location that must be zero beq not_last ;don't bother zero_loop cpy #$01FF ;are we near the end of the block? bcs setup_index ;If we are this close the end lda [drvr_buf_ptr],y bne bad_bitmap iny iny bra zero_loop setup_index ldy last_bitmap tya lsr a ;is it an even value? bcc word_loop ;Yes, so fall into loop iny ;make it even if it is not cpy #$01FE ;is it now greater then one block bcc word_loop ;no so fall into the loop not_last ldy #$01FE ;start scanning the block word_loop lda [drvr_buf_ptr],y bne count_bits return_loop dey dey bpl word_loop ;keep scanning the block please lda bitmap_blks ;see if we are done beq calc_done ;we are done inc drvr_blk_num ;read next block please bra block_loop ;Check to see if we already know the first bitmap block that contains ;free blocks. IF we do then just count the blocks free count_bits sta bits ;save bitmap word lda first_free_bm bne cont_count ;We now know the first bitmap block that contains available blocks, so lets ;save it please. phy sec ldy #vol_bitmap_addr lda drvr_blk_num sta first_free_bm sbc [prodos_vcr_ptr],y ldy #avail_bitmap sta [prodos_vcr_ptr],y ply cont_count ldx #16 ;cycle thru word 16 times lda bits ;get the bit count back inc a ;special case $FFFF to speed calc beq add_16 bit_loop dex bmi return_loop ;we have scanned the word lsr bits bcc bit_loop inc math_temp ;advance the count please bra bit_loop add_16 clc lda math_temp adc #$0010 ;$FFFF = 16 blocks free sta math_temp bra return_loop ;When we get here we have counted all the blocks that are marked as free. ;Now we need to see if there are any blocks marked as purgable. calc_done lda math_temp ;number of blocks free ;Now lets update the VCR to indicate that we know the number of free blocks save_and_exit ldy #free_blocks sta [prodos_vcr_ptr],y ;total free count jsr set_user_cache ;restore cache ('A' and 'P' preserved) clc rts EXPORT kill_bitmap kill_bitmap pha lda #bitmap_unknown ;flag bitmap as unknown ldy #curr_bitmap sta [prodos_vcr_ptr],y pla rts ENDP ;========================================================================== ;find_free_blks This routine will scan the bitmap looking for a sequence ; of blocks that are marked as free. The routine will always ; try to allocate the blocks in one large group. If a group ; cannot be found to satisfy the request count then this ; routine will allocate the first available block. ; At least one block MUST be free for allocation!!!!!!!!!! ; ;Input: A = number of blocks to allocate. ( 'n' blocks) ; X = starting block number for search. (might be minus 7 blks) ; prodos_vcr_ptr (must be setup) ; ^avail_bitmap (must be valid) ; ;output: A = error or number of blocks allocated. (1 or 'n') ; X = starting block number of allocated blocks ; P = nvmxdizc ; ..000..1 = no blocks allocated (error) ; 0 = allocated ; ;uses: calc_bits ; math_temp ; longa on longi on EXPORT find_free_blks find_free_blks PROC sta alloc_count ;number of blocks to allocate stx alloc_start ;starting block number for search stx first_free jsr calc_bit ;absolute blk to relative blk. ; ; calc_bit results: ; ;A = bit mask $80 $40 $20 $10 $08 $04 $02 $01 ;Y = byte offset in the bitmap buffer ;X = relative block number that contains the block number passed as input ; sty byte_offset ;starting byte in block xba align_loop ; ;set blk num to byte boundary asl a ;check bit position of user block num bcs chk_avail ;ok here dec first_free bra align_loop ;check next bit chk_avail lda byte_offset ;are we word aligned? lsr a bcc aligned ;yes we are OK dec byte_offset ;now set starting block to word boundary sec lda first_free sbc #$0008 sta first_free ;everything should be word aligned now. aligned txa ldy #avail_bitmap ;see if start is >= first free cmp [prodos_vcr_ptr],y bcs start_ok ;start is >= first free lda [prodos_vcr_ptr],y tax ror a ror a ror a ror a ror a ;calc starting block number sta first_free ;ex. rel blk #1 = blk #4096 or $1000 txa stz byte_offset start_ok stz last_blk ;starting block for caller stz math_temp ;reset the free block counter tax ;now load in the bitmap block next_blk lda math_temp pha ;save temp count jsr get_bit_block bcc got_block ply ;fix the stack rts ;return error please got_block pla ;reset temp count sta math_temp stz some_free ;indicates if ANY blocks are free! ldy byte_offset ;start looking here for 1st free block cpy #$01FF ;are we near then end? bcc next_word ldy #$01FE next_word ldx #16 ;scan all 16 bits lda [bitmap],y ;get a bitmap word (16 blocks) bne check_16 ;sorry no bits here. stz math_temp ;reset the counter please. stz last_blk bra no_change check_16 xba ;put bits in the right order sta bits sta some_free ;there are free blocks in this dir. inc a ;check 16 please bne scan_loop ; ;special case of all sixteen blocks allocated ; clc lda math_temp adc #16 ;easy case sta math_temp lda last_blk ;do we have the starting blk yet? bne chk_req_cnt ;we already have start block lda first_free sta last_blk chk_req_cnt lda math_temp ;see if we are done cmp alloc_count bcs req_filled ;request filled. We are done!!! no_change clc lda first_free adc #16 ;bump block number sta first_free bra bump_index ;go get the next word scan_loop lda math_temp ;see if we are done cmp alloc_count bcs req_filled ;request filled. We are done!!! asl bits ;see if this block is available bcc reset_count ;a used block inc math_temp ;add one to block count lda last_blk bne next_bit lda first_free sta last_blk ;update start block bra next_bit reset_count stz math_temp ;reset the counter stz last_blk ;reset start block next_bit ; inc first_free ;bump the block number dex bne scan_loop lda math_temp ;see if we are done cmp alloc_count bcs req_filled ;request filled. We are done!!! bump_index iny iny cpy #$01FF ;are we done? bcc next_word ;not yet ldy #curr_bitmap ;current loaded bitmap block lda [prodos_vcr_ptr],y inc a ;convert 0 to 'n' to 1 to 'n'+1 ldy #num_bitmap_blks cmp [prodos_vcr_ptr],y bcs find_one ;no more bitmap blocks to search! jsr bump_1st_free ;bump to next block if needed. stz byte_offset ;reset byte offset ldx first_free jsr abs_to_rel ;calc relative block number jmp next_blk ;load in the next block find_one ; ;allocate one block only lda #$0001 ldx #$0000 ;start at block 0 jsr find_free_blks rts ;now we need to update the bitmap blocks! req_filled ldx last_blk ldy alloc_count dey ;convert 1 to 'n' -> 0 to 'n-1' alloc_loop ; phy ;number of blocks wanted phx ;block number to allocate jsr alloc_block ;mark the block as used! plx ply bcs bad_news inx ;allocate the next block dey bpl alloc_loop lda alloc_count ;user request satisfied ldx last_blk ;starting block for allocation clc ;no error bad_news rts bump_1st_free lda some_free ;is this block empty? bne bad_news ;no... ldy #avail_bitmap ;bump avail to next block if needed lda [prodos_vcr_ptr],y ldy #curr_bitmap cmp [prodos_vcr_ptr],y bne bad_news ldy #avail_bitmap lda [prodos_vcr_ptr],y inc a sta [prodos_vcr_ptr],y rts ENDP ;====================================================================== ;free_vcr: This routine will free all memory associated with a ; volume control record. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; my_vcr_ptr (Points to main VCR) ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; release_seg (system routine to release a vcr) ; ;====================================================================== longa on longi on EXPORT free_vcr free_vcr PROC lda [my_vcr_ptr] ;get the volume ID jsl release_vcr ;and call the systems nuke vcr routine rts ENDP ;====================================================================== ;Remove_fcr: This routine will remove a FCR ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; my_fcr_ptr (must be setup) ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; ;====================================================================== longa on longi on EXPORT remove_fcr remove_fcr PROC ldy #dirty_file_cnt ;check if bitmap needs to be flushed lda [prodos_vcr_ptr],y dec a bne @did_flush ;we do not need to flush the bitmap jsr force_bitmap ;force a dirty block to disk bcs @error ;we have to be able to flush @did_flush ldy #vcr_open_cnt ;subtract one from the open count lda [my_vcr_ptr],y dec a bmi die_die_die ;the system is very sick sta [my_vcr_ptr],y ;Update the open count in the VCR lda [my_fcr_ptr] ;reference number to remove jsl release_fcr ;nuke the puppy clc ;we are very happy now @error rts die_die_die lda #'SK' jml sys_death ENDP ;====================================================================== ;setup_params This routine is called at the beginning of each system ; call. It will setup parameters and verify certain fields ; of the os call. If a VCR is used and the media is swapped ; out of the system then the system mount routine will be called ; ;Input: A = undefined ; X = two times the call number ; Y = two times the class ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = class of call/2 (MUST be last instruction before RTS!!) ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pcount (contains pcount for call. 0=class0) ; my_pblk_ptr (points past pcount to first param) ; my_vcr_ptr (if available) ; prodos_vcr_ptr ; my_fcr_ptr (if available) ; pro_fcr_ptr ; ;Uses: All registers ; math_temp ; pcount ; ;What the table looks like and what fields we verify. ; ; 1) Max PCount for the call ; 2) Max Class for the call ; 3) Pathnames used by call ; 4) volume control record used ; 5) file control record used. ; 6) io buffer used. ; 7) flush file to disk ; 8) damaged disk protect ; ; |8|7|6|5|4|3| 2 | 1 | ; ___|_|_|_|_|_|_|_____|_________| ; | | | | | | | | | | | | | | | | | ; |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| ; | | | ; 1 6 0 8 0 0 ; longa on longi on EXPORT setup_params setup_params PROC ;First we load the flags from the start table and save them for later ;use. lda gbuf_addr ;setup the general buffer pointer sta gbuf_ptr lda gbuf_addr+2 sta gbuf_ptr+2 stz drvr_vol_id ;zero the volume ID(for Mike). Allow each call to set it up stz search_flag ;indicate normal find file stz prodos_vcr_ptr stz prodos_vcr_ptr+2 stz my_vcr_ptr stz my_vcr_ptr+2 stz pro_fcr_ptr stz pro_fcr_ptr+2 stz case_bits ;indicate that the case is all upper. stz slug_block ;indicate no slug_ripple stz close_flag ;indicate that 'flush_file' will not ; ;call slug_ripple stz expand_record.expand_file stz expand_record.expand_flag stz chk_dirty_flag ;do not check the VCR to see if the file is dirty stz dirty_flags stz dirty_cnt_changed stz write_occurred ;If non-zero a write occurred to the disk. stz cp_device_flag ;indicate normal ChangePath 1/22/91 CAE stz cp_flags ;assume not a duplicate volume 5-Dec-91 MSD stz error_priority ;error priority is 0 3/05/91 CAE lda start_tbl-2,x ;get the flags for the call sta flags and #$001F sta max_pcount ;Go ahead and setup the default parameters. stz pcount ;Now verify the max class of the call. ; ;To do this we divide class by two and compare to the calls max class tya lsr a sta class beq class0 ;this is a OLD style call lda flags and #$00E0 ;clear other flags please asl a asl a asl a xba cmp class bcs good_class lda #invalid_class bra error_out good_class ;Now we need to verify the max pcount for the new class calls lda [param_blk_ptr] cmp max_pcount bcc good_pcount lda #invalid_pcount ;Carry has to be set before calling error_out!! error_out jmp main_exit good_pcount ;We get here if the pcount is good. We also get here with a 'BCC' ;so if this changes we must add a CLC to the following 'ADD' sta pcount lda param_blk_ptr ;CARRY CLEAR on entry!!!! adc #$0002 sta my_pblk_ptr lda param_blk_ptr+2 adc #$0000 sta my_pblk_ptr+2 bra cont01 class0 lda param_blk_ptr sta my_pblk_ptr lda param_blk_ptr+2 sta my_pblk_ptr+2 cont01 ldx #pro_id ;setup FST number for our FST. stx drvr_fst_num jsl lock_mem ;make sure data blocks do not move lda dev_num ;move the device number to driver sta drvr_dev_num ;direct page area ;when we get here we know that both class and pcount are valid. ;now we need to check if a VCR or FCR is used by the call. lda flags and #vcr_used beq check_fcr ;no VCR is used by the call ;setup my pointer to the VCR and deref VP to my local data. ldx vcr_ptr ldy vcr_ptr+2 jsl deref stx my_vcr_ptr sty my_vcr_ptr+2 jsr setup_my_vcr stx prodos_vcr_ptr sty prodos_vcr_ptr+2 lda flags ;do we need to check damage? and #damage beq vol_ok ;this must be a read only call. ldy #vol_damaged ;is this volume damaged?? lda [prodos_vcr_ptr],y inc a ;Have I already showed the error message bne vol_ok ;the disk is not damaged sec lda #invalid_access ;get the error code please jmp main_exit vol_ok ; ldy #vcr_status ;see if the volume is swapped out lda [my_vcr_ptr],y and #vcr_swapped beq check_fcr ;the volume is online. lda call_number ;see if this is a close call. and #$DFFF ;get rid of the class please cmp #$0014 ;Compare class zero close call number bne @do_mount ;we must do a mount message ldy #bitmap_dirty ;See if the Bitmap is dirty lda [prodos_vcr_ptr],y bne @do_mount ;we need the disk bad!!! ldy #dirty_file_cnt ;see if there open files on disk that are dirty? lda [prodos_vcr_ptr],y beq check_fcr ;no open dirty files so skip mount. @do_mount jsr mount_volume ;force the user to put our disk online check_fcr lda flags and #fcr_used beq check_path ;no FCR is used by the call ;setup my pointer to the FCR and deref VP to my local data. ldx fcr_ptr ldy fcr_ptr+2 jsl deref stx my_fcr_ptr sty my_fcr_ptr+2 jsr setup_my_fcr ;build pointer to local data stx pro_fcr_ptr sty pro_fcr_ptr+2 lda flags ;do we need to flush the file? and #flush_1st beq check_path ;no flush needed ldy #fcr_status ;see if the file is dirty lda [pro_fcr_ptr],y and #file_dirty beq check_path ;file is clean! jsr setup_io_ptrs jsr flush_file ;force dirty blocks to disk tax lda flags ;clear IO needed bit and #clr_io_used sta flags txa bcc check_path jmp main_exit ;Moved the check_path code into a seperate routine and we now ;only check for bad spans after we have located the target vol ;and determined that it is indeed a ProDOS volume. ; 10/10/91 JEV check_path ; lda flags ; and #path_used ; beq check_io_buf ;no pathname is used ;See if there are any pathnames available ; lda path_flag ; and #path1_mask ; beq check_path2 ; lda span1 ; beq bad_span ;added 11/12/90 CAE ; cmp #$0010 ; bcc check_path2 ;bad_span sec ;added 11/12/90 CAE ;backup lda #bad_path_syntax ; brl error_out ;check_path2 ; ;We don't check span2 here if we are doing a change path call ;we need to do some preprocessing first so that error priority ;gets setup properly for the change path call.. added 8/21/91 JEV ; lda call_number ;see if this is a changepath call. ; and #$DFFF ;get rid of the class please ; cmp #$0004 ;Compare with changepath call number ; beq check_io_buf ;just continue ; lda path_flag ; and #path2_mask ; beq check_io_buf ; lda span2 ; beq bad_span ;added 11/12/90 CAE ; cmp #$0010 ; bcs backup check_io_buf ; lda flags and #io_used beq end_buf_setup ;now we need to setup real pointers to the I/O buffer. There is only ;one I/O buffer for a file. However, the I/O buffer varies in it's size ;and structure. jsr setup_io_ptrs end_buf_setup lda flags ;see if we need to check for file dirty and #do_dirty beq @exit sta chk_dirty_flag ; 00 = do not check ldy #fcr_status ;get the status out of the File Control Record lda [pro_fcr_ptr],y and #file_dirty+data_dirty+index_dirty+master_dirty sta dirty_flags ;save the flags @exit lda class rts ENDP ;====================================================================== ;check_spans This routine is called when a pathname is used and we ; we need to verify that the spans are valid. If they ; are incorrect then we bail out. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = error code ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; EXPORT check_spans check_spans PROC lda path_flag and #path1_mask beq check_path2 lda span1 beq bad_span cmp #$0010 bcc check_path2 bad_span sec backup lda #bad_path_syntax jmp main_exit check_path2 ; lda path_flag and #path2_mask beq @spans_ok lda span2 beq bad_span cmp #$0010 bcs backup @spans_ok rts ENDP ;====================================================================== ;process_path This routine is called when a pathname needs to be ; processed and located on the disk. If the pathname is ; not a prodos name then we bail out. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = error code ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; drvr_buf_ptr (points to the file entry) ; entry_offset (offset to entry within I/O buffer) ; parent_blk (entries parent block address) ; ;Uses: All registers ; math_temp ; pcount ; longa on longi on EXPORT process_path process_path PROC lda #in_cache ;put directories in the cache sta drvr_cache lda #path1_mask ;and mask for path_flag ldx path1_ptr ldy path1_ptr+2 jsr build_path bcc @chk_root_only brl dev_or_vol ;No path just a device # or vol. name @chk_root_only lda search_flag ;do we allow a pathname? and #root_only beq @path_ok lda #bad_path_syntax sec rts ;return error to caller @path_ok ;If we fall thru then we know that there is a pathname to find. ;We also know that there is either a volume name or device. stx hold_path_ptr sty hold_path_ptr+2 lda dev_num ;There is a device number beq cont01 ;Find Volume Name sta drvr_dev_num ;next call removed 2/26/90 by Monte Benaresh ;leaving the call in doesn't let the user swap a new volumeÉ ;Éinto a device and specify a device name in the path ;jsr check_vcr_first ;see if we have a vcr for it ;bcc find_path ;we do? ;Look on a specific device go_id_disk lda drvr_dev_num jsr id_disk ;go and find out if it is our disk ;this also allocates a VCR if needed bcc find_path ;I own the disk. jmp main_exit ;return error to GS/OS cont01 ; jsr vol_to_buffer jsr find_volume ;locate the volume bcc find_path jmp main_exit find_path lda #$8000 ;indicate that we found the volume 3/5/91 CAE sta error_priority ;and it's a ProDOS volume 3/5/91 CAE ;So it's one of our volumes, now check to see if we are using paths, and ;the spans are ok. 10/10/91 JEV lda flags and #path_used beq check_damage ;no pathname is used jsr check_spans ;so check them check_damage lda flags ;is this a call to check the disk and #damage beq vol_good jsr setup_my_vcr ;setup the pointer first stx prodos_vcr_ptr sty prodos_vcr_ptr+2 ldy #vol_damaged ;see if the volume is damaged lda [prodos_vcr_ptr],y beq vol_good lda #dir_error ;write protected jmp damaged_message vol_good ; lda drvr_dev_num ldx hold_path_ptr ldy hold_path_ptr+2 jsr find_file ;try to locate the file bcc save_parent cmp #drvr_disk_sw ;was the media switched? beq go_id_disk bit search_flag ;is 'file not found' ok for this call? bvc not_ok ;no, tell caller about the error cmp #file_not_found bne not_ok ;this error cannot be handled! sec rts ;tell caller that an error occured. not_ok ; sec jmp main_exit save_parent ; sta entry_offset ;offset to the entry within the blk lda drvr_blk_num ;block number of parent sta parent_blk cont02 stx drvr_buf_ptr ;save pointer to name sty drvr_buf_ptr+2 process_exit ; jsr set_user_cache rts ;If we get here we know that there is no pathname to process. ;We also know if there is no device number then 'volume_name' contains ;a volume name that I am suppose to open. dev_or_vol ; lda dev_num beq use_vol_name ;we must have a volume name. jsr id_disk ;go and find out if it is our disk bcs to_main_exit ;Before we check to see if the volume name is legal we must see if the ;volume is online. The reason we do this is to be compatible with P16. ; ;Example: ; Create '/VOLUME' ;If '/VOLUME' is online then ; ;the error returned is 'BadPath' ; Create '/VOLUME' ;If '/VOLUME' is offline then ; ;the error returned is 'VolNotFound' ; its_mine lda #$8000 ;indicate that we found the volume 3/5/91 CAE sta error_priority ;and it's a ProDOS volume 3/5/91 CAE check_root bit search_flag ;is a root level valid? bpl continue1 ;no problem with root level. lda #bad_path_syntax sec to_main_exit ; jmp main_exit ;return error to M.A. and J.J. continue1 ; lda [drvr_buf_ptr] ;points to volume name ora #volume_header ;add back in the storage type sta [drvr_buf_ptr] lda #vol_dir_start sta parent_blk lda #$0004 sta entry_offset bra process_exit use_vol_name ; jsr find_volume ;locate the volume bcc its_mine jmp main_exit EXPORT set_user_cache set_user_cache ; pha ;save entry offset lda user_cache ;set cache to user setting sta drvr_cache pla rts ENDP ;====================================================================== ;send_info This routine is called when we need to return the ; informational parameters from a directory entry. ; This routine is called by 'OPEN' and 'GET_FILE_INFO' ;WARNING: ; This routine assumes parameters are in a certain order. ; I did this so I could use that same routine across several ; calls! ; ;Input: A = number of entries to send ; X = low word pointer to start of parameters ; Y = high word pointer to start of parameters ; P = nvmxdizc ; ..000... ; b = k ; ; one_entry (contians the info to send) ; drvr_buf_ptr (points to resource header block) ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; math_temp ; temp_ptr ; one_entry ; time_routines ; longa on longi on EXPORT send_info send_info PROC stx temp_ptr sty temp_ptr+2 ;Save the number of entries the user wants. sta math_temp tax bne continue rts ;First we return the access as it is stored on disk. continue ; lda call_number ;is this a class one call? and #$2000 beq class0 lda one_entry ;is this a volume entry? and #$00F0 ;isolate the storage type cmp #volume_header bne not_vol stz one_entry+aux_type_index not_vol ; cmp #subdir_type ;is it a subdir or volume? bcc class0 ;no stz one_entry+blks_used_index class0 ; ldy #pblk_s_access lda one_entry+access_index and #$00E7 sta [temp_ptr],y dec math_temp bne send_two end_send1 clc rts ;If we are here then we know the user wants the file type as well send_two ; ldy #pblk_s_ftype lda one_entry+file_type_index and #$00FF sta [temp_ptr],y dec math_temp beq end_send1 ;Now the user wants the aux type! ldy #pblk_s_aux lda one_entry+aux_type_index sta [temp_ptr],y iny iny lda #$0000 sta [temp_ptr],y dec math_temp beq end_send1 ;Also send the storage type of the file ldy #pblk_s_storage lda one_entry and #$00F0 lsr a lsr a lsr a lsr a sta [temp_ptr],y dec math_temp beq end_send1 ;Now convert the create date and send it to. send_five ; ldx one_entry+create_index ldy one_entry+create_index+2 jsr unpack_time ldy #pblk_s_create jsr send_time dec math_temp beq end_send1 ;Now convert the modification data and time ldx one_entry+last_mod_index ldy one_entry+last_mod_index+2 jsr unpack_time ldy #pblk_s_mod jsr send_time dec math_temp beq @go_to_end ; We now store the ProDOS FST ID in the 5th byte of the option list buffer ldy #pblk_s_opt ;index to option list pointer lda [temp_ptr],y ;get the address of the option list buffer tax iny iny lda [temp_ptr],y tay bne @save_fst_id txa beq @skip_save @save_fst_id pei temp_ptr ;save the working temp_ptr since I am going to use it pei temp_ptr+2 ;to handle the option list pointer stx temp_ptr sty temp_ptr+2 ; ;Now I need to verify the option list length. I need at least 6 bytes. ; lda [temp_ptr] ;get the length of the option list cmp #$0004 ;is the minimum count OK bcc opt_range_err ;the user doesn't even have the minimum size>>>> tax ;save the count for data area check lda #$0002 ;length of the ProDOS FST ID. tay sta [temp_ptr],y ;save the number of bytes stored txa cmp #$0006 bcc opt_size_error iny iny lda #pro_id sta [temp_ptr],y ;new code added 2/13/91 CAE txa cmp #6+32 ;is buffer big enough to hold HFS Finder Info? bcc @no_info ;no lda one_entry ;yes - so check storage type and #$00F0 cmp #resource_type ;is it a resource file? bne @no_info ;no - so no HFS info jsr get_hfs_info ;yes - so get the HFS info if we have it @no_info ;end of new code pla sta temp_ptr+2 ;restore pla sta temp_ptr @skip_save dec math_temp ;Option List is included in PCount @go_to_end beq end_send ;Give the EOF as well. If the storage type is a resource file then I will ;get the EOF info from the resource block instead of the directory entry ldy #pblk_s_storage lda one_entry and #$00F0 cmp #resource_type beq send_res_eof ldy #pblk_s_eof ;send the EOF for the file lda one_entry+eof_index+2 and #$00FF tax lda one_entry+eof_index jsr store_longword dec math_temp beq end_send ldy #pblk_s_blks ;send the number of blocks used lda one_entry+blks_used_index ldx #$0000 jsr store_longword dec math_temp beq end_send ldy #pblk_s_res_eof ;send the resource eof backup ; lda #$0000 tax jsr store_longword dec math_temp beq end_send ldy #pblk_s_res_blk ;send the number of blocks used by res bra backup ;please send a zero Mr. ProDOS. end_send clc rts opt_range_err pla sta temp_ptr+2 ;restore pla sta temp_ptr lda #parm_range_err sec rts opt_size_error pla sta temp_ptr+2 ;restore pla sta temp_ptr lda #buff_too_small sec rts ;Send the EOF and blocks used from the header block. send_res_eof ; ldy #$0000 ;go get the info please from fork 1 jsr get_res_info ;A/X = EOF, Y = Blocks Used phy ;save the blocks used field ldy #pblk_s_eof ;send the EOF for the file jsr store_longword ldy #pblk_s_blks ;send the Blocks used pla ;restore the Blocks used field dec math_temp ;now see if they want blocks used. beq end_res_send ;not today kind sir. ldx #$0000 jsr store_longword dec math_temp ;are we done beq end_res_send ldy #$0100 ;go get the info please from fork 2 jsr get_res_info ;A/X = EOF, Y = Blocks Used phy ldy #pblk_s_res_eof ;send the EOF for the file jsr store_longword ldy #pblk_s_res_blk ;send the Blocks used pla ;restore the Blocks used field dec math_temp ;are we done beq end_res_send ldx #$0000 ;send the blocks used by the res. fork jsr store_longword end_res_send ; rts ;========================================================================== ;Grab the information from the resource block. first fork starts at ;offset $0000 in the header block. The second fork starts at offset $0100 ;in the resource header block. ; ;format: storage_type (1 byte) ; key_block (2 bytes) ; blocks_used (2 bytes) ; eof (3 bytes) get_res_info ; lda [drvr_buf_ptr],y and #$0003 ;check the storage type beq file_dead ;this file is DOA cmp #(tree_type/$10)+1 bcs file_dead iny ;point to Key Block iny iny ;point to Blocks used lda [drvr_buf_ptr],y pha ;save blocks used for later iny iny ;point to EOF lda [drvr_buf_ptr],y pha ;save EOF low iny iny lda [drvr_buf_ptr],y and #$00FF ;clear any garbage tax ;save EOF high pla ;A = EOF Low ply ;Y = Blocks used rts ;A/X = EOF (A = Low) Y = Blocks Used file_dead ; sec ;sorry bad news lda #bad_store_type jmp main_exit ;no escape now! ;========================================================================== ;Get the HFS Finder Info if it has been stored in the resource block. ;The Finder Info is stored immediately after the mini-entry for the data fork, ;so it begins at offset $0008 in the block. ; ;format: entry size (1 byte) ; entry type (1 byte) ; HFS Finder Info (16 bytes) ; entry size (1 byte) ; entry type (1 byte) ; HFS Finder Info (16 bytes) ; ; entry_size = 18 ; entry_type = 1 for first 16 bytes of Finder Info (FInfo) ; 2 for second 16 bytes of Finder Info (xFInfo) ; ;Note - the ProDOS FSM which runs on the Mac, has the ability to store only ; the first 16 bytes of Finder Info or only the second 16 bytes. So, we ; can't assume that both entries exist, or that they exist in a specific ; order. ;========================================================================== entry get_hfs_info get_hfs_info ;added 2/13/91 CAE stz hfs_flag ;indicate that we have no HFS info ldx #30 @zero_loop stz hfs_finfo,x ;zero out storage area for HFS info dex ;since we may only find 1 entry dex bpl @zero_loop ldy #8 @loop lda [drvr_buf_ptr],y ;get entry size from resource block and #$00ff ;only want 1 byte cmp #18 ;is it the right size for HFS info? bne @done ;no - so we're done iny lda [drvr_buf_ptr],y ;yes - so get the entry type and #$00ff ;only want 1 byte cmp #finfo_type ;is it the first 16 bytes of HFS info? bne @cont ;no ldx #0 ;yes - so init index into storage area jsr get_finfo ;and get the info bra @loop ;loop @cont cmp #xfinfo_type ;is it the second 16 bytes of HFS info? bne @done ;no - so we're done ldx #16 ;yes - so init index into storage area jsr get_finfo ;and get the info bra @loop ;loop @done lda hfs_flag ;did we find any HFS info? beq @exit ;no - so nothing to copy ldx #0 ;init offsets ldy #6 @copy_loop lda hfs_finfo,x ;copy the HFS Finder Info into the sta [temp_ptr],y ;option list buffer iny iny inx inx cpx #32 bcc @copy_loop ldy #2 lda #2+32 sta [temp_ptr],y ;adjust the # of bytes stored @exit rts ;return get_finfo iny ;adjust offset lda #8 ;we're going to copy 8 words @loop pha ;save counter lda [drvr_buf_ptr],y ;copy HFS Finder Info sta hfs_finfo,x ;into storage area iny ;adjust offsets iny inx inx pla ;retrieve counter dec a bne @loop ;loop until done inc hfs_flag ;indicate that we found some HFS info rts ;and return ;========================================================================== store_longword ; sta [temp_ptr],y ;store low order 16 bits of EOF iny iny txa ;now store the upper 16 bits and #$00FF sta [temp_ptr],y rts ;====================================================================== ;This routine will store the time into the user's parameters block EXPORT send_time send_time ; lda minutes xba ;swap minutes and seconds sta [temp_ptr],y iny iny lda hours sta [temp_ptr],y iny lda year sta [temp_ptr],y iny lda day beq zero_day ;the day is unknown dec a ;convert to misc. tools hex format zero_day ; sta [temp_ptr],y iny lda month beq zero_month dec a ;convert to misc. tools hex format zero_month ; sta [temp_ptr],y iny lda day_of_week xba ;swap day of week and null byte sta [temp_ptr],y rts ENDP ;====================================================================== ;chk_protected: This routine will see if a volume is write protected. ; ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; drvr_dev_num ;must be setup. ; ;Output: A = status Word ;see if driver ERS ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; ; b = k ; ; ;Uses: All registers ; longa on longi on EXPORT chk_protected chk_protected PROC jsr save_drvr lda #drvr_status ;issue a status call to the device sta drvr_call_num lda #^status_list ;setup a pointer to the status list sta drvr_slist_ptr+2 lda #status_list sta drvr_slist_ptr lda #$0006 ;a six byte request count sta drvr_req_cnt stz drvr_req_cnt+2 lda #blk_size sta drvr_blk_size stz drvr_stat_code ;issue a 'driver status' call. jsr device_call ;blast off!! bcs status_error ;An error? lda status_list ;get the return status status_error php pha jsr restore_drvr pla plp rts save_drvr ldx #drvr_bytes ;number of bytes to save save_it lda drvr_dev_num,x sta drvr_save,x dex bpl save_it rts restore_drvr ldx #drvr_bytes restore_it lda drvr_save,x sta drvr_dev_num,x dex bpl restore_it rts EXPORT chk_disk_protect chk_disk_protect stz chk_prot_swap ; haven't got disk switched yet (20-Dec-91 MSD) lda my_vcr_ptr ;see if we have a VCR ora my_vcr_ptr+2 beq do_chk ;go ahead and do the check ldy #vcr_status ;do I need to status the disk? lda [my_vcr_ptr],y and #vcr_wr_enable beq do_chk ;yes we need to check the media rts ;just return to the caller do_chk ; jsr chk_protected ;is the disk protected? bcs big_problem tax and #$0010 ;is the disk offline? beq not_in_drive ;there is no disk!!! txa and #$0001 ;disk switched?? bne not_in_drive ;disk has been switched! txa and #disk_protect bne is_protected lda my_vcr_ptr ;see if we have a VCR ora my_vcr_ptr+2 beq no_change ;go ahead and set the vcr status flag ldy #vcr_status ;set the 'No Status' bit lda [my_vcr_ptr],y ora #vcr_wr_enable ;no need to do the status next time sta [my_vcr_ptr],y no_change txa ;restore original status word rts is_protected sec lda #drvr_wr_prot ;return write protect error to caller big_problem jmp main_exit not_in_drive ; ; Begin 20-Dec-91 MSD ; ; We got a disk switched status, so try to find the volume (ask the user if necessary). ; This will force a new VCR to be built, and my_vcr_ptr will point to it. ; lda chk_prot_swap ; already switched once? bne do_disk_sw ; yes, so return disk switched error inc chk_prot_swap ; found one disk swithced status *** added 28-Feb-92 DAL and GAB -- Save GBUF and important direct page stuff jsr save_drvr pei >16 pea chk_protect_gbuf pea 0 pea $0200 ; move 512 bytes pea move_sinc_dinc jsl move_info *** end 28-Feb-92, part one jsr mount_volume ; find the volume and build a VCR for it *** added 28-Feb-92 DAL and GAB -- Restore GBUF and important direct-page stuff php pha jsr restore_drvr pea chk_protect_gbuf>>16 pea chk_protect_gbuf pei 15 characters? -- 1/12/92 AEN bcc vol_name_loop ;no, keep copying lda #bad_path_syntax ;else we've got a bad pathname sec jmp main_exit loop_end tax ;save the terminating reason lda #$0000 ;terminate the string with a null byte sta volume_name+1,y dey ;adjust string length sty volume_name txa rts ; ;This routine will save the case bits for the last piece of the pathname and ;will convert the input string to all uppercase. ; Export set_case_bits set_case_bits pha phx phy ldy #$0000 ;start at the first character please @outter_loop lda #$4000 ;arm the case bit mask please sta case_bit_pattern stz case_bits @inner_loop lda [temp_ptr],y ;get the user's input character please and #$00FF ;now check delimiters beq @end_of_string cmp #delimiter beq @next_part ;do the next part of the path please if AllowLCPeriods then ;added 7-Aug-91 DAL cmp #' ' bne @not_a_blank lda #'.' bra @was_a_blank @not_a_blank endif ;end 7-Aug-91 DAL cmp #$0061 ;check if we need to convert to upper case. "a" bcc @no_upper cmp #$007B ;check "z"+1 bcs @no_upper and #$00DF ;convert to upper case @was_a_blank tax ;save the character please lda case_bit_pattern ora case_bits sta case_bits ;save the case bit for this character txa @no_upper sep #$20 ;8 Bit store sta [temp_ptr],y ;save the character back please rep #$20 ;back to 16 bit mode lsr case_bit_pattern iny ;move to the next position please bra @inner_loop @next_part iny ;advance to the next part of the pathname bra @outter_loop @end_of_string ply plx pla rts ENDP ;========================================================================== ;Move_vol_name: This routine will move the volume name pointed to by ; drvr_buf_ptr into the buffer pointed to by the address ; in the X and Y registers ; ;Input: A = undefined ; X = low word pointer to the destination buffer ; Y = high word pointer to the destination buffer ; P = nvmxdizc ; ..000... ; b = k ; ; drvr_buf_ptr ;points to the volume header in blk two ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; temp_ptr ; longa on longi on EXPORT move_vol_name move_vol_name PROC stx temp_ptr sty temp_ptr+2 lda [drvr_buf_ptr] and #$000F ;isolate name length sta [temp_ptr] ;save the length in word format tay clc lda temp_ptr adc #$0002 sta temp_ptr bcc ar1 inc temp_ptr+2 ar1 ; longa off sep #$20 move_loop ; lda [drvr_buf_ptr],y sta [temp_ptr],y dey bne move_loop longa on rep #$20 rts ENDP ;========================================================================== ;set_default_buf: sets up the default buffer pointer ; ; ;Enter: jsr ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: A register ; longa on longi on EXPORT set_default_buf set_default_buf PROC lda gbuf_addr ;setup the general I/O buffer sta drvr_buf_ptr lda gbuf_addr+2 sta drvr_buf_ptr+2 rts EXPORT standard_req standard_req ; lda #blk_size sta drvr_req_cnt stz drvr_req_cnt+2 rts ENDP ;====================================================================== ;setup_my_vcr: this routine sets up a pointer to the prodos specific ; volume control record. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; my_vcr_ptr (Points to main VCR) ; ;Output: A = undefined ; X = low word of prodos vcr ; Y = high word of prodos vcr ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; my_vcr_ptr ; longa on longi on EXPORT setup_my_vcr setup_my_vcr PROC clc lda my_vcr_ptr adc #vcr_dev+2 ;start of local data for vcr tax lda my_vcr_ptr+2 adc #$0000 tay rts ENDP ;====================================================================== ;setup_my_fcr: this routine sets up a pointer to the prodos specific ; file control record data. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; my_fcr_ptr (Points to main FCR) ; ;Output: A = undefined ; X = low word of prodos fcr ; Y = high word of prodos fcr ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; my_fcr_ptr ; longa on longi on EXPORT setup_my_fcr setup_my_fcr PROC clc lda my_fcr_ptr adc #fcr_access+2 ;start of local data for fcr tax lda my_fcr_ptr+2 adc #$0000 tay rts ENDP ;====================================================================== ;setup_io_ptrs this routine sets up pointers to the active data buffers ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; my_fcr_ptr (Points to main FCR) ; pro_fcr_ptr (points to specific data) ; ;Output: A = undefined ; X = low word of prodos vcr ; Y = high word of prodos vcr ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; my_fcr_ptr ; math_temp ; longa on longi on EXPORT setup_io_ptrs setup_io_ptrs PROC stz data_ptr ;init the pointers stz index_ptr stz master_ptr stz data_ptr+2 stz index_ptr+2 stz master_ptr+2 lda #fcr_io_start sta math_temp ;save the start of the I/O buffer ldy #fcr_status ;see if master index is active lda [pro_fcr_ptr],y and #master_active beq no_master ;there is no master index block clc lda my_fcr_ptr adc math_temp sta master_ptr lda my_fcr_ptr+2 adc #$0000 sta master_ptr+2 jsr next_block ;bump the pointer to the next block no_master ; ldy #fcr_status ;see if there is an index block lda [pro_fcr_ptr],y and #index_active beq no_index ;there is no index block clc lda my_fcr_ptr adc math_temp sta index_ptr lda my_fcr_ptr+2 adc #$0000 sta index_ptr+2 jsr next_block ;bump the pointer to the next block no_index ; ldy #fcr_status ;see if there is a data block lda [pro_fcr_ptr],y and #data_active beq end_io_setup ;there is no data block clc lda my_fcr_ptr adc math_temp sta data_ptr lda my_fcr_ptr+2 adc #$0000 sta data_ptr+2 end_io_setup ; rts next_block ; clc lda math_temp adc #blk_size sta math_temp rts ENDP ;====================================================================== ;setup_bitmap_ptr: This routine will return a pointer to the bitmap ; buffer and setup 'bitmap' to point to the bitmap buffer ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; my_vcr_ptr (Points to main VCR) ; ;Output: A = undefined ; X = low word of bitmap ; Y = high word of bitmap ; P = nvmxdizc ; ..000... ; b = k ; ; bitmap (bitmap pointer is setup) ; ;Uses: All registers ; my_vcr_ptr ; longa on longi on EXPORT setup_bitmap_ptr setup_bitmap_ptr PROC clc lda my_vcr_ptr adc #bitmap_start ;starting location of bitmap sta bitmap tax lda my_vcr_ptr+2 adc #$0000 sta bitmap+2 tay rts ENDP ;====================================================================== ;clear_gbuf_low This routine will zero the lower half of the general ; buffer. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; gbuf_ptr ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; gbuf_ptr ; longa on longi on EXPORT clear_gbuf_low clear_gbuf_low PROC lda #$0000 bra do_clear EXPORT fill_gbuf_low fill_gbuf_low ; lda #$FFFF do_clear ; ldy #$01FE clear ; sta [gbuf_ptr],y dey dey bpl clear rts ENDP ;====================================================================== ;clear_gbuf_hi. This routine will zero the upper half of the general ; buffer. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; gbuf_ptr ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: All registers ; gbuf_ptr ; temp3_ptr ; longa on longi on EXPORT clear_gbuf_high clear_gbuf_high PROC clc lda gbuf_ptr adc #$0200 sta temp3_ptr lda gbuf_ptr+2 adc #$0000 sta temp3_ptr+2 ldy #$01FE lda #$0000 clear ; sta [temp3_ptr],y dey dey bpl clear rts ENDP ;====================================================================== ;read_write_setup: ; this routine sets up common parameters between read/write ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pcount ;for cache check ; my_pblk_ptr ;must be setup ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; user_buf_ptr ; user_req_cnt ; drvr_cache ; tran_cnt ;set to zero ; ;Uses: All registers ; longa on longi on EXPORT read_write_setup read_write_setup PROC ;Start code by turning off disk caching and setting up other parameters lda user_cache sta drvr_cache stz tran_cnt stz tran_cnt+2 lda pcount ;is cache priority avail? cmp #$0005 bne no_cache ;If we get here then the user has provided a cache priority for the file. ;So we must verify that it is a legal value for caching. get_priority ; ldy #pblk_12_cache lda [my_pblk_ptr],y beq no_cache ;same as mine cmp #user_cache_val beq good_cache bra param_err good_cache ; sta drvr_cache ;Setup a pointer to the user's buffer. no_cache ; ldy #pblk_12_buf lda [my_pblk_ptr],y sta users_buf_ptr iny iny lda [my_pblk_ptr],y and #$00FF sta users_buf_ptr+2 ;Go ahead and zero the user's transfer count. ldy #pblk_12_tran ;zero the transfer count lda #$0000 sta [my_pblk_ptr],y iny iny sta [my_pblk_ptr],y ;Now lets get the user's request count. ldy #pblk_12_req lda [my_pblk_ptr],y sta user_req_cnt iny iny lda [my_pblk_ptr],y sta user_req_cnt+2 tax and #$FF00 ;is high byte zero? beq good_cnt param_err ; sec lda #parm_range_err bra to_scm ;Handle the easy case of a request count of zero first. good_cnt ; txa ora user_req_cnt bne not_zero clc to_scm ; jmp main_exit not_zero ; rts ENDP EXPORT rw_adjust rw_adjust PROC ;read/write adjust ;========================================================================== ;adjust the buffer pointer by the number of bytes read ; ;IMPORTANT NOTES: ; drvr_req_cnt is always =< $0001FE00 ; users_buf_ptr is always < $00FFFFFF ; clc lda users_buf_ptr adc drvr_req_cnt sta users_buf_ptr lda users_buf_ptr+2 adc drvr_req_cnt+2 sta users_buf_ptr+2 ;========================================================================== ;adjust the total number of bytes read from file ; ;IMPORTANT NOTES: ; tran_cnt is always =< $00FFFFFF ; drvr_req_cnt is always =< $0001FE00 ; ;Carry is clear from the above addition. lda tran_cnt adc drvr_req_cnt sta tran_cnt lda tran_cnt+2 adc drvr_req_cnt+2 sta tran_cnt+2 ;========================================================================== ;adjust the current file marker ; ;IMPORTANT NOTES: ; curr_mark is always =< $00FFFFFF ; drvr_req_cnt is always =< $0001FE00 ; lda curr_mark adc drvr_req_cnt sta curr_mark lda curr_mark+2 adc drvr_req_cnt+2 sta curr_mark+2 ;adjust the number of bytes remaining to send sec lda user_req_cnt sbc drvr_req_cnt sta user_req_cnt lda user_req_cnt+2 sbc drvr_req_cnt+2 sta user_req_cnt+2 rts ENDP ;========================================================================== ;entry_to_offset This routine will convert the data from a directory ; header to an offset. ; ;Input: A = entry_number ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = entry_offset ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; ;Uses: All registers longa on longi on EXPORT entry_to_offset entry_to_offset PROC and #$00FF dec a cmp #$000D ;is it out of range? bcs error asl a tay lda dir_offset_tbl,y clc error ; rts ENDP ;====================================================================== ;Issue Mount:calls the Mount_Message Routine with a pointer to the name ; stored in Volume_name. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; volume_name ;must be setup ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Mount_Message ; EXPORT issue_mount issue_mount PROC lda volume_name xba sta volume_name pea volume_name>>16 pea volume_name+1 ;push a pointer to the volume name lda #$0001 ;1 = manditory mount! jsl mount_message tax ;get the result code lda volume_name xba sta volume_name txa ;restore result code 0 = ok 1 = cancel bne cancel_mount clc ;user selected OK rts cancel_mount ; sec ;return volume not found error to user lda #vol_not_found rts ENDP ;====================================================================== ;Damaged_message: This routine will tell the user that the disk cannot ; be written too. The routine will also jmp to the ; main exit routine. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; EXPORT damaged_message damaged_message PROC pha jsr show_damage jsl unlock_mem ;release any memory sec pla ;get the error code please jml sys_exit EXPORT show_damage show_damage ; jsr setup_vol_mesg ;move the name from the VCR to buffer lda volume_name ;make Gstring a Pstring xba sta volume_name pea $0003 ;message number three pea volume_name>>16 pea volume_name+1 ;push a pointer to the volume name. pea $0000 pea $0000 ;push dummy space. jsl report_error lda volume_name ;make Pstring a Gstring xba sta volume_name rts EXPORT setup_vol_mesg setup_vol_mesg ; ldy #vcr_name ;index to Name VP lda [my_vcr_ptr],y tax iny iny lda [my_vcr_ptr],y tay jsl deref ;make a real pointer to vol name stx temp_ptr sty temp_ptr+2 lda [temp_ptr] ;get the length of the string tay iny move_loop ; lda [temp_ptr],y sta volume_name,y dey bpl move_loop rts ENDP ;====================================================================== ;read_with_mount: ; This routine with make a device read call and if an ; error occurs (other then the I/O error) the mount ; volume routine will be called. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; all parameters for the driver must be setup. ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Device Dispatcher (subroutine) ; device_call EXPORT read_with_mount read_with_mount PROC lda #drvr_read bra do_call EXPORT write_with_mount write_with_mount lda #drvr_write do_call sta drvr_call_num jsr dev_with_mount rts ENDP ;====================================================================== ;read_with_cache: ;write_with_cache: ; This routine with make a device read/write call and ; store the data in the system cache. error occurs ; (other then the I/O error) the mount volume routine ; will be called. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; all parameters for the driver must be setup. ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Device Dispatcher (subroutine) ; device_call EXPORT read_with_cache read_with_cache PROC lda #drvr_read bra continue EXPORT write_with_cache write_with_cache ; lda #drvr_write continue ; sta drvr_call_num lda [my_vcr_ptr] ;setup the Volume ID field sta drvr_vol_id lda drvr_cache ;save current cache setting pha lda #in_cache ;store this block in the cache sta drvr_cache jsr dev_with_mount php ;save processor status 'A' = error code tax ;save any error code lda 2,s ;restore old cache value sta drvr_cache txa plp ;restore carry bit plx ;fix the stack rts ENDP ;====================================================================== ;dev_with_mount This routine with make a device call and if an ; error occurs (other then the I/O error) the mount ; volume routine will be called. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; all parameters for the driver must be setup. ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Device Dispatcher (subroutine) ; device_call EXPORT dev_with_mount dev_with_mount PROC jsr device_call bcs check_err rts check_err cmp #drvr_disk_sw ;is this a disk switch error? beq do_find ;go and find the volume please cmp #drvr_off_line ;is the volume off-line? beq do_find sec rts ;This is some real error from the user do_find jsr mount_volume bcc dev_with_mount ;re-issue the original call please. rts ;return the error please ENDP ;====================================================================== ;Device_call:calls the dispatcher and trys to read or write. If the ; call returns a disk switched error then the routine will ; re-read the disk again. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; all parameters for the driver must be setup except for ; drvr_blk_size and drvr_fst_num, these are setup by the ; call. (ONLY if the call is a READ or WRITE) ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Device Dispatcher (subroutine) ; EXPORT device_call device_call PROC lda drvr_call_num cmp #drvr_status bcs to_device ;just call the device cmp #drvr_write beq is_write lda drvr_cache and #$7FFF ;clear the deferred bit if not a write sta drvr_cache bra do_it is_write sta write_occurred ;indicate that a write occured during this call lda drvr_dev_num ;save the device number that I have written too. sta write_dev_num do_it lda #blk_size sta drvr_blk_size stz drvr_blk_num+2 to_device jsl dev_dispatcher ;call the read routine rts ENDP ;====================================================================== ;flush_bitmap: This routine forces a dirty bitmap to be written to ; disk. The bitmap will be written to disk only if the ; file counter is equal to zero. ; ;force_bitmap: same as flush_bitmap except the bitmap block is ALWAYS ; flushed. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; prodos_vcr_ptr ; my_vcr_ptr ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; drvr_buf_ptr ; dev_with_mount ; longa on longi on EXPORT flush_bitmap flush_bitmap PROC ldy #dirty_file_cnt ;see if there open files on disk? lda [prodos_vcr_ptr],y beq force_bitmap ;no open files so do flush. clc rts ;just exit. EXPORT force_bitmap force_bitmap ;This entry point force block to disk ldy #bitmap_dirty lda [prodos_vcr_ptr],y beq no_change ;Get the device number first ldy #vcr_dev lda [my_vcr_ptr],y sta drvr_dev_num ;We need to update the disk since the bitmap is corrupt ;First we calculate the block number of the block to write ldy #vol_bitmap_addr lda [prodos_vcr_ptr],y ldy #curr_bitmap clc adc [prodos_vcr_ptr],y sta drvr_blk_num stz drvr_blk_num+2 ;Get the address of where the bitmap block is located. ;setup drvr_buf_ptr to point to the bitmap buffer jsr setup_bitmap_ptr stx drvr_buf_ptr sty drvr_buf_ptr+2 ;setup the call to do a write ;Force the request count to 512 bytes lda #blk_size sta drvr_req_cnt stz drvr_req_cnt+2 ;Call the device. jsr write_with_cache bcc clear_dirty rts clear_dirty ; ldy #bitmap_dirty lda #$0000 sta [prodos_vcr_ptr],y ldy #curr_bitmap ;see if this is first free block. lda [prodos_vcr_ptr],y ldy #avail_bitmap cmp [prodos_vcr_ptr],y bne no_change inc a ;see if this is the last bitmap blk. ldy #num_bitmap_blks cmp [prodos_vcr_ptr],y bcs no_change ;this is the last bitmap block ldy #$01FE ;we must check first free chk_first_free ; lda [drvr_buf_ptr],y bne no_change dey dey bpl chk_first_free ;check the entire block please. ldy #avail_bitmap ;bump avail to next block please lda [prodos_vcr_ptr],y inc a sta [prodos_vcr_ptr],y no_change ; clc rts ENDP ;========================================================================== ;flush_file: This routine will write any modified blocks to disk. ; ;Input: A = dev_number ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr (points to data to write) ; my_vcr_ptr (points to main VCR) ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers longa on longi on EXPORT flush_file flush_file PROC stz flush_entry ;indicate that we should flush everything bra cont_flush Entry do_fast_flush ;entry point used by the fast version of the flush call do_fast_flush lda #1 ;set flag bra stuffit EXPORT flush_io_Buffer flush_io_buffer lda #$FFFF ;do not flush the directory entry stuffit sta flush_entry cont_flush jsr standard_req ;First lets call flush bitmap which will update the bitmap for us jsr flush_bitmap bcs error_return ;return the error directly ;No we need to flush the file itself. We only flush blocks that need to ;be flushed. We will always update the file entry. flushed ; ldy #fcr_status ;get the status bits lda [pro_fcr_ptr],y sta flush_flags bit #file_dirty ;see if there is anything to update bne do_update clc error_return rts ;file does not need to be updated ;First lets see if we need to update the master index block. do_update bit #master_dirty beq check_index ldy #master_blk_num ;get the block number lda [pro_fcr_ptr],y sta drvr_blk_num beq clear_master ;master block is sparse so do not update disk ldx master_ptr ldy master_ptr+2 jsr flush_block bcs error_return ;return the error code clear_master ; lda #master_clean jsr clr_fcr_status ;mark master block as clean ;Update the index block if needed check_index ; lda flush_flags bit #index_dirty ;is the index block dirty beq check_data jsr flush_index bcs error_return ;Update the data block if needed. check_data ; lda flush_flags bit #data_dirty ;is the data block dirty beq update_entry jsr flush_data_blk bcs error_return update_entry lda flush_entry ;do we update the directory entry? beq @do_entry ;yup, update the whole thing bmi @just_data ;no, just flush the data blocks ; else we're doing a fast flush call here. flush dirty bitmap and ; dirty directory ('dirty' meaning that anything besides mod date ; and backup-bit have been changed). jsr force_bitmap ;force the bitmap update lda flush_flags ;is the directory dirty? bit #dirEntry_dirty bne @do_entry ;yes, so just go ahead and do the full flush @just_data clc rts @do_entry lda #file_clean jsr clr_fcr_status ;mark master block as clean ; ;Now lets update the VCR count to indicate that the file is clean ; lda dirty_cnt_changed bne @changed_once ;have we adjusted the number already? inc dirty_cnt_changed ldy #dirty_file_cnt lda [prodos_vcr_ptr],y beq @major_error dec a sta [prodos_vcr_ptr],y jsr flush_bitmap ;now go and update the bitmap bcs go_cannot_update @major_error @changed_once jsr set_default_buf ;use the system buffer jsr standard_req jsr update_mod_time ;make sure we use the correct time jsr get_parent ;load the I/O buffer with directory blk go_cannot_update bcs to_cannot_update jsr verify_storage ;verify storage type ; ;Change for final release 8/16/88 ; ; ; First we update the File Control Record to indicate the correct backup state ; ldy #fcr_disk_acc ;update fcr along with dir entry lda [pro_fcr_ptr],y ora #backup_on sta [pro_fcr_ptr],y ; ;Now we update the directory entry to indicate the correct backup state ; ldy #access_index ;index to the access byte in a dir entry lda [temp_ptr],y ora #backup_on ;set the backup bit before update of disk sta [temp_ptr],y bcs to_cannot_update ;If the file is a resource file then only update the modification time. ;Otherwise update the entire directory entry. ldy #fcr_file_id lda [pro_fcr_ptr],y ldy #fcr_key_blk cmp [pro_fcr_ptr],y beq entry_ok ;file is not a resource file jsr update_resource ;update the resource header bcs to_cannot_update ;cannot write info to disk! jsr set_default_buf ;restore buffer pointer ldy #fcr_modified ;index into FCR lda [pro_fcr_ptr],y ldy #last_mod_index ;index into directory block sta [temp_ptr],y ;update the directory entry ldy #fcr_modified+2 lda [pro_fcr_ptr],y ldy #last_mod_index+2 sta [temp_ptr],y bra update_disk ;now update the directory ;Move the entire directory info then write the block back to disk. entry_ok ; ldy #fcr_storage lda [temp_ptr] and #$FF0F ;clear current storage type ora [pro_fcr_ptr],y ;adjust the storage type sta [temp_ptr] ldx #fcr_eof ldy #fcr_curr_eof ;move the current EOF to disk EOF lda [pro_fcr_ptr],y phy txy sta [pro_fcr_ptr],y inx ply iny lda [pro_fcr_ptr],y txy sta [pro_fcr_ptr],y ldy #fcr_header_ptr ;start at the end ldx #header_ptr_index blast_loop ; lda [pro_fcr_ptr],y phy txy sta [temp_ptr],y dex ply dey cpy #fcr_file_type bne blast_loop update_disk jsr write_with_cache to_cannot_update bcs cannot_update lda #dirEntry_clean jsr clr_fcr_status ;mark directory entry as clean lda close_flag ;should we update the directories? ora time_stamp_opt ;check user's option for time stamp too ora flush_flags ;and which type of flush we're doing beq dont_bother ;no directory updates please ldy #header_ptr_index lda [temp_ptr],y sta drvr_blk_num cmp #vol_dir_start beq dont_bother jsr read_with_cache bcs cannot_update ldy #parent_index ;get the parent block number lda [drvr_buf_ptr],y sta slug_block ;save the block number ldy #par_entry_num lda [drvr_buf_ptr],y jsr entry_to_offset sta slug_offset jsr slug_ripple ;do the slug ripple rts dont_bother ; clc cannot_update ; rts EXPORT flush_index flush_index ; ldy #index_blk_num ;get the block number lda [pro_fcr_ptr],y sta drvr_blk_num beq clear_index ;the block is sparse so don't write it! ldx index_ptr ldy index_ptr+2 jsr flush_block bcc clear_index rts ;return the error code clear_index ; lda #index_clean jsr clr_fcr_status ;mark master block as clean rts EXPORT flush_data_blk flush_data_blk ; ldy #data_blk_num ;get the block number lda [pro_fcr_ptr],y sta drvr_blk_num beq clear_data ;the block is sparse so don't write it to disk ldx data_ptr ldy data_ptr+2 jsr flush_block2 bcc clear_data rts ;return the error code clear_data ; lda #data_clean jsr clr_fcr_status ;mark master block as clean clc rts ;If we get here then we are updating a resource file. So we need to update ;the resource header block with the following information. ; ; Storage Type ; key_block ; blocks used ; eof ; update_resource ; lda drvr_blk_num ;save the block number please pha jsr standard_req jsr set_default_buf inc drvr_buf_ptr+1 inc drvr_buf_ptr+1 ;use the high block of the buffer!!! ldy #fcr_file_id ;index to header block lda [pro_fcr_ptr],y sta drvr_blk_num ;read in the block please jsr read_with_cache bcs end_res_update ldy #fcr_res_num ;which resource are we updating? lda [pro_fcr_ptr],y xba ;make an index $0000 or $0100 tax ;point to start of header ldy #fcr_storage ;stoarge type of file lda [pro_fcr_ptr],y lsr a ;convert $10,$20,$30 -> $1,$2,$3 lsr a lsr a lsr a txy ;index to storage type sta [drvr_buf_ptr],y inx ;advance to key block ldy #fcr_key_blk lda [pro_fcr_ptr],y txy sta [drvr_buf_ptr],y inx inx ;advance to blocks used ldy #fcr_blks_used lda [pro_fcr_ptr],y txy sta [drvr_buf_ptr],y inx inx ;advance to EOF ldy #fcr_curr_eof lda [pro_fcr_ptr],y txy sta [drvr_buf_ptr],y inx ldy #fcr_curr_eof+1 lda [pro_fcr_ptr],y txy sta [drvr_buf_ptr],y jsr write_with_cache ;Update the disk bcs end_res_update clc ldy #$0003 ;index to the blocks used data lda [drvr_buf_ptr],y ldy #$0103 ;index to blocks used resource adc [drvr_buf_ptr],y adc #$0001 ;add in the header block ldy #blks_used_index ;index into directory block sta [temp_ptr],y ;update the directory entry clc end_res_update plx ;restore the block number stx drvr_blk_num rts ;========================================================================== ;This routine reads the GS clock and stores the time in the modification ;field of the current FCR. update_mod_time ; jsr pack_time ;time for mod date (X=low Y=high) phy ;save high word ldy #fcr_modified txa sta [pro_fcr_ptr],y iny iny pla sta [pro_fcr_ptr],y ;update high word rts ;========================================================================== ;This routine will read in the parent block for a FCR and update the ;modification date. ; ;input: pro_fcr_ptr ;MUST be setup ; ;output: carry = error ; temp_ptr ;points to the file entry get_parent ; ldy #fcr_parent lda [pro_fcr_ptr],y ;get the address of the directory blk sta drvr_blk_num jsr read_with_cache ;get the directory block please bcc block_loaded rts block_loaded ; ldy #fcr_entry_offs ;offset to directory entry lda [pro_fcr_ptr],y adc drvr_buf_ptr sta temp_ptr lda #$0000 adc drvr_buf_ptr+2 sta temp_ptr+2 clc rts ;========================================================================== ;This routine verifies that the entry pointed to by 'temp_ptr' is a valid ;ProDOS entry. It verifies this by looking at the storage type. verify_storage ; lda [temp_ptr] ;get stoarge/length byte and #$00F0 ;verify the storage type please cmp #resource_type beq good_entry cmp #seedling_type beq good_entry cmp #sapling_type beq good_entry cmp #tree_type beq good_entry cmp #subdir_type beq good_entry lda #dir_error ;the directory must be damaged sec rts good_entry clc rts ;Force the block to disk flush_block ; stx drvr_buf_ptr sty drvr_buf_ptr+2 jsr write_with_cache rts flush_block2 ; stx drvr_buf_ptr sty drvr_buf_ptr+2 jsr write_with_mount rts EXPORT clr_fcr_status clr_fcr_status ; ldy #fcr_status and [pro_fcr_ptr],y sta [pro_fcr_ptr],y rts ENDP ;========================================================================== ;slug_ripple: This routine will time stamp the parent directories for ALL ; operations that require writing to the directory. This ; routine is SLOW and is very stupid on our type of system. ; It is put here for compatability only. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; drvr_buf_ptr (points to the directory entry) ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; device_dispatcher ; longa on longi on EXPORT slug_ripple slug_ripple PROC lda time_stamp_opt ;are we time stamping at all? bne do_stamp clc rts do_stamp lda drvr_blk_num pha lda drvr_buf_ptr pha lda drvr_buf_ptr+2 pha jsr pack_time ;get the time please clc lda gbuf_addr adc #blk_size sta drvr_buf_ptr lda gbuf_addr+2 adc #$0000 sta drvr_buf_ptr+2 lda slug_block ;setup the block bne @around brl do_volume_mod ;no slug block, so time stamp the volume please @around sta drvr_blk_num slug_loop jsr read_with_cache ;read in the block please bcs end_slug_err ldy slug_offset ;offset to the entry lda [drvr_buf_ptr],y and #$00F0 ;check the storage type cmp #subdir_type bne bad_slug_dir ;sorry bud tya clc adc #last_mod_index tay ;index to the last mod field lda pro_time ;Get the time we are going to stamp with sta [drvr_buf_ptr],y lda pro_time+2 iny iny sta [drvr_buf_ptr],y ;new code added 3/15/91 CAE ldy slug_offset ;offset to the entry tya clc adc #access_index tay ;index to the access field lda [drvr_buf_ptr],y ora #backup_on ;set the backup bit sta [drvr_buf_ptr],y ;end of new code jsr write_with_cache bcs end_slug_err ;a major error lda time_stamp_opt ;are we walking to root? dec a beq end_slug ;not today. clc lda slug_offset ;offset to the entry adc #header_ptr_index ;point to the header pointer please tay lda [drvr_buf_ptr],y cmp #vol_dir_start ;is this the root? beq do_volume_mod ;set the volume modification date cmp drvr_blk_num ;is the block already loaded? beq block_loaded ;you bet-cha sta drvr_blk_num ;next block to read jsr read_with_cache bcs end_slug_err ;sorry bud major error block_loaded ldy #parent_index lda [drvr_buf_ptr],y sta drvr_blk_num ;new block number iny iny ;get the entry number lda [drvr_buf_ptr],y jsr entry_to_offset sta slug_offset ;the new offset bra slug_loop ;ripple to the top. bad_slug_dir lda #dir_error bra end_slug_err end_slug clc end_slug_err plx stx drvr_buf_ptr+2 plx stx drvr_buf_ptr plx stx drvr_blk_num rts ; ;Now lets go and time stamp the volume please ; do_volume_mod lda #vol_dir_start ;Setup the block number for the Root sta drvr_blk_num jsr read_with_cache ;read in the block please bcs end_slug_err ;I hate it with this happens ldy #vol_mod_offset ;offset to the Mod time field for the volume lda pro_time sta [drvr_buf_ptr],y iny iny lda pro_time+2 sta [drvr_buf_ptr],y ;store the time ;new code added 3/15/91 CAE ldy #vol_acc_offset ;offset to the access field lda [drvr_buf_ptr],y ora #backup_on ;set the backup bit on disk sta [drvr_buf_ptr],y ;end of new code ldy #vol_mod ;update the VCR as well as the disk lda pro_time sta [prodos_vcr_ptr],y iny iny lda pro_time+2 sta [prodos_vcr_ptr],y ;new code added 4/4/91 CAE ldy #vol_access ;offset to the access field lda [prodos_vcr_ptr],y ora #backup_on ;set the backup bit in the VCR sta [prodos_vcr_ptr],y ;so that the disk and VCR match ;end of new code jsr write_with_cache bcs end_slug_err ;a major error bra end_slug ;no error, all is wonderful ENDP ;========================================================================== ;extend_subdir This routine will extend a directory if needed. ; ;input: free_dir_blk ;dir blk with a empty entry. ; dir_start_blk ;starting block of the directory ; dir_last_blk ;last block of the directory ; ;output: free_dir_blk ;dir blk with a empty entry. ; free_dir_offset ;offset to directory entry within block ; dir_start_blk ;starting block of the directory ; dir_last_blk ;last block of the directory ; longa on longi on EXPORT extend_subdir extend_subdir PROC with expand_record bit expand_file ;are we adding a directory entry? bmi good_exit ;if we are expanding a file we donot need to extend the ;directory lda free_dir_blk ;is there a free entry for this file? bne good_exit ;do not extend the directory lda dir_start_blk cmp #vol_dir_start ;is this the root directory? bne not_root lda #vol_dir_full ;return an error please sec rts not_root ; lda #$0001 ;allocate one block for directory. ldx dir_last_blk ;start looking here for next block jsr find_Free_blks ;go and get one bcs error_out ;error out stx drvr_blk_num ;this is the new directory block stx free_dir_blk ;new block number lda #$0004 ;index to first free entry sta free_dir_offset jsr set_default_buf ;use the genaral buffer jsr standard_req ;512 byte write jsr clear_dir_buf ;clear the 512 byte general buffer jsr append_last_blk bcs error_out ;major problem jsr update_forw_lnk ;update forward link to new block bcs error_out jsr update_parent ;update parents blocks used count bcs error_out good_exit ; clc error_out ; rts ;extend complete ;========================================================================== ;Update_parent: This routine will update the blocks used and last mod date ; of the parent entry for the directory. update_parent ; lda dir_start_blk sta drvr_blk_num ;key block for directory jsr read_with_cache bcs exit_update ldy #parent_index lda [gbuf_ptr],y ;get the parent block number sta drvr_blk_num ldy #par_entry_num lda [gbuf_ptr],y and #$00FF ;get the number dec a cmp #$000D ;number of entries bcs bad_dir_bud asl a ;times 2 for a word table tay lda dir_offset_tbl,y sta entry_offset ;save offset to dir entry jsr read_with_cache ;read in the parent block bcs exit_update ldy entry_offset lda [gbuf_ptr],y and #$00F0 ;is this a subdir entry? cmp #subdir_type bne bad_dir_bud tyx clc tya adc #$0013 ;index to blocks used for file tay lda [gbuf_ptr],y inc a sta [gbuf_ptr],y iny iny ;point to EOF clc lda [gbuf_ptr],y adc #blk_size sta [gbuf_ptr],y ;add 512 to the EOF field bcc good_eof iny iny ;point to the third byte of EOF longa off sep #$20 ;short A lda [gbuf_ptr],y inc a sta [gbuf_ptr],y longa on rep #$20 good_eof ; clc txa adc #$0021 ;index to mod time pha jsr pack_time ply ;index lda pro_time sta [gbuf_ptr],y ;update mod time iny iny lda pro_time+2 sta [gbuf_ptr],y jsr write_with_cache exit_update ; rts bad_dir_bud ; lda #dir_error ;bad directory block sec rts ;========================================================================== ;update_forw.. This routine will link the new directory block just ; allocated to the current last block of the directory. update_forw_lnk ; lda dir_last_blk sta drvr_blk_num ;now read in the directory block. jsr read_with_cache bcs forw_exit ;major problems. sorry about droppings! ldy #$0002 ;index to next pointer lda [gbuf_ptr],y bne bad_dir_bud lda free_dir_blk ;forward link directory block. sta [gbuf_ptr],y jsr write_with_cache forw_exit rts ;========================================================================== ;append_last.. This routine will link the new block to the previous ; block in the directory. append_last_blk ; lda dir_last_blk ;setup the backward link sta [gbuf_ptr] jsr write_with_cache rts clear_dir_buf ; ldy #$01FE ;clear the general work buffer lda #$0000 clear_dir ; sta [gbuf_ptr],y dey dey bpl clear_dir ;every body happy now! rts ENDP ;========================================================================== ;Chk_swapped: This routine will determine if the volume has been swapped ; If the volume has been swapped then we will request the ; user to put the volume back online. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; my_vcr_ptr ;pointer to vcr ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; temp_ptr ; volume_name ; find_volume ; longa on longi on EXPORT chk_swapped chk_swapped PROC ;Now we have all of our data setup for the read. Now we need to see if ;the volume has been swapped out. If it has then we must go and find ;it again. ldy #vcr_status lda [my_vcr_ptr],y and #vcr_swapped ;disk logged out? beq disk_back ;Little Bo-Peep-Show has lost her disk and doesn't know where to find it! ;Therefore we will go and find it for her. ldy #vcr_name lda [my_vcr_ptr],y tax iny iny lda [my_vcr_ptr],y tay jsl deref stx temp_ptr sty temp_ptr+2 ;Now we have a pointer to the name but we must move it to 'volume_name' lda [temp_ptr] and #$000F tay dey move_name ; lda [temp_ptr],y sta volume_name,y dey bpl move_name ;Now that we have moved the name to volume_name buffer we need to call ;'find_volume' and let it look for it. jsr mount_volume rts disk_back ; clc rts ENDP ;====================================================================== ;ID.Disk: This file contains the code that will id the media ; to determine if the media is in ProDOS/SOS format. ; If the disk is a ProDOS disk and there is no VCR then ; a new VCR will be generated for that disk. If there is ; a VCR then it is marked active. ; ;Input: A = device number ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; drvr_buf_ptr ;points to storage/vol name field ; ;with storage type removed ;Uses: All registers ; Device Dispatcher (subroutine) ; General I/O Buffer (1K buffer, I read 512 bytes) ; ;Diagram of pointers and memory segments ; ; (I/O Buffer) ; ___________ ; | | <--- pointed to by 'drvr_buf_ptr' ; | | <--- 'drvr_buf_ptr' later points to volume name ; |___________| | ; |____ 'temp3_ptr' points to data AFTER volume name area ; ; ; (vcr) ; ___________ <-- pointed to by 'my_vcr_ptr' ; | | ___________________ ; | vol name -|------> |___________________| <-- pointed to by 'Temp2_Ptr' ; | | ; | | ; | | ; | | <-- pointed to by 'prodos_vcr_ptr' ; |___________| ; longa on longi on EXPORT id_disk id_disk PROC sta drvr_dev_num ;driver number lda #drvr_read sta drvr_call_num lda #vol_dir_start ;starting block of directory sta drvr_blk_num stz drvr_blk_num+2 jsr standard_req ldx gbuf_addr ;setup pointer to general I/O buffer ldy gbuf_addr+2 stx drvr_buf_ptr sty drvr_buf_ptr+2 try_again jsr device_call ;make a system call to drive bcc id_no_error ; ;error code in X already but it may ; ;change in the future. currently ; ;all code is cast in jello and #$00FF ;clear the dispatcher error code beq id_no_error ;Dispatcher returning disk switched cmp #drvr_disk_sw ;was the disk switched? beq try_again sec ;swapped out by device call routine rts ;if the disk was switched ;====================================================================== ;ID method used to determine disk is ProDOS format: ; ;(1) read in block two (First directory block) ;(2) backward link must be zero (first word) ;(3) storage type must be $F (high nibble: byte $04) ;(4) name length must be > $0 (low nibble: byte $04) ;(5) name must be valid syntax ;(6) minimum version must be $00 (byte $21) ;(7) entry length must be $27 (SOS/ProDOS size) ;(8) entries per block must be $0D ; ;If the above information causes problems with other disks then I will ;read in the second block of the directory and verify that the link ;fields are correct. This may cause a problem if there is no second ;block in the directory. If this is the case then I will check the ;bitmap allocation for correctness. If this fails then forget it. ; ;====================================================================== id_no_error lda [drvr_buf_ptr] ;load backward link bne bad_format ldy #$0021 ;offset to minimum version lda [drvr_buf_ptr],y and #$00FF bne bad_format ;Now that we have checked both the backward link and version we now ;need to adjust the pointer to point to the storage/name length field ;within the block. clc lda drvr_buf_ptr adc #$0004 sta drvr_buf_ptr bcc ar inc drvr_buf_ptr+2 ar ; lda [drvr_buf_ptr] ;load storage/name length tay and #$00F0 cmp #$00F0 ;is it a volume directory type? bne bad_format tya and #$000F ;isolate file name length beq bad_format ;must be $01 to $0F tay ; ;Now we need to verify that the name is a valid ProDOS filename ; loop lda [drvr_buf_ptr],y and #$00FF cmp #'A' bcc numeric cmp #'Z'+1 bcs bad_format dey bne loop ;If we get here then we need to check both the entry length and ;entries per block. If everything is OK then we will call a routine ;that will build a new vcr or mark the vcr as active its_mine ; ldy #$0023-4 ;index to entry length lda [drvr_buf_ptr],y cmp #$0D27 ;both entry length and entry per blk bne bad_format jsr build_vcr ;build a volume control record rts ;note: error set be build_vcr numeric ; cmp #'0' bcc period cmp #'9'+1 bcs bad_format continue dey bne loop bad_format ; lda #unknown_vol ;I don't know what this disk is sec rts period cmp #'.' bne bad_format bra continue ENDP ;====================================================================== ;Build_VCR: This routine will add a new VCR if one is currently not ; allocated, if the VCR is allocated then it will be ; marked as active. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; drvr_buf_ptr (points to volume header) ; cp_device_flag = 1 if doing a ChangePath call and source is device # ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; ;Uses: All registers ; find_vcr (system subroutine) ; alloc_vcr (system subroutine) ; General I/O Buffer (1K buffer, I read 512 bytes) ; longa on longi on EXPORT build_vcr build_vcr PROC jsr move_vol_entry ;move the entry to the work area jsr entry_to_gstr ; ; If bit 15 of cp_flag is set, assume the source disk is a duplicate volume ; and fall into the code that handles duplicate volumes with open files. ; Since cp_device_flag is already set, it will cause a fake VCR to be allocated. ; 5-Dec-91 MSD ; bit cp_flags ; should we assume the disk is a duplicate? bpl @not_dup ; no, so do the usual brl is_open ; yes, pretend duplicate volume with open files @not_dup ; End of 5-Dec-91 MSD change. ;Call system routine to see if it can find a vcr with the same volume ;name. If the accum contains a zero then the routine will will ;use x and y as a pointer to a volume name. If the accum contains ;a non zero value then the routine will try to find a vcr with ;the same volume id. ldx #gstring ;pointer to the volume name ldy #^gstring lda #0000 ;0000=search for vcr by name jsl find_vcr bcs no_vcr ;this name is not in any VCR jsl deref ;convert virtual to real stx my_vcr_ptr sty my_vcr_ptr+2 ;setup pointer to VCR ldy #vcr_fst_id lda [my_vcr_ptr],y cmp #pro_id ;is this my vcr bne check_active ;if not, can we kick it out? jsr setup_my_vcr ;make a pointer to my vcr stuff stx prodos_vcr_ptr sty prodos_vcr_ptr+2 bit drvr_fst_num ;are we looking at name only? bmi name_only ;yes. ldy #entry_length-18 compare_loop lda one_entry+16,y ;we add 16 so we pass the name field cmp [prodos_vcr_ptr],y bne check_active dey bpl compare_loop name_only ; ldy #vcr_dev ;update the last known device lda drvr_dev_num sta [my_vcr_ptr],y jsr activate_vcr ;mark the vcr as swapped in jsr reset_vcr ;reset blocks free etc. clc rts sorry_dup ; lda #dup_volume ;duplicate volume online sec rts ;If we get here it means that the volume name already exist in vcr. ;So I need to see if there are any open files on the volume. If there ;are no open files then I can kick the current vcr out of memory and ;build a new one. If there are open files then I will return a ;duplicate volume error. Note: I check to make sure that the volume ;header has not changed. This protects me from marking a volume as ;being swapped in and writing to it blindly if it has the same name. ; Note - If we get a duplicate volume error and cp_device_flag = 1 then ignore ; the error since we are doing a ChangePath call with a device # as the source. ; 1/22/91 CAE check_active ; ; ldy #vcr_open_cnt ; lda [my_vcr_ptr],y ; bne sorry_dup ;files open so don't log in new volume ; jsr free_vcr ;free vcr pointed to by 'my_vcr_ptr' ldy #vcr_open_cnt lda [my_vcr_ptr],y ;any open files? beq not_open ;no is_open ;Added 5-Dec-91 MSD lda cp_device_flag ;are we doing a special ChangePath call? beq sorry_dup ;no - so report a duplicate volume error ora #$8000 ;yes - so indicate we got a dup vol error sta cp_device_flag lda /FOO (Rename) ;(2) /FOO1 --> /FOO (Rename) ;(3) /FOO1/PATHNAME --> /FOO1/NEWNAME (Rename) ;(4) /FOO1/SUB/FILE --> /FOO1/FILE (Change path) ;(5) .DEV1/FILE --> /FOO/NEW.NAME (Rename) ;(6) .DEV1/FILE --> /FOO/SUB/FILE (Change path) ;(7) /FOO/FILE --> .DEV1/SUB/NEW (Change path) ;(8) /FOO/FILE --> .DEV1/NEW (rename) ; ;Invalid Pathnames: ; ;(1) /FOO --> .DEV1 ;(2) /FOO --> /FOO/FILE ;(3) /FOO/SUB/ --> /FOO/SUB/SUB1/SUB ;(4) /FOO/FILE --> /FOO ;(5) /FOO/FILE --> .DEV1 ; ;====================================================================== valid_change stz cp_to_child ; assume source is not a subset of dest stz vol_rename_flag lda path_flag and #path2_mask ;there has to be a second pathname beq to_bad_path jsr setup_path1 ;Path1_ptr --> temp_ptr jsr setup_path2 ;Path2_ptr --> temp2_ptr ; ;IF (Path1 = device_name) THEN ; (Path2 must be a volume name only) ; ; lda path_flag ;is path1 a device name only? and #path1_mask bne not_device ;not just a device name lda dev2_num bne to_bad_path ;path2 cannot contain a device name ldx temp2_ptr ldy temp2_ptr+2 jsr scan_pass_vol ;pass the volume name IF possible bcc to_bad_path ;there is more then just a volume name ; ;We are doing the following: '.DEV1' to '/FOO' ; bra volume_rename to_bad_path ; brl bad_path ; ; IF (Path1 = volume_only) THEN ; (Path2 must be volume only) ; not_device ; lda dev1_num ;IF dev <> 00 THEN not volume only bne chk_same_dev ldx temp_ptr ;pointer to path1 ldy temp_ptr+2 jsr scan_pass_vol bcc not_vol_only ;path1 <> volume only ; ; IF (path1 - volume) and ((path2 = device) or (path2 = dev/vol)) THEN ; bad_path_syntax ; lda path_flag and #path2_mask beq to_bad_path lda dev2_num ;is there a device name also? bne a_bad_path ldx temp2_ptr ldy temp2_ptr+2 jsr scan_pass_vol ;pass the volume name IF possible bcc to_bad_path ;path2 <> volume only ; ;We are doing the following: '/FOO1' to '/FOO' ; volume_rename ; dec vol_rename_flag clc rts ; ;IF (Path1 <> volume only) THEN ; (Path2 MUST be a pathname) ; chk_same_dev ; lda dev2_num ;is the rename on the same device? beq not_vol_only cmp dev1_num a_bad_path bne to_bad_path not_vol_only ; lda path_flag and #path2_mask ;is there a pathname? if AllowLCPeriods then ;added 7-Aug-91 DAL beq to_bad_path else ;original code beq bad_path ;must be device name only endif ;end 7-Aug-91 DAL lda dev2_num ;IF (dev = true) and (path = true) THEN bne path2_is_path ; (path2 = pathname) ldx temp2_ptr ldy temp2_ptr+2 jsr scan_pass_vol bcs bad_path ;Path2 = volume name only! stx temp2_ptr sty temp2_ptr+2 ; ;IF (path2 = path2-volume_name) and (path1 = volume_name) THEN ; Path1 := Path1-volume_name ; lda dev1_num ;does path1 contain a volume name? bne do_scan ;no it does not ldx temp_ptr ldy temp_ptr+2 jsr scan_pass_vol ;scan past the volume name stx temp_ptr sty temp_ptr+2 bra do_scan ; ; When Here Path1 and Path2 are both pathnames! ; ; IF (Path1 = dev) and (path2 = vol) THEN ; path2 := path2-volume name ; path2_is_path ; lda dev1_num ;does path1 contain a device name? beq path1_volume ;NO lda dev2_num ;does path2 contain a device name? bne do_scan ;path1 and path2 contains device names ldx temp2_ptr ldy temp2_ptr+2 ;scan pass the volume name jsr scan_pass_vol stx temp2_ptr sty temp2_ptr+2 bra do_scan ;everything is OK so far ; ; IF (path1 = volume) and (path2 = dev) THEN ; path1 := path1-volume_name path1_volume ; lda dev2_num ;does path2 contain a beq do_scan ;Path1 and path2 contain volume names ; ; IF (path2 = dev) and (path1 = vol) THEN ; path1 := path1-volume_name ; scan_path1 ; ldx temp_ptr ;path1 ldy temp_ptr+2 jsr scan_pass_vol ;pass the volume name stx temp_ptr sty temp_ptr+2 ;The following code was moved into the changepath code so ;that ProDOS conforms to the way AppleShare and HFS do a ;changepath. The check to see if the path1 is a subset ;of path2 should not be done until after we check to see ;if the path2 allready exsists. 10/3/91 JEV ; ; IF (path1 is a subset of path2) THEN ; set cp_to_child ;The following code has been changed to do a case-insensitive ;compare in order to fix a bug which was allowing illegal moves ;if the case of the pathnames was different. 1/22/91 CAE do_scan ; ldy #$0000 ;start scan at beginning longa off sep #$20 subset_loop ; ; lda [temp_ptr],y ;source file ; cmp [temp2_ptr],y ;destination ; bne more_chk ; iny ; bra subset_loop lda [temp_ptr],y ;get source file char if AllowLCPeriods then ;added 7-Aug-91 DAL cmp #' ' bne @not_blank1 lda #'.' @not_blank1 endif ;end 7-Aug-91 DAL cmp #'a' ;upper case? bcc @its_upper1 ;yes and #$DF ;no - so convert to upper case @its_upper1 pha ;save char lda [temp2_ptr],y ;get dest file char if AllowLCPeriods then ;added 7-Aug-91 DAL cmp #' ' bne @not_blank2 lda #'.' @not_blank2 endif ;end 7-Aug-91 DAL cmp #'a' ;upper case? bcc @its_upper2 ;yes and #$DF ;no - so convert to upper case @its_upper2 cmp 1,s ;same as source file char? bne @no_match ;nope pla ;yes - so clean up stack iny ;adjust index bra subset_loop ;and loop @no_match pla ;clean up stack more_chk ; lda [temp2_ptr],y ;this cannot be a 'delimiter' cmp #delimiter longa on ;go ahead and fix the mode rep #$20 bne paths_ok lda [temp_ptr],y ;is this the end of the source? and #$00FF bne paths_ok ;not the end of source name inc cp_to_child ; source was subset of dest! 27-Jan-92 MSD paths_ok clc rts bad_path lda #bad_path_syntax sec jmp main_exit ;====================================================================== scan_pass_vol ; stx temp3_ptr ;pointer to the string sty temp3_ptr+2 ldy #$0001 longa off sep #$20 scanner ; lda [temp3_ptr],y beq scan_failed ;sorry volume name only cmp #delimiter beq scan_passed iny bra scanner scan_passed ; ; 27-Jan-92 MSD: This routine was returning a pointer to the character ; before the pathname separator. It should have been returning a pointer ; to the character after the separator. Removed the DEY and changed a ; CLC to a SEC before adding (so it will add 1 to point past separator). ; ; dey longa on rep #$20 ;back to 16 bit mode sec ; 27-Jan-92 MSD (was CLC) tya adc temp3_ptr tax lda #$0000 adc temp3_ptr+2 tay clc ;not just a volume name rts scan_failed ; longa on rep #$20 ; ldx temp3_ptr ldy temp3_ptr+2 ;restore X and Y sec rts ;====================================================================== setup_path2 ; ldx path2_ptr ldy path2_ptr+2 inx bne do_again iny do_again inx bne cont iny cont ; stx temp2_ptr ;pointer to pathname two sty temp2_ptr+2 rts ;====================================================================== setup_path1 ; ldx path1_ptr ldy path1_ptr+2 inx bne do2_again iny do2_again inx bne cont2 iny cont2 ; stx temp_ptr ;pointer to pathname one sty temp_ptr+2 rts ENDP ;========================================================================== ;Set_file_info: This routine will alter information about a file on disk. ; ;Created: may 26, 1987 ;Modified: jan 06, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; find_file ; ;Call Format: ; ;Class 0 Pathname Pointer (4 Bytes) ; Access (2 Bytes: Disk Format) ; File Type (2 Bytes) ; Aux Type (4 Bytes) ; Null Field (2 Bytes) ; Create Date/Time (4 Bytes: ProDOS Format) ; Mod Date/Time (4 Bytes: ProDOS Format) ; ;Class 1 PCount (2 Bytes) ; Pathname Pointer (4 Bytes) ; Access (2 Bytes: Disk Format) ; File Type (2 Bytes) ; Aux Type (4 Bytes) ; Null Field (2 Bytes) ; Create Date/Time (8 Bytes: Misc. Tools Format) ; Mod Date/Time (8 Bytes: Misc. Tools Format) ; Option List (4 Bytes) ; Null Field (4 Bytes) ; Null Field (4 Bytes) ; Null Field (4 Bytes) ; Null Field (4 Bytes) ;========================================================================== longa on longi on EXPORT set_file_info set_file_info PROC ;========================================================================== ;Indicate that we don't have any HFS Finder Info. ;========================================================================== stz hfs_flag ;========================================================================== ;Reset all time fields to zero. This forces me to calculate the time if ;needed. However, if the create time is set to zero then the create date ;and time fields will be left unchanged. ;========================================================================== stz mod_time stz mod_time+2 stz create_time stz create_time+2 ;========================================================================== ;Go and setup the default parameters for the call. ;========================================================================== jsr setup_params php ;save class state ;========================================================================== ;Process the file name and locate it. ;========================================================================== jsr process_path jsr chk_disk_protect ;========================================================================== ;See if this is a volume header. If it is then return 'bad_path_syntax' ;========================================================================== lda [drvr_buf_ptr] and #$00F0 cmp #volume_header bne ok_to_change lda #bad_path_syntax set_info_err ; sec set_info_exit ; jmp main_exit ;========================================================================== ;Move the directory entry into one entry please ;========================================================================== ok_to_change ; jsr move_dir_entry lda alloc_entry ;get the length word ora storage_type ;add in the storage type ora one_entry ;add in the 1st char of name sta one_entry plp ;restore class flag. beq class0 ;========================================================================== ;When we get here we know that this is a class one call. ;So now we start processing the parameters supplied. ;========================================================================== dec pcount dec pcount jsr get_access ;setup the access field dec pcount bmi to_no_time_change ;========================================================================== ;go and grab the file type that the user has provided. ;If the storage type is a directory then we must nake sure the file ;type field is $0F, which indicates that the file is a directory. ;========================================================================== jsr get_ftype jsr set_dir_type dec pcount bmi to_no_time_change ;========================================================================== ;The user's has also provided the aux type. ;========================================================================== jsr get_aux_type ;========================================================================== ;Skip all the null fields ;========================================================================== dec pcount dec pcount bpl cont to_no_time_change brl no_time_change cont ;========================================================================== ;user's has also provided the create data. Isn't that special! ;========================================================================== ldy #pblk_05_create jsr get_pblk_time bcc @good1 ; 27-Jan-92 MSD: ldy #$8000 ; invalid, but non-zero @good1 stx create_time sty create_time+2 dec pcount bmi do_create_only ;========================================================================== ;Holly Cow Batman the user's has even given us the modification date! ;========================================================================== ldy #pblk_05_mod jsr get_pblk_time bcc @good2 ; 27-Jan-92 MSD: ldy #$8000 ; invalid, but non-zero @good2 stx mod_time sty mod_time+2 ;new code added 2/13/91 CAE dec pcount bmi set_the_info ;========================================================================== ;An option list was also provided ;========================================================================== jsr get_option_list ;end of new code bra set_the_info class0 ;========================================================================== ;The old style call has to provide everything, So go ahead and get it. ;========================================================================== jsr get_access jsr get_ftype jsr set_dir_type jsr get_aux_type ;========================================================================== ;get the create date and time ;========================================================================== ldy #$000E ;index to the create time lda [my_pblk_ptr],y sta create_time iny iny lda [my_pblk_ptr],y sta create_time+2 ;========================================================================== ;Get the modification date and time. ;========================================================================== iny iny lda [my_pblk_ptr],y sta mod_time iny iny lda [my_pblk_ptr],y sta mod_time+2 ;========================================================================== ;We get to 'set_the_info' from both the class1 and class0 style calls. ;========================================================================== set_the_info jsr pack_time ;read the system clock please ;X & Y contain the date and time lda mod_time ;did the user supply the date and time? ora mod_time+2 ;(i.e. is the parameter != 0?) beq @use_current ;yes, use the current date and time ldx mod_time ;else use the user supplied values lda mod_time+2 and #$1F3F ;make sure parameters are in range tay @use_current stx one_entry+last_mod_index sty one_entry+last_mod_index+2 do_create_only lda create_time ;did the user supply a creation date & time? ora create_time+2 beq no_time_change ;no, just leave it alone lda create_time ;else copy user's values to entry sta one_entry+create_index lda create_time+2 and #$1F3F ;make sure parameters are in range sta one_entry+create_index+2 no_time_change ldy #entry_length-1 put_back ; lda one_entry,y sta [drvr_buf_ptr],y dey dey bpl put_back lda gbuf_addr sta drvr_buf_ptr lda gbuf_addr+2 sta drvr_buf_ptr+2 jsr standard_req jsr write_with_cache bcs all_done jsr fix_the_fcr ;update the File Control Record if needed jsr slug_ripple bcs all_done ;new code code added 2/13/91 CAE lda hfs_flag ;do we have any HFS info? beq all_done ;no - so we're done jsr store_hfs_info ;yes - so store it in the resource header ;end of new code all_done jmp set_info_exit ;========================================================================== ;=============== END OF THE MAIN CODE FOR SET_FILE_INFO =================== ;========================================================================== ;========================================================================== ;Below is the subroutines used by SET_FILE_INFO. ;========================================================================== ;========================================================================== ;Now we see if the file is already open. We do this by calling ;get_next_fcr. If this routine finds a ProDOS FCR then we see if the key ;block is the same. If it is then we also update the FCR along with the ;disk ;========================================================================== fix_the_fcr stz fcr_wanted ;reset counter for Get_Next_FCR look_loop ; jsr get_next_fcr ;go grab a FCR bcs no_fcr ldy #fcr_vol_id lda [my_fcr_ptr],y ;get the Volume ID so we can make sure the file is on cmp [my_vcr_ptr] ;the same volume. bne look_loop ;File is on another volume ldy #fcr_file_id lda [pro_fcr_ptr],y cmp one_entry+key_blk_index bne look_loop ;========================================================================== ;Save a modified Aux type please ;========================================================================== ldy #fcr_aux_type ;update the aux type please lda one_entry+aux_type_index sta [pro_fcr_ptr],y ;========================================================================== ;Save file type please ;========================================================================== ldy #fcr_file_type lda one_entry+file_type_index sep #$20 ;a short store sta [pro_fcr_ptr],y rep #$20 ;========================================================================== ;Save create time please ;========================================================================== ldy #fcr_create ;update the create time lda one_entry+create_index sta [pro_fcr_ptr],y iny iny lda one_entry+create_index+2 sta [pro_fcr_ptr],y no_fcr rts ;========================================================================== ;Store the user's access field in the ;========================================================================== get_access ; ldy #pblk_05_accs lda [my_pblk_ptr],y tax and #$FF18 ;clear the reserved bits bne bad_bits ;sorry bud you are out of range longa off sep #$20 txa ora #backup_on ;force the backup bit on sta one_entry+access_index longa on rep #$20 rts bad_bits lda #parm_range_err brl set_info_err ;========================================================================== ;get_aux_type and store it ;========================================================================== get_aux_type ldy #pblk_05_aux+2 lda [my_pblk_ptr],y bne range_problem dey dey lda [my_pblk_ptr],y sta one_entry+aux_type_index rts range_problem lda #parm_range_err brl set_info_err ;========================================================================== ;Get the file type ;========================================================================== get_ftype ldy #pblk_05_ftype lda [my_pblk_ptr],y tax and #$FF00 bne range_problem longa off sep #$20 txa sta one_entry+file_type_index longa on rep #$20 rts ;========================================================================== ;This routine is used to convert the extended date and time fields into ;ProDOS data and time fields ;========================================================================== get_pblk_time lda [my_pblk_ptr],y ;Get the second field so I can range check it and #$00FF ;clear the minutes field cmp #60 bcs range_problem iny ;get the minutes field lda [my_pblk_ptr],y tax and #$00FF cmp #60 ;minutes are 00 to 59 bcs range_problem sta minutes ;save the minutes field txa xba and #$00FF cmp #24 ;hours are 00 to 23 bcs range_problem sta hours ;save the hours field iny iny lda [my_pblk_ptr],y tax and #$00FF sta year ;save the year as well txa xba and #$00FF cmp #31 ;days are 00 to 30 bcs range_problem sta day ;don't forget the day now. iny iny lda [my_pblk_ptr],y and #$00FF sta month cmp #12 ;month = 0 to 11 bcs range_problem iny ;get the null/day of week field lda [my_pblk_ptr],y xba ;put null in the high byte for easy compare cmp #$0008 ;max value is 7 for day of week bcs range_problem lda hours ora minutes ora year ora day ora month beq use_clock inc day inc month ;comvert to ProDOS format jsr convert_time ;convert the time to ProDOS format rts use_clock ; tax ;return 0000 so we use the current time txy clc ; 27-Jan-92 MSD: date was valid rts ;========================================================================== ;This routine will change the file type to $0F if the storage type of the ;file is a subdirectory ;========================================================================== set_dir_type ; lda storage_type ;if storage is a directory only allow cmp #subdir_type ;file type of $0F please bne norm_file longa off ;short mode for a second please sep #$20 lda #$000F ;File type for directories sta one_entry+file_type_index longa on rep #$20 ;back to 16 bit mode norm_file ; rts ;========================================================================== ;Get the option list info. ; ;The option list is structured as follows - ; ; word - buffer size ; word - data size ; word - FST ID ; additional data (FST-specific) ;========================================================================== get_option_list ;added 2/13/91 CAE ; If the file is not a resource file then skip the option list since there's ; no place to store the info anyway. lda storage_type ;get storage type cmp #resource_type ;is it a resource file? bne @done ;no - so skip option list ; Store ptr to option list buffer on direct page. Exit if ptr = 0. ldy #pblk_05_opt lda [my_pblk_ptr],y ;get option list ptr sta 0 inc a ;name length is 0 so sta [temp_ptr] ;set length to 1 bra stuff_a ;and insert the 'A' @not_zero ldy #2 lda [temp_ptr],y ;get first 2 chars and #$00ff ;only want first char cmp #'A' ;is it a letter? bcs char1_ok ;yes - so we're ok lda [temp_ptr] ;get name length tay ;and save clc adc #4 cmp EOF THEN ; req_cnt := (EOF-curr_mark) ; ;NOTE: carry must be clear when we get here. ;========================================================================== lda curr_mark adc user_req_cnt sta math_temp lda curr_mark+2 adc user_req_cnt+2 cmp curr_eof+2 bcc not_greater ;no problem with request count bne too_large lda math_temp cmp curr_eof ;check lower 16 bits bcc not_greater beq not_greater too_large ; ;========================================================================== ;If the request is too large then we need to adjust the request count. ;========================================================================== sec lda curr_eof sbc curr_mark sta user_req_cnt lda curr_eof+2 sbc curr_mark+2 sta user_req_cnt+2 not_greater ; ;========================================================================== ;Lets stop here and take a brief look at the current file marker. ; ;Diagram: (A) (B) (C) ; ; | | $00 to $7F | $00 to $FF | $000 to $1FF | ; | | | | | ; | MUST BE ZERO |<- master ->|<- index ->|<- Byte index ->| ; |_______________|_____________|_______________|_________________| ; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ; |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| ; | | | | | ; 3 2 2 4 1 6 0 8 0 0 ; ; (A) = Index into the master index block: ; This value goes upto 127. This means that the total ; number of index blocks that a file can contain is ; 127. ; ; (B) = Index into the index block: ; This value goes upto 255. This means that there ; can be upto 255 data blocks per index block. ; ; (C) = index into the data block: ; This value goes upto 512. This means that there ; can be upto 512 bytes of data in the data block. ; ;========================================================================== ;========================================================================== ;see if newline is enabled. If it is not then call the fast routines. ;otherwise fall into snell mode. ;========================================================================== lda newline_len beq fast_read ;runs like a bat out of hell! dec a ;see if this is a single char newline bne fast_read lda [newline_ptr] and #$00FF ;clear garbage byte sta newline_char EXPORT fast_read fast_read ; ;========================================================================== ;If we get here we know that newline is disabled so we do not have to check ;each character that we read. This means that multiple blocks can be moved ;into the user's buffer directly without having to go into the I/O buffer. ;Note however that the last block is moved into the I/O buffer. ; ;before we can start sending multiply blocks we must empty the current ;data block that is in our buffer. If there are enough bytes to satisfy ;the read request we just send the bytes and exit. ;========================================================================== single_block ; jsr send_partial bcc fast_loop clc brl end_read_write ;all done with read. ;========================================================================== ;First lets calculate how many bytes are left in this block. ;========================================================================== fast_loop ; lda user_req_cnt+2 bne do_seq_blks lda user_req_cnt cmp #blk_size+1 bcs do_seq_blks jmp send_last ;we have less then 512 bytes left do_seq_blks ; ;========================================================================== ;We know that the user still has more then 512 bytes to go before the read ;request is satisfied. So lets go and see if there are any sequential ;blocks that we can read. If there are no sequential blocks then we must ;get the block address our selves and issue a read of one block. This ;of course makes mister happy face very sad since he will have to double ;buffer. ;========================================================================== lda storage_type cmp #subdir_type bcs single_block jsr num_seq_blks ;see if there are any sequential blks beq single_block seq_avail ; ;========================================================================== ;when we get here we know that there are some sequential blocks that can ;be read. But we must see if the number of sequential blocks is less then ;the number of blocks wanted. ;========================================================================== stx drvr_blk_num ;save block number for read inc a sta math_temp ;number of sequential blocks avail. stz drvr_req_cnt stz drvr_req_cnt+2 stz drvr_blk_num+2 lda user_req_cnt+1 ;first convert bytes wanted to blocks lsr a cmp math_temp bcc use_users_size lda math_temp ;use ALL sequential blocks. use_users_size ; asl a ;convert block count to bytes sta drvr_req_cnt+1 ;========================================================================== ;Now setup the buffer pointer to point to the user's buffer. ;========================================================================== lda users_buf_ptr sta drvr_buf_ptr lda users_buf_ptr+2 sta drvr_buf_ptr+2 jsr read_with_mount bcc cont001 ;good. jmp end_read_write cont001 ; jsr rw_adjust ;adjust the following: ; ;(1) user_buf_ptr ; ;(2) tran_cnt ; ;(3) curr_mark ; ;(4) user_req_cnt jmp fast_loop ;========================================================================== ; ;========================================================================== send_last ; jsr send_partial clc ;========================================================================== ;===== END of READ call. We save the processor status and error code ===== ;===== We then send back the number of bytes that ===== ;===== were read successfully. Then we restore any===== ;===== error condition and exit thru sys_exit. ===== ;========================================================================== EXPORT end_read_write end_read_write ; ;common exit for read and write php pha ldy #pblk_12_tran lda tran_cnt sta [my_pblk_ptr],y iny iny lda tran_cnt+2 sta [my_pblk_ptr],y ;========================================================================== ;Save the current file marker after the read call completes. ;========================================================================== jsr save_curr_mark pla plp jmp main_exit ;========================================================================== ;bump_mark This routine will adjust the following fields: ; ; 1) users_buf_ptr := users_buf_ptr + bytes_sent ; 2) curr_mark := curr_mark + bytes_sent ; 3) user_req_cnt := user_req_cnt - bytes_sent ; 4) tran_cnt := tran_cnt+bytes_sent ;input: ; A = number of bytes to bump fields by. ; ;Uses: math_temp ;========================================================================== EXPORT bump_mark bump_mark ; sta math_temp clc lda users_buf_ptr adc math_temp sta users_buf_ptr bcc do_mark inc users_buf_ptr+2 clc do_mark ; ;========================================================================== ;IMPORTANT NOTES: ; ; users_buf_ptr is always =< $00FFFFFF ; ;WARNING! --> CARRY must be clear when we get here! ;========================================================================== lda curr_mark adc math_temp sta curr_mark bcc do_tran inc curr_mark+2 clc do_tran ; ;========================================================================== ;IMPORTANT NOTES: ; ; curr_mark+math_temp is always less the $00FFFFFF ; ;WARNING! --> CARRY must be clear when we get here! ;========================================================================== lda tran_cnt adc math_temp sta tran_cnt bcc do_req_cnt inc tran_cnt+2 do_req_cnt ; sec lda user_req_cnt sbc math_temp sta user_req_cnt bcs end_bump dec user_req_cnt+2 end_bump rts ;========================================================================== ;Set_users_buf This routine moves the users buffer pointer into ; drvr_buf_ptr. This allows block read from a device driver ; to go directly to the users buffer. ;========================================================================== set_users_buf ; lda users_buf_ptr ;bypass my I/O buffer sta drvr_buf_ptr lda users_buf_ptr+2 sta drvr_buf_ptr+2 rts ENDP ;========================================================================== ;send_partial This routine will send data from the current file marker to ; the end of the data buffer. ; ;Input: A = undefined ; X = indefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_mark (must be correct) ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = data transfer complete ; 0 = no error ; b = k ; ;Uses: All registers ; move_block ;========================================================================== EXPORT send_partial send_partial PROC ;========================================================================== ;first make sure the I/O buffer is filled to the brim. ;========================================================================== jsr fill_io_buf bcc filled_up ;buffer is now ok jmp end_read_write ;========================================================================== ;lets see how many bytes are left in the currently loaded data block. ;========================================================================== filled_up ; lda curr_mark and #$01FF sta math_temp sec lda #blk_size ;Bytes_left := buf_size-curr_position sbc math_temp sta math_temp ;number of bytes left in buffer. ;========================================================================== ;now lets calculate how many bytes we need to send to the user ;========================================================================== ldx user_req_cnt+2 bne send_all_bytes ;he wants as many as I can give cmp user_req_cnt beq send_all_bytes bcc send_all_bytes lda user_req_cnt ;the user wants less then I have send_all_bytes ; sta math_temp tay ;========================================================================== ;If newline is enabled then we have to do processing on each character ;so we avoid the block move routine. ;========================================================================== lda newline_len bne check_newline ;========================================================================== ;If we get here then newline is disabled so use the block move instruction ;========================================================================== clc lda curr_mark ;adjust the starting position and #$01FF adc data_ptr tax ;save low address of buf pointer lda #$0000 adc data_ptr+2 cpy #min_send_cnt ;minimum bytes needed to use blk move bcc send_small pha ;push high word of buffer pointer phx ;push low word of buffer pointer pei users_buf_ptr+2 ;destination address pei users_buf_ptr pea $0000 ;high word of count phy ;number of bytes to send pea move_sinc_dinc jsl move_info bra end_partial ;========================================================================== ;This routine will transfer a request count of less than $20 characters to ;the user's buffer. We do this to speed things up. ;========================================================================== send_small ; stx temp_ptr sta temp_ptr+2 ;pointer to the user's buffer dey tya bmi end_partial ;zero bytes to move? cmp #$0002 ;are we moving less then two bytes? bcc send_8_bit dec a ;second decrement for word check ror a ;is it an even transfer? bcs send_8_bit dey loop_16 ; lda [temp_ptr],y sta [users_buf_ptr],y dey dey bpl loop_16 bra end_partial send_8_bit ; sep #$20 ;8 bit accum loop_8 ; lda [temp_ptr],y sta [users_buf_ptr],y dey bpl loop_8 rep #$20 ;========================================================================== ;Now that we have send the data adjust the pointers etc. ;========================================================================== end_partial lda math_temp jsr bump_mark lda user_req_cnt ora user_req_cnt+2 beq all_done ;request count satisfied ldy #fcr_status ;we are going to read another block so make sure lda [pro_fcr_ptr],y ;the I/O buffer is clean and #file_dirty beq @not_dirty jsr flush_io_buffer ;write the dirty blocks to disk bcc @not_dirty jmp main_exit @not_dirty clc rts all_done sec rts ;========================================================================== ;Below is the code used to handle the newline checking. For this code we ;set the accumulator into 8 bit mode so we do not overflow the user's ;buffer. ;========================================================================== check_newline ; tax ;save newline length for a second lda curr_mark ;isolate block index and #$01FF tay sta entries_checked sec lda users_buf_ptr sbc entries_checked sta temp_ptr lda users_buf_ptr+2 sbc #$0000 sta temp_ptr+2 clc tya adc math_temp ;calculate the last byte address sta entries_checked dex ;see if this is a special case bne slow_read php ;save the mode please longa off sep #$20 ;short accumulator fast_newline ; lda [data_ptr],y sta [temp_ptr],y and newline_mask cmp newline_char beq found_newline iny cpy entries_checked ;are we done yet bne fast_newline plp ;be nice and restore last mode please. bra end_partial found_newline ; plp ;restore last mode please longa on ;========================================================================== ;Number of bytes := Ending position minus starting position ; Y = ending position ; curr_mark = starting position ;========================================================================== lda curr_mark and #$01FF sta math_temp sec tya sbc math_temp inc a jsr bump_mark ;adjust the pointers etc stz user_req_cnt stz user_req_cnt+2 sec rts ;========================================================================== ;This routine is called when there is more then one newline character to ;check. This routine is slower then the above newline read since I have ;to scan all newline characters against a list ;========================================================================== slow_read ; ;========================================================================== ;newline_len := newline_len-1 So I can use it as an index into the newline ;list. ;========================================================================== *** removed 13-Jul-92 DAL to make multi-character newline mode keep working across blocks *** (newline_len was getting decremented farther and farther on each block...ouch!) ;;; dec newline_len *** end 13-Jul-92, part 1 of 2 php longa off sep #$20 slow_newline ; lda [data_ptr],y sta [temp_ptr],y and newline_mask tyx ;save index first ldy newline_len *** added 13-Jul-92 DAL, because I took out a dec newline_len a few lines above dey *** end 13-Jul-92, part 2 of 2 next_newline ; cmp [newline_ptr],y beq found_one dey bpl next_newline txy ;restore index first iny cpy entries_checked ;are we done yet bne slow_newline plp ;be nice and restore last mode please. brl end_partial found_one ; txy ;restore Index first bra found_newline ENDP ;========================================================================== ;fill_io_buf: This routine will load into the I/O buffer the correct ; index and data blocks. It will also adjust the FCR data ; ; WARNING: curr_mark must not point beyond the current ; structure of the file, even though that mark may be within ; the file's EOF. This could happen if a file has a trailing ; portion which is all sparse from a position <128K to a ; position >128K. In this case the file is stored as a ; sapling, not a tree, but owns a sparse area that is ; logically within the "tree" range. In such a case,curr_mark ; must never be in that range when entering this routine. ; ;Input: A = undefined ; X = indefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_mark (must be correct) ; master_ptr (must pointer to master index block) ; index_ptr (must point to the correct index block) ; data_ptr ; pro_fcr_ptr (points to prodos data in FCR) ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; drvr_blk_num ; drvr_call_num ; drvr_buf_ptr ; drvr_req_cnt ; device_dispatcher ; ; ;========================================================================== longa on longi on EXPORT fill_io_buf fill_io_buf PROC stz data_flag ;flag says load data block bra fill_up EXPORT load_indexes load_indexes ; lda #$FFFF ;flag says do not load data block sta data_flag fill_up ; stz mark_changed jsr setup_curr_eof lda curr_mark ;is the mark zero? ora curr_mark+2 beq mark_ok ;yes so don't subtract one lda curr_mark+2 cmp curr_eof+2 ;see if current mark = eof bcc mark_ok lda curr_mark cmp curr_eof bcc mark_ok ;no problem sbc #$0001 ;curr_mark := curr_mark-1 sta curr_mark lda curr_mark+2 sbc #$0000 sta curr_mark+2 dec mark_changed mark_ok ; jsr standard_req ;read 512 bytes only ldy #fcr_storage ;see if this is a subdirectory. lda [pro_fcr_ptr],y cmp #subdir_type bcc standard_file ;File is not a directory jsr fill_directory ;fill it up bud! jsr restore_mark ;fix it if it was changed! rts ;return to caller standard_file ; jsr fill_index ;fill up the index block bcc chk_data rts ;major error chk_data ; bit data_flag ;'-' = fill index block only bpl do_data jsr restore_mark rts do_data ; jsr fill_data ;fill the data buffer jsr restore_mark rts ;exit restore_mark ; php ;save error flag pha ;save error code bit mark_changed bpl no_change inc curr_mark bne no_change inc curr_mark+2 no_change ; pla plp rts ;========================================================================== ;Fill_index: This routine will fill up the index block if it can. ; ;Below is pascal type segment which indicates how fill_index works. ; ;IF master = defined THEN ; BEGIN ; blk_num := get_blk_address(curr_mark) ; {Get block address from index blk} ; IF blk_num = $0000 THEN ; sparse_blk(index_buffer) ; {Fill Index buffer with zeros} ; ELSE ; IF curr_blk <> blk_to_read THEN ; read_blk(index_buffer) ; {Load index block from disk} ; END ; ELSE {master undefined} ; IF curr_mark > $20000 THEN ; BEGIN ; IF sapling = defined THEN ; sparse_blk(index_buffer) {fill index block to zeros} ; ELSE ; BEGIN ; sparse_blk(data_buffer) ; {force data block to zeros} ; data_flag := data_flag-1 {This forces the calling routine ; to exit without loading the data ; block, since I have already loaded ; the blocks with zeros} ; END ; END ; ; WARNING: curr_mark must not point beyond the current ; structure of the file, even though that mark may be within ; the file's EOF. This could happen if a file has a trailing ; portion which is all sparse from a position <128K to a ; position >128K. In this case the file is stored as a ; sapling, not a tree, but owns a sparse area that is ; logically within the "tree" range. In such a case,curr_mark ; must never be in that range when entering this routine. ; ;========================================================================== fill_index ; ldy #fcr_status ;see if the master index block is lda [pro_fcr_ptr],y ;active and #master_active beq no_master ;the master block is not defined lda curr_mark+2 ;make an index into the index block lsr a and #$007F tay ora #$0100 ;build index for upper half of buffer tax lda [master_ptr],y sta drvr_blk_num txy lda [master_ptr],y sta drvr_blk_num+1 ;save the block number to read stz drvr_blk_num+2 lda drvr_blk_num ;see if blk_num = $0000 beq sparse_index ldy #index_blk_num ;see if the block is already loaded cmp [pro_fcr_ptr],y bne load_index clc rts ;no problem here ;========================================================================== ;If Y=$0100 then we know that the master index block is not really active ;If it were active then there would be a real index block. If this is the ;case then we should load in the index block if there is one available. ;========================================================================== sparse_index ; cpy #$0100 ;If non-first index is sparse then bne zero_index ;zero the index block ldy #fcr_storage ;is there an index block to load? lda [pro_fcr_ptr],y cmp #sapling_type bne index_sparse ;just exit no index to load ldy #fcr_key_blk lda [pro_fcr_ptr],y ldy #index_blk_num ;see if the block is already loaded cmp [pro_fcr_ptr],y beq index_sparse ;just exit since the block is loaded sta drvr_blk_num bra load_index zero_index ; jsr chk_index_clean ;make sure the current block is not dirty bcc @no_problem rts @no_problem ldy #index_blk_num ;see if the index block is sparse lda [pro_fcr_ptr],y beq index_sparse ;block is already sparse ldx index_ptr ldy index_ptr+2 jsr send_sparse_blk ldy #index_blk_num lda #$0000 sta [pro_fcr_ptr],y ;indicate index block loaded is sparse index_sparse ; clc rts load_index ; jsr chk_index_clean ;make sure the current block is not dirty bcc @no_problem rts @no_problem lda index_ptr sta drvr_buf_ptr lda index_ptr+2 sta drvr_buf_ptr+2 jsr read_with_cache ;read in the block please bcc index_loaded rts index_loaded ldy #index_blk_num lda drvr_blk_num sta [pro_fcr_ptr],y ;update the loaded block number field rts ;========================================================================== ;If we get here we know that there is no master index block defined. ;========================================================================== no_master lda curr_mark+2 ;see if the mark > $20000 lsr a and #$007F bne index_pain clc rts index_pain ;see if the index block is defined stz drvr_blk_num jsr chk_index_clean bcc @its_clean rts ;return the error @its_clean ldy #fcr_status lda [pro_fcr_ptr],y and #index_active bne sparse_index ;make the index block all zeros sparse_data jsr chk_data_clean ;make sure the data block is OK bcc @good_data rts @good_data ldy #data_blk_num ;see if the block is already sparse lda [pro_fcr_ptr],y beq data_sparse ;data block is alreay sparse ldx data_ptr ldy data_ptr+2 jsr send_sparse_blk ;make the data block sparse ldy #data_blk_num ;see if the block is already sparse lda #$0000 ;indicate block is sparse sta [pro_fcr_ptr],y data_sparse ; dec data_flag ;indicate to the main routine that the clc ;data block does not need checking rts ;========================================================================== ;Chk_index_clean will determine if the current index block needs to be ;written to disk before the new block is loaded and will write it out if ;necessary. ;========================================================================== chk_index_clean phy ldy #fcr_status ;we are going to read another block so make sure lda [pro_fcr_ptr],y ;the I/O buffer is clean and #index_dirty beq @not_dirty ;easy case. lda drvr_blk_num ;get the block number we want to load ldy #index_blk_num ;see if the block is already loaded cmp [pro_fcr_ptr],y beq @not_dirty ;another easy case. pha ;save the driver block number jsr flush_index ;save the data to disk plx ;get the drvr_blk_number back please stx drvr_blk_num ply rts ;carry will return any error @not_dirty ply clc rts ;========================================================================== ;Fill_data: This routine will fill up the data block if it can. ; ;Below is pascal type segment which indicates how Fill_data works. ; ;IF index = defined THEN ; BEGIN ; blk_num := get_blk_address(curr_mark) ; {Get block address from index blk} ; IF blk_num = $0000 THEN ; sparse_blk(data_buffer) ; {Fill Index buffer with zeros} ; ELSE ; IF curr_blk <> blk_to_read THEN ; read_blk(index_buffer) ; {Load index block from disk} ; END ; ELSE ; IF curr_mark > $200 THEN ; sparse_blk(data_buffer) ; {Clear the data buffer} ; ELSE ; read_blk(key_block) ; {main block for file} ; ;========================================================================== fill_data ; ldy #fcr_status lda [pro_fcr_ptr],y and #index_active beq no_index ;there is no index buffer jsr get_data_num ;setup drvr_blk_num from index blk lda drvr_blk_num bne not_sparse ;make the data block sparse cpy #$0100 ;was it the 1st entry bne sparse_data ;make data block sparse lda curr_mark+2 ;see if the master index is zero lsr a and #$007F bne sparse_data ldy #fcr_storage ;is there an index block to load? lda [pro_fcr_ptr],y cmp #seedling_type bne sparse_data ;make block sparse please ldy #fcr_key_blk ;this is a seedling so load the block lda [pro_fcr_ptr],y sta drvr_blk_num not_sparse ; jsr chk_data_clean ;make sure the data buffer is OK bcc @still_ok rts @still_ok lda drvr_blk_num ldy #data_blk_num ;see if the block is already loaded cmp [pro_fcr_ptr],y bne load_data exit_fill_data ; clc rts ;no problem here load_data ; lda data_ptr sta drvr_buf_ptr lda data_ptr+2 sta drvr_buf_ptr+2 jsr read_with_mount ;read in the block please bcc store_data_num rts store_data_num ; ldy #data_blk_num ;update current block loaded field lda drvr_blk_num sta [pro_fcr_ptr],y rts ;========================================================================== ;If we get here we know that there is no index block loaded ;========================================================================== no_index ; lda curr_mark+1 lsr a and #$00FF beq @need_long brl sparse_data ;make the data block sparse if needed @need_long ldy #fcr_key_blk lda [pro_fcr_ptr],y ldy #data_blk_num ;current block that is loaded cmp [pro_fcr_ptr],y bne reload_data clc rts ;block is already loaded reload_data ; sta drvr_blk_num lda data_ptr sta drvr_buf_ptr lda data_ptr+2 sta drvr_buf_ptr+2 jsr read_with_mount bcc data_read rts data_read ; ldy #data_blk_num lda drvr_blk_num ;update the current block loaded sta [pro_fcr_ptr],y rts ;========================================================================== EXPORT get_data_num get_data_num ; lda curr_mark+1 lsr a and #$00FF tay ora #$0100 tax lda [index_ptr],y ;setup the block number sta drvr_blk_num txy lda [index_ptr],y sta drvr_blk_num+1 stz drvr_blk_num+2 rts ;========================================================================== ;Chk_data_clean will determine if the current data block needs to be ;written to disk before the new block is loaded ;========================================================================== chk_data_clean phy ldy #fcr_status ;we are going to read another block so make sure lda [pro_fcr_ptr],y ;the I/O buffer is clean and #data_dirty beq @not_dirty ;easy case. lda drvr_blk_num ;get the block number we want to load ldy #data_blk_num ;see if the block is already loaded cmp [pro_fcr_ptr],y beq @not_dirty ;another easy case. pha ;save the driver block number jsr flush_data_blk ;save the data to disk plx ;get the drvr_blk_number back please stx drvr_blk_num ply rts ;carry will return any error @not_dirty ply clc rts fill_directory ; ;========================================================================== ;OK this file is a directory so lets handle this pain in the butt case. ; ;The way it works: ; ; The master index field contains the current block number ; that is loaded into the data buffer. So when I'm called ; with the current mark I calculate the block number that ; that is needed. If the block number is less then the ; current block number then I walk the backward links till ; I find the block needed. If the block wanted is greater ; then the current block I walk the links forward till I ; find the correct block, and at the end I update the FCR. ; ;========================================================================== lda #in_cache sta drvr_cache lda data_ptr ;setup buffer pointer to data buffer sta drvr_buf_ptr lda data_ptr+2 sta drvr_buf_ptr+2 lda curr_mark+1 lsr a ;bytes to blocks sta math_temp ldy #data_blk_num lda [pro_fcr_ptr],y sta entries_blk_num ldy #master_blk_num lda [pro_fcr_ptr],y cmp math_temp bne have_to_look clc rts have_to_look ; sta last_blk bcs look_backward ;IF current > wanted THEN go backward ;========================================================================== ;Of we get here we walk thru the forward links till we find the right blk ;========================================================================== forward_loop ; ldy #$0002 lda [data_ptr],y beq bad_dir_blk ;This should NEVER happen!!!!! sta drvr_blk_num jsr go_get_block ;go read the block bcc ar16 rts ;return the error ar16 ; lda [data_ptr] ;verify backward links please cmp entries_blk_num beq cont16 lda #dir_error bra dir_bad cont16 ; ldy #data_blk_num lda drvr_blk_num sta [pro_fcr_ptr],y sta entries_blk_num ;update both the FCR and Link verify inc last_blk ;advance the block counter lda last_blk cmp math_temp ;See if this the right bloc number bne forward_loop ;go and get the next block end_links ldy #master_blk_num ;update the current block sta [pro_fcr_ptr],y clc rts ;========================================================================== ;We need to set the mark backward. So we need to walk the links backward ;========================================================================== look_backward ; lda [data_ptr] beq bad_dir_blk ;This should NEVER happen!!!!! sta drvr_blk_num jsr go_get_block ;go read the block bcc ar18 rts ;return the error ar18 ; ldy #$0002 lda [data_ptr],y cmp entries_blk_num bne dir_bad lda drvr_blk_num ldy #data_blk_num sta [pro_fcr_ptr],y sta entries_blk_num dec last_blk ;advance the block counter lda last_blk cmp math_temp ;See if this the right bloc number bne look_backward ;go and get the next block bra end_links ;we are done ;========================================================================== bad_dir_blk ; lda #parm_range_err dir_bad ; sec jmp main_exit ;========================================================================== go_get_block ; jsr standard_req jsr read_with_cache ;issue the read call rts data_flag DC.W 00 ENDP ;========================================================================== ;send_sparse_blk: This routine will zero out 512 bytes of memory. ; ;Input: A = undefined ; X = low word pointer to buffer ; Y = high word pointer to buffer ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; ;========================================================================== longa on longi on EXPORT send_sparse_blk send_sparse_blk PROC stx sparse_ptr sty sparse_ptr+2 ldy #$01FE ;starting index lda #$0000 sparse_loop ; sta [sparse_ptr],y dey dey bpl sparse_loop rts ENDP ;========================================================================== ;calc_seg_blks: This routine will calculate the number of sequential ; blocks in an index block. This routine will NOT calculate ; across index blocks. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; index_ptr (points to the index pointer) ; curr_mark (curr_mark must be on block boundary!) ; ;Output: A = number of blocks that are sequential ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; math_temp (just a temp counter) ; comp_temp = and_mask ; check_blk = entries_checked ;========================================================================== longa on longi on EXPORT num_seq_blks num_seq_blks PROC ;========================================================================== ;Local equates for this routine ;========================================================================== comp_temp equ and_mask ;(same ZP location different name) check_blk equ entries_checked ;(same ZP location different name) ;========================================================================== ;Zero the counter and save the current file marker ;========================================================================== stz math_temp lda curr_mark pha lda curr_mark+2 pha ;========================================================================== ;first make sure the index blocks are loaded correctly ;========================================================================== jsr load_indexes ;========================================================================== ;No go and get the first block from the Index block buffer. ;========================================================================== jsr get_blk_num sta check_blk pha ;save starting block number lda storage_type cmp #subdir_type bcs seq_exit ;always return zero for a directory lda newline_len bne seq_exit ;always return zero if newline enabled calc_loop ; ;========================================================================== ;Calculate the index to the next block number. ;========================================================================== jsr get_blk_num bcs seq_exit ;we have looked at the entire block dec a ;subtract one from the block cmp #$FFFF ;see if this block is sparse beq seq_exit ;this must be a sparse block! cmp check_blk bne seq_exit inc a ;restore the block number sta check_blk ;setup for next compare inc math_temp bra calc_loop seq_exit ; ;========================================================================== ;restore the current marker and return the number of sequential blocks. ;========================================================================== plx ;load X with starting block pla sta curr_mark+2 pla sta curr_mark lda math_temp ;return number of sequential blocks rts ;========================================================================== ;get_blk_num: This routine will return the block number out of the index ; block based on the current file marker. It will also ; advance the file marker by 512 bytes. ; ;Input: curr_mark ; ;Output: carry set = end of block ; A = block number ;========================================================================== get_blk_num ; lda curr_mark+1 lsr a and #$00FF pha tay ora #$0100 tax lda [index_ptr],y and #$00FF sta comp_temp txy lda [index_ptr],y and #$00FF xba ora comp_temp tax clc lda curr_mark adc #blk_size sta curr_mark bcc ar11 inc curr_mark+2 clc ar11 ; txa ;block number plx ;get the first index value beq end_seq ;just set the carry ;========================================================================== ;WARNING!! --> Carry must be clear when we get here. ;========================================================================== rts end_seq ; sec rts ENDP ;========================================================================== ;setup_curr_mark This routine will load the current file marker out of the ; FCR and store it in curr_mark ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr (points to my FCR data) ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_mark (contains current file marker) ; ;Uses: All registers ;========================================================================== longa on longi on EXPORT setup_curr_mark setup_curr_mark PROC ldy #fcr_curr_mark lda [pro_fcr_ptr],y sta curr_mark iny iny lda [pro_fcr_ptr],y sta curr_mark+2 rts ENDP ;========================================================================== ;setup_curr_eof This routine will load the current end of file out of the ; FCR and store it in curr_eof ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr (points to my FCR data) ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_eof (contains current end fo file) ; ;Uses: All registers ;========================================================================== longa on longi on EXPORT setup_curr_eof setup_curr_eof PROC ldy #fcr_curr_eof lda [pro_fcr_ptr],y sta curr_eof iny iny lda [pro_fcr_ptr],y sta curr_eof+2 rts ENDP ;========================================================================== ;save_curr_mark This routine will save the current end of file into the ; FCR. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr (points to my FCR data) ; curr_mark ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Uses: A and Y registers ;========================================================================== longa on longi on EXPORT save_curr_mark save_curr_mark PROC ldy #fcr_curr_mark lda curr_mark sta [pro_fcr_ptr],y iny iny lda curr_mark+2 sta [pro_fcr_ptr],y rts ENDP ;========================================================================== ;Write: This file contains code used to write data to a file. ; The types of files supported are: ; ; 1) seedling ; 2) sapling ; 3) tree ; ;Created: oct 06, 1987 ;Modified: oct 15, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Device Dispatcher (subroutine) ; General I/O Buffer (1K buffer, I read 512 bytes) ; and lots of other stuff. ; ;Call Format: ; ;Class 0 Reference Number (2 Bytes) ; Pointer to Data Buffer (4 Bytes) ; Request Count (4 Bytes) ; Transfer Count (4 Bytes) ; ;Class 1 PCount (2 Bytes) ; Reference Number (2 Bytes) ; Pointer to Data Buffer (4 Bytes) ; Request Count (4 Bytes) ; Transfer Count (4 Bytes) ; Cache Priority (2 Bytes) ; ;========================================================================== longa on longi on EXPORT write write PROC stz seq_write_cnt ;reset sequential block counter jsr setup_params ;setup standard parameters ldy #fcr_access ;see if the file is write protected lda [my_fcr_ptr],y and #ClrAllButAccess cmp #write_access bcs write_ok ;write access is enabled. bad_access ; ;user cannot write to this file. lda #invalid_access sec jmp main_exit write_ok ; ldy #vcr_dev ;last known location of volume lda [my_vcr_ptr],y sta drvr_dev_num ;I hope that the disk is still here. jsr chk_disk_protect not_protected ; jsr read_write_setup jsr setup_curr_mark jsr setup_curr_eof jsr setup_io_ptrs ;setup pointers to I/O buffer jsr chk_swapped ;mount the volume if needed bcc vol_online jmp main_exit ;========================================================================== ; IF curr_mark NOT block_aligned THEN ;========================================================================== vol_online ; jsr users_to_drvrs ;move user's pointer to driver's ptr jsr user_to_temp ;temp_ptr := user_buf_ptr block_loop ; lda curr_mark ;see if we are block aligned and #$01FF beq block_aligned ;yes we are block aligned jsr partial_write ;write until data is block aligned. bcs write_exit ;major problem bra next_block block_aligned ; lda user_req_cnt+2 ;is req_cnt >= 512? bne more_then_512 lda user_req_cnt cmp #blk_size bcc less_then_512 more_then_512 ; jsr full_write ;transfer full 512 bytes. bcs write_exit bra next_block ;go to the next block please ;========================================================================== ;Less_then_512. we have less then 512 bytes to write. ;========================================================================== less_then_512 ; jsr partial_write ;write the partial block to disk bcs write_exit ;major problem. next_block ; jsr rw_adjust ;adjust the following: ; ;(1) user_buf_ptr ; ;(2) tran_cnt ; ;(3) curr_mark ; ;(4) user_req_cnt lda user_req_cnt+2 ;see if we are done yet bne block_loop lda user_req_cnt bne block_loop clc write_exit php pha bcc @10 ;there is no error so skip flush jsr flush_file ;try to save the world @10 jsr update_mark_eof ;make sure the mark is OK ldy #fcr_curr_eof ;update the current end of file please lda curr_eof sta [pro_fcr_ptr],y iny iny lda curr_eof+2 sta [pro_fcr_ptr],y lda #file_dirty jsr set_fcr_status ;indicate that something changed. jsr standard_req ;make sure we write 512 bytes only jsr flush_blocks ;flush any blocks to disk. bcs write_failed ;bad news we cannot complete the flush!!! ; ;We know that the mark actually points to one past where the last byte is so ;lets reduce the mark by one please ;v00.06 a06 ; lda curr_mark bne @no_high dec curr_mark+2 @no_high dec curr_mark clc jsr get_write_blk ;make sure I/O buffer is OK bcs write_failed txa ;block to load beq holy_cow ;I hope not jsr load_data ;load the data buffer please bcs write_failed holy_cow ; inc curr_mark bne @low_only inc curr_mark+2 @low_only pla ;restore error code plp jmp end_read_write ;exit thru wonder code in read file write_failed plx ;kill the old exit code plp ;kill the old processor flag sec ;make sure the error is set jmp end_read_write ;exit please. ;========================================================================== ;Write blocks of 512 to disk ;========================================================================== full_write lda #blk_size jsr range_chk_eof ;see if we overrun the EOF bcs eof_error ;sorry we have an eof error jsr standard_req ;transfer of 512 bytes ldy #fcr_status ;see if the data block is dirty lda [pro_fcr_ptr],y and #data_dirty beq clean_blk ;no flush needed jsr flush_data_blk ;write the data block to disk bcs write_exit ;get out of here with the error code clean_blk ; jsr user_to_temp ;temp_ptr := user_buf_ptr clc jsr get_write_blk ;is there a current block allocated? bne block_allocated ;yes there is a block allocated. jsr chk_sparse ;is the user's data sparse? bcc do_flush ;data sparse so flush queued data blocks ; sec jsr get_write_blk ;allocate a block please bcc @no_error brl write_exit ;cannot allocate a new block? @no_error pha jsr user_to_temp ;point to user's buffer pla block_allocated ; sta drvr_blk_num ;save the block number to write. jsr user_to_data ;move user's data to data buffer jsr write_data_blk ;write the data block to disk. rts do_flush ; jsr flush_blocks ;issue the flush command rts user_to_data ; lda users_buf_ptr ;setup driver buffer pointer to sta drvr_buf_ptr ;point to the user's data! lda users_buf_ptr+2 sta drvr_buf_ptr+2 rts eof_error lda #out_of_range ;you have pushed me too far!!! sec rts ; ldy #$01FE ;move 512 bytes please ;user_loop anop ; lda [drvr_buf_ptr],y ; sta [data_ptr],y ; dey ; dey ; bpl user_loop ; rts ;========================================================================== ;partial_write: This routine will handle reading/writing a partial block ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ;========================================================================== partial_write ; jsr build_index ;simulate a disk write jsr range_chk_eof ;see if we overrun the EOF bcs eof_error ;sorry we have an eof error jsr standard_req ;we can only write 512 bytes! jsr flush_blocks ;write any left over seq. blocks bcs end_partial ;error condition clc jsr get_write_blk ;is there a current block allocated? bne block_is_avail ;there is a block allocated. ; we know that the block is not allocated so check the data jsr chk_sparse ;AND (data NOT sparse) bcc is_sparse ;... (data IS sparse) jsr get_write_blk ;allocate a block for the new data bcs end_partial pha ;save the block number ldx data_ptr ;clear the new data block ldy data_ptr+2 jsr clear_index pla block_is_avail ; jsr load_data ;load in the data block bcs end_partial jsr user_to_temp jsr merge_data ;add data to current block! lda #file_dirty+data_dirty jsr set_fcr_status ;indicate that something changed. clc rts is_sparse ; ldy #data_blk_num lda [pro_fcr_ptr],y ;is block already loaded? beq @sparse_loaded ldy #fcr_status lda [pro_fcr_ptr],y and #data_dirty beq @just_clear_buf ;no need to update the data block jsr flush_data_blk bcs end_partial @just_clear_buf ldx data_ptr ;clear the new data block ldy data_ptr+2 jsr clear_index ldy #data_blk_num lda #$0000 sta [pro_fcr_ptr],y ;is block already loaded? @sparse_loaded jsr build_index ;simulate a disk write sta drvr_req_cnt stz drvr_req_cnt+2 clc end_partial ; rts ;========================================================================== ;Range_chk_eof This routine will make sure the write call will work with ; the three byte eof. ; ;Input: A = write_count ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_eof ;the current eof ; ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ;========================================================================== range_chk_eof clc adc curr_mark lda #0000 adc curr_mark+2 ;check the high word and #$FF00 ;clear the result bne range_err clc rts range_err sec rts ;========================================================================== ;write_data_blk This routine will write data blocks to disk. The code will ; determine if we can hold off writing to disk so we can ; gain performance by doing a multi-block transfer call. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; drvr_blk_num ;block number to write ; drvr_buf_ptr ;pointer to the data ; ; ;Output: A = error code if carry set otherwise undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ;========================================================================== write_data_blk ; lda seq_write_cnt ;do we have anything to write? beq new_block ;no lda drvr_blk_num ;is this a sequential block write? dec a cmp seq_write_blk beq bump_seq ;bump the sequential counter lda drvr_blk_num ;save block number to write pha lda drvr_buf_ptr pha lda drvr_buf_ptr+2 pha jsr flush_blocks ;write any seq. blocks to disk plx stx drvr_buf_ptr+2 plx stx drvr_buf_ptr plx stx drvr_blk_num stz seq_write_cnt bcs end_write_data ;error new_block ; inc seq_write_cnt ;advance the number of sequential blks lda drvr_blk_num sta seq_write_blk ;starting block for write call jsr move_to_data_buf lda drvr_buf_ptr sta seq_write_start lda drvr_buf_ptr+2 sta seq_write_start+2 end_write_data lda #data_clean ;indicate that we have written block. jsr clr_fcr_status jsr standard_req ;set drvr_req_cnt to 512 bytes. clc ;exit rts bump_seq inc seq_write_cnt ;advance the block counter inc seq_write_blk ;update new last sequential block lda user_req_cnt+2 bne end_write_data lda user_req_cnt cmp #blk_size*2 bcs end_write_data ldy #data_blk_num lda drvr_blk_num cmp [pro_fcr_ptr],y ;Should I Copy the data to the buffer bne end_write_data ;Do not move the data. jsr do_data_update bra end_write_data ; ;This routine copies the user's data to the I/O Buffer ; ;input: A = block number ; move_to_data_buf ldy #data_blk_num cmp [pro_fcr_ptr],y ;is block already loaded? bne io_buf_ok ;don't worry about I/O buffer update do_data_update pei drvr_buf_ptr+2 ;address of user's data pei drvr_buf_ptr pei data_ptr+2 ;destination address pei data_ptr pea $0000 ;high word of count pea blk_size ;number of bytes to send pea move_sinc_dinc jsl move_info io_buf_ok rts ;========================================================================== ;flush_blocks: This routine will write out any data blocks that have not ; been written to disk. If will also make sure that the I/O ; buffer contains valid data. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = error code if carry set otherwise undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ;========================================================================== EXPORT flush_blocks flush_blocks ; lda seq_write_cnt ;is there anything to write? bne must_write clc rts must_write ; stz seq_write_cnt ;reset the sequential block counter stz drvr_req_cnt ;setup the write count asl a ;convert blocks to bytes sta drvr_req_cnt+1 lsr a ;now get the starting block dec a ;subtract one please pha sec lda seq_write_blk sbc 1,s sta drvr_blk_num ;starting block number pla ;fix the stack lda seq_write_start sta drvr_buf_ptr lda seq_write_start+2 sta drvr_buf_ptr+2 ;pointer to the data jsr write_with_mount bcs flush_error jsr standard_req clc flush_error ; rts ;========================================================================== ;Set temp_ptr to the user's buffer pointer ;========================================================================== user_to_temp ; lda users_buf_ptr sta temp_ptr ;set pointer to head of data lda users_buf_ptr+2 sta temp_ptr+2 rts users_to_drvrs ; lda users_buf_ptr sta drvr_buf_ptr ;set pointer to head of data lda users_buf_ptr+2 sta drvr_buf_ptr+2 rts ;========================================================================== ;merge_data: This routine will add in the user's data into the I/O ; buffer. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_mark ;current file marker ; pro_fcr_ptr ;points to file control record ; data_ptr ;points to data block in I/O buffer. ; temp_ptr ;points to user data ; user_req_cnt ;used by build_index ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; ; b = k ; ; drvr_req_cnt ;equals bytes moved ; ; ;uses: all registers ; math_temp ;========================================================================== merge_data ; jsr build_index ;'A' = 1 to $1FF sta math_temp ;save count sta drvr_req_cnt ;simulate a write to disk. dec a ;A,X,Y perserved by 'update..' routine pha tay ;'Y' = 0 to $1FE (move count) clc lda curr_mark and #$01FF adc 1,s ;make index from END of buffer tax ;index into data buffer pla ;fix the stack longa off ;block after the merge sep #$20 merge_loop ; lda [temp_ptr],y ;pointer to user's data phy ;save user index txy sta [data_ptr],y ;store in the I/O buffer dex ply dey bpl merge_loop ;I/O buffer updated. longa on rep #$20 clc lda curr_mark ;save the mark pha adc math_temp sta curr_mark lda curr_mark+2 pha adc #$0000 sta curr_mark+2 jsr clr_to_boundary ;Clear to blk boundary pla sta curr_mark+2 pla sta curr_mark rts ;========================================================================== ;See if we have to deal with a sparse block. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_mark ;current file marker ; pro_fcr_ptr ;pointer to file control record ; temp_ptr ;pointer to user's data buffer ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = sparse ; 0 = not sparse ; b = k ; ;uses: all registers ; math_temp ; ;FUNCTION sparse():boolean ; ; BEGIN ; index := (curr_mark MOD 512) ; ; sparse := true ; ; While (index < block_size) and (index < user_req) and (sparse = true) DO ; BEGIN ; IF data[index] <> 0 THEN ; sparse := flase ; index := index + 1 ; ; END ; END ;========================================================================== chk_sparse ; jsr user_to_temp ;temp_ptr := user_buf_ptr jsr build_index tay ;number of bytes to scan dey ;force 1 to $0200 to 0 to $01FF longa off sep #$20 ;short accum for test scan_loop ; lda [temp_ptr],y ;pointer to user's data bne non_sparse dey bpl scan_loop longa on rep #$20 ;restore 16 bit mode clc rts ;user data is all sparse non_sparse ; longa on rep #$20 ;restore 16 bit mode sec rts build_index ; lda curr_mark ;number of bytes to check in user buf. and #$01FF ;0 to $1FF pha sec lda #blk_size ;calc number of bytes to scan sbc 1,s ;range $0001 to $0200 ply ;fix the stack ldy user_req_cnt+2 ;how many bytes do we need to write? bne full_scan cmp user_req_cnt bcc full_scan lda user_req_cnt full_scan ; rts ENDP ;========================================================================== ;update_mark_eof: ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_mark ;current file marker ; curr_eof ;current end of file ; pro_fcr_ptr ;pointer to file control record ; ;Output: A = restored ; X = restored ; Y = restored ; P = nvmxdizc ; ..000... ; ; b = k ;========================================================================== EXPORT update_mark_eof update_mark_eof PROC pha phx phy lda curr_mark+2 cmp curr_eof+2 bcc end_update ;EOF still OK beq chk_low_eof bra update_the_eof chk_low_eof ; lda curr_mark cmp curr_eof beq end_update bcc end_update ;EOF still OK update_the_eof ; lda curr_mark+2 sta curr_eof+2 ;save the high byte lda curr_mark sta curr_eof ;save the low byte end_update ; ply plx pla rts ENDP ;========================================================================== ;get_write_blk: This routine will return the block number for the new data. ; If the file has a block allocated then that block number ; is returned otherwise a new block is allocated for the file. ; If the file needs to be expanded then it will be. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = allocate a new block if block not allocated ; 0 = just return current block number. (0 or blk num) ; b = k ; ; curr_mark ;current file marker ; pro_fcr_ptr ;points to file control record ; ;Output: A = block number of error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; ;uses: all registers ; math_temp ;========================================================================== EXPORT get_write_blk get_write_blk PROC php ;save check flag. php pla sta alloc_chk_flag lsr a ;are we looking for a bcs do_allocation jsr chk_allocation rts ; ;If here then we need to allocate or return the current block. ; do_allocation ; clc lda curr_mark adc #$0001 sta data_eof lda curr_mark+2 adc #$0000 sta data_eof+2 jsr eof_to_blks ;convert current position to blks. lda data_storage ;storage type needed (seed,sapling,tree) cmp #seedling_type bne sapling_case brl add_new_block ;just go and get the block please sapling_case ; cmp #sapling_type bne tree_case ; ;IF new_type = sapling THEN ; IF old_type = seedling THEN ; seedling_to_sapling ; ELSE ; add_index ; ; ldy #fcr_storage ;current storage type lda [pro_fcr_ptr],y cmp #seedling_type bne add_new_block jsr seed_to_sap ;convert a seedling to a sapling bcc add_new_block rts ; ;IF new_type = tree THEN ; IF old_type = seedling THEN ; BEGIN ; seedling_to_sapling ; sapling_to_tree ; END ; ELSE ; IF old_type = sapling THEN ; sapling_to_tree ; ELSE ; IF old_type = tree THEN ; BEGIN ; IF master_index[curr_mark] = nil THEN ; add_master_index ; add_index ; END ; tree_case ; ldy #fcr_storage ;current storage type lda [pro_fcr_ptr],y cmp #seedling_type bne not_seed jsr seed_to_sap ;convert seedling to a sapling bcs abort_tree jsr sapling_to_tree ;convert a sapling to a tree bcc add_new_block abort_tree rts not_seed ; cmp #sapling_type ;is this a sapling file bne not_sapling jsr sapling_to_tree ;convert a sapling to a tree bcs abort_tree bra add_new_block not_sapling ; lda curr_mark+2 ;see if the index block is allocated lsr a ldx master_ptr ldy master_ptr+2 jsr get_index_blk ;get the index block out of master blk tax bne add_new_block ;we do not need to add an index block jsr tree_to_tree ;add a new index block bcs abort_tree ;========================================================================== ;Now lets see if we need to add a new block or return the current block. ;========================================================================== add_new_block ; jsr calc_free_blks ;make sure that we have a block avail. bcs abort_tree ;just exit tax bne we_have_room brl out_of_room we_have_room ; ldy #master_blk_num ;see if we should even have looked at lda [pro_fcr_ptr],y beq no_master ;there is no master block for this file lda curr_mark+2 ;see if we need the master index block lsr a ldx master_ptr ;get the block number from index block ldy master_ptr+2 jsr get_index_blk ;A = block number tax bne cont01 ;there is an index block ldy #fcr_status ;see if old index needs to be flushed lda [pro_fcr_ptr],y and #index_dirty beq no_index_flush jsr flush_index bcs abort_tree ;exit no_index_flush ; ldx master_ptr ldy master_ptr+2 lda curr_mark+2 lsr a ;now build a new index block jsr new_block bcs abort_tree ;sorry major problem pha ;save the block number lda #master_dirty+index_dirty+file_dirty jsr set_fcr_status ;indicate master block dirty ldx index_ptr ;clear the new buffer ldy index_ptr+2 jsr clear_index pla ldy #index_blk_num sta [pro_fcr_ptr],y cont01 ; ldy #index_blk_num cmp [pro_fcr_ptr],y ;is the block loaded? beq no_master ;no problem sta key_block ;save the block wanted. jsr flush_index ;write any dirty blocks to disk bcs end_write_blk ;major problems lda key_block ;load in the index block please pha jsr load_index plx ;restore block number bcs end_write_blk txa ldy #index_blk_num sta [pro_fcr_ptr],y no_master ; lda curr_mark+1 lsr a and #$00FF ldx index_ptr ;get the block number from index block ldy index_ptr+2 jsr get_index_blk ;A = block number tax bne have_blk ldy #fcr_status ;see if data block needs to be written lda [pro_fcr_ptr],y and #data_dirty beq data1_clean jsr flush_data_blk bcs end_write_blk data1_clean ; ldx index_ptr ldy index_ptr+2 lda curr_mark+1 lsr a ;now build a new index block and #$00FF jsr new_block bcs end_write_blk ;sorry major problem pha ;save the block number ldy #data_blk_num sta [pro_fcr_ptr],y ;save the new block number lda #index_dirty+file_dirty+data_dirty jsr set_fcr_status ;indicate master block dirty pla have_blk ; jsr load_data bcs end_write_blk lda drvr_blk_num clc end_write_blk ; rts EXPORT load_data load_data ; ;input A= block to load ldy #data_blk_num cmp [pro_fcr_ptr],y ;is block already loaded? beq exit_load_data pha ;save the block to load ldy #fcr_status lda [pro_fcr_ptr],y and #data_dirty beq dont_update jsr flush_data_blk bcs end_load_data dont_update ; lda data_ptr sta drvr_buf_ptr lda data_ptr+2 sta drvr_buf_ptr+2 lda 1,s ;get the block number to load sta drvr_blk_num jsr read_with_mount ;read in the new data block bcs end_load_data ldy #data_blk_num ;update current loaded block lda drvr_blk_num sta [pro_fcr_ptr],y pla exit_load_data ; clc sta drvr_blk_num rts end_load_data ; plx ;fix the stack please sec rts ;========================================================================== ;new_block: This routine will allocate a new block from the system ; and add the block number in the index block pointed to ; by the X and Y registers. ; ;Input: A = index ; X = low word pointer to index block ; Y = high word pointer to index block ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = block number allocated or error code ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; ;uses: all registers ; temp4_ptr ;========================================================================== new_block ; stx temp4_ptr ;pointer to the index block sty temp4_ptr+2 pha ;save the index jsr calc_free_blks ;make sure that we a free block bcs add_failed tax beq to_no_room lda #$0001 ;allocate one block ldx #$0000 ;start at block zero jsr find_free_blks bcs add_failed phx ;save the block number jsr bump_blks_used lda 3,s ;get the index please tay ;save the low index ora #$0100 tax ;save the high index pla longa off sep #$20 ;8 bit mode sta [temp4_ptr],y xba txy sta [temp4_ptr],y longa on rep #$20 ;16 bit mode xba plx ;fix the stack clc rts add_failed plx ;fix the stack rts to_no_room pla ;fix the stack brl out_of_room bump_blks_used ; ldy #fcr_blks_used lda [pro_fcr_ptr],y inc a ;advance the blocks used count sta [pro_fcr_ptr],y lda #dirEntry_dirty ;the directory entry needs updating when flushed jsr set_fcr_status rts ;========================================================================== ;get_index_blk: This routine will load a block number out of an index block ; ;Input: A = index ; X = low word pointer to index block ; Y = high word pointer to index block ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = block number ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;uses: all registers ; temp_ptr ;========================================================================== EXPORT get_index_blk get_index_blk ; stx temp_ptr sty temp_ptr+2 tax ;low word index ora #$0100 ;high word index tay longa off sep #$20 ;8 bit accum lda [temp_ptr],y ;get the high word block number xba txy lda [temp_ptr],y ;get the low word block number longa on rep #$20 ;16 bit accum rts ;========================================================================== ;Convert a seedling file into a sapling file. ;========================================================================== seed_to_sap ; jsr flush_blocks ;flush anydata still around bcc do_sap rts do_sap ; jsr calc_free_blks ;see how many blocks we have tax bne lots_of_room brl out_of_room ;sorry bud not today lots_of_room ; lda #$0001 ;go get me a new block ldx #$0000 ;start looking at block zero jsr find_free_blks bcs end_to_sap txa ;new key block pha ldy index_ptr sty temp4_ptr ldy index_ptr+2 sty temp4_ptr+2 dec a ;see if we should flip data and index ldy #fcr_key_blk ; cmp [pro_fcr_ptr],y beq do_flip txa ldy #index_blk_num sta [pro_fcr_ptr],y ;save the new index block number jsr bump_blks_used ldy #fcr_key_blk ;data block address lda [pro_fcr_ptr],y ldy #$0000 ;store as first entry in index block jsr add_index lda #index_active+index_dirty+file_dirty jsr set_fcr_status ;mark index block active pla ;restore key block ldx #sapling_type jsr update_new_type rts end_to_sap ; rts do_flip ; ldy #fcr_status ;see if the data block is dirty lda [pro_fcr_ptr],y and #data_dirty beq onward jsr flush_data_blk bcc onward plx ;fix the stack!!!! rts onward ; ldy #fcr_key_blk ;load in the data block lda [pro_fcr_ptr],y sta drvr_blk_num ldy #data_blk_num sta [pro_fcr_ptr],y ;update current data block lda data_ptr sta drvr_buf_ptr lda data_ptr+2 sta drvr_buf_ptr+2 jsr read_with_mount ;read in the data block bcc onward2 plx ;fix the stack rts onward2 ; pla ;get the new block number ldy #data_blk_num sta [pro_fcr_ptr],y ;now the data block has changed ldy #$0000 ;store as first entry in index block jsr add_index lda #index_active+index_dirty+file_dirty+data_dirty jsr set_fcr_status ;mark index block active jsr bump_blks_used ldy #fcr_key_blk lda [pro_fcr_ptr],y ldy #index_blk_num sta [pro_fcr_ptr],y ;now the index is new ldx #sapling_type jsr update_new_type rts out_of_room ; lda #volume_full sec rts sapling_to_tree ; jsr calc_free_blks ;see how many blocks we have tax beq out_of_room ;sorry bud not today lda #$0001 ;go get me a new block ldx #$0000 ;start looking at block zero jsr find_free_blks bcs end_to_tree txa ;new key block pha ldy #master_blk_num sta [pro_fcr_ptr],y ;save the master index blk num jsr bump_blks_used lda master_ptr sta temp4_ptr lda master_ptr+2 sta temp4_ptr+2 ldy #fcr_key_blk ;current data block lda [pro_fcr_ptr],y ldy #$0000 ;store as first entry in index block jsr add_index lda #master_active+master_dirty+file_dirty jsr set_fcr_status ;mark index block active pla ;restore key block ldx #tree_type jsr update_new_type end_to_tree ; rts tree_to_tree ; jsr calc_free_blks ;see how many blocks we have tax beq out_of_room ;sorry bud not today lda #$0001 ;go get me a new block ldx #$0000 ;start looking at block zero jsr find_free_blks bcs end_to_tree phx ;save the block number lda master_ptr sta temp4_ptr lda master_ptr+2 sta temp4_ptr+2 jsr bump_blks_used ;must not use X register lda curr_mark+2 lsr a tay ;index into master block txa ;new index block jsr add_index lda #master_dirty+file_dirty jsr set_fcr_status ;indicate master index block is dirty ldy #fcr_status ;see if current index block is dirty lda [pro_fcr_ptr],y and #index_dirty beq mister_clean jsr flush_index bcc mister_clean plx ;fix the stack rts mister_clean ; ldy #index_blk_num ;the current index block pla ;restore new index block number sta [pro_fcr_ptr],y lda #index_dirty+file_dirty jsr set_fcr_status ;indicate that this block is dirty ldx index_ptr ldy index_ptr+2 ;clear the current index jsr clear_index clc rts EXPORT clear_index clear_index ; stx temp4_ptr ;zero out the buffer pointed to by sty temp4_ptr+2 ;X and Y ldy #$01FE lda #$0000 clr_index sta [temp4_ptr],y dey dey bpl clr_index rts ;========================================================================== ;update_new_type: ; This routine will update the FCR to reflect the new storage ; type, and key block for a file ; ;Input: A = new key block ; X = new storage type ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr ;points to file control record ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; ;uses: all registers ;========================================================================== update_new_type ; pha ;save new key block ldy #fcr_key_blk sta [pro_fcr_ptr],y ldy #fcr_entry_type lda [pro_fcr_ptr],y ;is this a resource type? cmp #resource_type beq is_resource txa ;save the new storage type sta [pro_fcr_ptr],y lda 1,s ;save the new key block ldy #fcr_file_id sta [pro_fcr_ptr],y is_resource ; pla ;fix the stack ldy #fcr_storage ;store the new storage type txa sta [pro_fcr_ptr],y jsr flush_file ;force directory update. rts ENDP ;========================================================================== ;chk_allocation: ; This routine will return the block number of a data block ; if the file contains a data block ; ;Input: A = undefined ; X = undefin ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr ;points to file control record ; ;Output: A = block number if 'z' = 0 ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error and 'z' flag valid ; 1 = no block allocated ; 0 = A = block number ; b = k ; ; ;uses: all registers ;========================================================================== ;========================================================================== ;IF (curr_mark = tree) AND (storage <> tree) THEN ; no_block allocated ; ;========================================================================== EXPORT chk_allocation chk_allocation PROC ;see if there is block allocated. lda curr_mark+2 ;see if we need the master index block lsr a ldx master_ptr ;get the block number from index block ldy master_ptr+2 jsr get_index_blk ;A = block number tax bne cont01 ;there is an index block ; ;IF (type = tree) AND (index = sparse) THEN block_not_allocated ; chk_tree ; ldy #fcr_storage lda [pro_fcr_ptr],y cmp #tree_type ;does this puppy even have a master blk?> bne chk_sapling ;there is no master index block clc rts ; ;IF (type <> tree) AND (curr_mark = tree) THEN block_not_allocated ; chk_sapling ; lda curr_mark+2 ;is the mark in tree range lsr a beq index_loaded ;mark not in tree range bra no_block cont01 ; ldy #index_blk_num cmp [pro_fcr_ptr],y ;is the block already loaded? beq index_loaded pha ;save the block number ldy #fcr_status lda [pro_fcr_ptr],y and #index_dirty ;is the current index dirty? beq index1_clean jsr flush_index bcc index1_clean plx rts index1_clean ; pla ;retore block number ldy #index_blk_num sta [pro_fcr_ptr],y ;save the new block please jsr load_index bcc index_loaded rts index_loaded ; lda curr_mark+1 lsr a and #$00FF ldx index_ptr ;get the block number from index block ldy index_ptr+2 jsr get_index_blk ;A = block number tax bne exit_chk_alloc ; ;IF (type = sapling) AND (data = sparse) THEN block_not_allocated ; ldy #fcr_storage lda [pro_fcr_ptr],y cmp #sapling_type ;does this puppy even have an index blk bcc chk_seedling ;there is no index block txa ;reset the flag please exit_chk_alloc ; clc rts chk_seedling lda curr_mark+1 lsr a and #$00FF beq get_key_blk ;mark < 512 no_block ldx #$0000 sep #$02 ;set the 'Z' flag clc rts get_key_blk ; ldy #fcr_key_blk lda [pro_fcr_ptr],y tax ;setup the x register with the block number clc rts EXPORT load_index load_index ;enter with A = block number ;next 3 lines added 8/6/90 by Monte Benaresh pha ;save block # for a moment jsr standard_req ;set drvr_req_cnt to $200 pla ;restore block number sta drvr_blk_num lda index_ptr sta drvr_buf_ptr lda index_ptr+2 sta drvr_buf_ptr+2 jsr read_with_cache rts ENDP ;========================================================================== ;Clr_to_boundary This routine will clear data from the current EOF ; to the end of the block. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; curr_mark ;current file marker ; curr_eof ;current end of file ; pro_fcr_ptr ;points to file control record ; data_ptr ;points to data block in I/O buffer. ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; ; b = k ; ; ; IF (eof >= (curr_mark AND $FE00 + 512)) THEN ; EXIT(clr_to_boundary) ; IF eof > curr_mark THEN ; clear_index := eof ; ELSE ; clear_index := curr_mark ; clear_block ;========================================================================== longa on longi on EXPORT clr_to_boundary clr_to_boundary PROC lda curr_eof pha lda curr_eof+2 ;save the current end of file pha lda curr_mark pha ;save the current mark lda curr_mark+2 pha lda curr_mark ;if block aligned then exit and #$01FF bne not_aligned brl exit_clr ;we do not have to clear anything not_aligned ; ;curr_mark := ((curr_mark and $FE00) + 512) ; ; clc lda curr_mark ;move to a block boundary and #$FE00 adc #blk_size ;add in 512 bytes sta curr_mark lda curr_mark+2 adc #$0000 sta curr_mark+2 ; ; IF (eof >= (curr_mark AND $FE00 + 512)) THEN ; EXIT(clr_to_boundary) ; lda curr_eof+2 cmp curr_mark+2 beq chk_low bcs exit_clr ;EOF not in this block bcc second_if ;continue process chk_low ; lda curr_eof cmp curr_mark bcs exit_clr ;EOF not in this block ; ; IF EOF < curr_mark AND $FE00 THEN ; clear_index := curr_mark ; second_if ; lda 3,s ;get the low word of the mark and #$FE00 sta curr_mark lda curr_eof+2 cmp 1,s ;check high word beq second_low bcs third_if ;EOF is in this block bcc use_mark ;EOF not in this block second_low ; lda curr_eof cmp curr_mark bcs third_if ;EOF is in the block bcc use_mark ;EOF not in this block ; ; IF eof > curr_mark THEN ; clear_index := eof ; third_if ; lda curr_eof+2 ;is eof > curr_mark cmp 1,s ;high word of curr_mark beq third_low bcs use_eof ;clear from EOF bcc use_mark ;clear from current mark third_low ; lda curr_eof cmp 3,s bcs use_eof ;use the eof as the value use_mark ; lda 3,s ;get the low word of current mark and #$01FF ;clear garbage beq exit_clr ;do not clear the buffer bra do_clear use_eof ; lda curr_eof and #$01FF beq exit_clr ;do not clear the buffer do_clear tay ;make an index into block iny cpy #blk_size beq exit_clr tya ;can we clear the block fast lsr a bcc clear_it_fast lda #$0000 ;clear value longa off sep #$20 ;8 bit mode bra enter ;start the loop clear_it sta [data_ptr],y iny enter cpy #blk_size ;are we done bcc clear_it longa on rep #$20 bra exit_clr clear_it_fast lda #$0000 bra enter_fast fast_loop sta [data_ptr],y iny iny enter_fast cpy #$0200 ;are we done bcc fast_loop exit_clr ; pla ;restore the curr_mark sta curr_mark+2 pla sta curr_mark pla sta curr_eof+2 ;restore the current end of file pla sta curr_eof lda #data_dirty+file_dirty jsr set_fcr_status rts ENDP ;========================================================================== ;Close: This routine will close a file. ; ;Created: aug 04, 1987 ;Modified: aug 04, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; fill_io_buf ; ;Call Format: ; ;Class 0 Reference Number (2 Bytes) ; ;Class 1 PCount (2 Bytes) ; Reference Number (2 Bytes) ; ;========================================================================== longa on longi on EXPORT close close PROC ;========================================================================== ;First preprocess the call to setup the needed parameters. ;========================================================================== jsr setup_params dec close_flag ;call slug ripple please jsr flush_file ;force data to the disk bcc flushed jmp main_exit flushed ; jsr remove_fcr jmp main_exit ENDP ;========================================================================== ;flush: This routine will flush a file. ; ;Created: aug 04, 1987 ;Modified: aug 04, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; fill_io_buf ; ;Call Format: ; ;Class 0 Reference Number (2 Bytes) ; ;Class 1 PCount (2 Bytes) ; Reference Number (2 Bytes) ; ;========================================================================== longa on longi on EXPORT flush flush PROC ;========================================================================== ;First preprocess the call to setup the needed parameters. ;========================================================================== jsr setup_params dec close_flag ;call slug_ripple please ; New code added March 27, 1990 to support fast/slow flush, ; by Monte Benaresh, based on Andy Stadler's proposed ; changes. lda pcount ;check number of params given by caller cmp #2 ;did he specify type of flush? bcc slow_flush ;too few, default to full flush choose_flush ;caller specified type of flush ; valid flush types are: ; $0000 = full flush, data and directory blocks ; $8000 = fast flush, data blocks only ldy #4 ;offset to flush type in param block lda [param_blk_ptr],y ;get flush type asl a ;get high bit beq flush_type_ok ;low bits must be 0! bad_flush_type ;invalid value for flush type lda #parm_range_err sec bra flush_done ;return with error flush_type_ok ;get here with high bit of flush type in carry bcc slow_flush ;flush type was $0000 fast_flush ;flush type was $8000 jsr do_fast_flush ;write out all dirty data blocks, dirty ; bitmap blocks, and the directory entry ; only if it's been changed (mod date doesn't count!) bra flush_done ;handle error elsewhere slow_flush jsr flush_file ;force data to the disk flush_done jmp main_exit ENDP ;========================================================================== ;Set_mark: This routine will set a file position marker. ; ;Created: may 23, 1987 ;Modified: may 23, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; fill_io_buf ; ;Call Format: ; ;Class 0 Reference Number (2 Bytes) ; File Position (4 Bytes) ; ;Class 1 PCount (2 Bytes) ; Reference Number (2 Bytes) ; Base (2 Bytes) ; 00 = Absolute ; 01 = Backward From EOF ; 02 = Forward From Current Mark ; 03 = Backward From Current Mark ; Displacement (4 Bytes) ; ;========================================================================== longa on longi on EXPORT set_mark set_mark PROC ;========================================================================== ;First preprocess the call to setup the needed parameters. ;========================================================================== stz base jsr setup_params beq class0 ;========================================================================== ;Fall thru if this is a class1 call ;========================================================================== ldy #pblk_16_base jsr check_base ldy #pblk_16_disp bra main_entry class0 ; ;========================================================================== ;If this is a class zero call then setup an index to the file position ;and continue on. ;========================================================================== ldy #$0002 ;index to displacement main_entry ; ;========================================================================== ;Save the user's requested displacement ;========================================================================== lda [my_pblk_ptr],y sta displacement iny iny lda [my_pblk_ptr],y sta displacement+2 ;========================================================================== ;Setup 'curr_eof' and 'curr_mark' ; ; IF (curr_mark < 00) or (curr_mark > EOF) THEN ; BEGIN ; Error:= position_out_of_range_error ; EXIT(Set_Mark) ; END ;========================================================================== jsr calc_curr_mark bcc set_the_mark lda #out_of_range set_mark_exit jmp main_exit set_the_mark ;========================================================================== ;refill I/O buffer with the new data blocks needed. ;========================================================================== jsr fill_io_buf bcs set_mark_exit ;========================================================================== ;go and update the FCR with the new curr_mark. ;========================================================================== jsr save_curr_mark clc ;========================================================================== ;Exit all happy since the call was successful ;========================================================================== bra set_mark_exit ENDP ;========================================================================== ;check_base This routine will verify that the base is within range ; ;Created: may 23, 1987 ;Modified: may 23, 1987 ;Author: Rob Turner ; ; ;Enter: jsr ; ;Input: A = undefined ; X = undefined ; Y = offset to base field ; P = nvmxdizc ; ..000... ; b = k ; ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ; BASE (contains value of the base) ; ;Uses: All registers ; ;========================================================================== longa on longi on EXPORT check_base check_base PROC lda [my_pblk_ptr],y cmp #max_base+1 bcs range_error sta base rts EXPORT range_error range_error ; lda #parm_range_err jmp main_exit ENDP ;========================================================================== ;calc_curr_mark This routine will calculate the current mark for a file ; given BASE and DISPLACEMENT as input. ; ;Created: may 23, 1987 ;Modified: may 23, 1987 ;Author: Rob Turner ; ; ;Enter: jsr ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; BASE (base from param block) ; $00 = Absolute ; $01 = Backward From EOF ; $02 = Forward From Current Mark ; $03 = Backward From Current Mark ; ; DISPLACEMENT (displacement from param block) ; pro_fcr_ptr (pointer to my data in FCR ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; .<<000..1 = error if out of range ; | 0 = no error ; | ; |__ 1 = error out of range any cases ; 0 = result greater then current EOF ; ; b = k ; ; curr_mark (contains correct position for mark) ; ;Uses: All registers ; ;========================================================================== longa on longi on EXPORT calc_curr_mark calc_curr_mark PROC ;========================================================================== ;Setup the current EOF ;========================================================================== jsr setup_curr_eof ;========================================================================== ;Setup the current file marker. ;========================================================================== jsr setup_curr_mark ;========================================================================== ;Now we need to decide which way we need to move the mark. ;========================================================================== lda base beq absolute dec a beq back_from_eof dec a beq forward_mark ;========================================================================== ;If we fall thru to here then we need to set the mark backward from the ;current mark. ;========================================================================== backward_mark ; sec lda curr_mark sbc displacement sta curr_mark lda curr_mark+2 sbc displacement+2 sta curr_mark+2 bcs mark_ok bad_range ; sep #carry+overflow ;set both carry and overflow flags rts ;exit with carry set to indicate error ;========================================================================== ;User wants to set the mark backward from the current end of file ;========================================================================== back_from_eof ; sec lda curr_eof sbc displacement sta curr_mark lda curr_eof+2 sbc displacement+2 sta curr_mark+2 bcc bad_range mark_ok ; clc rts ;========================================================================== ;Set the mark forward from the current mark. ;========================================================================== forward_mark ; clc lda curr_mark adc displacement sta curr_mark lda curr_mark+2 adc displacement+2 sta curr_mark+2 bcc check_range greater_EOF ; clv ;mark greater then current EOF! rts ;bad mark bud! ;========================================================================== ;Set the file marker to an absolute position. ;========================================================================== absolute ; lda displacement sta curr_mark lda displacement+2 sta curr_mark+2 check_range ; ;========================================================================== ;Make sure the curr_mark =< EOF. ;========================================================================== lda curr_mark+2 cmp curr_eof+2 beq check_low_word ;more checking to do bcs greater_eof ;value is greater then EOF rts ;carry clear no problem check_low_word ; lda curr_mark cmp curr_eof beq good_mark bcs greater_eof ;value is greater then EOF good_mark ; clc rts ENDP ;========================================================================== ;Get_mark: This routine will return the file position marker. ; ;Created: may 23, 1987 ;Modified: may 23, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; ;Call Format: ; ;Class 0 Reference Number (2 Bytes) ; File Position (4 Bytes) ; ;Class 1 PCount (2 Bytes) ; Reference Number (2 Bytes) ; File Position (4 Bytes) ; ;========================================================================== longa on longi on EXPORT get_mark get_mark PROC ;========================================================================== ;Call standard setup routine. ;========================================================================== jsr setup_params ;========================================================================== ;Get the current file marker out of the FCR data area ;========================================================================== ldy #fcr_curr_mark lda [pro_fcr_ptr],y tax ;save low word iny iny lda [pro_fcr_ptr],y ;========================================================================== ;Store the current file position into the user's parameter block. ;========================================================================== ldy #pblk_17_pos+2 ;file position sta [my_pblk_ptr],y dey dey txa sta [my_pblk_ptr],y clc jmp main_exit ENDP ;========================================================================== ;Set_eof: This routine will set the EOF of a file. ; ;Created: jun 15, 1987 ;Modified: jun 15, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; ;Call Format: ; ;Class 0 Reference Number (2 Bytes) ; File Position (4 Bytes) ; ;Class 1 PCount (2 Bytes) ; Reference Number (2 Bytes) ; Base (2 Bytes) ; 00 = Absolute ; 01 = Backward From EOF ; 02 = Forward From Current Mark ; 03 = Backward From Current Mark ; Displacement (4 Bytes) ; ;========================================================================== longa on longi on EXPORT set_eof set_eof PROC stz base ;set default to absolute stz key_blk_changed ;========================================================================== ;Call standard setup routine. ;========================================================================== jsr setup_params beq class0 ;this is an old style call ;========================================================================== ;Now lets go and setup the base parameter please ;========================================================================== ldy #pblk_18_base jsr check_base ldy #pblk_18_disp bra main_entry Class0 ; ldy #pblk_18_odisp main_entry ; lda [my_pblk_ptr],y sta displacement iny iny lda [my_pblk_ptr],y sta displacement+2 ;========================================================================== ;make sure the file is write enabled. ;========================================================================== ldy #fcr_access lda [my_fcr_ptr],y and #ClrAllButAccess cmp #write_access bcs set_eof_ok lda #invalid_access bra set_eof_error set_eof_ok ; jsr chk_disk_protect ;========================================================================== ;Get the current end of file out of the FCR data area and call routine ;that will calculate the new eof. The new value for the EOF is returned ;in 'curr_mark' ;========================================================================== ;brk $B2 jsr calc_curr_mark php ;save results lda curr_mark sta displacement lda curr_mark+2 sta displacement+2 plp ;Following code changed 7/21/90 by Monte Benaresh ;Since setup_real_eof finds the last physically allocated EOF of ;the file, and since that number can be greater than the logical ;EOF (when pre-allocated blocks exist beyond the logical EOF) or ;less (when a trailing portion of the file is entirely sparse), ;we need to call setup_real_eof before deciding whether we need ;to cut blocks. ;bcc less_or_equal ;new EOF is =< current EOF ;bvc eof_greater ;new EOF is > current EOF bcc calc_ok ;new EOF is =< current EOF bvc calc_ok ;new EOF is > current EOF ;The following error code was changed from "parm_range_err" ;to "out_of_range". 1/22/91 CAE bad_eof ; lda #out_of_range ;position out of range set_eof_error sec set_eof_exit jmp main_exit calc_ok ;next call added 8/6/90 by Monte Benaresh to fix bug ;introduced by change of 7/21/90 jsr flush_file ;force any dirty blocks to disk bcs set_eof_error ;Major problems bud. jsr setup_real_eof ;generate EOF based on allocation not logical bcs set_eof_error ;Major problems bud. ;code added 7/21/90 by Monte Benaresh (see note above) lda curr_eof+2 ;this points to last physical allocation cmp displacement+2 ;determine whether we need to cut blocks bcc eof_greater bne less_or_equal ;this line added 8/8/90 by Monte Benaresh lda curr_eof cmp displacement bcs less_or_equal ; eof_greater lda displacement+2 and #$FF00 bne bad_eof save_eof jsr update_fcr_eof lda key_blk_changed ;Did the Key Block for the file change? beq @no_key_changed jsr flush_file ;update both the Bitmap and Directory please bra set_eof_exit @no_key_changed jsr flush_io_buffer ;update the disk please bra set_eof_exit ;we are out of here ;If we get here we know that the new EOF is equal to (easy) or less then ;(hard) the current ("real") EOF. If the EOF is less then the current eof then ;we must release blocks from the disk. less_or_equal jsr flush_file ;force any dirty blocks to disk bcs set_eof_error ;Major problems bud. ;jsr setup_real_eof ;generate EOF based on allocation not logical ;bcs set_eof_error ;Major problems bud. ;last 2 lines not needed now -- Monte Benaresh, 7/21/90 lda displacement+2 cmp curr_eof+2 bne must_be_less ;the new eof is less then old eof lda displacement cmp curr_eof ;bne must_be_less beq save_eof ;same as what caller wants, but save this EOF ;since it was calculated by setup_real_eof ;Monte Benaresh -- 7/21/90 ;next 2 removed 7/21/90 ;clc ;bra set_eof_exit ;nothing to do must_be_less ;If we get here we know the new EOF is less then the old EOF so we must ;do the cut back. ;convert current eof into relative block number ;last_block := ((current_eof-1) DIV 512) ;last_block = $0000 to $7FFF lda curr_eof ora curr_eof+2 ;if zero DO NOT subtract one beq no_sub1 lda curr_eof bne ar1 dec curr_eof+2 ar1 dec curr_eof no_sub1 lda curr_eof+1 ;convert EOF to blocks lsr a sta last_blk ;save block number of last block beq save_eof ;file is already a seedling ;convert new_eof into relative block number ;new_last := ((displacement-1) DIV 512) ;new_last = $0000 to $7FFF lda displacement sta tran_cnt lda displacement+2 sta tran_cnt+2 lda tran_cnt ora tran_cnt+2 ;if zero DO NOT subtract one beq no_sub lda tran_cnt bne ar2 dec tran_cnt+2 ar2 dec tran_cnt no_sub lda tran_cnt+1 ;convert EOF to blocks lsr a sta new_last ;save block number of last block ;WHILE last_blk <> new_last DO while_loop lda last_blk cmp new_last beq save_eof ;just exit with new EOF ;We now need to remove the last block in the file jsr cut_block ;reduce blocks by one bcs update_and_exit ;error occured dec last_blk bra while_loop update_and_exit pha jsr update_fcr_eof pla sec brl set_eof_error ;Update the FCR with the new EOF value. Also mark the FCR dirty update_fcr_eof ldy #fcr_eof lda displacement ;store the NEW eof in the FCR tax sta curr_eof sta [pro_fcr_ptr],y iny lda displacement+1 sta [pro_fcr_ptr],y sta curr_eof+1 ldy #fcr_curr_eof ;update working EOF as well txa sta [pro_fcr_ptr],y iny lda displacement+1 sta [pro_fcr_ptr],y ldy #fcr_status lda [pro_fcr_ptr],y ;update file status word ora #file_dirty ;we need to write to disk on close sta [pro_fcr_ptr],y ;IF the new EOF is =< curr_mark THEN ; curr_mark := EOF jsr setup_curr_mark jsr fill_io_buf ;added 1/23/90 to fix "Bredon" sparse file shrink bug bcc @filledUp rts @filledUp lda curr_mark+2 cmp displacement+2 beq check_lower bcs adjust_mark bra adjust_buffer ;current_mark < new EOF check_lower lda curr_mark cmp displacement beq no_adjust bcs adjust_mark no_adjust bra adjust_buffer adjust_mark lda displacement sta curr_mark lda displacement+2 sta curr_mark+2 jsr save_curr_mark ;update the FCR adjust_buffer jsr clr_to_boundary clc rts ;========================================================================== ;Cut_block: This routine will remove the last block from the file. ; ;Input: last_blk (contains relative block number to delete. 0 thur n) ; ;output: A = error code if carry set. ; ; WARNING: last_blk must not point beyond the current ; structure of the file, even though that block num may be within ; the file's EOF. This could happen if a file has a trailing ; portion which is all sparse from a position <128K to a ; position >128K. In this case the file is stored as a ; sapling, not a tree, but owns a sparse area that is ; logically within the "tree" range. In such a case, last_blk ; must never be in that range when entering this routine. ; cut_block ;The first thing we do is to convert last_blk into a mark value. stz curr_mark stz curr_mark+2 lda last_blk asl a sta curr_mark+1 jsr load_indexes ;load the I/O buffer correctly bcc @no_error rts @no_error ;After we call data_blk_num we know that drvr_blk_num contains the data ;block that is to be removed from the file. jsr get_data_num ;setup drvr_blk_num ldx drvr_blk_num beq gone ;sparse block jsr dealloc_block ;remove the block please bcc dec_gone rts ;return error dec_gone jsr dec_blk_count ;blks_used := blks_used-1 gone ;IF (index_block = true) AND (deleted_entry > 1) THEN ; BEGIN ;if this is anything but a seedling, we must check whether it's time toÉ ;Érelease an index block and possibly change storage type ldy #fcr_storage ;IF (index_block = true) lda [pro_fcr_ptr],y cmp #sapling_type bcs index_true ;index_block = TRUE rts ;we MUST be done index_true lda curr_mark+1 ;AND (deleted_entry > 1) THEN lsr a and #$00FF cmp #$0002 bcc first_ELSE ;deleting first or second entry ; zero_index(deleted_blk) ; ;clear the entry from index block ; index_dirty := true ; ;and mark index dirty ;fall through if not on 1st or 2nd entry not_sapling jsr zero_one_index ;zero an entry in index blk update_eof clc rts ; END ;ELSE ; IF (index_block = true) and (one_entry = true) and (storage = sapling) THEN ; BEGIN ; convert_sapling_to_seedling ; END first_else ;we know index_block = true cmp #$0001 ;did we just delete entry #0? bcc second_else ;check tree case ldy #fcr_storage lda [pro_fcr_ptr],y cmp #sapling_type ;(stoarge = sapling)? bne not_sapling jsr zero_one_index jsr sapling_seed ;convert the sapling file to seedling bcc update_eof rts ; ELSE ; IF (index_block = true) and (one_entry = true) and (storage = tree) THEN ; BEGIN second_else ;we are deleting the 1st entry in index blk jsr remove_index ;remove the index and update master bcc cont01 rts cont01 ;did we just eliminate 2nd index block? lda curr_mark+2 lsr a and #$007F ;see if we are going to be a sapling cmp #$0001 ;see if there is only one entry left bne update_eof ;no conversion yet jsr tree_sapling bcc update_eof rts ;===============END of CUT_BLOCK ;========================================================================== ;This routine will setup curr_eof with the EOF based on blocks allocated ;to the file instead of logical EOF. For example, an file can have an ;EOF of 0, but have hundreds of blocks allocated to it. This happens ;when a file is created with a request to pre-allocate space. ;Diagram: (A) (B) (C) ; ; | | $00 to $7F | $00 to $FF | $000 to $1FF | ; | | | | | ; | MUST BE ZERO |<- master ->|<- index ->|<- Byte index ->| ; |_______________|_____________|_______________|_________________| ; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ; |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_| ; | | | | | ; 3 2 2 4 1 6 0 8 0 0 ; ; WARNING: Index blocks must be clean because they will be ; overwritten! ; ;========================================================================== setup_real_eof stz new_eof stz new_eof+2 ;init new eof ldy #fcr_storage lda [pro_fcr_ptr],y cmp #tree_type ;(storage = tree)? beq @calc_tree cmp #sapling_type beq @calc_sapling clc rts ;seedling works OK @calc_tree ldx master_ptr ;setup pointer to master index block ldy master_ptr+2 jsr get_last_index ;get the lndex to the last index block out of master index clc ;A=index $00 thru $7F, X = block number. asl A ;double index sta new_eof+2 txa ;load block if needed ldy #index_blk_num cmp [pro_fcr_ptr],y ;is the block already loaded? beq @calc_sapling jsr load_index ;load in the index block ;bcc @calc_sapling bcc @index_ok ;changed 8/7/90 by Monte Benaresh rts ;sorry friend no EOF change today! @index_ok ;next lines added 8/7/90 by Monte Benaresh ldy #index_blk_num lda drvr_blk_num ;save the block num of the index block sta [pro_fcr_ptr],y @calc_sapling ldx index_ptr ;get address of the index block in memory ldy index_ptr+2 jsr get_last_index ;get the lndex to the last data block out of index block clc ;A=index $00 thru $FF, X is not used! asl A ;double index ora new_eof+1 ;set the new value sta new_eof+1 clc lda new_eof adc #blk_size ;change added 6/21/90 by Monte Benaresh ;reverted 7/21/90 by Monte Benaresh because the "fix" could cause new_eof ;to point to a sparse portion of the file that was out of the range of ;the current structure (e.g., beyond the 128K mark in a sapling), a ;condition which is illegal for the cut_block routine which gets called ;by set_eof sta curr_eof lda new_eof+2 adc #$0000 sta curr_eof+2 ;update the global EOF that is used by SET_EOF clc rts ;========================================================================== ;Get_Last_index will walk an index block looking for the last valid entry. ; ;input: X&Y = pointer to index buffer ; ;output: A = index offset 0 thru $FF ; X = block number get_last_index stx temp2_ptr ;setup pointer to lower half of the buffer sty temp2_ptr+2 clc txa adc #$0100 ;point to high half of the index block sta temp3_ptr tya adc #$0000 sta temp3_ptr+2 ldy #$00FF ;start from end of index block @loop longa off sep #$20 lda [temp3_ptr],y ;grab the high block number xba ;put high block number in upper byte lda [temp2_ptr],y ;get the low block number longa on rep #$20 tax ;check for zero bne @done ;we have the block number dey bpl @loop ;try the next location sec rts @done tya clc ;A=Index, X = block number rts ;========================================================================== ;This routine will zero out one entry in the master index block. It will ;also mark the index block as being dirty and decrement the block count remove_index ldy #index_blk_num ;is the index block sparse? lda [pro_fcr_ptr],y bne @not_sparse ;there is an index block rts @not_sparse jsr dec_blk_count lda curr_mark+2 lsr a and #$007F tay ora #$0100 tax longa off sep #$20 lda [master_ptr],y sta drvr_blk_num ;save the one we are deleting lda #$00 sta [master_ptr],y ;zero the deleted entry please txy lda [master_ptr],y sta drvr_blk_num+1 ;high byte of one to delete lda #$00 sta [master_ptr],y longa on rep #$20 ldy #fcr_status lda [pro_fcr_ptr],y ora #master_dirty+file_dirty sta [pro_fcr_ptr],y ldx drvr_blk_num ;remove the index block please jsr dealloc_block rts ;========================================================================== ;This routine will zero out one entry in the current index block. It will ;also mark the index block as being dirty ;========================================================================== zero_one_index ldy #index_blk_num ;is the index block sparse? lda [pro_fcr_ptr],y bne @not_sparse ;there is an index block rts @not_sparse lda curr_mark+1 lsr a and #$00FF tay ora #$0100 tax longa off sep #$20 lda #$00 sta [index_ptr],y ;zero the deleted entry please txy sta [index_ptr],y longa on rep #$20 ldy #fcr_status lda [pro_fcr_ptr],y ora #index_dirty+file_dirty sta [pro_fcr_ptr],y rts EXPORT dec_blk_count dec_blk_count ; reduce number of blocks used by a file by one ldy #fcr_blks_used lda [pro_fcr_ptr],y dec a ;next 2 checks removed 8/5/90 by Monte Benaresh: ; The bmi is wrong since a 16-megabyte file can have ; $8041 blocks, ; ; The beq doesn't do anything except return without updating ; the directory. ;beq bad_news ;bmi bad_news sta [pro_fcr_ptr],y lda #dirEntry_dirty ;the directory entry needs updating when flushed jsr set_fcr_status bad_news rts ENDP ;========================================================================== ;sapling_seed: This routine will convert a sapling file into a seedling ; file. (I hope) Of course in the long run it will do the ; conversion. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr (points to VCR local data) ; index_ptr (MUST point to the index block) ; ;Output: A = error code if carry set otherwise undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; pro_fcr_ptr ; ; ;========================================================================== longa on longi on EXPORT sapling_seed sapling_seed PROC ;========================================================================== ;Grab the first entry out of the index block. This is to become the new ;key pointer for the file. ;========================================================================== lda [index_ptr] sta drvr_blk_num ldy #blk_size-$0100 lda [index_ptr],y sta drvr_blk_num+1 lda #$0000 ;now delete the block from the index sta [index_ptr] sta [index_ptr],y ;get the high byte ldx drvr_blk_num jsr update_key_blk ldy #fcr_storage lda #seedling_type tax sta [pro_fcr_ptr],y ;change storage type to seedling ldy #fcr_entry_type lda [pro_fcr_ptr],y cmp #resource_type beq is_res_type1 txa sta [pro_fcr_ptr],y is_res_type1 ; jsr dec_blk_count ;reduce count by one lda #index_clean jsr clr_fcr_status ;do not write a index block ldy #index_blk_num lda [pro_fcr_ptr],y ;block number for index block tax ;used by deallocate beq exit lda #$0000 sta [pro_fcr_ptr],y ;zero the block number jsr dealloc_block ;remove the block please bcc exit rts exit ; stz curr_mark ;reload the correct blocks stz curr_mark+2 jsr fill_io_buf rts ;========================================================================== ;We need to see if this is a resource file. IF it not then we need to ;update both the key block and file id fields. Otherwise we only adjust ;the key block field. ; ;input: X = new key block ;========================================================================== EXPORT update_key_blk update_key_blk ; ldy #fcr_file_id lda [pro_fcr_ptr],y ldy #fcr_key_blk ;update the key block pointer cmp [pro_fcr_ptr],y bne only_key_blk ;update only the key block txa ldy #fcr_file_id sta [pro_fcr_ptr],y only_key_blk ; txa ldy #fcr_key_blk sta [pro_fcr_ptr],y inc key_blk_changed ;indicate that the key block has changed rts ENDP ;========================================================================== ;tree_sapling: This routine will convert a tree file into a sapling ; file. (I hope) Of course in the long run it will do the ; conversion. ; ;Input: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ; pro_fcr_ptr (points to VCR local data) ; master_ptr (MUST point to the master block) ; ;Output: A = error code if carry set otherwise undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; pro_fcr_ptr ; ; ;========================================================================== longa on longi on EXPORT tree_sapling tree_sapling PROC ;========================================================================== ;Grab the first entry out of the master index block. This is to become the ;new key pointer for the file. ;========================================================================== stz curr_mark ;force mark to zero for correct stz curr_mark+2 ;loading of index blocks jsr fill_io_buf ;make sure the I/O buffer looks Ok bcc have_index rts have_index ; lda [master_ptr] sta drvr_blk_num ldy #blk_size-$0100 lda [master_ptr],y and #$00FF ;clear any garbage left sta drvr_blk_num+1 lda #$0000 sta [master_ptr] ;clear the last entry please sta [master_ptr],y jsr dec_blk_count ldx drvr_blk_num jsr update_key_blk ldy #fcr_storage lda #sapling_type tax sta [pro_fcr_ptr],y ;change storage type to sapling ldy #fcr_entry_type lda [pro_fcr_ptr],y cmp #resource_type beq is_res_type2 txa sta [pro_fcr_ptr],y is_res_type2 ; lda #master_clean jsr clr_fcr_status ;do not write a index block ldy #master_blk_num lda [pro_fcr_ptr],y ;block number for master index block tax ;used by deallocate beq exit lda #$0000 sta [pro_fcr_ptr],y ;zero the block number jsr dealloc_block ;remove the block please rts exit ; clc rts ENDP ;========================================================================== ;Get_eof: This routine will return the current EOF for an open file. ; ;Created: may 23, 1987 ;Modified: may 23, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000... ; b = k ; ;Uses: All registers ; ;Call Format: ; ;Class 0 Reference Number (2 Bytes) ; EOF (4 Bytes) ; ;Class 1 PCount (2 Bytes) ; Reference Number (2 Bytes) ; EOF (4 Bytes) ;========================================================================== longa on longi on EXPORT get_eof get_eof PROC ;========================================================================== ;Call standard setup routine. ;========================================================================== jsr setup_params ;========================================================================== ;Get the current end of file out of the FCR data area ;========================================================================== ldy #fcr_curr_eof lda [pro_fcr_ptr],y tax ;save low word iny iny lda [pro_fcr_ptr],y ldy #pblk_19_eof+2 sta [my_pblk_ptr],y dey dey txa sta [my_pblk_ptr],y clc jmp main_exit ENDP ;========================================================================== ;Get_dir_entry: This routine will return a single entry from a directory. ; ; ;Created: Nov 10, 1987 ;Modified: Nov 10, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; find_file ; ;Call Format: ; ;Class 0 Reference number (2 Bytes) ; RESERVED (2 Bytes) ; Base (2 Bytes) ; $0000 = Absolute ; $0001 = Forward releative ; $0002 = Backward relative ; Displacement (2 Bytes) ; Pointer to name buffer (4 Bytes) ; Entry Number (2 Bytes) Absolute entry read ; File Type (2 Bytes) ; EOF (4 Bytes) ; Blocks Used (4 Bytes) ; Create Date/Time (8 Bytes: Misc. Tools Format) ; Mod Date/Time (8 Bytes: Misc. Tools Format) ; Access (2 Bytes) ; Aux Type (4 Bytes) ; File System Id (2 Bytes) ; ;Class 1 PCount (2 Bytes: Minimum = 5) ; Reference Number (2 Bytes) ; RESERVED (2 Bytes) ; Base (2 Bytes) ; $0000 = Absolute ; $0001 = Forward releative ; $0002 = Backward relative ; Displacement (2 Bytes) ; Pointer to name buffer (4 Bytes) ; Entry Number (2 Bytes) Absolute entry read ; File Type (2 Bytes) ; EOF (4 Bytes) ; Blocks Used (4 Bytes) ; Create Date/Time (8 Bytes: Misc. Tools Format) ; Mod Date/Time (8 Bytes: Misc. Tools Format) ; Access (2 Bytes) ; Aux Type (4 Bytes) ; File System Id (2 Bytes) ; Option List Pointer (4 Bytes) ; ;========================================================================== longa on longi on EXPORT get_dir_entry get_dir_entry PROC import gde_temp jsr setup_params ;general setup routine php ;save status lda my_pblk_ptr+2 sta temp2_ptr+2 clc lda my_pblk_ptr sta temp2_ptr ;save a pointer for extended bit adc #$0004 ;pass ref # and Reserved fields sta my_pblk_ptr bcc not_high inc my_pblk_ptr+2 not_high ; plp bne class1 ;this is a new call lda #$000E ;make PCount = to class 0 normal sta pcount class1 ; ldy #fcr_storage ;make sure this is a directory lda [pro_fcr_ptr],y cmp #subdir_type bcs type_ok sec lda #bad_file_format jmp main_exit type_ok ; lda [my_pblk_ptr] ;load the base field sta base ;save user's base value cmp #gde_max_base+1 bcc base_good lda #parm_range_err gde_exit ; jmp main_exit directory_err ; sec lda #dir_error ;report error to user bra gde_exit base_good ; ldy #pblk_1c_name lda [my_pblk_ptr],y sta temp_ptr ;save the pointer iny iny lda [my_pblk_ptr],y and #$00FF ;clear the garbage sta temp_ptr+2 ldy #pblk_1c_disp ;offset to displacement lda [my_pblk_ptr],y sta displacement ora base ;is base and displacement zero? bne nothing_special jsr reset_gde ;reset the call please nothing_special ; ldy #pblk_1c_extend ;clear the extended word lda #$0000 sta [temp2_ptr],y jsr standard_req ldy #gde_curr_blk ;have we loaded a directory yet? lda [pro_fcr_ptr],y sta drvr_blk_num bne dir_loaded ;yes. ldy #fcr_key_blk ;key block of the directory lda [pro_fcr_ptr],y sta drvr_blk_num jsr read_gde_blk ;read in a block please bcs gde_exit ;bad news bud lda [index_ptr] ;make sure this is a directory bne directory_err ldy #$0004 ;index to storage type lda [index_ptr],y tax and #$00F0 ;check the storage type cmp #subdir_header bcc directory_err ;a bad directory txa and #$000F ;check the name length beq directory_err ldy #header_file_cnt lda [index_ptr],y ;save the header file count ldy #gde_tot_files sta [pro_fcr_ptr],y ldy #gde_curr_blk ;save the current block also lda drvr_blk_num sta [pro_fcr_ptr],y lda #$0004 ;save gde_offset ldy #gde_offset sta [pro_fcr_ptr],y dir_loaded ; ldy #gde_offset lda [pro_fcr_ptr],y ;setup the current offset sta entry_offset lda base ;see if we are returning total files tax ora displacement bne not_first jsr send_tot_files clc jmp main_exit ;exit back to caller not_first ; ldy #gde_entry_num lda [pro_fcr_ptr],y sta math_temp ;current entry number tay txa ;restore base beq absolute ;do absolute entry please dec a beq forward ;do forward relative please backward ; sec tya ;get the last entry we looked at sbc displacement ;entry that we want bcc end_dir_err bne find_entry ;go find the entry please end_dir_err ; sec lda #end_of_dir jmp main_exit absolute ; lda displacement ;get this entry please bra to_forward forward ; clc tya ;get the current entry please adc displacement bcs end_dir_err ;over flow! to_forward ; ldy #gde_tot_files ;see if we need to look cmp [pro_fcr_ptr],y beq find_entry bcs end_dir_err find_entry ; ldy entry_offset ;pre-load the entry offset sta find_this_entry ;save entry number to find cmp math_temp ;compare to current entry beq send_entry ;we have the correct entry bcc search_backward ;do a backward search search_forward ; cpy #$01FF beq get_forward_blk ;go read the next block please jsr add_entry_len forward_loop ; lda [index_ptr],y ;load the entry please and #$00F0 ;is this entry active? beq search_forward ;look at the next entry please sty entry_offset ;save the offset inc math_temp ;bump the current entry by one lda math_temp cmp find_this_entry ;is this the correct entry bne search_forward bra send_entry get_forward_blk ; ldy #$0002 ;index to forward link lda [index_ptr],y beq end_dir_err ;sorry no more directory blocks sta drvr_blk_num jsr read_gde_blk ;load the block please ldy #$0004 ;index to first entry bcc forward_loop jmp main_exit ;tell user about the error search_backward ; cpy #$0004 beq get_back_blk ;go read the prev block please jsr sub_entry_len backward_loop ; lda [index_ptr],y ;load the entry please and #$00F0 ;is this entry active? beq search_backward ;look at the next entry please sty entry_offset ;save the offset dec math_temp ;bump the current entry by one lda math_temp cmp find_this_entry ;is this the correct entry bne search_backward bra send_entry get_back_blk ; lda [index_ptr] beq end_dir_err ;sorry no more directory blocks sta drvr_blk_num jsr read_gde_blk ;load the block please ldy #$01FF ;index to first entry bcc backward_loop jmp main_exit ;tell user about the error send_entry ; ldy #gde_curr_blk lda drvr_blk_num sta [pro_fcr_ptr],y ;save the current dir block ldy #gde_entry_num lda math_temp sta [pro_fcr_ptr],y ;save the current entry number ldy #gde_offset lda entry_offset sta [pro_fcr_ptr],y ;save the entry offset tay stz res_storage ;default is type is not resource lda [index_ptr],y ;get the storage type and #$00F0 cmp #resource_type bne not_extended ldy #pblk_1c_extend lda #$8000 sta [temp2_ptr],y sta res_storage ;type of file is extended not_extended ; ; ;Now move the entry into the user's data area ; lda entry_offset clc adc index_ptr sta drvr_buf_ptr lda #$0000 adc index_ptr+2 sta drvr_buf_ptr+2 jsr move_dir_entry ;move the entry to 'one_entry' lda #buff_too_small ;assume user screwed up sta math_temp lda [temp_ptr] cmp #$0004 bcc no_name ;sorry no name avail ldy #$0002 ;store the name length lda alloc_entry sta [temp_ptr],y clc adc #$0004 cmp [temp_ptr] ;load the buffer size beq len_ok ;length is ok bcc len_ok ; ;(BufferSize - 4) ; sec lda [temp_ptr] ;use the user's buf length sbc #$0004 beq no_name ;a buffer size of 4 was used so store length only. bcc no_name ;do not send any of the name bra do_name ;use the user's length as count to send. len_ok ; stz math_temp ;no error lda alloc_entry ;number of bytes to move ; ;Code added to fix a bug cataloging a bad disk. ; bne do_name lda #dir_error ;the directory entry is bad sta math_temp bra end_gde ;exit with the error please do_name tay ;number of bytes to send clc ;make pointer to ascii string lda temp_ptr adc #$0003 sta temp_ptr lda temp_ptr+2 adc #$0000 sta temp_ptr+2 stz case_bits ;all upper case is the defalut lda fst_attr ;if the high bit is set skip Upper/Lower stuff bmi @its_upper lda one_entry+version_index bpl @its_upper asl a ;remove the case ON/OFF bit sta case_bits ;set the case bits for this file. @its_upper sty gde_temp ;save the count please ldy #$0001 ;start at the front longa off sep #$20 looper lda one_entry,y rep #$20 rol case_bits ;see if this char is lower case sep #$20 bcc @its_upper if AllowLCPeriods then ;added 7-Aug-91 DAL cmp #'.' bne @not_lc_period lda #0 ;let it ORA our 0 into a $20 (blank) @not_lc_period endif ;end 7-Aug-91 DAL ora #$20 ;set the lower case bit please @its_upper sta [temp_ptr],y cpy gde_temp beq @we_done iny bra looper ;move the name to the user's buffer @we_done longa on rep #$20 lda math_temp cmp #buff_too_small ;if the error was buffer too small then leave it. beq no_name stz math_temp ;reset the error code please no_name sec ;adjust the pcount please lda pcount sbc #$0005 sta pcount beq end_gde jsr send_gde_stuff ;send the info that the user wants end_gde ; lda math_temp ;was there an error? cmp #$0001 jmp main_exit send_gde_stuff ; lda my_pblk_ptr sta temp_ptr lda my_pblk_ptr+2 sta temp_ptr+2 ldy #pblk_1c_entry ;return the absolute entry lda find_this_entry sta [temp_ptr],y dec pcount beq to_end_send_gde ldy #pblk_1c_ftype lda one_entry+file_type_index and #$00FF sta [temp_ptr],y dec pcount beq to_end_send_gde lda res_storage ;is the file extended? bpl @not_extended ;no it is not jsr load_ext_blk ;load in the extended block please @not_extended jsr send_data_eof ;send the eof for data fork dec pcount beq to_end_send_gde jsr send_data_blks ;send the blks_used for data fork dec pcount beq to_end_send_gde ldx one_entry+create_index ldy one_entry+create_index+2 jsr unpack_time ldy #pblk_1c_create jsr send_time dec pcount beq to_end_send_gde ldx one_entry+last_mod_index ldy one_entry+last_mod_index+2 jsr unpack_time ldy #pblk_1c_mod jsr send_time dec pcount beq to_end_send_gde lda one_entry+access_index and #$00E7 ldy #pblk_1c_access sta [temp_ptr],y dec pcount beq to_end_send_gde lda one_entry+aux_type_index ldy #pblk_1c_aux sta [temp_ptr],y lda #$0000 iny iny sta [temp_ptr],y dec pcount ;does the user want FST ID? to_end_send_gde beq end_send_gde ;No lda #pro_id ldy #pblk_1c_id sta [temp_ptr],y dec pcount ;Skip the option list please beq end_send_gde ;========================================================================== ; We now store the ProDOS FST ID in the 5th byte of the option list buffer ;========================================================================== ldy #pblk_1c_opt ;index to option list pointer lda [temp_ptr],y ;get the address of the option list buffer tax iny iny lda [temp_ptr],y tay bne @save_fst_id txa beq @skip_save @save_fst_id pei temp_ptr ;save the working temp_ptr since I am going to use it pei temp_ptr+2 ;to handle the option list pointer stx temp_ptr sty temp_ptr+2 ; ;Now I need to verify the option list length. I need at least 6 bytes. ; lda [temp_ptr] ;get the length of the option list cmp #$0004 ;is the minimum count OK bcs @min_ok ;the user has the min lda #parm_range_err ;store the error bra option_list_err @min_ok tax ;save the count for data area check lda #$0002 ;length of the ProDOS FST ID. tay sta [temp_ptr],y ;save the number of bytes stored txa cmp #$0006 bcs @size_fine lda #buff_too_small ;store the error bra option_list_err @size_fine iny iny lda #pro_id sta [temp_ptr],y ;new code added 2/13/91 CAE txa cmp #6+32 ;is buffer big enough to hold HFS Finder Info? bcc @no_info ;no lda res_storage ;is the file extended? bpl @no_info ;no - so no HFS info jsr get_hfs_info ;yes - so get the HFS info if we have it @no_info ;end of new code pla sta temp_ptr+2 ;restore pla sta temp_ptr @skip_save dec pcount ;does the user want resource eof? beq end_send_gde ;no jsr send_res_eof ;send the resource EOF please dec pcount ;does the user want resource blocks? beq end_send_gde ;no jsr send_res_blks end_send_gde rts option_list_err sta math_temp pla sta temp_ptr+2 ;restore pla sta temp_ptr rts send_data_eof lda res_storage ;is the file extended? bpl @not_extended ldy #$0005 ;index to EOF field lda [drvr_buf_ptr],y sta one_entry+eof_index iny lda [drvr_buf_ptr],y sta one_entry+eof_index+1 @not_extended ldy #pblk_1c_eof lda one_entry+eof_index sta [temp_ptr],y iny iny lda one_entry+eof_index+2 and #$00FF sta [temp_ptr],y rts send_data_blks lda res_storage ;is the file extended? bpl @not_extended ldy #$0003 ;index to blocks used field lda [drvr_buf_ptr],y sta one_entry+blks_used_index @not_extended lda one_entry+blks_used_index ldy #pblk_1c_blks sta [temp_ptr],y iny iny lda #$0000 sta [temp_ptr],y ;Zero the high word rts send_res_eof lda res_storage ;is the file extended? bpl @not_extended ldy #$0105 ;index to eof field lda [drvr_buf_ptr],y tax ;low word of eof iny iny lda [drvr_buf_ptr],y and #$00FF tay ;upper word of EOF txa ;save low word in 'A' tyx ;save upper word in 'X' bra @send_res_eof @not_extended lda #$0000 ;eof is nothing tax @send_res_eof ldy #pblk_1c_res_eof sta [temp_ptr],y iny iny txa sta [temp_ptr],y ;save upper word please rts send_res_blks lda res_storage ;is the file extended? bpl @not_extended ldy #$0103 ;index to blocks used field lda [drvr_buf_ptr],y bra @send_res_blks @not_extended lda #$0000 ;no blocks @send_res_blks ldy #pblk_1c_res_blks sta [temp_ptr],y iny iny lda #$0000 sta [temp_ptr],y ;save upper word please rts add_entry_len tya clc adc #entry_length tay rts sub_entry_len tya sec sbc #entry_length tay rts send_tot_files ; lda pcount ;is there room cmp #$0006 bcc end_tot ldy #gde_tot_files lda [pro_fcr_ptr],y ;get the total number of entries ldy #pblk_1c_entry sta [my_pblk_ptr],y end_tot rts reset_gde lda #$0000 ;reset gde by zero all data ldy #gde_entry_num sta [pro_fcr_ptr],y ldy #gde_offset sta [pro_fcr_ptr],y ldy #gde_curr_blk sta [pro_fcr_ptr],y ldy #gde_tot_files sta [pro_fcr_ptr],y rts read_gde_blk lda index_ptr ;pointer to GDE buffer sta drvr_buf_ptr lda index_ptr+2 sta drvr_buf_ptr+2 jsr read_with_cache ;read in directory block rts load_ext_blk jsr set_default_buf ;use the standard buffer please jsr standard_req lda one_entry+key_blk_index sta drvr_blk_num jsr read_with_cache bcc @no_problem jmp main_exit ;abort please @no_problem rts ENDP ;========================================================================== ;get_dev_num This file contains code that will find a volume and return ; a device number. ; ;Created: aug 17, 1987 ;Modified: aug 17, 1987 ;Author: Rob Turner ; ;Enter: jml ; ;Input: A = undefined ; X = call number times 2 ; Y = class times 2 ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Device Dispatcher (subroutine) ; General I/O Buffer (1K buffer, I read 512 bytes) ; and lots of other stuff to. ; ;Call Format: ; ;Class 0 Dev/Vol Name Pointer (4 Bytes) ; Device Number (2 Bytes) ; ;Class 1 PCount (2 Bytes) ; Dev/Vol Name Pointer (4 Bytes) ; Device Number (2 Bytes) ; ;========================================================================== longa on longi on EXPORT get_dev_num get_dev_num PROC jsr setup_params ;go ahead do your thing lda dev_num ;did the shell find a device? bne have_device lda #no_dup ;allow me to handle file not found sta search_flag jsr process_path ;do ahead and find the volume bcc no_err ;no problem cmp #file_not_found ;was the error file not found? bne @dev_err_exit lda dev_num bne no_err ;give him the device number lda #bad_path_syntax @dev_err_exit sec jmp main_exit no_err lda drvr_dev_num have_device ; ldy #$0004 ;return the device number sta [my_pblk_ptr],y clc jmp main_exit ENDP ;====================================================================== ;read_block and write_block calls ; ; This routine will read or write ; one block from the device number specified ; ;created: mar 23, 1987 ;modified: jan 06, 1988 ;author: Rob Turner ; ;Enter: jmp ; ;input: param_blk_ptr = pointer to user's parameter block ; A = undefined ; X = call number * 2 ; Y = class of call (0 thru 7) ; P = nvmxdizc ; ..000... ; b = k ; ;output: A = error code if carry set otherwise undefined ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;uses: all register ; param_blk_ptr (direct page) ; uses dispatcher (system call) ; ;exit: via common exit routine ; ;Call Format for Both Read and Write: ; ;Class 0 Device Number (2 Bytes) ; Pointer to Data Buffer (4 Bytes) ; Block Number (2 Bytes) ; ;Class 1 PCount (2 Bytes) ; Device Number (2 Bytes) ; Pointer to Data Buffer (4 Bytes) ; Block Number (2 Bytes) ; ;====================================================================== longa on longi on EXPORT read_block read_block PROC lda #drvr_read bra common_block ;common code for block read/write EXPORT write_block write_block ; lda #drvr_write ;do a write call common_block ; sta drvr_call_num tya lsr a tay dey ;y = class of the call bmi class0 ;old style call... class1 ; lda [param_blk_ptr] ;get the PCount cmp #0003 ;min and max PCount for this call beq good_pcount lda #invalid_pcount ;I have a headache tonight error_out ; sec read_out ; jmp main_exit good_pcount ; iny class0 ; iny ;make index to 'Device Number' lda [param_blk_ptr],y sta drvr_dev_num phy jsr chk_owner ;see if this is my disk ply bcs error_out iny iny ;index to the buffer pointer lda [param_blk_ptr],y sta drvr_buf_ptr iny iny lda [param_blk_ptr],y sta drvr_buf_ptr+2 iny iny ;index to the block number lda [param_blk_ptr],y sta drvr_blk_num stz drvr_blk_num+2 ;init all other parameters that the driver/dispatcher will use lda #blk_size sta drvr_req_cnt ;read one block only stz drvr_req_cnt+2 try_again jsr device_call ;call the driver bcs check_error bra read_out ;error is returned check_error ; cmp #drvr_disk_sw ;disk switched behind my back? bne error_out stz prodos_vcr_ptr ;indicate that we do not know the owner. stz prodos_vcr_ptr+2 bra try_again ;tell the user ;====================================================================== ;chk_owner: This routine will try to find a VCR associated with ; the device we are going to write to. If we find the ; VCR we will see if it is a ProDOS volume, if it is then ; we will mark the bitmap undefined. If the bitmap is dirty ; or there are open files on the volume we will not allow ; the caller to write to the disk. ;====================================================================== chk_owner lda drvr_dev_num ;see if there is a VCR sta dev_num jsr check_vcr_first bcs exit_owner ;there is no VCR jsr setup_my_vcr stx prodos_vcr_ptr sty prodos_vcr_ptr+2 jsr reset_vcr rts exit_owner stz prodos_vcr_ptr ;indicate that we do not know the owner. stz prodos_vcr_ptr+2 clc rts EXPORT reset_vcr reset_vcr lda drvr_call_num cmp #drvr_write ;is this a write block call? beq @is_write clc rts @is_write ldy #bitmap_dirty ;see if the bitmap is dirty lda [prodos_vcr_ptr],y bne no_action ;sorry not tonight ldy #vcr_open_cnt ;see if files are open lda [my_vcr_ptr],y bne no_action lda #$FFFF ;reset the volume please ldy #curr_bitmap ;flush bitmap blocks sta [prodos_vcr_ptr],y ldy #free_blocks ;unknown free block count sta [prodos_vcr_ptr],y ldy #avail_bitmap sta [prodos_vcr_ptr],y clc rts no_action ; lda #invalid_access sec rts ENDP ;====================================================================== ;format/Erase This file will format or erase of volume ; ;Created: dec 05, 1987 ;Modified: mar 15, 1988 ;Author: Rob Turner ; ;Enter: From GS/OS jmp table ; ;Input: A = undefined ; X = (call number * 2) ; Y = (class number * 2) ; P = nvmxdizc ; ..000... ; b = k ; ;Output: A = error code if carry set (exit via system exit routine) ; X = undefined ; Y = undefined ; P = nvmxdizc ; ..000..1 = error ; 0 = no error ; b = k ; ;Uses: All registers ; Device Dispatcher (subroutine) ; General I/O Buffer (1K buffer, I read 512 bytes) ; ;Call Format: ; ;Class 0 Device Name Pointer (4 Bytes) ; Volume Name Pointer (4 Bytes) ; FST ID (2 Bytes) ; ;Class 1 PCount (2 Bytes) ; Device Name Pointer (4 Bytes) ; Volume Name Pointer (4 Bytes) ; FST ID (2 Bytes) ; ;====================================================================== longa on longi on EXPORT format_disk format_disk PROC import boot_size jsr setup_params ;standard setup routine ** 2/28/92 GAB jsr check_spans ;make sure the volume name isn't too long ** lda dev_num ;move device number from SCM to sta drvr_dev_num ;driver area on direct page jsr clear_any_vcrs ;keep VCRs in order jsr setup_vol_name ;move the volume name please jsr hard_format ;issue a hard format please bcs init_exit bra continue EXPORT erase_disk erase_disk ; jsr setup_params ;standard setup routine ** 2/28/92 GAB jsr check_spans ;make sure the volume name isn't too long ** lda dev_num ;move device number from SCM to sta drvr_dev_num ;driver area on direct page jsr clear_any_vcrs ;keep VCRs in order jsr setup_vol_name ;move the volume name please continue ; jsr set_partition ;assign the partion map name ; ;Start of code that will write to disk ; jsr write_boot_code ;write the boot code out to disk bcs init_exit jsr build_directory ;build the directory please bcs init_exit jsr build_bitmap ;build the correct bitmap please init_exit ; jmp main_exit ;====================================================================== ;setup_vol_name This routine will verify the volume name is ok, and ; move the name into the format header. ;====================================================================== setup_vol_name ; clc lda path2_ptr adc #$0003 sta temp_ptr ;setup pointer to the name lda path2_ptr+2 adc #$0000 sta temp_ptr+2 jsr set_case_bits ;setup the case please (Temp_Ptr is Input) lda temp_ptr ;subtract one from the pointer. bne @do_low dec temp_ptr+2 @do_low dec temp_ptr lda #$0001 sta chars_checked ;parameter for setup_name jsr setup_name ldy #15 ;first clear the format header lda #$0000 clr_loop ; sta new_vol_name,y dey bpl clr_loop lda search_length ;length of the volume name and #$000F tay ora #volume_header sta new_vol_name ;the length is now stored longa off sep #$20 ;8 bit Accum move_vol ; lda search_name-1,y sta new_vol_name,y dey bne move_vol longa on rep #$20 ;16 bit Accum ; ;Save the case please ; stz new_vol_date-2 ;zap any old data that might be around lda case_bits ;get the user's case beq @skip_save ora #$8000 sta new_vol_date-2 @skip_save jsr pack_time ;set the create date stx new_vol_date stx new_vol_mod sty new_vol_date+2 sty new_vol_mod+2 ;set the mod time to the create time rts ;====================================================================== ;hard_format: This routine will issue the hard format call to the ; device driver. ;====================================================================== hard_format ; lda #drvr_control ;issue hard format call to device sta drvr_call_num lda #drvr_format ;issue the format call sta drvr_ctrl_code lda #^format_ctrl sta drvr_clist_ptr+2 lda #format_ctrl sta drvr_clist_ptr lda #$0002 ;length of control list sta drvr_req_cnt stz drvr_req_cnt+2 jsr device_call ;issue the format call to the device bcc formatted cmp #drvr_disk_sw ;is it a disk switched problem? beq hard_format ;try again sec formatted ; rts ;return with the error code. ;====================================================================== ;indicate_erase This routine will tell the driver what name to store ; in the device partion map. ;====================================================================== set_partition ; lda #drvr_control ;setup for a control call sta drvr_call_num lda #$0006 ;setup control code sta drvr_ctrl_code lda #^control_list ;setup pointer to the parameter list sta drvr_clist_ptr+2 lda #control_list sta drvr_clist_ptr stz drvr_req_cnt stz drvr_req_cnt+2 ;no request count jsr device_call rts ;====================================================================== ;write_boot_code This routine will write out to disk the ProDOS ; boot code. Note that the SOS boot code has ; been removed from the boot blocks. This means that ; a disk formatted with the ProDOS FST cannot be booted ; on the Apple ///. ;====================================================================== write_boot_code ; jsr set_default_buf ;use general work buffer jsr standard_req ;512 byte write jsr clear_gbuf_low ;clear the working buffer with zeros. lda #drvr_write sta drvr_call_num stz drvr_blk_num stz drvr_blk_num+2 ldy #boot_size-2 ;move the boot code to please boot_loop ; lda boot_code_start,y sta [drvr_buf_ptr],y dey bpl boot_loop re_boot ; jsr device_call ;issue the device call please bcc boot_done cmp #drvr_disk_sw beq re_boot ;try again sec boot_done ; rts ;====================================================================== ;Build_directory This routine will build the first four blocks of the ; directory. ;====================================================================== build_directory jsr get_dev_blks ;get the number of blocks on the device. bcs exit_dir ;sorry we are out of here. sta new_tot_blks ;number of blocks on the volume jsr set_default_buf ;use general work buffer jsr standard_req ;512 byte write jsr clear_gbuf_low ;clear the working buffer with zeros. lda #drvr_write ;setup for write calls sta drvr_call_num lda #vol_dir_start sta drvr_blk_num stz drvr_blk_num+2 ldy #entry_length+2 ;now move the entry to work buffer header_loop ; lda format_header,y sta [drvr_buf_ptr],y dey bpl header_loop ; ;Write Block Two To Disk ; jsr device_call ;issue the device call please bcs exit_dir ; ;Write Block Three To Disk ; jsr clear_gbuf_low ;clear the block again ldx #vol_dir_start ;backward link to block 2 ldy #vol_dir_start+2 ;forward link to block 3 jsr do_dir_blk ;write directory block to disk bcs exit_dir ; ;Write Block Four To Disk ; ldx #vol_dir_start+1 ;Backward link to block 3 ldy #vol_dir_start+3 ;Forward link to block 5 jsr do_dir_blk bcs exit_dir ; ;Write Block Five To Disk ; ldx #vol_dir_start+2 ;Backward link to block 4 ldy #$0000 ;Forward link NIL jsr do_dir_blk exit_dir ; rts do_dir_blk ; txa ;previous link sta [drvr_buf_ptr] tya ldy #$0002 ;index to forward link sta [drvr_buf_ptr],y inc drvr_blk_num ;move to the next block please jsr device_call ;issue write call rts ;====================================================================== ;build_bitmap This routine will build a bitmap for the device ; being formatted. ;====================================================================== build_bitmap ; lda #bitmap_strt_blk ;starting block number of bitmap sta drvr_blk_num ; ;Calculate the number of bitmap blocks needed for this volume ; ldx #$0001 ;default = one bitmap block lda new_tot_blks ;number of blocks on volume count_blks ; sec sbc #4096 ;one bitmap block beq end_count bcc end_count inx ;add one to the block count bra count_blks end_count ; stx bitmap_blks ;total number of bitmap blocks txa clc adc #$0005 ;add in boot blks and directory sta last_bitmap ;blk number of last bitmap blk jsr fill_gbuf_low ;allocate 4096 blocks please ldx last_bitmap ;block number of last bitmap block dir_build ; jsr alloc_bit_blk ;allocate a bitmap block please dex ;allocate the next block please bpl dir_build bra chk_last ;see if we are done full_loop ; jsr fill_gbuf_low ;allocate 4096 blocks chk_last ; lda drvr_blk_num ;our we done? cmp last_bitmap beq clear_to_end ;yes we are jsr device_call ;issue write call bcs end1_bitmap inc drvr_blk_num ;move to the next block please bra full_loop clear_to_end ; ;clear from last bit to the end lda new_tot_blks tax and #$0FFF ;do we need to clear anything? beq just_write txa ;we must clear some bits and #$0007 ;are we byte aligned? beq fast_clr ;yes we are jsr alloc_bit_blk ;allocate the odd block inx stx new_tot_blks bra clear_to_end fast_clr ; jsr calc_bit ;get the index please lda #$0000 fast_loop sta [drvr_buf_ptr],y iny iny ;WARNING! we might overwrite a byte cpy #$0200 ;past $200 this is OK with a 1K buffer bcc fast_loop ;since we are using 512 bytes only just_write ; jsr device_call ;issue write call end1_bitmap ; rts alloc_bit_blk ; phx ;save the block number jsr calc_bit ;convert block number to bit pattern eor #$FFFF ;clear the correct bit please and [drvr_buf_ptr],y sta [drvr_buf_ptr],y plx ;restore block number rts ;====================================================================== ;get_dev_blks This routine will return the number of blocks on ; the volume. ; ;Output: A = number of blocks ;====================================================================== get_dev_blks ; lda #drvr_status ;issue a status call to the device sta drvr_call_num lda #^status_list ;setup a pointer to the status list sta drvr_slist_ptr+2 lda #status_list sta drvr_slist_ptr lda #$0006 ;a six byte request count sta drvr_req_cnt stz drvr_req_cnt+2 lda #blk_size sta drvr_blk_size stz drvr_stat_code ;issue a 'driver status' call. jsr device_call ;blast off!! bcs holy_cow_batman ;An error? ldx #$FFFF ;a 32 meg volume lda return_blks+2 ;return the blocks please bne big_boy ldx return_blks cpx #$0007 bcc range_problem ;sorry this device is too small big_boy ; txa ;number of blocks on volume clc holy_cow_batman rts range_problem lda #drvr_bad_block ;we will not do it. sec rts ;====================================================================== ;This routine will mark any VCR's that are logged on this device as ;being swapped. This will allow any FST to rebuild the VCR after the ;media has been erased or formatted. ;====================================================================== clear_any_vcrs ; lda dev_num ;device number we are going to erase jsl swap_out ;mark volumes offline rts ENDP ;========================================================================== ;This file contians the calls the handle FST specific calls ; ;created: Mar 19, 1988 ;modified: Mar 19, 1988 ;Author: Rob Turner ; ; ;========================================================================== longa on longi on EXPORT fst_specific fst_specific PROC ldy #$0004 ;index to command number lda [param_blk_ptr],y cmp #set_time_stamp beq set_time cmp #get_time_stamp beq get_time cmp #set_upper_case beq set_fst_attr ;set the Upper case flag please cmp #get_upper_case beq get_fst_attr IF debug_on<>0 THEN jsr fst_debug ;check special commands for debugger bra exit ;exit with error ENDIF lda #invalid_fst_op bra error_out parm_range lda #parm_range_err ;parameter out of range bra error_out bad_pcnt lda #invalid_pcount error_out sec exit jmp main_exit ;========================================================================== ;This call allows the user to set the time stamp option. Below is the valid ;list of values. ; ; $0000 = Time stamp files only ; $0001 = Time stamp file + Parent Directory ; $0002 = Time stamp file + all directories to the root ; ;========================================================================== set_time lda [param_blk_ptr] ;verify the Pcount cmp #$0003 bne bad_pcnt iny iny ;point to the stamp size lda [param_blk_ptr],y cmp #$0003 bcs parm_range ;sorry bad sta time_stamp_opt clc bra exit ;========================================================================== ;This call returns the current time stamp option. Below is the valid ;list of values. ; ; $0000 = Time stamp files only ; $0001 = Time stamp file + Parent Directory ; $0002 = Time stamp file + all directories to the root ; ;========================================================================== get_time lda [param_blk_ptr] ;verify the Pcount cmp #$0003 bne bad_pcnt iny iny ;point to the stamp size lda time_stamp_opt sta [param_blk_ptr],y clc bra exit ;========================================================================== ;This call allows the user to set the upper case state to on or off ;If set to off all file names will be returned in upper case, otherwise ;they will be returned in the cae they were created in. ; ; $0000 = Turn OFF upper/lower case ; $0001 = Return case as created/renamed ; ;========================================================================== set_fst_attr lda [param_blk_ptr] ;verify the Pcount cmp #$0003 bne bad_pcnt iny iny ;point to the input parameter lda [param_blk_ptr],y beq @set_high_bit dec a bne parm_range ;sorry bad lda fst_attr ;clear the bit please and #$7FFF sta fst_attr clc bra exit @set_high_bit lda fst_attr ;turn off upper/lower case. ora #$8000 sta fst_attr clc bra exit ;========================================================================== ;This call allows the user to get the upper case state. ; ; $0000 = files are returned in all UPPERCASE ; $0001 = Return case as created/renamed ; ;========================================================================== get_fst_attr lda [param_blk_ptr] ;verify the Pcount cmp #$0003 bne bad_pcnt iny iny ;point to the input parameter ldx #$0000 lda fst_attr bmi @return_zero inx @return_zero txa sta [param_blk_ptr],y clc bra exit ENDP EXPORT end_segment end_segment PROC EXPORT end_code end_code ENDP end