--- uae/src/filesys.c 2018/04/24 16:42:15 1.1.1.4 +++ uae/src/filesys.c 2018/04/24 16:44:58 1.1.1.6 @@ -14,7 +14,7 @@ * * Known limitations: * Does not support ACTION_INHIBIT (big deal). - * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK) + * Does not support several 2.0+ packet types. * Does not support removable volumes. * May not return the correct error code in some cases. * Does not check for sane values passed by AmigaDOS. May crash the emulation @@ -64,7 +64,7 @@ #define ERROR_DIRECTORY_NOT_EMPTY 216 #define ERROR_DEVICE_NOT_MOUNTED 218 #define ERROR_SEEK_ERROR 219 -#define ERROR_DISK_FULL 221 +#define ERROR_DISK_IS_FULL 221 #define ERROR_DELETE_PROTECTED 222 #define ERROR_WRITE_PROTECTED 223 #define ERROR_READ_PROTECTED 224 @@ -82,7 +82,7 @@ static long dos_errno(void) case EACCES: return ERROR_WRITE_PROTECTED; case ENOENT: return ERROR_OBJECT_NOT_FOUND; case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE; - case ENOSPC: return ERROR_DISK_FULL; + case ENOSPC: return ERROR_DISK_IS_FULL; case EBUSY: return ERROR_OBJECT_IN_USE; case EISDIR: return ERROR_OBJECT_WRONG_TYPE; #if defined(ETXTBSY) @@ -186,10 +186,8 @@ int is_hardfile (struct uaedev_mount_inf return mountinfo->ui[unit_no].volname == 0; } -static void close_filesys_unit (struct uaedev_mount_info *mountinfo, int nr) +static void close_filesys_unit (UnitInfo *uip) { - UnitInfo *uip = mountinfo->ui + nr; - if (uip->hf.fd != 0) fclose (uip->hf.fd); if (uip->volname != 0) @@ -215,7 +213,7 @@ static void close_filesys_unit (struct u char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, char **volname, char **rootdir, int *readonly, int *secspertrack, int *surfaces, int *reserved, - int *cylinders, int *size) + int *cylinders, int *size, int *blocksize) { UnitInfo *uip = mountinfo->ui + nr; @@ -230,58 +228,83 @@ char *get_filesys_unit (struct uaedev_mo *reserved = uip->hf.reservedblocks; *size = uip->hf.size; *cylinders = uip->hf.nrcyls; + *blocksize = uip->hf.blocksize; return 0; } -char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, - char *volname, char *rootdir, int readonly, - int secspertrack, int surfaces, int reserved) +static char *set_filesys_unit_1 (struct uaedev_mount_info *mountinfo, int nr, + char *volname, char *rootdir, int readonly, + int secspertrack, int surfaces, int reserved, + int blocksize) { - UnitInfo tmpui; + UnitInfo *ui = mountinfo->ui + nr; if (nr >= mountinfo->num_units) return "No slot allocated for this unit"; + ui->hf.fd = 0; + ui->devname = 0; + ui->volname = 0; + ui->rootdir = 0; + ui->unit_pipe = 0; + ui->back_pipe = 0; + if (volname != 0) { - tmpui.volname = my_strdup (volname); - tmpui.hf.fd = 0; + ui->volname = my_strdup (volname); + ui->hf.fd = 0; } else { - tmpui.volname = 0; - tmpui.hf.fd = fopen (rootdir, "r+b"); - if (tmpui.hf.fd == 0) { + ui->volname = 0; + ui->hf.fd = fopen (rootdir, "r+b"); + if (ui->hf.fd == 0) { readonly = 1; - tmpui.hf.fd = fopen (rootdir, "rb"); + ui->hf.fd = fopen (rootdir, "rb"); } - if (tmpui.hf.fd == 0) + if (ui->hf.fd == 0) return "Hardfile not found"; if (secspertrack < 1 || secspertrack > 32767 || surfaces < 1 || surfaces > 1023 - || reserved < 0 || reserved > 1023) + || reserved < 0 || reserved > 1023 + || (blocksize & (blocksize - 1)) != 0) { return "Bad hardfile geometry"; } - fseek (tmpui.hf.fd, 0, SEEK_END); - tmpui.hf.size = ftell (tmpui.hf.fd); - tmpui.hf.secspertrack = secspertrack; - tmpui.hf.surfaces = surfaces; - tmpui.hf.reservedblocks = reserved; - tmpui.hf.nrcyls = (tmpui.hf.size >> 9) / (secspertrack * surfaces); - } - tmpui.self = 0; - tmpui.reset_state = FS_STARTUP; - tmpui.rootdir = my_strdup (rootdir); - tmpui.readonly = readonly; - - close_filesys_unit (mountinfo, nr); - mountinfo->ui[nr] = tmpui; + fseek (ui->hf.fd, 0, SEEK_END); + ui->hf.size = ftell (ui->hf.fd); + ui->hf.secspertrack = secspertrack; + ui->hf.surfaces = surfaces; + ui->hf.reservedblocks = reserved; + ui->hf.nrcyls = (ui->hf.size / blocksize) / (secspertrack * surfaces); + ui->hf.blocksize = blocksize; + } + ui->self = 0; + ui->reset_state = FS_STARTUP; + ui->rootdir = my_strdup (rootdir); + ui->readonly = readonly; return 0; } - + +char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, + char *volname, char *rootdir, int readonly, + int secspertrack, int surfaces, int reserved, + int blocksize) +{ + UnitInfo ui = mountinfo->ui[nr]; + char *result = set_filesys_unit_1 (mountinfo, nr, volname, rootdir, readonly, + secspertrack, surfaces, reserved, blocksize); + if (result) + mountinfo->ui[nr] = ui; + else + close_filesys_unit (&ui); + + return result; +} + char *add_filesys_unit (struct uaedev_mount_info *mountinfo, char *volname, char *rootdir, int readonly, - int secspertrack, int surfaces, int reserved) + int secspertrack, int surfaces, int reserved, + int blocksize) { char *retval; int nr = mountinfo->num_units; @@ -290,16 +313,9 @@ char *add_filesys_unit (struct uaedev_mo if (nr >= MAX_UNITS) return "Maximum number of file systems mounted"; - uip->hf.fd = 0; - uip->devname = 0; - uip->volname = 0; - uip->rootdir = 0; - uip->unit_pipe = 0; - uip->back_pipe = 0; - mountinfo->num_units++; - retval = set_filesys_unit (mountinfo, nr, volname, rootdir, readonly, - secspertrack, surfaces, reserved); + retval = set_filesys_unit_1 (mountinfo, nr, volname, rootdir, readonly, + secspertrack, surfaces, reserved, blocksize); if (retval) mountinfo->num_units--; return retval; @@ -311,7 +327,7 @@ int kill_filesys_unit (struct uaedev_mou if (nr >= mountinfo->num_units || nr < 0) return -1; - close_filesys_unit (mountinfo, nr); + close_filesys_unit (mountinfo->ui + nr); mountinfo->num_units--; for (; nr < mountinfo->num_units; nr++) { @@ -350,28 +366,31 @@ int sprintf_filesys_unit (struct uaedev_ return -1; if (uip[num].volname != 0) - sprintf (buffer, "(UAE%d:) Filesystem, %s: %s %s", num, uip[num].volname, + sprintf (buffer, "(DH%d:) Filesystem, %s: %s %s", num, uip[num].volname, uip[num].rootdir, uip[num].readonly ? "ro" : ""); else - sprintf (buffer, "(UAE%d:) Hardfile, \"%s\", size %d bytes", num, + sprintf (buffer, "(DH%d:) Hardfile, \"%s\", size %d bytes", num, uip[num].rootdir, uip[num].hf.size); return 0; } -void write_filesys_config (struct uaedev_mount_info *mountinfo, FILE *f) +void write_filesys_config (struct uaedev_mount_info *mountinfo, + const char *unexpanded, const char *default_path, FILE *f) { UnitInfo *uip = mountinfo->ui; int i; for (i = 0; i < mountinfo->num_units; i++) { + char *str; + str = cfgfile_subst_path (default_path, unexpanded, uip[i].rootdir); if (uip[i].volname != 0) { - fprintf (f, "-%c %s:%s\n", uip[i].readonly ? 'M' : 'm', - uip[i].volname, uip[i].rootdir); + fprintf (f, "filesystem=%s,%s:%s", uip[i].readonly ? "ro" : "rw", + uip[i].volname, str); } else { - fprintf (f, "-W %d:%d:%d:%s\n", uip[i].hf.secspertrack, - uip[i].hf.surfaces, uip[i].hf.reservedblocks, - uip[i].rootdir); + fprintf (f, "hardfile=%s,%d,%d,%d,%d,%s", uip[i].hf.secspertrack, + uip[i].hf.surfaces, uip[i].hf.reservedblocks, 512, str); } + free (str); } } @@ -379,6 +398,7 @@ struct uaedev_mount_info *alloc_mountinf { struct uaedev_mount_info *info; info = (struct uaedev_mount_info *)malloc (sizeof *info); + /* memset (info, 0xaa, sizeof *info);*/ info->num_units = 0; return info; } @@ -406,7 +426,7 @@ void free_mountinfo (struct uaedev_mount { int i; for (i = 0; i < mip->num_units; i++) - close_filesys_unit (mip, i); + close_filesys_unit (mip->ui + i); free (mip); } @@ -950,6 +970,7 @@ static struct a_inode *new_child_aino (U } else { get_file_attrs (aino); } + recycle_aino (unit, aino); TRACE(("created aino %x, normal\n", aino->uniq)); return aino; @@ -1797,7 +1818,7 @@ static void do_find (Unit *unit, dpacket aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1); if (aino == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */ + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ return; } aino_created = 1; @@ -1834,6 +1855,59 @@ static void do_find (Unit *unit, dpacket } static void +action_fh_from_lock (Unit *unit, dpacket packet) +{ + uaecptr fh = GET_PCK_ARG1 (packet) << 2; + uaecptr lock = GET_PCK_ARG2 (packet) << 2; + struct a_inode *aino; + Key *k; + int fd; + mode_t openmode; + int mode; + + TRACE(("ACTION_FH_FROM_LOCK(0x%lx,0x%lx)\n",fh,lock)); + DUMPLOCK(unit,lock); + + if (!lock) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, 0); + return; + } + + aino = lookup_aino (unit, get_long (lock + 4)); + if (aino == 0) + aino = &unit->rootnode; + mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */ + + prepare_for_open (aino->nname); + + openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY + : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY + : O_RDWR)); + + fd = open (aino->nname, openmode | O_BINARY, 0777); + + if (fd < 0) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, dos_errno()); + return; + } + k = new_key (unit); + k->fd = fd; + k->aino = aino; + + put_long (fh+36, k->uniq); + /* I don't think I need to play with shlock count here, because I'm + opening from an existing lock ??? */ + + /* Is this right? I don't completely understand how this works. Do I + also need to free_lock() my lock, since nobody else is going to? */ + de_recycle_aino (unit, aino); + PUT_PCK_RES1 (packet, DOS_TRUE); + /* PUT_PCK_RES2 (packet, k->uniq); - this shouldn't be necessary, try without it */ +} + +static void action_find_input (Unit *unit, dpacket packet) { do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1); @@ -2072,20 +2146,66 @@ action_same_lock (Unit *unit, dpacket pa } static void -action_parent (Unit *unit, dpacket packet) +action_change_mode (Unit *unit, dpacket packet) { - uaecptr lock = GET_PCK_ARG1 (packet) << 2; - struct a_inode *olda; - - TRACE(("ACTION_PARENT(0x%lx)\n",lock)); +#define CHANGE_LOCK 0 +#define CHANGE_FH 1 + /* will be CHANGE_FH or CHANGE_LOCK value */ + long type = GET_PCK_ARG1 (packet); + /* either a file-handle or lock */ + uaecptr object = GET_PCK_ARG2 (packet) << 2; + /* will be EXCLUSIVE_LOCK/SHARED_LOCK if CHANGE_LOCK, + * or MODE_OLDFILE/MODE_NEWFILE/MODE_READWRITE if CHANGE_FH */ + long mode = GET_PCK_ARG3 (packet); + uaecptr fh; + struct a_inode *a = NULL, *olda = NULL; + uae_u32 err = 0; + TRACE(("ACTION_CHANGE_MODE(0x%lx,%d,%d)\n",object,type,mode)); + + if (! object + || (type != CHANGE_FH && type != CHANGE_LOCK)) + { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK); + return; + } - if (!lock) { - PUT_PCK_RES1 (packet, 0); - PUT_PCK_RES2 (packet, 0); - return; + /* @@@ Brian: shouldn't this be good enough to support + CHANGE_FH? */ + if (type == CHANGE_FH) + mode = (mode == 1006 ? -1 : -2); + fh = (type == CHANGE_LOCK ? get_long (object + 4) : object); + a = lookup_aino (unit, get_long(object + 4)); + if (! a) + err = ERROR_INVALID_LOCK; + else { + if (mode == -1) { + if (a->shlock > 1) + err = ERROR_OBJECT_IN_USE; + else { + a->shlock = 0; + a->elock = 1; + } + } else { /* Must be SHARED_LOCK == -2 */ + a->elock = 0; + a->shlock++; + } + } + + if (err) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, err); + return; + } else { + de_recycle_aino (unit, a); + PUT_PCK_RES1 (packet, DOS_TRUE); } +} - olda = lookup_aino (unit, get_long(lock + 4)); +static void +action_parent_common (Unit *unit, dpacket packet, uaecptr fh) +{ + struct a_inode *olda = lookup_aino (unit, fh); if (olda == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK); @@ -2108,6 +2228,35 @@ action_parent (Unit *unit, dpacket packe } static void +action_parent_fh (Unit *unit, dpacket packet) +{ + uaecptr fh = GET_PCK_ARG1 (packet) << 2; + TRACE(("ACTION_PARENT_FH(0x%lx)\n",fh)); + + if (! fh) { + PUT_PCK_RES1 (packet, DOS_FALSE); + PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND); + return; + } + action_parent_common (unit, packet, fh); +} + +static void +action_parent (Unit *unit, dpacket packet) +{ + uaecptr lock = GET_PCK_ARG1 (packet) << 2; + + TRACE(("ACTION_PARENT(0x%lx)\n",lock)); + + if (!lock) { + PUT_PCK_RES1 (packet, 0); + PUT_PCK_RES2 (packet, 0); + return; + } + action_parent_common (unit, packet, get_long (lock + 4)); +} + +static void action_create_dir (Unit *unit, dpacket packet) { uaecptr lock = GET_PCK_ARG1 (packet) << 2; @@ -2139,7 +2288,7 @@ action_create_dir (Unit *unit, dpacket p aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 2); if (aino == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */ + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ return; } @@ -2160,7 +2309,8 @@ action_examine_fh (Unit *unit, dpacket p struct a_inode *aino = 0; uaecptr info = GET_PCK_ARG2 (packet) << 2; - TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) )); + TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", + GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) )); k = lookup_key (unit, GET_PCK_ARG1 (packet)); if (k != 0) @@ -2170,9 +2320,9 @@ action_examine_fh (Unit *unit, dpacket p get_fileinfo (unit, packet, info, aino); if (aino->dir) - put_long(info, 0xFFFFFFFF); + put_long (info, 0xFFFFFFFF); else - put_long(info, 0); + put_long (info, 0); } /* For a nice example of just how contradictory documentation can be, see the @@ -2215,7 +2365,11 @@ action_set_file_size (Unit *unit, dpacke k->file_pos = offset; lseek (k->fd, k->file_pos, SEEK_SET); - if (truncate (k->aino->nname, k->file_pos) == -1) { + /* Brian: no bug here; the file _must_ be one byte too large after writing + The write is supposed to guarantee that the file can't be smaller than + the requested size, the truncate guarantees that it can't be larger. + If we were to write one byte earlier we'd clobber file data. */ + if (truncate (k->aino->nname, offset) == -1) { PUT_PCK_RES1 (packet, DOS_FALSE); PUT_PCK_RES2 (packet, dos_errno ()); return; @@ -2292,7 +2446,8 @@ action_set_date (Unit *unit, dpacket pac return; } - ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8)); + ut.actime = ut.modtime = put_time(get_long (date), get_long (date + 4), + get_long (date + 8)); a = find_aino (unit, lock, bstr (unit, name), &err); if (err == 0 && utime (a->nname, &ut) == -1) err = dos_errno (); @@ -2335,17 +2490,18 @@ action_rename_object (Unit *unit, dpacke return; } /* Object does not exist. aino points to containing directory. */ - a2 = new_child_aino (unit, a2, my_strdup (bstr_cut (unit, name2)), a1->dir ? 2 : 1); + a2 = new_child_aino (unit, a2, my_strdup (bstr_cut (unit, name2)), + a1->dir ? 2 : 1); if (a2 == 0) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */ + PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */ return; } /* @@@ what should we do if there are locks on a1? */ - if (-1 == rename(a1->nname, a2->nname)) { + if (-1 == rename (a1->nname, a2->nname)) { PUT_PCK_RES1 (packet, DOS_FALSE); - PUT_PCK_RES2 (packet, dos_errno()); + PUT_PCK_RES2 (packet, dos_errno ()); return; } move_aino_children (unit, a1, a2); @@ -2518,14 +2674,14 @@ static int handle_packet (Unit *unit, dp /* 2.0+ packet types */ case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break; case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break; + case ACTION_FH_FROM_LOCK: action_fh_from_lock (unit, pck); break; + case ACTION_CHANGE_MODE: action_change_mode (unit, pck); break; + case ACTION_PARENT_FH: action_parent_fh (unit, pck); break; /* unsupported packets */ case ACTION_LOCK_RECORD: case ACTION_FREE_RECORD: - case ACTION_CHANGE_MODE: - case ACTION_FH_FROM_LOCK: case ACTION_COPY_DIR_FH: - case ACTION_PARENT_FH: case ACTION_EXAMINE_ALL: case ACTION_MAKE_LINK: case ACTION_READ_LINK: @@ -2778,7 +2934,7 @@ static uae_u32 filesys_dev_storeinfo (vo put_long (parmpacket + 8, uip[unit_no].devno); put_long (parmpacket + 12, 0); /* Device flags */ put_long (parmpacket + 16, 16); /* Env. size */ - put_long (parmpacket + 20, 128); /* 512 bytes per block */ + put_long (parmpacket + 20, uip[unit_no].hf.blocksize >> 2); /* longwords per block */ put_long (parmpacket + 24, 0); /* unused */ put_long (parmpacket + 28, uip[unit_no].hf.surfaces); /* heads */ put_long (parmpacket + 32, 0); /* unused */ @@ -2788,7 +2944,7 @@ static uae_u32 filesys_dev_storeinfo (vo put_long (parmpacket + 48, 0); /* interleave */ put_long (parmpacket + 52, 0); /* lowCyl */ put_long (parmpacket + 56, uip[unit_no].hf.nrcyls - 1); /* hiCyl */ - put_long (parmpacket + 60, 0); /* Number of buffers */ + put_long (parmpacket + 60, 50); /* Number of buffers */ put_long (parmpacket + 64, 0); /* Buffer mem type */ put_long (parmpacket + 68, 0x7FFFFFFF); /* largest transfer */ put_long (parmpacket + 72, ~1); /* addMask (?) */