2004-06-17 01:47:21 +00:00
|
|
|
/*
|
|
|
|
|
* To understand this code, see Rock Ridge Interchange Protocol
|
|
|
|
|
* standard 1.12 and System Use Sharing Protocol version 1.12
|
|
|
|
|
* (search for rrip112.ps and susp112.ps on the web).
|
|
|
|
|
*
|
|
|
|
|
* Even better, go read something else.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <u.h>
|
|
|
|
|
#include <libc.h>
|
|
|
|
|
#include <bio.h>
|
|
|
|
|
#include <libsec.h>
|
|
|
|
|
#include "iso9660.h"
|
|
|
|
|
|
|
|
|
|
static long mode(Direc*, int);
|
|
|
|
|
static long nlink(Direc*);
|
|
|
|
|
static ulong suspdirflags(Direc*, int);
|
|
|
|
|
static ulong CputsuspCE(Cdimg *cd, ulong offset);
|
|
|
|
|
static int CputsuspER(Cdimg*, int);
|
|
|
|
|
static int CputsuspRR(Cdimg*, int, int);
|
|
|
|
|
static int CputsuspSP(Cdimg*, int);
|
2006-04-01 19:24:03 +00:00
|
|
|
/*static int CputsuspST(Cdimg*, int); */
|
2004-06-17 01:47:21 +00:00
|
|
|
static int Cputrripname(Cdimg*, char*, int, char*, int);
|
|
|
|
|
static int CputrripSL(Cdimg*, int, int, char*, int);
|
|
|
|
|
static int CputrripPX(Cdimg*, Direc*, int, int);
|
|
|
|
|
static int CputrripTF(Cdimg*, Direc*, int, int);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Patch the length field in a CE record.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
setcelen(Cdimg *cd, ulong woffset, ulong len)
|
|
|
|
|
{
|
|
|
|
|
ulong o;
|
|
|
|
|
|
|
|
|
|
o = Cwoffset(cd);
|
|
|
|
|
Cwseek(cd, woffset);
|
|
|
|
|
Cputn(cd, len, 4);
|
|
|
|
|
Cwseek(cd, o);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Rock Ridge data is put into little blockettes, which can be
|
|
|
|
|
* at most 256 bytes including a one-byte length. Some number
|
|
|
|
|
* of blockettes get packed together into a normal 2048-byte block.
|
|
|
|
|
* Blockettes cannot cross block boundaries.
|
|
|
|
|
*
|
|
|
|
|
* A Cbuf is a blockette buffer. Len contains
|
|
|
|
|
* the length of the buffer written so far, and we can
|
|
|
|
|
* write up to 254-28.
|
|
|
|
|
*
|
|
|
|
|
* We only have one active Cbuf at a time; cdimg.rrcontin is the byte
|
|
|
|
|
* offset of the beginning of that Cbuf.
|
|
|
|
|
*
|
|
|
|
|
* The blockette can be at most 255 bytes. The last 28
|
|
|
|
|
* will be (in the worst case) a CE record pointing at
|
|
|
|
|
* a new blockette. If we do write 255 bytes though,
|
|
|
|
|
* we'll try to pad it out to be even, and overflow.
|
|
|
|
|
* So the maximum is 254-28.
|
|
|
|
|
*
|
|
|
|
|
* Ceoffset contains the offset to be used with setcelen
|
|
|
|
|
* to patch the CE pointing at the Cbuf once we know how
|
|
|
|
|
* long the Cbuf is.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct Cbuf Cbuf;
|
|
|
|
|
struct Cbuf {
|
|
|
|
|
int len; /* written so far, of 254-28 */
|
|
|
|
|
ulong ceoffset;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
freespace(Cbuf *cp)
|
|
|
|
|
{
|
|
|
|
|
return (254-28) - cp->len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Cbuf*
|
|
|
|
|
ensurespace(Cdimg *cd, int n, Cbuf *co, Cbuf *cn, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
ulong end;
|
|
|
|
|
|
|
|
|
|
if(co->len+n <= 254-28) {
|
|
|
|
|
co->len += n;
|
|
|
|
|
return co;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
co->len += 28;
|
|
|
|
|
assert(co->len <= 254);
|
|
|
|
|
|
|
|
|
|
if(dowrite == 0) {
|
|
|
|
|
cn->len = n;
|
|
|
|
|
return cn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* the current blockette is full; update cd->rrcontin and then
|
|
|
|
|
* write a CE record to finish it. Unfortunately we need to
|
|
|
|
|
* figure out which block will be next before we write the CE.
|
|
|
|
|
*/
|
|
|
|
|
end = Cwoffset(cd)+28;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if we're in a continuation blockette, update rrcontin.
|
|
|
|
|
* also, write our length into the field of the CE record
|
|
|
|
|
* that points at us.
|
|
|
|
|
*/
|
|
|
|
|
if(cd->rrcontin+co->len == end) {
|
|
|
|
|
assert(cd->rrcontin != 0);
|
|
|
|
|
assert(co == cn);
|
|
|
|
|
cd->rrcontin += co->len;
|
|
|
|
|
setcelen(cd, co->ceoffset, co->len);
|
|
|
|
|
} else
|
|
|
|
|
assert(co != cn);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if the current continuation block can't fit another
|
|
|
|
|
* blockette, then start a new continuation block.
|
|
|
|
|
* rrcontin = 0 (mod Blocksize) means we just finished
|
|
|
|
|
* one, not that we've just started one.
|
|
|
|
|
*/
|
|
|
|
|
if(cd->rrcontin%Blocksize == 0
|
|
|
|
|
|| cd->rrcontin/Blocksize != (cd->rrcontin+256)/Blocksize) {
|
|
|
|
|
cd->rrcontin = cd->nextblock*Blocksize;
|
|
|
|
|
cd->nextblock++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cn->ceoffset = CputsuspCE(cd, cd->rrcontin);
|
|
|
|
|
|
|
|
|
|
assert(Cwoffset(cd) == end);
|
|
|
|
|
|
|
|
|
|
cn->len = n;
|
|
|
|
|
Cwseek(cd, cd->rrcontin);
|
|
|
|
|
assert(cd->rrcontin != 0);
|
|
|
|
|
|
|
|
|
|
return cn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put down the name, but we might need to break it
|
|
|
|
|
* into chunks so that each chunk fits in 254-28-5 bytes.
|
|
|
|
|
* What a crock.
|
|
|
|
|
*
|
|
|
|
|
* The new Plan 9 format uses strings of this form too,
|
|
|
|
|
* since they're already there.
|
|
|
|
|
*/
|
|
|
|
|
Cbuf*
|
|
|
|
|
Cputstring(Cdimg *cd, Cbuf *cp, Cbuf *cn, char *nm, char *p, int flags, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
char buf[256], *q;
|
|
|
|
|
int free;
|
|
|
|
|
|
|
|
|
|
for(; p[0] != '\0'; p = q) {
|
|
|
|
|
cp = ensurespace(cd, 5+1, cp, cn, dowrite);
|
|
|
|
|
cp->len -= 5+1;
|
|
|
|
|
free = freespace(cp);
|
|
|
|
|
assert(5+1 <= free && free < 256);
|
|
|
|
|
|
|
|
|
|
strncpy(buf, p, free-5);
|
|
|
|
|
buf[free-5] = '\0';
|
|
|
|
|
q = p+strlen(buf);
|
|
|
|
|
p = buf;
|
|
|
|
|
|
|
|
|
|
ensurespace(cd, 5+strlen(p), cp, nil, dowrite); /* nil: better not use this. */
|
|
|
|
|
Cputrripname(cd, nm, flags | (q[0] ? NMcontinue : 0), p, dowrite);
|
|
|
|
|
}
|
|
|
|
|
return cp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Write a Rock Ridge SUSP set of records for a directory entry.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
Cputsysuse(Cdimg *cd, Direc *d, int dot, int dowrite, int initlen)
|
|
|
|
|
{
|
|
|
|
|
char buf[256], buf0[256], *nextpath, *p, *path, *q;
|
|
|
|
|
int flags, free, m, what;
|
|
|
|
|
ulong o;
|
|
|
|
|
Cbuf cn, co, *cp;
|
|
|
|
|
|
|
|
|
|
assert(cd != nil);
|
|
|
|
|
assert((initlen&1) == 0);
|
|
|
|
|
|
|
|
|
|
if(dot == DTroot)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
co.len = initlen;
|
|
|
|
|
|
|
|
|
|
o = Cwoffset(cd);
|
|
|
|
|
|
|
|
|
|
assert(dowrite==0 || Cwoffset(cd) == o+co.len-initlen);
|
|
|
|
|
cp = &co;
|
|
|
|
|
|
|
|
|
|
if (dot == DTrootdot) {
|
|
|
|
|
m = CputsuspSP(cd, 0);
|
|
|
|
|
cp = ensurespace(cd, m, cp, &cn, dowrite);
|
|
|
|
|
CputsuspSP(cd, dowrite);
|
|
|
|
|
|
|
|
|
|
m = CputsuspER(cd, 0);
|
|
|
|
|
cp = ensurespace(cd, m, cp, &cn, dowrite);
|
|
|
|
|
CputsuspER(cd, dowrite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* In a perfect world, we'd be able to omit the NM
|
|
|
|
|
* entries when our name was all lowercase and conformant,
|
|
|
|
|
* but OpenBSD insists on uppercasing (really, not lowercasing)
|
|
|
|
|
* the ISO9660 names.
|
|
|
|
|
*/
|
|
|
|
|
what = RR_PX | RR_TF | RR_NM;
|
|
|
|
|
if(d != nil && (d->mode & CHLINK))
|
|
|
|
|
what |= RR_SL;
|
|
|
|
|
|
|
|
|
|
m = CputsuspRR(cd, what, 0);
|
|
|
|
|
cp = ensurespace(cd, m, cp, &cn, dowrite);
|
|
|
|
|
CputsuspRR(cd, what, dowrite);
|
|
|
|
|
|
|
|
|
|
if(what & RR_PX) {
|
|
|
|
|
m = CputrripPX(cd, d, dot, 0);
|
|
|
|
|
cp = ensurespace(cd, m, cp, &cn, dowrite);
|
|
|
|
|
CputrripPX(cd, d, dot, dowrite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(what & RR_NM) {
|
|
|
|
|
if(dot == DTiden)
|
|
|
|
|
p = d->name;
|
|
|
|
|
else if(dot == DTdotdot)
|
|
|
|
|
p = "..";
|
|
|
|
|
else
|
|
|
|
|
p = ".";
|
|
|
|
|
|
|
|
|
|
flags = suspdirflags(d, dot);
|
|
|
|
|
assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
|
|
|
|
|
cp = Cputstring(cd, cp, &cn, "NM", p, flags, dowrite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put down the symbolic link. This is even more of a crock.
|
|
|
|
|
* Not only are the individual elements potentially split,
|
|
|
|
|
* but the whole path itself can be split across SL blocks.
|
|
|
|
|
* To keep the code simple as possible (really), we write
|
|
|
|
|
* only one element per SL block, wasting 6 bytes per element.
|
|
|
|
|
*/
|
|
|
|
|
if(what & RR_SL) {
|
|
|
|
|
for(path=d->symlink; path[0] != '\0'; path=nextpath) {
|
|
|
|
|
/* break off one component */
|
|
|
|
|
if((nextpath = strchr(path, '/')) == nil)
|
|
|
|
|
nextpath = path+strlen(path);
|
|
|
|
|
strncpy(buf0, path, nextpath-path);
|
|
|
|
|
buf0[nextpath-path] = '\0';
|
|
|
|
|
if(nextpath[0] == '/')
|
|
|
|
|
nextpath++;
|
|
|
|
|
p = buf0;
|
|
|
|
|
|
|
|
|
|
/* write the name, perhaps broken into pieces */
|
|
|
|
|
if(strcmp(p, "") == 0)
|
|
|
|
|
flags = NMroot;
|
|
|
|
|
else if(strcmp(p, ".") == 0)
|
|
|
|
|
flags = NMcurrent;
|
|
|
|
|
else if(strcmp(p, "..") == 0)
|
|
|
|
|
flags = NMparent;
|
|
|
|
|
else
|
|
|
|
|
flags = 0;
|
|
|
|
|
|
|
|
|
|
/* the do-while handles the empty string properly */
|
|
|
|
|
do {
|
|
|
|
|
/* must have room for at least 1 byte of name */
|
|
|
|
|
cp = ensurespace(cd, 7+1, cp, &cn, dowrite);
|
|
|
|
|
cp->len -= 7+1;
|
|
|
|
|
free = freespace(cp);
|
|
|
|
|
assert(7+1 <= free && free < 256);
|
|
|
|
|
|
|
|
|
|
strncpy(buf, p, free-7);
|
|
|
|
|
buf[free-7] = '\0';
|
|
|
|
|
q = p+strlen(buf);
|
|
|
|
|
p = buf;
|
|
|
|
|
|
|
|
|
|
/* nil: better not need to expand */
|
|
|
|
|
assert(7+strlen(p) <= free);
|
|
|
|
|
ensurespace(cd, 7+strlen(p), cp, nil, dowrite);
|
|
|
|
|
CputrripSL(cd, nextpath[0], flags | (q[0] ? NMcontinue : 0), p, dowrite);
|
|
|
|
|
p = q;
|
|
|
|
|
} while(p[0] != '\0');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
|
|
|
|
|
|
|
|
|
|
if(what & RR_TF) {
|
|
|
|
|
m = CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, 0);
|
|
|
|
|
cp = ensurespace(cd, m, cp, &cn, dowrite);
|
|
|
|
|
CputrripTF(cd, d, TFcreation|TFmodify|TFaccess|TFattributes, dowrite);
|
|
|
|
|
}
|
|
|
|
|
assert(dowrite==0 || cp != &co || Cwoffset(cd) == o+co.len-initlen);
|
|
|
|
|
|
|
|
|
|
if(cp == &cn && dowrite) {
|
|
|
|
|
/* seek out of continuation, but mark our place */
|
|
|
|
|
cd->rrcontin = Cwoffset(cd);
|
|
|
|
|
setcelen(cd, cn.ceoffset, cn.len);
|
|
|
|
|
Cwseek(cd, o+co.len-initlen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(co.len & 1) {
|
|
|
|
|
co.len++;
|
|
|
|
|
if(dowrite)
|
|
|
|
|
Cputc(cd, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
if(Cwoffset(cd) != o+co.len-initlen)
|
|
|
|
|
fprint(2, "offset %lud o+co.len-initlen %lud\n", Cwoffset(cd), o+co.len-initlen);
|
|
|
|
|
assert(Cwoffset(cd) == o+co.len-initlen);
|
|
|
|
|
} else
|
|
|
|
|
assert(Cwoffset(cd) == o);
|
|
|
|
|
|
|
|
|
|
assert(co.len <= 255);
|
|
|
|
|
return co.len - initlen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char SUSPrrip[10] = "RRIP_1991A";
|
|
|
|
|
static char SUSPdesc[84] = "RRIP <more garbage here>";
|
|
|
|
|
static char SUSPsrc[135] = "RRIP <more garbage here>";
|
|
|
|
|
|
|
|
|
|
static ulong
|
|
|
|
|
CputsuspCE(Cdimg *cd, ulong offset)
|
|
|
|
|
{
|
|
|
|
|
ulong o, x;
|
|
|
|
|
|
|
|
|
|
chat("writing SUSP CE record pointing to %ld, %ld\n", offset/Blocksize, offset%Blocksize);
|
|
|
|
|
o = Cwoffset(cd);
|
|
|
|
|
Cputc(cd, 'C');
|
|
|
|
|
Cputc(cd, 'E');
|
|
|
|
|
Cputc(cd, 28);
|
|
|
|
|
Cputc(cd, 1);
|
|
|
|
|
Cputn(cd, offset/Blocksize, 4);
|
|
|
|
|
Cputn(cd, offset%Blocksize, 4);
|
|
|
|
|
x = Cwoffset(cd);
|
|
|
|
|
Cputn(cd, 0, 4);
|
|
|
|
|
assert(Cwoffset(cd) == o+28);
|
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
CputsuspER(Cdimg *cd, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
assert(cd != nil);
|
|
|
|
|
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
chat("writing SUSP ER record\n");
|
|
|
|
|
Cputc(cd, 'E'); /* ER field marker */
|
|
|
|
|
Cputc(cd, 'R');
|
|
|
|
|
Cputc(cd, 26); /* Length */
|
|
|
|
|
Cputc(cd, 1); /* Version */
|
|
|
|
|
Cputc(cd, 10); /* LEN_ID */
|
|
|
|
|
Cputc(cd, 4); /* LEN_DESC */
|
|
|
|
|
Cputc(cd, 4); /* LEN_SRC */
|
|
|
|
|
Cputc(cd, 1); /* EXT_VER */
|
|
|
|
|
Cputs(cd, SUSPrrip, 10); /* EXT_ID */
|
|
|
|
|
Cputs(cd, SUSPdesc, 4); /* EXT_DESC */
|
|
|
|
|
Cputs(cd, SUSPsrc, 4); /* EXT_SRC */
|
|
|
|
|
}
|
|
|
|
|
return 8+10+4+4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
CputsuspRR(Cdimg *cd, int what, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
assert(cd != nil);
|
|
|
|
|
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
Cputc(cd, 'R'); /* RR field marker */
|
|
|
|
|
Cputc(cd, 'R');
|
|
|
|
|
Cputc(cd, 5); /* Length */
|
|
|
|
|
Cputc(cd, 1); /* Version number */
|
|
|
|
|
Cputc(cd, what); /* Flags */
|
|
|
|
|
}
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
CputsuspSP(Cdimg *cd, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
assert(cd!=0);
|
|
|
|
|
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
chat("writing SUSP SP record\n");
|
|
|
|
|
Cputc(cd, 'S'); /* SP field marker */
|
|
|
|
|
Cputc(cd, 'P');
|
|
|
|
|
Cputc(cd, 7); /* Length */
|
|
|
|
|
Cputc(cd, 1); /* Version */
|
|
|
|
|
Cputc(cd, 0xBE); /* Magic */
|
|
|
|
|
Cputc(cd, 0xEF);
|
|
|
|
|
Cputc(cd, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef NOTUSED
|
|
|
|
|
static int
|
|
|
|
|
CputsuspST(Cdimg *cd, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
assert(cd!=0);
|
|
|
|
|
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
Cputc(cd, 'S'); /* ST field marker */
|
|
|
|
|
Cputc(cd, 'T');
|
|
|
|
|
Cputc(cd, 4); /* Length */
|
|
|
|
|
Cputc(cd, 1); /* Version */
|
|
|
|
|
}
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static ulong
|
|
|
|
|
suspdirflags(Direc *d, int dot)
|
|
|
|
|
{
|
|
|
|
|
uchar flags;
|
|
|
|
|
|
|
|
|
|
USED(d);
|
|
|
|
|
flags = 0;
|
|
|
|
|
switch(dot) {
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
case DTdot:
|
|
|
|
|
case DTrootdot:
|
|
|
|
|
flags |= NMcurrent;
|
|
|
|
|
break;
|
|
|
|
|
case DTdotdot:
|
|
|
|
|
flags |= NMparent;
|
|
|
|
|
break;
|
|
|
|
|
case DTroot:
|
|
|
|
|
flags |= NMvolroot;
|
|
|
|
|
break;
|
|
|
|
|
case DTiden:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
Cputrripname(Cdimg *cd, char *nm, int flags, char *name, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
int l;
|
|
|
|
|
|
|
|
|
|
l = strlen(name);
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
Cputc(cd, nm[0]); /* NM field marker */
|
|
|
|
|
Cputc(cd, nm[1]);
|
|
|
|
|
Cputc(cd, l+5); /* Length */
|
|
|
|
|
Cputc(cd, 1); /* Version */
|
|
|
|
|
Cputc(cd, flags); /* Flags */
|
|
|
|
|
Cputs(cd, name, l); /* Alternate name */
|
|
|
|
|
}
|
|
|
|
|
return 5+l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
CputrripSL(Cdimg *cd, int contin, int flags, char *name, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
int l;
|
|
|
|
|
|
|
|
|
|
l = strlen(name);
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
Cputc(cd, 'S');
|
|
|
|
|
Cputc(cd, 'L');
|
|
|
|
|
Cputc(cd, l+7);
|
|
|
|
|
Cputc(cd, 1);
|
|
|
|
|
Cputc(cd, contin ? 1 : 0);
|
|
|
|
|
Cputc(cd, flags);
|
|
|
|
|
Cputc(cd, l);
|
|
|
|
|
Cputs(cd, name, l);
|
|
|
|
|
}
|
|
|
|
|
return 7+l;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
CputrripPX(Cdimg *cd, Direc *d, int dot, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
assert(cd!=0);
|
|
|
|
|
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
Cputc(cd, 'P'); /* PX field marker */
|
|
|
|
|
Cputc(cd, 'X');
|
|
|
|
|
Cputc(cd, 36); /* Length */
|
|
|
|
|
Cputc(cd, 1); /* Version */
|
|
|
|
|
|
|
|
|
|
Cputn(cd, mode(d, dot), 4); /* POSIX File mode */
|
|
|
|
|
Cputn(cd, nlink(d), 4); /* POSIX st_nlink */
|
|
|
|
|
Cputn(cd, d?d->uidno:0, 4); /* POSIX st_uid */
|
|
|
|
|
Cputn(cd, d?d->gidno:0, 4); /* POSIX st_gid */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 36;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
CputrripTF(Cdimg *cd, Direc *d, int type, int dowrite)
|
|
|
|
|
{
|
|
|
|
|
int i, length;
|
|
|
|
|
|
|
|
|
|
assert(cd!=0);
|
|
|
|
|
assert(!(type & TFlongform));
|
|
|
|
|
|
|
|
|
|
length = 0;
|
|
|
|
|
for(i=0; i<7; i++)
|
|
|
|
|
if (type & (1<<i))
|
|
|
|
|
length++;
|
|
|
|
|
assert(length == 4);
|
|
|
|
|
|
|
|
|
|
if(dowrite) {
|
|
|
|
|
Cputc(cd, 'T'); /* TF field marker */
|
|
|
|
|
Cputc(cd, 'F');
|
|
|
|
|
Cputc(cd, 5+7*length); /* Length */
|
|
|
|
|
Cputc(cd, 1); /* Version */
|
|
|
|
|
Cputc(cd, type); /* Flags (types) */
|
|
|
|
|
|
|
|
|
|
if (type & TFcreation)
|
|
|
|
|
Cputdate(cd, d?d->ctime:0);
|
|
|
|
|
if (type & TFmodify)
|
|
|
|
|
Cputdate(cd, d?d->mtime:0);
|
|
|
|
|
if (type & TFaccess)
|
|
|
|
|
Cputdate(cd, d?d->atime:0);
|
|
|
|
|
if (type & TFattributes)
|
|
|
|
|
Cputdate(cd, d?d->ctime:0);
|
|
|
|
|
|
2006-04-01 19:24:03 +00:00
|
|
|
/* if (type & TFbackup) */
|
|
|
|
|
/* Cputdate(cd, 0); */
|
|
|
|
|
/* if (type & TFexpiration) */
|
|
|
|
|
/* Cputdate(cd, 0); */
|
|
|
|
|
/* if (type & TFeffective) */
|
|
|
|
|
/* Cputdate(cd, 0); */
|
2004-06-17 01:47:21 +00:00
|
|
|
}
|
|
|
|
|
return 5+7*length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define NONPXMODES (DMDIR & DMAPPEND & DMEXCL & DMMOUNT)
|
|
|
|
|
#define POSIXMODEMASK (0177777)
|
|
|
|
|
#ifndef S_IFMT
|
|
|
|
|
#define S_IFMT (0170000)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_IFDIR
|
|
|
|
|
#define S_IFDIR (0040000)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_IFREG
|
|
|
|
|
#define S_IFREG (0100000)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_IFLNK
|
|
|
|
|
#define S_IFLNK (0120000)
|
|
|
|
|
#endif
|
|
|
|
|
#undef ISTYPE
|
|
|
|
|
#define ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
|
|
|
|
|
#ifndef S_ISDIR
|
|
|
|
|
#define S_ISDIR(mode) ISTYPE(mode, S_IFDIR)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_ISREG
|
|
|
|
|
#define S_ISREG(mode) ISTYPE(mode, S_IREG)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_ISLNK
|
|
|
|
|
#define S_ISLNK(mode) ISTYPE(mode, S_ILNK)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
|
mode(Direc *d, int dot)
|
|
|
|
|
{
|
|
|
|
|
long mode;
|
|
|
|
|
|
|
|
|
|
if (!d)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if ((dot != DTroot) && (dot != DTrootdot)) {
|
|
|
|
|
mode = (d->mode & ~(NONPXMODES));
|
|
|
|
|
if (d->mode & DMDIR)
|
|
|
|
|
mode |= S_IFDIR;
|
|
|
|
|
else if (d->mode & CHLINK)
|
|
|
|
|
mode |= S_IFLNK;
|
|
|
|
|
else
|
|
|
|
|
mode |= S_IFREG;
|
|
|
|
|
} else
|
|
|
|
|
mode = S_IFDIR | (0755);
|
|
|
|
|
|
|
|
|
|
mode &= POSIXMODEMASK;
|
|
|
|
|
|
|
|
|
|
/* Botch: not all POSIX types supported yet */
|
|
|
|
|
assert(mode & (S_IFDIR|S_IFREG));
|
|
|
|
|
|
|
|
|
|
chat("writing PX record mode field %ulo with dot %d and name \"%s\"\n", mode, dot, d->name);
|
|
|
|
|
|
|
|
|
|
return mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
|
nlink(Direc *d) /* Trump up the nlink field for POSIX compliance */
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
long n;
|
|
|
|
|
|
|
|
|
|
if (!d)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
n = 1;
|
|
|
|
|
if (d->mode & DMDIR) /* One for "." and one more for ".." */
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
|
|
for(i=0; i<d->nchild; i++)
|
|
|
|
|
if (d->child[i].mode & DMDIR)
|
|
|
|
|
n++;
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|