C library "chown()" & AmigaDOS "SetOwnerInfo()" bug

This forum is for general developer support questions.
Post Reply
xenic
Posts: 1185
Joined: Sun Jun 19, 2011 12:06 am

C library "chown()" & AmigaDOS "SetOwnerInfo()" bug

Post by xenic »

I ported an old GG (*nix) program that uses the "chown" command and discovered that setting the owner of a file with chown causes the directory containing the file to be locked and cannot be deleted. An attempt to delete the directory results in an AmigaDOS "object in use" requester.

I can't tell for sure about newlib but I checked the clib2 sources for "chown" and found that it's using AmigaDOS "SetOwner()". I wrote a short test program using OS4 AmigaDOS SetOwnerInfo() and it also causes a directory containing a file that has the owner set by SetOwnerInfo() to be locked and can't be deleted.

Summary: Setting a file owner with "chown()" or "SetOwnerInfo()" causes the directory containing the file to be locked and not deletable.
AmigaOne X1000 with 2GB memory - OS4.1 FE
User avatar
colinw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 207
Joined: Mon Aug 15, 2011 9:20 am
Location: Brisbane, QLD. Australia.

Re: C library "chown()" & AmigaDOS "SetOwnerInfo()" bug

Post by colinw »

Please show me the code (and tags) that you are using for SetOwnerInfo() call.
I also need to know what filesystem you are using for this test.
xenic
Posts: 1185
Joined: Sun Jun 19, 2011 12:06 am

Re: C library "chown()" & AmigaDOS "SetOwnerInfo()" bug

Post by xenic »

@colinw
colinw wrote:Please show me the code (and tags) that you are using for SetOwnerInfo() call.
I also need to know what filesystem you are using for this test.
My bad for not considering that the problem could be filesystem related. I was testing in the ram disk. I did some more testing and the problem DOES NOT occur on SFS2, FFS or FAT filesystems. I usually test in ram: to avoid disk damage from unknown programs (espectially *nix ported stuff).

The problem only occurs with the ram disk so it could be a ram filesystem bug. Here is the test program I was using:

Code: Select all

/* Compile: gcc -O2 setown.c -o setown -Wall -lauto */

#include <proto/exec.h>
#include <proto/dos.h>
#include <signal.h>

#define TEMPLATE "NAME/A"

enum
{
	S_NAME, S_MAX
};

struct RDArgs *argsdata;

const char version[] = "$VER: setown 1.0 [OS4/PPC] ("__DATE__") xenic";

int main(int argc, char **argv)
{
	int32 args[S_MAX] = {0};
	char *name = NULL;
	TEXT errbuf[256];
	int32 result = 0;
	BPTR lock = 0;

	signal(SIGINT, SIG_IGN);
	if (argc == 0)
	{
		IDOS->PutErrStr("Error: Shell program\n");
		return(RETURN_ERROR);
	}

	argsdata = IDOS->ReadArgs(TEMPLATE, args, NULL);
	if (argsdata)
	{
		name = (char *)args[S_NAME];
	}
	else
	{
		result = IDOS->Fault(IDOS->IoErr(), "Error:", (STRPTR)&errbuf, 256);
		if (result > 0)
		{
			IDOS->PutErrStr((CONST_STRPTR)&errbuf);
			IDOS->PutErrStr("\n");
		}
		else
		{
			IDOS->PutErrStr("Error: Invalid args\n");
		}
		return(RETURN_ERROR);
	}

	if ((name[0] != '\0') && (lock = IDOS->Lock(name, SHARED_LOCK)))
	{
		IDOS->UnLock(lock);
		IDOS->Printf("Name: %s\n", name);
		result = IDOS->SetOwnerInfoTags(OI_StringNameInput, name,
		                                OI_OwnerUID, DOS_OWNER_ROOT,
		                                OI_OwnerGID, DOS_OWNER_ROOT,
		                                TAG_DONE);
		if (result)
		{
			IDOS->Printf("User & Group owner set to ROOT\n");
		}
		else
		{
			result = IDOS->Fault(IDOS->IoErr(), "Error:", (STRPTR)&errbuf, 256);
			if (result > 0)
			{
				IDOS->PutErrStr((CONST_STRPTR)&errbuf);
				IDOS->PutErrStr("\n");
			}
			else
			{
				IDOS->PutErrStr("Error: Invalid args\n");
			}
			IDOS->FreeArgs(argsdata);
			return(RETURN_ERROR);
		}
	}
	else
	{
		IDOS->PutErrStr("Error: Invalid path or filename\n");
		IDOS->FreeArgs(argsdata);
		return(RETURN_ERROR);
	}

	IDOS->FreeArgs(argsdata);
	return(RETURN_OK);
}
I created a directory named "testdir" in ram: and copied a file into that directory as "testfile". From a shell with the current directory being ram: I entered "setown testdir/testfile". When I attempt to delete the "testdir" directory, I get a DOS requester stating: DOS error code 202 - object is in use.

Performing the same procedure on an FFS, SFS2 partition or FAT formatted USB drive, the directory is deleted as expected and there isn't any problem.

As a seperate issue, I reported a "packet" problem with the C:Owner command in the General AmigaOS forum. I doubt that problem is related to the above issue but it did seem strange to me that SetOwnerInfo() accepts 32bit inputs while the C:owner docs show it accepting string (alphabetic) input.
AmigaOne X1000 with 2GB memory - OS4.1 FE
User avatar
colinw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 207
Joined: Mon Aug 15, 2011 9:20 am
Location: Brisbane, QLD. Australia.

Re: C library "chown()" & AmigaDOS "SetOwnerInfo()" bug

Post by colinw »

I found the problem, it was in the DOS path resolver used for vectorport filesystems and packet handlers with long names.

What basically happened was that one lock for the parent of the specified name, was overwritten by the way the UID and GID
are separately handled in DOS. This was the only DOS call that called the path resolver twice, using the same DevProc and
that just happened to orphan the first parent directory lock, if both a GID and UID are specified in the same function call.

As a workaround, just do them separately and check for failure on each call.
IDOS->SetOwnerInfoTags(OI_StringNameInput, name, OI_OwnerUID, DOS_OWNER_ROOT, TAG_DONE);
IDOS->SetOwnerInfoTags(OI_StringNameInput, name, OI_OwnerGID, DOS_OWNER_ROOT, TAG_DONE);
This should work fine until an update can be sent out.

On the other topic...
The 'c:owner' and 'c:group' commands havn't been touched in a decade or more and still have some old stuff lurking in there,
they should still work (i'll check later) until and updated DOS library will shut up the unknown packet requester on newer filesystems.

Thanks for the report.

BTW:
Your test code is a bit broken and not so robust.
You need to lose the ampersand on &errbuf or specify what element of errbuf you wish to pass the address of.
An array name is a constant pointer to the first element of the array.
Also, it's never a good idea to use numerical size constants in function calls;

Your code;
IDOS->Fault(IDOS->IoErr(), "Error:", (STRPTR)&errbuf, 256);

Should have been;
IDOS->Fault(IDOS->IoErr(), "Error:", &errbuf[0], sizeof(errbuf));

But would be far simpler just using the name as the pointer to the array;
IDOS->Fault(IDOS->IoErr(), "Error:", errbuf, sizeof(errbuf));

Here's a link that explains it. http://www.tutorialspoint.com/cprogramm ... _array.htm
xenic
Posts: 1185
Joined: Sun Jun 19, 2011 12:06 am

Re: C library "chown()" & AmigaDOS "SetOwnerInfo()" bug

Post by xenic »

@colinw
I'll fix my test program and save it for future testing. I'm glad you found the problem and will fix it. I don't really think I will have any use for the SetOwnerInfo() command myself but just pointed out the error because of the C language "chown" command apparently calls SetOwnerInfo(). In the code I was porting, chown sets both the group and user ownership so I assume that other ported Linux code could do the same. Since it only happens in ram: it's not as important an issue as I first thought.

Thanks for your response.
AmigaOne X1000 with 2GB memory - OS4.1 FE
Post Reply