xref: /openbsd/gnu/usr.sbin/mkhybrid/src/rock.c (revision 68cbdb5e)
1 /*
2  * File rock.c - generate RRIP  records for iso9660 filesystems.
3 
4    Written by Eric Youngdale (1993).
5 
6    Copyright 1993 Yggdrasil Computing, Incorporated
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21 
22 #include <stdlib.h>
23 
24 #include "config.h"
25 
26 #ifndef VMS
27 #if defined(MAJOR_IN_SYSMACROS)
28 #include <sys/sysmacros.h>
29 #endif
30 
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 
35 #endif
36 #if defined(MAJOR_IN_MKDEV)
37 #include <sys/types.h>
38 #include <sys/mkdev.h>
39 #endif
40 
41 #include "mkisofs.h"
42 #include "iso9660.h"
43 #include <string.h>
44 
45 #ifdef	DOESNT_WORK
46 
47 #ifdef NON_UNIXFS
48 #define S_ISLNK(m)	(0)
49 #else
50 #ifndef S_ISLNK
51 #define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
52 #endif
53 #endif
54 
55 #else
56 #include <statdefs.h>
57 #endif
58 
59 #define SU_VERSION 1
60 
61 #define SL_ROOT    8
62 #define SL_PARENT  4
63 #define SL_CURRENT 2
64 #define SL_CONTINUE 1
65 
66 #define CE_SIZE 28
67 #define CL_SIZE 12
68 #define ER_SIZE 8
69 #define NM_SIZE 5
70 #define PL_SIZE 12
71 #define PN_SIZE 20
72 #define PX_SIZE 36
73 #define RE_SIZE 4
74 #define SL_SIZE 20
75 #define ZZ_SIZE 15
76 #ifdef APPLE_HYB
77 #define AA_SIZE 14		/* size of Apple extension */
78 #endif /* APPLE_HYB */
79 #ifdef __QNX__
80 #define TF_SIZE (5 + 4 * 7)
81 #else
82 #define TF_SIZE (5 + 3 * 7)
83 #endif
84 
85 /* If we need to store this number of bytes, make sure we
86    do not box ourselves in so that we do not have room for
87    a CE entry for the continuation record */
88 
89 #define MAYBE_ADD_CE_ENTRY(BYTES) \
90     (BYTES + CE_SIZE + currlen + (ipnt - recstart) > reclimit ? 1 : 0)
91 
92 /*
93  * Buffer to build RR attributes
94  */
95 
96 static unsigned char Rock[16384];
97 static unsigned char symlink_buff[256];
98 static int ipnt = 0;
99 static int recstart = 0;
100 static int currlen = 0;
101 static int mainrec = 0;
102 static int reclimit;
103 
104 #ifdef APPLE_HYB
105 /* if we are using the HFS name, we don't want the '/' character */
106 static void
rstrncpy(char * t,char * f,int c)107 rstrncpy(char *t, char *f, int c)
108 {
109 	while (c-- && *f) {
110 	    switch (*f) {
111 		case '/':
112 		    *t = '_';
113 		    break;
114 		default:
115 		    *t = *f;
116 		    break;
117 	    }
118 	    t++; f++;
119 	}
120 }
121 #endif /* APPLE HYB */
122 
123 static void add_CE_entry	__PR((void));
124 
add_CE_entry()125 static void add_CE_entry(){
126           if(recstart)
127 	    set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart);
128 	  Rock[ipnt++] ='C';
129 	  Rock[ipnt++] ='E';
130 	  Rock[ipnt++] = CE_SIZE;
131 	  Rock[ipnt++] = SU_VERSION;
132 	  set_733((char*)Rock + ipnt, 0);
133 	  ipnt += 8;
134 	  set_733((char*)Rock + ipnt, 0);
135 	  ipnt += 8;
136 	  set_733((char*)Rock + ipnt, 0);
137 	  ipnt += 8;
138 	  recstart = ipnt;
139 	  currlen = 0;
140 	  if(!mainrec) mainrec = ipnt;
141 	  reclimit = SECTOR_SIZE - 8; /* Limit to one sector */
142 }
143 
144 #ifdef __STDC__
generate_rock_ridge_attributes(char * whole_name,char * name,struct directory_entry * s_entry,struct stat * statbuf,struct stat * lstatbuf,int deep_opt)145 int generate_rock_ridge_attributes (char * whole_name, char * name,
146 				    struct directory_entry * s_entry,
147 				    struct stat * statbuf,
148 				    struct stat * lstatbuf,
149 				    int deep_opt)
150 #else
151 int generate_rock_ridge_attributes (whole_name, name,
152 				    s_entry,
153 				    statbuf,
154 				    lstatbuf,
155 				    deep_opt)
156 char * whole_name; char * name; struct directory_entry * s_entry;
157 struct stat * statbuf, *lstatbuf;
158 int deep_opt;
159 #endif
160 {
161   int flagpos, flagval;
162   int need_ce;
163 
164   statbuf = statbuf;        /* this shuts up unreferenced compiler warnings */
165   mainrec = recstart = ipnt = 0;
166   reclimit = 0xf8;
167 
168   /* no need to fill in the RR stuff if we won't see the file */
169   if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY)
170     return 0;
171 
172   /* Obtain the amount of space that is currently used for the directory
173      record.  Assume max for name, since name conflicts may cause us
174      to rename the file later on */
175   currlen = sizeof(s_entry->isorec);
176 
177 #ifdef APPLE_HYB
178   /* if we have regular file, then add Apple extensions */
179   if (S_ISREG(lstatbuf->st_mode) && apple_ext && s_entry->hfs_ent) {
180     Rock[ipnt++] ='A';		/* AppleSignature */
181     Rock[ipnt++] ='A';
182     Rock[ipnt++] = AA_SIZE;	/* includes AppleSignature bytes */
183     Rock[ipnt++] = 0x02;	/* SystemUseID */
184     Rock[ipnt++] = s_entry->hfs_ent->type[0];
185     Rock[ipnt++] = s_entry->hfs_ent->type[1];
186     Rock[ipnt++] = s_entry->hfs_ent->type[2];
187     Rock[ipnt++] = s_entry->hfs_ent->type[3];
188     Rock[ipnt++] = s_entry->hfs_ent->creator[0];
189     Rock[ipnt++] = s_entry->hfs_ent->creator[1];
190     Rock[ipnt++] = s_entry->hfs_ent->creator[2];
191     Rock[ipnt++] = s_entry->hfs_ent->creator[3];
192     Rock[ipnt++] = (s_entry->hfs_ent->fdflags >> 8) & 0xff;
193     Rock[ipnt++] = s_entry->hfs_ent->fdflags & 0xff;
194   }
195 #endif /* APPLE_HYB */
196 
197   /* Identify that we are using the SUSP protocol */
198   if(deep_opt & NEED_SP){
199 	  Rock[ipnt++] ='S';
200 	  Rock[ipnt++] ='P';
201 	  Rock[ipnt++] = 7;
202 	  Rock[ipnt++] = SU_VERSION;
203 	  Rock[ipnt++] = 0xbe;
204 	  Rock[ipnt++] = 0xef;
205 	  Rock[ipnt++] = 0;
206   };
207 
208   /* First build the posix name field */
209   Rock[ipnt++] ='R';
210   Rock[ipnt++] ='R';
211   Rock[ipnt++] = 5;
212   Rock[ipnt++] = SU_VERSION;
213   flagpos = ipnt;
214   flagval = 0;
215   Rock[ipnt++] = 0;   /* We go back and fix this later */
216 
217   if(strcmp(name,".")  && strcmp(name,"..")){
218     char * npnt;
219     int remain, use;
220 
221 #ifdef APPLE_HYB
222     /* use the HFS name if it exists */
223     if (USE_MAC_NAME(mac_name, s_entry)) {
224 	remain = strlen(s_entry->hfs_ent->name);
225 	npnt = s_entry->hfs_ent->name;
226     }
227     else {
228 #endif
229 
230 	remain = strlen(name);
231 	npnt = name;
232 #ifdef APPLE_HYB
233     }
234 #endif /* APPLE_HYB */
235 
236     while(remain){
237           use = remain;
238 	  need_ce = 0;
239 	  /* Can we fit this SUSP and a CE entry? */
240 	  if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
241 	    use = reclimit - currlen - CE_SIZE - (ipnt - recstart);
242 	    need_ce++;
243 	  }
244 
245 	  /* Only room for 256 per SUSP field */
246 	  if(use > 0xf8) use = 0xf8;
247 
248 	  /* First build the posix name field */
249 	  Rock[ipnt++] ='N';
250 	  Rock[ipnt++] ='M';
251 	  Rock[ipnt++] = NM_SIZE + use;
252 	  Rock[ipnt++] = SU_VERSION;
253 	  Rock[ipnt++] = (remain != use ? 1 : 0);
254 	  flagval |= (1<<3);
255 #ifdef APPLE_HYB
256 	  /* filter out any '/' character in HFS filename */
257 	  if (USE_MAC_NAME(mac_name, s_entry))
258 	    rstrncpy((char *)&Rock[ipnt], npnt, use);
259 	  else
260 #endif /* APPLE_HYB */
261 	    strncpy((char *)&Rock[ipnt], npnt, use);
262 	  npnt += use;
263 	  ipnt += use;
264 	  remain -= use;
265 	  if(remain && need_ce) add_CE_entry();
266 	};
267   };
268 
269   /*
270    * Add the posix modes
271    */
272   if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry();
273   Rock[ipnt++] ='P';
274   Rock[ipnt++] ='X';
275   Rock[ipnt++] = PX_SIZE;
276   Rock[ipnt++] = SU_VERSION;
277   flagval |= (1<<0);
278   set_733((char*)Rock + ipnt, lstatbuf->st_mode);
279   ipnt += 8;
280   set_733((char*)Rock + ipnt, lstatbuf->st_nlink);
281   ipnt += 8;
282   set_733((char*)Rock + ipnt, lstatbuf->st_uid);
283   ipnt += 8;
284   set_733((char*)Rock + ipnt, lstatbuf->st_gid);
285   ipnt += 8;
286 
287   /*
288    * Check for special devices
289    */
290 #ifndef NON_UNIXFS
291   if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) {
292     if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry();
293     Rock[ipnt++] ='P';
294     Rock[ipnt++] ='N';
295     Rock[ipnt++] = PN_SIZE;
296     Rock[ipnt++] = SU_VERSION;
297     flagval |= (1<<1);
298 #if defined(MAJOR_IN_SYSMACROS) || defined(MAJOR_IN_MKDEV)
299     set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev ));
300     ipnt += 8;
301     set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev));
302     ipnt += 8;
303 #else
304     /*
305      * If we don't have sysmacros.h, then we have to guess as to how
306      * best to pick apart the device number for major/minor.
307      * Note: this may very well be wrong for many systems, so
308      * it is always best to use the major/minor macros if the
309      * system supports it.
310      */
311     if(sizeof(dev_t) <= 2) {
312         set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8));
313         ipnt += 8;
314         set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff);
315         ipnt += 8;
316     }
317     else if(sizeof(dev_t) <= 4) {
318         set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8);
319         ipnt += 8;
320         set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff);
321         ipnt += 8;
322     }
323     else {
324         set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16);
325         ipnt += 8;
326         set_733((char*)Rock + ipnt, lstatbuf->st_rdev);
327         ipnt += 8;
328     }
329 #endif
330   };
331 #endif
332   /*
333    * Check for and symbolic links.  VMS does not have these.
334    */
335   if (S_ISLNK(lstatbuf->st_mode)){
336     int lenpos, lenval, j0, j1;
337     int nchar;
338     unsigned char * cpnt, *cpnt1;
339     nchar = readlink(whole_name, (char *)symlink_buff, sizeof(symlink_buff)-1);
340     symlink_buff[nchar < 0 ? 0 : nchar] = 0;
341     nchar = strlen((char *) symlink_buff);
342     set_733(s_entry->isorec.size, 0);
343     cpnt = &symlink_buff[0];
344     flagval |= (1<<2);
345 
346     if (! split_SL_field)
347       {
348 	int sl_bytes = 0;
349 	for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++)
350 	  {
351 	    if (*cpnt1 == '/')
352 	      {
353 		sl_bytes += 4;
354 	      }
355 	    else
356 	      {
357 		sl_bytes += 1;
358 	      }
359 	  }
360 	if (sl_bytes > 250)
361 	  {
362 	    /*
363 	     * the symbolic link won't fit into one SL System Use Field
364 	     * print an error message and continue with splited one
365 	     */
366 	    fprintf(stderr,"symbolic link ``%s'' to long for one SL System Use Field, splitting", cpnt);
367 	  }
368        if(MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry();
369      }
370 
371     while(nchar){
372       if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry();
373       Rock[ipnt++] ='S';
374       Rock[ipnt++] ='L';
375       lenpos = ipnt;
376       Rock[ipnt++] = SL_SIZE;
377       Rock[ipnt++] = SU_VERSION;
378       Rock[ipnt++] = 0; /* Flags */
379       lenval = 5;
380       while(*cpnt){
381 	cpnt1 = (unsigned char *) strchr((char *) cpnt, '/');
382 	if(cpnt1) {
383 	  nchar--;
384 	  *cpnt1 = 0;
385 	};
386 
387 	/* We treat certain components in a special way.  */
388 	if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){
389 	  if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
390 	  Rock[ipnt++] = SL_PARENT;
391 	  Rock[ipnt++] = 0;  /* length is zero */
392 	  lenval += 2;
393 	  nchar -= 2;
394 	} else if(cpnt[0] == '.' && cpnt[1] == 0){
395 	  if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
396 	  Rock[ipnt++] = SL_CURRENT;
397 	  Rock[ipnt++] = 0;  /* length is zero */
398 	  lenval += 2;
399 	  nchar -= 1;
400 	} else if(cpnt[0] == 0){
401 	  if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry();
402 	  Rock[ipnt++] = SL_ROOT;
403 	  Rock[ipnt++] = 0;  /* length is zero */
404 	  lenval += 2;
405 	} else {
406 	  /* If we do not have enough room for a component, start
407 	     a new continuations segment now */
408          if(split_SL_component ? MAYBE_ADD_CE_ENTRY(6) :
409                                  MAYBE_ADD_CE_ENTRY(6 + strlen ((char *) cpnt)))
410 	   {
411 	     add_CE_entry();
412 	     if(cpnt1)
413 	       {
414 		 *cpnt1 = '/';
415 		 nchar++;
416 		 cpnt1 = NULL; /* A kluge so that we can restart properly */
417 	       }
418 	     break;
419 	   }
420 	  j0 = strlen((char *) cpnt);
421 	  while(j0) {
422 	    j1 = j0;
423 	    if(j1 > 0xf8) j1 = 0xf8;
424 	    need_ce = 0;
425 	    if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) {
426 	      j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart);
427 	      need_ce++;
428 	    }
429 	    Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0);
430 	    Rock[ipnt++] = j1;
431 	    strncpy((char *) Rock + ipnt, (char *) cpnt, j1);
432 	    ipnt += j1;
433 	    lenval += j1 + 2;
434 	    cpnt += j1;
435 	    nchar -= j1;  /* Number we processed this time */
436 	    j0 -= j1;
437 	    if(need_ce) {
438 	      add_CE_entry();
439 	      if(cpnt1) {
440 		*cpnt1 = '/';
441                 nchar++;
442 		cpnt1 = NULL; /* A kluge so that we can restart properly */
443 	      }
444 	      break;
445 	    }
446 	  }
447 	};
448 	if(cpnt1) {
449 	  cpnt = cpnt1 + 1;
450 	} else
451 	  break;
452       }
453       Rock[lenpos] = lenval;
454       if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */
455     } /* while nchar */
456   } /* Is a symbolic link */
457   /*
458    * Add in the Rock Ridge TF time field
459    */
460   if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry();
461   Rock[ipnt++] ='T';
462   Rock[ipnt++] ='F';
463   Rock[ipnt++] = TF_SIZE;
464   Rock[ipnt++] = SU_VERSION;
465 #ifdef __QNX__
466   Rock[ipnt++] = 0x0f;
467 #else
468   Rock[ipnt++] = 0x0e;
469 #endif
470   flagval |= (1<<7);
471 #ifdef __QNX__
472   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime);
473   ipnt += 7;
474 #endif
475   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime);
476   ipnt += 7;
477   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime);
478   ipnt += 7;
479   iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime);
480   ipnt += 7;
481 
482   /*
483    * Add in the Rock Ridge RE time field
484    */
485   if(deep_opt & NEED_RE){
486           if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry();
487 	  Rock[ipnt++] ='R';
488 	  Rock[ipnt++] ='E';
489 	  Rock[ipnt++] = RE_SIZE;
490 	  Rock[ipnt++] = SU_VERSION;
491 	  flagval |= (1<<6);
492   };
493   /*
494    * Add in the Rock Ridge PL record, if required.
495    */
496   if(deep_opt & NEED_PL){
497           if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry();
498 	  Rock[ipnt++] ='P';
499 	  Rock[ipnt++] ='L';
500 	  Rock[ipnt++] = PL_SIZE;
501 	  Rock[ipnt++] = SU_VERSION;
502 	  set_733((char*)Rock + ipnt, 0);
503 	  ipnt += 8;
504 	  flagval |= (1<<5);
505   };
506 
507   /*
508    * Add in the Rock Ridge CL field, if required.
509    */
510   if(deep_opt & NEED_CL){
511           if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry();
512 	  Rock[ipnt++] ='C';
513 	  Rock[ipnt++] ='L';
514 	  Rock[ipnt++] = CL_SIZE;
515 	  Rock[ipnt++] = SU_VERSION;
516 	  set_733((char*)Rock + ipnt, 0);
517 	  ipnt += 8;
518 	  flagval |= (1<<4);
519   };
520 
521 #ifndef VMS
522   /* If transparent compression was requested, fill in the correct
523      field for this file */
524   if(transparent_compression &&
525      S_ISREG(lstatbuf->st_mode) &&
526      strlen(name) > 3 &&
527      strcmp(name + strlen(name) - 3,".gZ") == 0){
528     FILE * zipfile;
529     char * checkname;
530     unsigned int file_size;
531     unsigned char header[8];
532     int OK_flag;
533 
534     /* First open file and verify that the correct algorithm was used */
535     file_size = 0;
536     OK_flag = 1;
537 
538     zipfile = fopen(whole_name, "rb");
539     fread(header, 1, sizeof(header), zipfile);
540 
541     /* Check some magic numbers from gzip. */
542     if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0;
543     /* Make sure file was blocksized. */
544     if(((header[3] & 0x40) == 0)) OK_flag = 0;
545     /* OK, now go to the end of the file and get some more info */
546     if(OK_flag){
547       int status;
548       status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END);
549       if(status == -1) OK_flag = 0;
550     }
551     if(OK_flag){
552       if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header))
553 	OK_flag = 0;
554       else {
555 	int blocksize;
556 	blocksize = (header[3] << 8) | header[2];
557 	file_size = ((unsigned int)header[7] << 24) |
558 		    ((unsigned int)header[6] << 16) |
559 		    ((unsigned int)header[5] << 8)  | header[4];
560 #if 0
561 	fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size);
562 #endif
563 	if(blocksize != SECTOR_SIZE) OK_flag = 0;
564       }
565     }
566     fclose(zipfile);
567 
568     checkname = strdup(whole_name);
569     checkname[strlen(whole_name)-3] = 0;
570     zipfile = fopen(checkname, "rb");
571     if(zipfile) {
572       OK_flag = 0;
573       fprintf(stderr,"Unable to insert transparent compressed file - name conflict\n");
574       fclose(zipfile);
575     }
576 
577     free(checkname);
578 
579     if(OK_flag){
580       if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry();
581       Rock[ipnt++] ='Z';
582       Rock[ipnt++] ='Z';
583       Rock[ipnt++] = ZZ_SIZE;
584       Rock[ipnt++] = SU_VERSION;
585       Rock[ipnt++] = 'g'; /* Identify compression technique used */
586       Rock[ipnt++] = 'z';
587       Rock[ipnt++] = 3;
588       set_733((char*)Rock + ipnt, file_size); /* Real file size */
589       ipnt += 8;
590     };
591   }
592 #endif
593   /*
594    * Add in the Rock Ridge CE field, if required.  We use  this for the
595    * extension record that is stored in the root directory.
596    */
597   if(deep_opt & NEED_CE) add_CE_entry();
598   /*
599    * Done filling in all of the fields.  Now copy it back to a buffer for the
600    * file in question.
601    */
602 
603   /* Now copy this back to the buffer for the file */
604   Rock[flagpos] = flagval;
605 
606   /* If there was a CE, fill in the size field */
607   if(recstart)
608     set_733((char*)Rock + recstart - 8, ipnt - recstart);
609 
610   s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt);
611   s_entry->total_rr_attr_size = ipnt;
612   s_entry->rr_attr_size = (mainrec ? mainrec : ipnt);
613   memcpy(s_entry->rr_attributes, Rock, ipnt);
614   return ipnt;
615 }
616 
617 /* Guaranteed to  return a single sector with the relevant info */
618 
FDECL4(generate_rr_extension_record,char *,id,char *,descriptor,char *,source,int *,size)619 char * FDECL4(generate_rr_extension_record, char *, id,  char  *, descriptor,
620 				    char *, source, int  *, size){
621   int lipnt = 0;
622   char * pnt;
623   int len_id, len_des, len_src;
624 
625   len_id = strlen(id);
626   len_des =  strlen(descriptor);
627   len_src = strlen(source);
628   Rock[lipnt++] ='E';
629   Rock[lipnt++] ='R';
630   Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src;
631   Rock[lipnt++] = 1;
632   Rock[lipnt++] = len_id;
633   Rock[lipnt++] = len_des;
634   Rock[lipnt++] = len_src;
635   Rock[lipnt++] = 1;
636 
637   memcpy(Rock  + lipnt, id, len_id);
638   lipnt += len_id;
639 
640   memcpy(Rock  + lipnt, descriptor, len_des);
641   lipnt += len_des;
642 
643   memcpy(Rock  + lipnt, source, len_src);
644   lipnt += len_src;
645 
646   if(lipnt  > SECTOR_SIZE) {
647 	  fprintf(stderr,"Extension record too  long\n");
648 	  exit(1);
649   };
650   pnt = (char *) e_malloc(SECTOR_SIZE);
651   memset(pnt, 0,  SECTOR_SIZE);
652   memcpy(pnt, Rock, lipnt);
653   *size = lipnt;
654   return pnt;
655 }
656