Unix – Store st_mode (from stat) in a file and reuse it in chmod

cchmodstatunix

i'm going crazy for this.
I'm trying to write an archive library which can store and extract files. An archive file looks like this:

<0,/home/user/file.txt,154,0755>
file contents (154 byte)

Each file is identified by an header ( <…> ), with four "tags" (separated by commas), file type (0 for file and 1 for directory), path, size in bytes, permissions (in octal).
I retrieve the size and the permissions with the stat system call (i'm on Linux).
My problem is that i have to convert the octal value from st_mode to a string, store it in the archive file (the fourth tag in the header),then extract it and use it with the chmod syscall.

To convert it to string i use:

char mode[6];
sprintf (mode, "%o", statr.st_mode);

and to retrieve it i use atoi, but it does not seem to work. For example, the value stored in the 4th tag is 100644, but chmod set the permissions wrong (file not readable by my user).

I'm not sure if i explained well, i wil post the whole code if is needed (but it don't think there are implementation problem, is just a problem between conversion from octal to string)

EDIT: Solved! Actually the strtol method worked, but i had forgotten to apply it to the directories too (so extracting a directory with files inside caused Segfault because of the bad folder's permission mask). Thanks everybody for help!

Best Answer

As far as I know, there's not a unix standard function to do this.

You will most likely have to mask st_mode to get each permissions bit that you want and translate into something that makes sense to you.

related post

There's maybe an easier way to do this, but I've including a simple example which shows how to get each bit that you are interested in. This does compile and seemed to run as expected.

st_mode.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


#define SET_UID_BIT     0x4000
#define SET_GID_BIT     0x2000
#define STICKY_BIT      0x1000

// Readable USER bits defined here
#define USR_READ_BIT    0x400
#define USR_WRITE_BIT   0x200
#define USR_EXEC_BIT    0x100

// Readable GROUP bits defined here
#define GRP_READ_BIT    0x040
#define GRP_WRITE_BIT   0x020
#define GRP_EXEC_BIT    0x010

// Readable OTHER bits defined here
#define OTH_READ_BIT    0x004
#define OTH_WRITE_BIT   0x002
#define OTH_EXEC_BIT    0x001


int main()
{
    // The file I'm opening
    const char fp[] = "myfile.txt"; // -rw-rw-r--
    struct stat stats;

    // Get the stats
    if ( 0 == stat( fp, &stats ) )
    {
        // store st_mode
        mode_t mode = stats.st_mode;
        // init printable_mode
        unsigned int printable_mode = 0;        


        // Test for each permission bit in mode.
        // If the bit is present, mark the corresponding bit in printable_mode
        // using defined bits above.
        if( mode & S_ISUID )
        printable_mode |= SET_UID_BIT;

        if( mode & S_ISGID )
        printable_mode |= SET_GID_BIT;

        if( mode & S_ISVTX )
        printable_mode |= STICKY_BIT;

        if( mode & S_IRUSR )
        printable_mode |= USR_READ_BIT;

        if( mode & S_IWUSR )
        printable_mode |= USR_WRITE_BIT;

        if( mode & S_IXUSR )
        printable_mode |= USR_EXEC_BIT;

        if( mode & S_IRGRP )
        printable_mode |= GRP_READ_BIT;

        if( mode & S_IWGRP )
        printable_mode |= GRP_WRITE_BIT;

        if( mode & S_IXGRP )
        printable_mode |= GRP_EXEC_BIT;

        if( mode & S_IROTH )
        printable_mode |= OTH_READ_BIT;

        if( mode & S_IWOTH )
        printable_mode |= OTH_WRITE_BIT;

        if( mode & S_IXOTH )
        printable_mode |= OTH_EXEC_BIT;

        // Let's see what it looks like....
        printf("%04x\n", printable_mode);
        printf("%x\n", mode);
    }

    return 0;
}
Related Topic