📄 sysuse.c
字号:
/* * 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);//static int CputsuspST(Cdimg*, int);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 voidsetcelen(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 intfreespace(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. */intCputsysuse(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 ulongCputsuspCE(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 intCputsuspER(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 intCputsuspRR(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 intCputsuspSP(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 NOTUSEDstatic intCputsuspST(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;}#endifstatic ulongsuspdirflags(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 intCputrripname(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 intCputrripSL(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 intCputrripPX(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 intCputrripTF(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); // if (type & TFbackup) // Cputdate(cd, 0); // if (type & TFexpiration) // Cputdate(cd, 0); // if (type & TFeffective) // Cputdate(cd, 0); } 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)#endifstatic longmode(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 longnlink(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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -