On the host OS, write protecting files that an application opens in read-write-mode but never writes to, should result in the read-only behavior. That is, the application's fileopen call should succeed, and, because the application never writes to the file, operate as expected.
There's also the scenario where the application may write to the file, such as described in DOS's attrib man-page: If a file has an attribute of +R, it can be read from, but not written to (for example, you can use your word processor to look at it but not to alter it).
https://web.csulb.edu/~murdock/attrib.html
Dosbox would also not permit this scenario because the word processor will be blocked from opening the read-only document in the first place.
I beleive the fix is to downgrade application requests for "rb+" fileopen calls to "rb" calls if the file is in indeed read-only on the host filesystem. How the application behaves with a read-only file is up to the application, and not preempted by dosbox.
(I will follow up with a list of games that open their data files read-write without ever writing to them, to show this behavior in action)
Here's a list of games that attempt open "data" files read-write but never write to them.
To reproduce the behavior, chmod -w the list of files, then launch the game in dosbox.
Champions of Krynn will stall at a black screen after making two attempts to open its first .dax file; but when read-only pass-thru is permitted, the game loads as expected (the only writes it actually performs are only within its "save" directory)
AD&D Dragonlance I Champions of Krynn:
8x8d1.dax
comspr.dax
cursor.dax
items
sky.dax
AD&D Dragonlance II Death Knights of Krynn:
8x8d1.dax
8x8d4.dax
back4.dax
comspr.dax
cpic1.dax
ecl1.dax
geo1.dax
item0.dax
items
mon1cha.dax
mon1itm.dax
mon1spc.dax
mon1wiz.dax
music.dax
pic4.dax
skygrnd.dax
title.dax
walldef4.dax
AD&D Forgotten Realms II Curse of the Azure Bonds:
8x8d1.dax
comspr.dax
items
sky.dax
title.dax
AD&D Forgotten Realms III Secret of The Silver Blades:
8x8d1.dax
8x8d5.dax
comspr.dax
items
sky.dax
sound.dax
title.dax
AD&D Legend III Eye of the Beholder III Assault of Myth Drannor:
intro.gff
AD&D Savage Frontier I Gateway to the Savage Frontier:
8x8d1.dax
8x8d.dax
comspr.dax
dungcom.dax
items.1
music.dax
randcom.dax
sky.dax
title.dax
zounds.dax
AD&D Savage Frontier II Treasures of the Savage Frontier:
8x8d0.dax
bord.dax
cursor.dax
item0.dax
items
music.dax
title.dax
zounds.dax
Air Duel 80 Years of Dogfighting:
_dog_a
_dog_b
_dog_c
_index
B-17 Flying Fortress:
_fonts
_front
_index
_intro
_music
Blood:
blood000.dem
surface.dat
tiles000.art
tiles001.art
tiles002.art
tiles003.art
tiles004.art
tiles005.art
tiles006.art
tiles007.art
tiles008.art
tiles009.art
tiles010.art
tiles011.art
tiles012.art
tiles013.art
tiles014.art
tiles015.art
voxel.dat
Boston Bomb Club:
blancpc.io
Brix:
brix0.dat
brixb.dat
Caesar I:
houses2.pl8
imprlogo.256
romfont.pl8
shade.256
title3.256
Cruise for a Corpse:
d1
delphine.lng
system.fnt
vgadrv.bin
vol.1
vol.cnf
Darklands:
cine.gff
darkrun.gff
gpldata.gff
resource.gff
rgnff.gff
segobjex.gff
Duke Nukem 3D:
duke3d.grp
Duke Nukem II:
nukem2.cmp
nukem2.f2
nukem2.f5
Epic Pinball:
ep1.dat
ep1.exe
ep2.dat
ep2.exe
ep3.dat
ep3.exe
ep4.dat
ep4.exe
ep5.dat
ep5.exe
ep6.dat
ep6.exe
ep7.dat
ep7.exe
ep8.dat
ep8.exe
id1.dat
id2.dat
id3.dat
id4.dat
id5.dat
id6.dat
id7.dat
id8.dat
intro.pin
pinball.exe
reg.dat
sfx0.pin
Fury of the Furries:
dat
lang.dat
Highway Hunter:
123.dat
Hoyle Official Book of Games 1:
hoyle.set
Hoyle Official Book of Games 3:
version
Hoyle's Classic Card Games:
version
IndyCar Series:
cars
effects
tracks
a32mt32.dll
a32sbdg.dll
calib.val
fat.mt
main.dat
Lemmings 1:
russell.dat
(write protecting this file foils the copy-protection)
Lode Runner:
lr.usr
Lotus The Ultimate Challenge:
lotus.dat
MechWarrior 1:
6x6.fnt
fox88.fnt
mech.mus
mw_2pics.bin
mw_apics.bin
mw_cpics.bin
mw_gpics.bin
mw_tpics.bin
Metaltech Battledrome:
data
Metaltech EarthSiege:
data
Might and Magic II Gates to Another World:
master.16
mcga.drv
mm2.ch
nwcp.16
timer.drv
Might and Magic III Isles of Terra:
mm3.cc
NASCAR Racing:
cars
effects
objs
rol
sound
tracks
calendar
main.dat
Operation Carnage:
resource.1
resource.2
resource.3
resource.4
resource.5
resource.6
resource.des
Pinball Dreams II:
21stlogo.vga
font.spr
presents.vga
spider.vga
title.vga
Pizza Tycoon:
pizza
Project Space Station:
opening.bin
q7t.dat
screen2.bin
screen3.bin
text1.dat
t.vit
Prophecy of the Shadow:
font.jrm
pattern.jrm
pointer.jrm
pots8.jrm
splash.jrm
stone.jrm
title.jrm
Realms of Arkania I Blade of Destiny:
introdat.dir
introdat.vol
Redneck Rampage:
redneck.grp
Rise of the Triad Dark War:
darkwar.wad
remote1.rts
Secret Agent Mission 1:
sam101e.snd
sam101.gfx
sam102e.snd
sam102.gfx
sam103e.snd
Secret Agent Mission 2 Kill Again Island:
sam201e.snd
sam201.gfx
sam202e.snd
sam202.gfx
sam203e.snd
Shadow Warrior:
sw.grp
SimAnt The Electronic Ant Colony:
hcegant.dat
hcegant.ndx
shared.dat
shared.ndx
sound.dat
sound.ndx
SimEarth The Living Planet:
hcegaia.dat
hcegaia.ndx
shared.dat
shared.ndx
SimFarm:
megadata.eea
megadata.idx
SimLife:
cpl4life.dat
cpl4life.ndx
Space Quest I (1991) The Sarien Encounter:
version
Space Quest IV The Time Rippers:
version
Space Quest VI The Spinal Frontier:
version
Space Quest V The Next Mutation:
version
Terminator (1993) Rampage:
logo1.flc
logo2.flc
Terminator 2 The Arcade Game:
arena.lbm
probprod.lbm
roland.bin
virgin.lbm
xfontbig.bin
xfonthud.bin
xfontit.bin
xfontsml.bin
xmisc.bin
xshrap1.bin
Tex Murphy Martian Memorandum:
adlib.drv
music.ap
title.ap
The Games Winter Challenge:
winter.exe
The Smurfs:
drum.bnk
melodic.bnk
Tyrian 2000:
music.mus
newsh1.shp
newsh$.shp
palette.dat
tyrian.hdt
tyrian.pic
tyrian.shp
tyrian.snd
voices.snd
Ultima 6 The False Prophet:
blocks.shp
bootup.m
intro_1.shp
intro.ptr
mainmenu.shp
mcgadrv.bin
midi.dat
palettes.int
titles.shp
u6roland.drv
u6.set
ultima.m
Ultima 7 Part One The Black Gate:
static
install.prm
Ultima 7 Part Two Serpent Isle:
static
install.prm
Ultima 8 Pagan:
static
usecode
ailxmi.dll
Ultima Worlds of Adventure 1 The Savage Empire:
create.lzc
music.lzc
savage.fnt
savage.pal
savage.tim
strax.drv
supertm.drv
title.lzc
tm.drv
Ultima Worlds of Adventure 2 Martian Dreams:
fonts.lzc
mdd_mus.lzc
md.tim
strax.drv
strx_mus.lzc
supertm.drv
title.lzc
tm.drv
Vette!:
bigvet.bin
egapic.bin
egaskill.bin
garage.bin
highsc.bin
horizon0.bin
horizon1.bin
horizon2.bin
mappic.bin
redvette.bin
spetrum.bin
title.bin
vx.bin
Warlords II:
data
erythea
pics
sound
udb
black.pal
chance17.fin
chance17.fnt
chance36.fin
chance36.fnt
sound.dat
standard.pal
stand.pck
text.fin
text.fnt
Wasteland:
colorf.fnt
curs
ic0_9.wlf
masks.wlf
title.pic
transtbl
wla.bin
Witchaven:
palette.dat
setup.dat
tables.dat
Wizardry 1 Proving Grounds of the Mad Overlord:
wiz1.dsk
Wizardry 2 Knight of Diamonds:
wiz2.dsk
Wizardry 3 Legacy of Llylgamyn:
wiz3.dsk
Wizardry 4 The Return of Werdna:
wiz4.dsk
Wizardry 5 Heart of the Maelstrom:
wiz5.dsk
Wrath of Earth:
woe.rsc
Zone 66:
font.z66
m03gmuz.z66
mapadat3.z66
mapapic.z66
mapbdat3.z66
mapbpic.z66
mapcdat3.z66
mapcpic.z66
mapdat.z66
mapddat3.z66
mapdpic.z66
mapedat3.z66
mapepic.z66
mapfdat3.z66
mapfpic.z66
mapgdat3.z66
mapgpic.z66
maphdat3.z66
maphpic.z66
mpal.z66
prefs.z66
shipdat0.z66
shipdat1.z66
title.z66
tpal.z66
zil0.z66
zim2.z66
Here's a small patch that permits read-only pass through.
The "isWriteProtectedFileNew(filename)" member function keeps a simple vector<string> record of read-only files already encountered to avoid redudant log messages, as some games repeatedly open and close the same file(s) in read-write mode.
Here's the output from a clean run of Champions of Krynn with all files write-protected except for its "save" directory.
DOSBox version SVN
Copyright 2002-2017 DOSBox Team, published under GNU GPL.
CONFIG:Loading primary settings from config file /home/kcroft/.dosbox/dosbox-SVN.conf
ALSA:Client initialised [128:0]
MIDI: Opened device:alsa
FILESYSTEM: protecting ./8x8d1.dax from writes because it's read-only
FILESYSTEM: protecting ./comspr.dax from writes because it's read-only
FILESYSTEM: protecting ./sky.dax from writes because it's read-only
FILESYSTEM: protecting ./cursor.dax from writes because it's read-only
FILESYSTEM: protecting ./items from writes because it's read-only
FILESYSTEM: protecting ./chead.dax from writes because it's read-only
FILESYSTEM: protecting ./cbody.dax from writes because it's read-only
FILESYSTEM: protecting ./ecl1.dax from writes because it's read-only
FILESYSTEM: protecting ./bigpic1.dax from writes because it's read-only
In real DOS, attempting to open a file for write (or read/write) access when the file has the read-only attribute results in "access denied" (error code 5); and DOSBox emulates this behavior. DOS programs handle file open errors with varying degrees of grace -- and hanging at a black screen is indeed one of the more ungraceful. In any case, the message that DOSBox prints in its status window regarding why the file failed to open is a courtesy users of real DOS do not receive.
If I'm not mistaken, you're suggesting that DOSBox take a "hope for the best" approach by proceeding to open read-only files even though write access has been requested, and maybe the DOS program won't try to write to it. However, if the program does try to write, then what should DOSBox do? An access denied error, I suppose; but since the file couldn't be opened in the first place in real DOS, that'd be just making something up. Besides, a DOS program that doesn't handle open errors gracefully may not handle write errors any better.
Thanks Ripsaw, yes - that's the behavior I was thinking should occur.
The hope-for-the-best approach shifts the point of failure from the read event to the write event, which might never happen (in the case of the file lists I sent), or would only happen if the user did something to trigger an actual write (save game). It's an interesting feature but because DOS programmers didn't have to deal with it, it shouldn't be allowed.
I had infered from that Attrib documentation that DOS itself permitted the reading of write-protecting file that applications attempt to open read-write, without confirming actual behavior on DOS. Indeed, DOSBox is doing the right thing.
It's unfortunate so many games from that era attempt to open strict data files with read & write flags, but it goes with the times.. single-user-system (no concept of separating application data vs. user files besides simple sub-directories), no concept of security or trying to minimize the "rights" a given operation needs to get its task done; and for these early games, they likely re-used a single "do-everything" file handler function.
But in most cases, I think it was just lazy programming.
Please feel free to close this false-positive issue!
Last edit: krcroft 2018-04-20