19 July 2021, 02:09 | #1 |
Registered User
Join Date: Aug 2018
Location: Minneapolis, USA
Posts: 301
|
GetDeviceProc when 2 floppies share same name?
I need some help.
Outline of what I'm trying to do: - on IDCMP_DISKREMOVED and IDCMP_DISKINSERTED, refresh the list of volumes attached to the system - When a disk is removed, close any windows that referenced the contents of that disk (root level, but also any child directories that might have been opened) How I tried to do it: - on disk insert/eject event, get a new list of volumes, and compare against previous one. See which volumes got ejected, which got added. - I used LockDosList + NextDosEntry to step through all the volume names. This gets me the human-readable names like "Work:", "Workbench:", "Games:", etc, not HD0:, HD1:, WORK:, DF0:, etc. - Look through all the windows that are open, and check the name of an ejected disk against a property of the window, and if they matched, close the window. - This works just fine until you put 2 disks with the same name into the system. For example, 2 disks named "my_disk" inserted in DF0 and DF1. If the user has windows for both open, all those windows gets closed when the disk is ejected. Solution Design: - I thought I could use both the file path (disk name) and the drive code (my term for DF0, DF1, HD0, etc. type dol_Names) to know if a window is from a given device. - I can only get the drive code from the_dos_list->dol_Name (when the_dos_list->dol_Task == the_device_process->dvp_Port), which I get by calling GetDeviceProc with "my_disk" as the path - The problem is that the paths for DF0:my_disk and DF1:my_disk are exactly the same ("my_path"). I don't even know if it's DF0 or DF1 until I query GetDeviceProc. So when I call GetDeviceProc(the_disk_name,NULL) for each one, it returns the SAME process for both. So I can never really get to the fssm for the 2nd disk. Is there some easier way to build up the volume list, including device names, etc.? Rather than using GetDeviceProc, is there a way to just step through the DOS processes one by one? (I've looked through the AmigaDOS books I have, and dos.doc a few times, and it's not obvious to me, but I'm definitely not an expert in AmigaDOS). Is there maybe some other approach altogether I should be taking to manage disk insertion/removal tracking? I focused on floppies here, but same thing would happen with 2 hard drives with same name, or any combination. Called on disk insert/disk remove events: Code:
// populate the folder's List by iterating through the DOS List objects and treating each as a folder/file boolean Folder_PopulateVolumeList(WB2KFolderObject* the_folder) { // reset panel's file count, as we will be starting over from zero the_folder->file_count_ = 0; // get a date object, because we need something for File_New() struct DateStamp the_date = {0,0,0}; // get the DOS list and iterate through it struct DosList* the_dos_list; the_dos_list = LockDosList(LDF_VOLUMES|LDF_READ); while ( (the_dos_list = NextDosEntry(the_dos_list, LDF_VOLUMES|LDF_READ)) != NULL) { // NOTE: the_dos_list->dol_Name is a BSTR! char path_buffer[FILE_MAX_PATHNAME_SIZE]; char* the_path_buffer = path_buffer; char* this_name = (char*)BADDR(the_dos_list->dol_Name); char* disk_name = this_name + 1; General_Strlcpy(the_path_buffer, disk_name, FILE_MAX_PATHNAME_SIZE); General_Strlcat(the_path_buffer, ":", FILE_MAX_PATHNAME_SIZE); WB2KFileObject* this_file = File_New(disk_name, the_path_buffer, NULL, true, the_folder->icon_rport_, 0, the_date); if (this_file == NULL) { LOG_ERR(("Folder_PopulateVolumeList %d: Could not allocate memory for file object for '%s'", __LINE__, disk_name)); goto error; } // Add this file to the list of files WB2KList* the_new_item = List_NewItem((void*)this_file); List_AddItem(the_folder->list_, the_new_item); the_folder->file_count_++; } UnLockDosList(LDF_VOLUMES|LDF_READ); // now assign all volumes with a file type Folder_AssignDeviceInformation(the_folder); return true; error: return false; } Code:
// Iterate through all files in the folder, and find and assign the drive code file type. Allows for multiple devices to have same filepath. boolean Folder_AssignDeviceInformation(WB2KFolderObject* the_folder) { // LOGIC: // Challenge: // GetDeviceProc() is the DOS function that lets you get to the low level stuff like DF0 vs DH0, but it takes a file path. // If you have 2 floppies with same exact name, it returns after it hits the first one each time // So both items in your volume list get listed as DF1 (or DF0), not one of each. // Solution: // Loop through all files in the folder // For each one, call GetDeviceProc. On any match, get the drive code, and check the folder for matches to that drive code // If match found, then go back to NextDosEntry // If no match, assign this drive code to the file and iterate to the next file // code for using GetDeviceProc based on this post on eab: // http://eab.abime.net/showthread.php?t=91496 boolean ok = true; struct DevProc* the_device_process; WB2KList* the_item = *(the_folder->list_); unsigned short node_count = 0; while (the_item != NULL) { WB2KFileObject* this_file = (WB2KFileObject*)(the_item->payload_); // RAMdisk vs all others: RAMdisk will not have a device process if (Strnicmp((STRPTR)this_file->file_name_, (STRPTR)RAM_DISK_NAME, FILE_MAX_FILENAME_SIZE) == 0) { this_file->file_type_ = global_app->file_type_db_->disk_ram_filetype_; this_file->drive_code_ = General_StrlcpyWithAlloc((STRPTR)RAM_DISK_NAME, MAX_BSTR_SIZE); } else { // try to get device info boolean found = false; the_device_process = NULL; if ((the_device_process = GetDeviceProc((STRPTR)this_file->file_path_, NULL)) != NULL) { struct DosList* the_dos_list; struct FileSysStartupMsg* fssm; the_dos_list = LockDosList (LDF_DEVICES | LDF_READ); while ((the_dos_list = NextDosEntry(the_dos_list, LDF_DEVICES))) { if (the_dos_list->dol_Task == the_device_process->dvp_Port) { // we have an appropriate kind of DOS list, and it is for a file that matches our filepath. // need to see if this item has already been scanned or not fssm = BADDR(the_dos_list->dol_misc.dol_handler.dol_Startup); if (TypeOfMem(fssm) && (APTR)fssm > (APTR)1000) { WB2KList* matched_item; char temp_drive_code[MAX_BSTR_SIZE]; char device_name[MAX_BSTR_SIZE]; unsigned char* the_drive_code = temp_drive_code; unsigned char* the_device_name = device_name; General_StrCpyBStr(device_name,BADDR(fssm->fssm_Device)); General_StrCpyBStr(temp_drive_code,BADDR(the_dos_list->dol_Name)); matched_item = Folder_FindListItemByFilePath(the_folder, this_file->file_path_, (short)FILE_MAX_PATHNAME_SIZE, true, the_drive_code); if ( matched_item == NULL) { // this is the first time we've seen this filepath + drive code combination this_file->drive_code_ = General_StrlcpyWithAlloc(temp_drive_code, MAX_BSTR_SIZE); File_DetermineDriveType(this_file, the_device_name); DEBUG_OUT(("Folder_AssignDeviceInformation %d: device_name '%s', drive_code='%s' assigned to file %u, '%s'", __LINE__, the_device_name, the_drive_code, node_count, this_file->file_path_)); found = true; break; } else { DEBUG_OUT(("Folder_AssignDeviceInformation %d: device_name '%s', drive_code='%s' had already been assigned to file %d, '%s'", __LINE__, the_device_name, the_drive_code, node_count, this_file->file_path_)); } } } } UnLockDosList(LDF_DEVICES | LDF_READ); FreeDeviceProc(the_device_process); } if (found == false) { // this can happen on a same-filepath, different drive situation DEBUG_OUT(("Folder_AssignDeviceInformation %d: file %u, '%s' couldn't get a match", __LINE__, node_count, this_file->file_path_)); // err, now what?? } } node_count++; the_item = the_item->next_item_; } return (ok); } |
19 July 2021, 04:12 | #2 |
Registered User
Join Date: Mar 2018
Location: Hastings, New Zealand
Posts: 2,543
|
|
19 July 2021, 04:27 | #3 |
Registered User
Join Date: Aug 2018
Location: Minneapolis, USA
Posts: 301
|
I ask myself that question quite a lot recently.
Oh, wait, you mean "why do you want to close the windows when they eject the disk"? Mostly, I think it's confusing to have windows open when the floppy that they represent is no longer inserted. Also, I don't want to bother tracking ejected-but-still-remembered junk. If they eject it, it's gone. Bigger picture, it's a file manager app I'm making to get up to speed on Amiga development. Tends to touch a pretty big range of the libraries, so it's been pretty effective as a learning tool. If a little frustrating at times, of course. |
19 July 2021, 06:07 | #4 | |
Registered User
Join Date: Aug 2018
Location: Minneapolis, USA
Posts: 301
|
<phew> got it working. Biggest help was from here:
https://forum.amiga.org/index.php?topic=73225.0 I'll post the code tomorrow after some clean-up. In essence, you go through the device list from DOSBase->dl_Root->rn_Info, look at each one with dl_Type == DLT_VOLUME to get the volume names, then pass that to another routine that goes through dvi->dvi_Type == DLT_DEVICE items, and compares dvi->dvi_Task to the dl_Task from the first function. If they match, it's the same drive/volume, and you have access to the device name (eg, DF0 and the 'driver' name (scsi.device, etc.). I also found this little nugget, which suggests how AmigaDOS keeps them distinct: Quote:
So far my device name + volume name is adequate to keeping windows from various disks separate. |
|
20 July 2021, 02:39 | #5 |
Registered User
Join Date: Aug 2018
Location: Minneapolis, USA
Posts: 301
|
Here's the final code if anyone is looking for same thing in the future.
The flow is simple: - Folder_PopulateVolumeList() iterates through DOSBase->dl_Root->rn_Info - For each item it finds that is a volume, it is going to create a "file" object in my code, and then try to do 2 things: - 1) find out what the device name (DH0:, DF0:, etc.) is. It calls General_FindMatchingDeviceName() to do this (see below) - 2) it tries to classify the object as a floppy, RAM disk, Hard Drive, or CD-ROM. The logic should be pretty obvious. If you were going to be very complete, you'd want to add handling for other devices. - General_FindMatchingDeviceName() takes a task, and then scans through the DOS list again, this time looking for items of type Device. For each of those, it compares to the task, and when they match, then that's the device info for the passed volume (task). Code:
// populate the folder's List by iterating through the DOS List objects and treating each as a folder/file boolean Folder_PopulateVolumeList(WB2KFolderObject* the_folder) { // tricky stuff based on code from https://forum.amiga.org/index.php?topic=73225.0 // reset panel's file count, as we will be starting over from zero the_folder->file_count_ = 0; // get the DOS list and iterate through it struct DosInfo* the_dos_info = (struct DosInfo*)BADDR(DOSBase->dl_Root->rn_Info); struct DeviceList* the_device_list; struct DeviceList* this_volume = NULL; Forbid(); for(the_device_list = (struct DeviceList *)BADDR(the_dos_info->di_DevInfo) ; the_device_list != NULL ; the_device_list = (struct DeviceList *)BADDR(the_device_list->dl_Next)) { if(the_device_list->dl_Type == DLT_VOLUME) { // NOTE: the_device_list->dl_Name is a BSTR! unsigned char path_buffer[FILE_MAX_PATHNAME_SIZE]; unsigned char* the_path_buffer = path_buffer; unsigned char* this_name = (char*)BADDR(the_device_list->dl_Name); unsigned char* volume_name = this_name + 1; unsigned char* the_device_name; unsigned char* the_driver_name; General_Strlcpy(the_path_buffer, volume_name, FILE_MAX_PATHNAME_SIZE); General_Strlcat(the_path_buffer, ":", FILE_MAX_PATHNAME_SIZE); // we have volume name, need to get a device name that matches up to the volume name, and also get the device type if (General_FindMatchingDeviceName(the_dos_info, the_device_list->, &the_device_name, &the_driver_name) == false) { LOG_ERR(("Folder_PopulateVolumeList %d: Could not find a device name for volume '%s'", __LINE__, the_path_buffer)); return false; } //DEBUG_OUT(("Folder_PopulateVolumeList %d: device name '%s', driver name '%s'", __LINE__, the_device_name, the_driver_name)); // now we can make a file object, we'll sort out device type and device name shortly WB2KFileObject* this_file = File_New(volume_name, the_path_buffer, the_device_name, true, the_folder->icon_rport_, 0, the_device_list->dl_VolumeDate); if (this_file == NULL) { LOG_ERR(("Folder_PopulateVolumeList %d: Could not allocate memory for file object for '%s'", __LINE__, volume_name)); goto error; } // finally, set the file type // RAMdisk vs all others: RAMdisk will not have a device process; Amiga RAM Disks are always named "Ram Disk", regardless of language if (Strnicmp((STRPTR)this_file->file_name_, (STRPTR)RAM_DISK_NAME, FILE_MAX_FILENAME_SIZE) == 0) { this_file->file_type_ = global_app->file_type_db_->disk_ram_filetype_; } else { File_DetermineDriveType(this_file, the_driver_name); } // Add this file to the list of files WB2KList* the_new_item = List_NewItem((void*)this_file); List_AddItem(the_folder->list_, the_new_item); the_folder->file_count_++; } } Permit(); //DEBUG //DEBUG_OUT(("Folder_PopulateVolumeList %d: file list:", __LINE__)); //List_Print(the_folder->list_, &File_Print); return true; error: return false; } Code:
// iterates through device list, looking for devices who dvi_Task matches the passed device list task. if found, sets the device name and driver name boolean General_FindMatchingDeviceName(struct DosInfo* the_dos_info, struct MsgPort* the_device_list_task, unsigned char** the_device_name, unsigned char** the_driver_name) { struct DevInfo* dvi; boolean found_device = false; for (dvi = (struct DevInfo *)BADDR(the_dos_info->di_DevInfo) ; dvi != NULL ; dvi = (struct DevInfo *)BADDR(dvi->dvi_Next)) { if (dvi->dvi_Type == DLT_DEVICE && dvi->dvi_Task == the_device_list_task) { UBYTE* name = BADDR(dvi->dvi_Name); int name_len = name[0]; struct FileSysStartupMsg* fssm; fssm = BADDR(dvi->dvi_Startup); if (TypeOfMem(fssm) && (APTR)fssm > (APTR)1000) { UBYTE* driver_name = BADDR(fssm->fssm_Device); int driver_name_len = driver_name[0]; driver_name++; *the_driver_name = General_StrlcpyWithAlloc(driver_name, driver_name_len + 1); //DEBUG_OUT(("General_FindMatchingDeviceName %d: found device driver name '%s'", __LINE__, *the_driver_name)); } name++; *the_device_name = General_StrlcpyWithAlloc(name, name_len + 1); //DEBUG_OUT(("General_FindMatchingDeviceName %d: found device name '%s'", __LINE__, *the_device_name)); found_device = true; break; } } return (found_device); } |
20 July 2021, 11:26 | #6 |
Registered User
Join Date: Jan 2002
Location: Germany
Posts: 6,985
|
The thread title mentions GetDeviceProc which exists only in Kick 2.0+, so your target is not Kick 1.3, right?
In this case you should not peek DosBase for the top of the device list but rather work with LockDosList, NextDosEntry and UnlockDosList. Edit: here is an example: Code:
#include <proto/dos.h> int main (void) { struct DosList *dl,*dev,*vol; dl = LockDosList (LDF_DEVICES | LDF_VOLUMES | LDF_READ); vol = dl; while ((vol = NextDosEntry (vol,LDF_VOLUMES))) { if (vol->dol_Task) { dev = dl; while ((dev = NextDosEntry (dev,LDF_DEVICES))) { if (dev->dol_Task == vol->dol_Task) break; } if (dev) Printf ("%-30b %b\n",dev->dol_Name,vol->dol_Name); else Printf ("%-30s %b\n","(internal error)",vol->dol_Name); } else Printf ("%-30s %b\n","(not mounted)",vol->dol_Name); } UnLockDosList (LDF_DEVICES | LDF_VOLUMES | LDF_READ); return (RETURN_OK); } Last edited by thomas; 20 July 2021 at 15:08. |
21 July 2021, 04:30 | #7 |
Registered User
Join Date: Aug 2018
Location: Minneapolis, USA
Posts: 301
|
Thanks for putting together that example Thomas! I adapted my code to that. I think I finally understand now how to traverse the list for devices and volumes. I hadn't really noticed what LDF_DEVICES and LDF_VOLUMES were doing.
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Got new games to share :) | dlfrsilver | request.Old Rare Games | 14 | 16 November 2015 20:38 |
Network share PC to AMIGA | paulisthebest | support.Other | 3 | 21 September 2010 16:36 |
Share Your Save Games | Djay | Nostalgia & memories | 2 | 10 May 2010 21:30 |
Have to share this :) | Washac | Retrogaming General Discussion | 23 | 13 February 2010 11:14 |
Just thought I'd share this with everyone | alkis21 | Retrogaming General Discussion | 5 | 09 September 2002 18:46 |
|
|