/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* @(#)rock.c 1.43 05/05/01 joerg */ /* * File rock.c - generate RRIP records for iso9660 filesystems. * * Written by Eric Youngdale (1993). * * Copyright 1993 Yggdrasil Computing, Incorporated * Copyright (c) 1999,2000-2003 J. Schilling * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "genisoimage.h" #include #include #define SU_VERSION 1 #define SL_ROOT 8 #define SL_PARENT 4 #define SL_CURRENT 2 #define SL_CONTINUE 1 #define CE_SIZE 28 /* SUSP Continuation aerea */ #define CL_SIZE 12 /* RR Child Link for deep dir relocation */ #define ER_SIZE 8 /* RR Extension record for RR signature */ #define NM_SIZE 5 /* RR Real name */ #define PL_SIZE 12 /* RR Paren Link for deep dir relocation */ #define PN_SIZE 20 /* RR POSIX device modes (Major/Minor) */ #define PX_SIZE 36 /* RR POSIX Extensions (mode/nlink(uid/gid) */ #define RE_SIZE 4 /* RR Relocated directory */ #define RR_SIZE 5 /* RR RR Signature in every file */ #define SL_SIZE 20 /* RR Symlink */ #define ZF_SIZE 16 /* RR* Linux compression extension */ #ifdef APPLE_HYB #define AA_SIZE 14 /* size of Apple extension */ #endif /* APPLE_HYB */ #if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */ #define TF_SIZE (5 + 4 * 7) /* RR Time field */ #else #define TF_SIZE (5 + 3 * 7) #endif static void rstrncpy(char *t, char *f, int c, struct unls_table *inls, struct unls_table *onls); static void add_CE_entry(char *field, int line); static int gen_xa_attr(mode_t attr); static void gen_xa(struct stat *lstatbuf); int generate_xa_rr_attributes(char *whole_name, char *name, struct directory_entry *s_entry, struct stat *statbuf, struct stat *lstatbuf, int deep_opt); char *generate_rr_extension_record(char *id, char *descriptor, char *source, int *size); /* * If we need to store this number of bytes, make sure we * do not box ourselves in so that we do not have room for * a CE entry for the continuation record */ #define RR_CUR_USE (CE_SIZE + currlen + (ipnt - recstart)) #define MAYBE_ADD_CE_ENTRY(BYTES) \ (((int)(BYTES)) + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0) /* * Buffer to build RR attributes */ static Uchar Rock[16384]; static Uchar symlink_buff[PATH_MAX+1]; static int ipnt = 0; /* Current "write" offset in Rock[] */ static int recstart = 0; /* Start offset in Rock[] for this area */ static int currlen = 0; /* # of non RR bytes used in this area */ static int mainrec = 0; /* # of RR bytes use in main dir area */ static int reclimit; /* Max. # of bytes usable in this area */ /* if we are using converted filenames, we don't want the '/' character */ static void rstrncpy(char *t, char *f, int c, struct unls_table *inls, struct unls_table *onls) { while (c-- && *f) { *t = conv_charset(*f, inls, onls); if (*t == '/') { *t = '_'; } t++; f++; } } static void add_CE_entry(char *field, int line) { if (MAYBE_ADD_CE_ENTRY(0)) { errmsgno(EX_BAD, "Panic: no space, cannot add RR CE entry (%d bytes mising) for %s line %d.\n", (CE_SIZE + currlen + (ipnt - recstart) - reclimit), field, line); errmsgno(EX_BAD, "currlen: %d ipnt: %d, recstart: %d\n", currlen, ipnt, recstart); errmsgno(EX_BAD, "Send bug report to the maintainer.\n"); comerrno(EX_BAD, "Aborting.\n"); } if (recstart) set_733((char *) Rock + recstart - 8, ipnt + 28 - recstart); Rock[ipnt++] = 'C'; Rock[ipnt++] = 'E'; Rock[ipnt++] = CE_SIZE; Rock[ipnt++] = SU_VERSION; set_733((char *) Rock + ipnt, 0); ipnt += 8; set_733((char *) Rock + ipnt, 0); ipnt += 8; set_733((char *) Rock + ipnt, 0); ipnt += 8; recstart = ipnt; currlen = 0; if (!mainrec) mainrec = ipnt; reclimit = SECTOR_SIZE - 8; /* Limit to one sector */ } static int gen_xa_attr(mode_t attr) { int ret = 0; if (attr & S_IRUSR) ret |= XA_O_READ; if (attr & S_IXUSR) ret |= XA_O_EXEC; if (attr & S_IRGRP) ret |= XA_G_READ; if (attr & S_IXGRP) ret |= XA_G_EXEC; if (attr & S_IROTH) ret |= XA_W_READ; if (attr & S_IXOTH) ret |= XA_W_EXEC; ret |= XA_FORM1; if (S_ISDIR(attr)) ret |= XA_DIR; return (ret); } static void gen_xa(struct stat *lstatbuf) { /* * Group ID */ set_722((char *) Rock + ipnt, lstatbuf->st_gid); ipnt += 2; /* * User ID */ set_722((char *) Rock + ipnt, lstatbuf->st_uid); ipnt += 2; /* * Attributes */ set_722((char *) Rock + ipnt, gen_xa_attr(lstatbuf->st_mode)); ipnt += 2; Rock[ipnt++] = 'X'; /* XA Signature */ Rock[ipnt++] = 'A'; Rock[ipnt++] = 0; /* File number (we always use '0' */ Rock[ipnt++] = 0; /* Reserved (5 Byte) */ Rock[ipnt++] = 0; Rock[ipnt++] = 0; Rock[ipnt++] = 0; Rock[ipnt++] = 0; } int generate_xa_rr_attributes(char *whole_name, char *name, struct directory_entry *s_entry, struct stat *statbuf, struct stat *lstatbuf, int deep_opt) { int flagpos; int flagval; int need_ce; statbuf = statbuf; /* this shuts up unreferenced compiler */ /* warnings */ mainrec = recstart = ipnt = 0; if (use_XA) { gen_xa(lstatbuf); } /* reclimit = 0xf8; XXX we now use 254 == 0xfe */ reclimit = MAX_ISODIR; /* no need to fill in the RR stuff if we won't see the file */ if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) return (0); /* * Obtain the amount of space that is currently used for the directory * record. We may safely use the current name length; because if name * confilcts force us to change the ISO-9660 name later, the name will * never become longer than now. */ if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { s_entry->isorec.name_len[0] = 1; } else { s_entry->isorec.name_len[0] = strlen(s_entry->isorec.name); } currlen = s_entry->isorec.length[0] = s_entry->isorec.name_len[0] + offsetof(struct iso_directory_record, name[0]); if (currlen & 1) s_entry->isorec.length[0] = ++currlen; if (currlen < 33+37) { /* * If the ISO-9660 name length is less than 37, we may use * ISO-9660:1988 name rules and for this reason, the name len * may later increase from adding e.g. ".;1"; in this case * just use the upper limit. */ currlen = 33+37; } #ifdef APPLE_HYB /* if we have regular file, then add Apple extensions */ if (S_ISREG(lstatbuf->st_mode) && apple_ext && s_entry->hfs_ent) { if (MAYBE_ADD_CE_ENTRY(AA_SIZE)) add_CE_entry("AA", __LINE__); Rock[ipnt++] = 'A'; /* AppleSignature */ Rock[ipnt++] = 'A'; Rock[ipnt++] = AA_SIZE; /* includes AppleSignature bytes */ Rock[ipnt++] = 0x02; /* SystemUseID */ Rock[ipnt++] = s_entry->hfs_ent->u.file.type[0]; Rock[ipnt++] = s_entry->hfs_ent->u.file.type[1]; Rock[ipnt++] = s_entry->hfs_ent->u.file.type[2]; Rock[ipnt++] = s_entry->hfs_ent->u.file.type[3]; Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[0]; Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[1]; Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[2]; Rock[ipnt++] = s_entry->hfs_ent->u.file.creator[3]; Rock[ipnt++] = (s_entry->hfs_ent->fdflags >> 8) & 0xff; Rock[ipnt++] = s_entry->hfs_ent->fdflags & 0xff; } #endif /* APPLE_HYB */ if (!use_RockRidge) goto xa_only; /* Identify that we are using the SUSP protocol */ if (deep_opt & NEED_SP) { /* * We may not use a CE record here but we never will need to * do so, as this SP record is only used for the "." entry * of the root directory. */ Rock[ipnt++] = 'S'; Rock[ipnt++] = 'P'; Rock[ipnt++] = 7; Rock[ipnt++] = SU_VERSION; Rock[ipnt++] = 0xbe; Rock[ipnt++] = 0xef; if (use_XA) Rock[ipnt++] = sizeof (struct iso_xa_dir_record); else Rock[ipnt++] = 0; } /* First build the posix name field */ if (MAYBE_ADD_CE_ENTRY(RR_SIZE)) add_CE_entry("RR", __LINE__); Rock[ipnt++] = 'R'; Rock[ipnt++] = 'R'; Rock[ipnt++] = 5; Rock[ipnt++] = SU_VERSION; flagpos = ipnt; flagval = 0; Rock[ipnt++] = 0; /* We go back and fix this later */ if (strcmp(name, ".") && strcmp(name, "..")) { char *npnt; int remain; /* Remaining name length */ int use; /* Current name part used */ #ifdef APPLE_HYB /* use the HFS name if it exists */ if (USE_MAC_NAME(s_entry)) { remain = strlen(s_entry->hfs_ent->name); npnt = s_entry->hfs_ent->name; } else { #endif /* APPLE_HYB */ remain = strlen(name); npnt = name; #ifdef APPLE_HYB } #endif /* APPLE_HYB */ if (MAYBE_ADD_CE_ENTRY(NM_SIZE+1)) add_CE_entry("NM", __LINE__); while (remain) { use = remain; need_ce = 0; /* Can we fit this SUSP and a CE entry? */ if (MAYBE_ADD_CE_ENTRY(NM_SIZE+use)) { use = reclimit - NM_SIZE - RR_CUR_USE; need_ce++; } /* Only room for 256 per SUSP field */ if (use > 0xf8) { use = 0xf8; need_ce++; } if (use < 0) { comerrno(EX_BAD, "Negative RR name length residual: %d\n", use); } /* First build the posix name field */ Rock[ipnt++] = 'N'; Rock[ipnt++] = 'M'; Rock[ipnt++] = NM_SIZE + use; Rock[ipnt++] = SU_VERSION; Rock[ipnt++] = (remain != use ? 1 : 0); flagval |= (1 << 3); /* convert charsets as required */ #ifdef APPLE_HYB if (USE_MAC_NAME(s_entry)) rstrncpy((char *) &Rock[ipnt], npnt, use, hfs_inls, out_nls); else #endif /* APPLE_HYB */ rstrncpy((char *) &Rock[ipnt], npnt, use, in_nls, out_nls); npnt += use; ipnt += use; remain -= use; if (remain && need_ce) add_CE_entry("NM", __LINE__); } } /* Add the posix modes */ if (MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry("PX", __LINE__); Rock[ipnt++] = 'P'; Rock[ipnt++] = 'X'; Rock[ipnt++] = PX_SIZE; Rock[ipnt++] = SU_VERSION; flagval |= (1 << 0); set_733((char *) Rock + ipnt, lstatbuf->st_mode); ipnt += 8; set_733((char *) Rock + ipnt, lstatbuf->st_nlink); ipnt += 8; set_733((char *) Rock + ipnt, lstatbuf->st_uid); ipnt += 8; set_733((char *) Rock + ipnt, lstatbuf->st_gid); ipnt += 8; /* Check for special devices */ #if defined(S_IFCHR) || defined(S_IFBLK) /* * The code in this if statement used to be #ifdef'd with NON_UNIXFS. * But as statdefs.h always provides the macros S_ISCHR() & S_ISBLK() * and device.h always provides major()/minor() it is not needed * anymore. */ if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) { if (MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry("PN", __LINE__); Rock[ipnt++] = 'P'; Rock[ipnt++] = 'N'; Rock[ipnt++] = PN_SIZE; Rock[ipnt++] = SU_VERSION; flagval |= (1 << 1); #if 1 /* This is the new and only code which uses */ set_733((char *) Rock + ipnt, major(lstatbuf->st_rdev)); ipnt += 8; set_733((char *) Rock + ipnt, minor(lstatbuf->st_rdev)); ipnt += 8; #else /* * If we don't have sysmacros.h, then we have to guess as to * how best to pick apart the device number for major/minor. * Note: this may very well be wrong for many systems, so it * is always best to use the major/minor macros if the system * supports it. */ if (sizeof (dev_t) <= 2) { set_733((char *)Rock + ipnt, (lstatbuf->st_rdev >> 8)); ipnt += 8; set_733((char *)Rock + ipnt, lstatbuf->st_rdev & 0xff); ipnt += 8; } else if (sizeof (dev_t) <= 4) { set_733((char *)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8); ipnt += 8; set_733((char *)Rock + ipnt, lstatbuf->st_rdev & 0xffff); ipnt += 8; } else { set_733((char *)Rock + ipnt, (lstatbuf->st_rdev >> 16)>>16); ipnt += 8; set_733((char *)Rock + ipnt, lstatbuf->st_rdev); ipnt += 8; } #endif } #endif /* defined(S_IFCHR) || defined(S_IFBLK) */ /* Check for and symbolic links. VMS does not have these. */ #ifdef S_IFLNK if (S_ISLNK(lstatbuf->st_mode)) { int lenpos; int lenval; int j0; int j1; int nchar; Uchar *cpnt; Uchar *cpnt1; #ifdef HAVE_READLINK nchar = readlink(whole_name, (char *)symlink_buff, sizeof (symlink_buff)-1); #else nchar = -1; #endif /* HAVE_READLINK */ symlink_buff[nchar < 0 ? 0 : nchar] = 0; nchar = strlen((char *) symlink_buff); set_733(s_entry->isorec.size, 0); cpnt = &symlink_buff[0]; flagval |= (1 << 2); if (!split_SL_field) { int sl_bytes = 0; for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) { if (*cpnt1 == '/') { sl_bytes += 4; } else { sl_bytes += 1; } } if (sl_bytes > 250) { /* * the symbolic link won't fit into one * SL System Use Field print an error message * and continue with splited one */ fprintf(stderr, "symbolic link ``%s'' to long for one SL System Use Field, splitting", cpnt); } if (MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry("SL+", __LINE__); } while (nchar) { if (MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry("SL", __LINE__); Rock[ipnt++] = 'S'; Rock[ipnt++] = 'L'; lenpos = ipnt; Rock[ipnt++] = SL_SIZE; Rock[ipnt++] = SU_VERSION; Rock[ipnt++] = 0; /* Flags */ lenval = 5; while (*cpnt) { cpnt1 = (Uchar *) strchr((char *)cpnt, '/'); if (cpnt1) { nchar--; *cpnt1 = 0; } /* * We treat certain components in a special * way. */ if (cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0) { if (MAYBE_ADD_CE_ENTRY(2)) { add_CE_entry("SL-parent", __LINE__); if (cpnt1) { *cpnt1 = '/'; nchar++; /* * A kluge so that we * can restart properly */ cpnt1 = NULL; } break; } Rock[ipnt++] = SL_PARENT; Rock[ipnt++] = 0; /* length is zero */ lenval += 2; nchar -= 2; } else if (cpnt[0] == '.' && cpnt[1] == 0) { if (MAYBE_ADD_CE_ENTRY(2)) { add_CE_entry("SL-current", __LINE__); if (cpnt1) { *cpnt1 = '/'; nchar++; /* * A kluge so that we * can restart properly */ cpnt1 = NULL; } break; } Rock[ipnt++] = SL_CURRENT; Rock[ipnt++] = 0; /* length is zero */ lenval += 2; nchar -= 1; } else if (cpnt[0] == 0) { if (MAYBE_ADD_CE_ENTRY(2)) { add_CE_entry("SL-root", __LINE__); if (cpnt1) { *cpnt1 = '/'; nchar++; /* * A kluge so that we * can restart properly */ cpnt1 = NULL; } break; } Rock[ipnt++] = SL_ROOT; Rock[ipnt++] = 0; /* length is zero */ lenval += 2; } else { /* * If we do not have enough room for a * component, start a new continuations * segment now */ if (split_SL_component ? MAYBE_ADD_CE_ENTRY(6) : MAYBE_ADD_CE_ENTRY(6 + strlen((char *) cpnt))) { add_CE_entry("SL++", __LINE__); if (cpnt1) { *cpnt1 = '/'; nchar++; /* * A kluge so that we * can restart properly */ cpnt1 = NULL; } break; } j0 = strlen((char *) cpnt); while (j0) { j1 = j0; if (j1 > 0xf8) j1 = 0xf8; need_ce = 0; if (j1 + currlen + 2 + CE_SIZE + (ipnt - recstart) > reclimit) { j1 = reclimit - (currlen + 2) - CE_SIZE - (ipnt - recstart); need_ce++; } Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0); Rock[ipnt++] = j1; strncpy((char *)Rock + ipnt, (char *) cpnt, j1); ipnt += j1; lenval += j1 + 2; cpnt += j1; /* * Number we processed * this time */ nchar -= j1; j0 -= j1; if (need_ce) { add_CE_entry( "SL-path-split", __LINE__); if (cpnt1) { *cpnt1 = '/'; nchar++; /* * A kluge so * that we can * restart * properly */ cpnt1 = NULL; } break; } } } if (cpnt1) { cpnt = cpnt1 + 1; } else break; } Rock[lenpos] = lenval; if (nchar) { /* We need another SL entry */ Rock[lenpos + 2] = SL_CONTINUE; } } /* while nchar */ } /* Is a symbolic link */ #endif /* S_IFLNK */ /* Add in the Rock Ridge TF time field */ if (MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry("TF", __LINE__); Rock[ipnt++] = 'T'; Rock[ipnt++] = 'F'; Rock[ipnt++] = TF_SIZE; Rock[ipnt++] = SU_VERSION; #if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */ Rock[ipnt++] = 0x0f; #else Rock[ipnt++] = 0x0e; #endif flagval |= (1 << 7); #if defined(__QNX__) && !defined(__QNXNTO__) /* Not on Neutrino! never OK? */ iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime); ipnt += 7; #endif iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime); ipnt += 7; iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime); ipnt += 7; iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime); ipnt += 7; /* Add in the Rock Ridge RE (relocated dir) field */ if (deep_opt & NEED_RE) { if (MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry("RE", __LINE__); Rock[ipnt++] = 'R'; Rock[ipnt++] = 'E'; Rock[ipnt++] = RE_SIZE; Rock[ipnt++] = SU_VERSION; flagval |= (1 << 6); } /* Add in the Rock Ridge PL record, if required. */ if (deep_opt & NEED_PL) { if (MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry("PL", __LINE__); Rock[ipnt++] = 'P'; Rock[ipnt++] = 'L'; Rock[ipnt++] = PL_SIZE; Rock[ipnt++] = SU_VERSION; set_733((char *) Rock + ipnt, 0); ipnt += 8; flagval |= (1 << 5); } /* Add in the Rock Ridge CL field, if required. */ if (deep_opt & NEED_CL) { if (MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry("CL", __LINE__); Rock[ipnt++] = 'C'; Rock[ipnt++] = 'L'; Rock[ipnt++] = CL_SIZE; Rock[ipnt++] = SU_VERSION; set_733((char *) Rock + ipnt, 0); ipnt += 8; flagval |= (1 << 4); } #ifndef VMS /* * If transparent compression was requested, fill in the correct field * for this file, if (and only if) it is actually a compressed file! * This relies only on magic number, but it should in general not * be an issue since if you're using -z odds are most of your * files are already compressed. * * In the future it would be nice if genisoimage actually did the * compression. */ if (transparent_compression && S_ISREG(lstatbuf->st_mode)) { static const Uchar zisofs_magic[8] = { 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07 }; FILE *zffile; unsigned int file_size; Uchar header[16]; int OK_flag; int blocksize; int headersize; /* * First open file and verify that the correct algorithm was * used */ file_size = 0; OK_flag = 1; memset(header, 0, sizeof (header)); zffile = fopen(whole_name, "rb"); if (zffile != NULL) { if (fread(header, 1, sizeof (header), zffile) != sizeof (header)) OK_flag = 0; /* Check magic number */ if (memcmp(header, zisofs_magic, sizeof (zisofs_magic))) OK_flag = 0; /* Get the real size of the file */ file_size = get_731((char *)header+8); /* Get the header size (>> 2) */ headersize = header[12]; /* Get the block size (log2) */ blocksize = header[13]; fclose(zffile); } else { OK_flag = 0; blocksize = headersize = 0; /* Make silly GCC quiet */ } if (OK_flag) { if (MAYBE_ADD_CE_ENTRY(ZF_SIZE)) add_CE_entry("ZF", __LINE__); Rock[ipnt++] = 'Z'; Rock[ipnt++] = 'F'; Rock[ipnt++] = ZF_SIZE; Rock[ipnt++] = SU_VERSION; Rock[ipnt++] = 'p'; /* Algorithm: "paged zlib" */ Rock[ipnt++] = 'z'; /* 2 bytes for algorithm-specific information */ Rock[ipnt++] = headersize; Rock[ipnt++] = blocksize; set_733((char *) Rock + ipnt, file_size); /* Real file size */ ipnt += 8; } } #endif /* * Add in the Rock Ridge CE field, if required. We use this for the * extension record that is stored in the root directory. */ if (deep_opt & NEED_CE) add_CE_entry("ER", __LINE__); /* * Done filling in all of the fields. Now copy it back to a buffer * for the file in question. */ /* Now copy this back to the buffer for the file */ Rock[flagpos] = flagval; /* If there was a CE, fill in the size field */ if (recstart) set_733((char *) Rock + recstart - 8, ipnt - recstart); xa_only: s_entry->rr_attributes = (Uchar *) e_malloc(ipnt); s_entry->total_rr_attr_size = ipnt; s_entry->rr_attr_size = (mainrec ? mainrec : ipnt); memcpy(s_entry->rr_attributes, Rock, ipnt); return (ipnt); } /* * Guaranteed to return a single sector with the relevant info */ char * generate_rr_extension_record(char *id, char *descriptor, char *source, int *size) { int lipnt = 0; char *pnt; int len_id; int len_des; int len_src; len_id = strlen(id); len_des = strlen(descriptor); len_src = strlen(source); Rock[lipnt++] = 'E'; Rock[lipnt++] = 'R'; Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src; Rock[lipnt++] = 1; Rock[lipnt++] = len_id; Rock[lipnt++] = len_des; Rock[lipnt++] = len_src; Rock[lipnt++] = 1; memcpy(Rock + lipnt, id, len_id); lipnt += len_id; memcpy(Rock + lipnt, descriptor, len_des); lipnt += len_des; memcpy(Rock + lipnt, source, len_src); lipnt += len_src; if (lipnt > SECTOR_SIZE) { #ifdef USE_LIBSCHILY comerrno(EX_BAD, "Extension record too long\n"); #else fprintf(stderr, "Extension record too long\n"); exit(1); #endif } pnt = (char *) e_malloc(SECTOR_SIZE); memset(pnt, 0, SECTOR_SIZE); memcpy(pnt, Rock, lipnt); *size = lipnt; return (pnt); }