revert between 56095 -> 55830 in arch
[AROS.git] / rom / filesys / CDVDFS / src / rock.c
bloba3ee8a6c3ccb48579a411ad081e40848d2de6351
1 /* rock.c:
3 * Support for the Rock Ridge filing system.
5 * ----------------------------------------------------------------------
6 * This code is (C) Copyright 1993,1994 by Frank Munkert.
7 * All rights reserved.
8 * This software may be freely distributed and redistributed for
9 * non-commercial purposes, provided this notice is included.
10 * ----------------------------------------------------------------------
11 * History:
13 * 08-Dec-10 neil Do not mark files/dirs as unwritable/undeletable.
14 * 06-Mar-09 error - Removed madness, fixed insanity. Cleanup started
15 * 18-Aug-07 sonic Fixed reading CL and PL fields on little-endian machines
16 * 04-Jun-07 sonic Fixed endianess check in Is_A_Symbolic_Link()
17 * 05-May-07 sonic Added support for RockRidge protection bits and file comments
18 * 07-Jul-02 sheutlin various changes when porting to AROS
19 * - global variables are now in a struct Globals *global
20 * - replaced (unsigned) long by (U)LONG
21 * 05-Feb-94 fmu Added support for relocated directories.
22 * 16-Oct-93 fmu Adapted to new VOLUME structure.
25 #include <proto/exec.h>
26 #include <exec/memory.h>
27 #include <sys/stat.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #include "debug.h"
32 #include "rock.h"
33 #include "globals.h"
34 #include "aros_stuff.h"
35 #include "clib_stuff.h"
37 #define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
38 #define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
40 /* Check whether the given volume uses the Rock Ridge Interchange Protocol.
41 * The protocol is identified by the sequence
42 * 'S' 'P' 7 1 0xbe 0xef
43 * in the system use field of the (00) directory in the root directory of
44 * the volume.
46 * Returns 1 iff the RR protocol is used; 0 otherwise.
47 * If the RR protocol is used, *p_skip will be set to the skip length
48 * specified in the SP system use field.
51 t_bool Uses_Rock_Ridge_Protocol(VOLUME *p_volume, int *p_skip) {
52 ULONG loc = VOL(p_volume,pvd).root.extent_loc;
53 directory_record *dir;
54 int system_use_pos;
55 unsigned char *sys;
57 if (!(dir = Get_Directory_Record(p_volume, loc, 0)))
58 return 0;
60 system_use_pos = 33 + dir->file_id_length;
61 if (system_use_pos & 1)
62 system_use_pos++;
64 if (system_use_pos >= dir->length)
65 return 0;
67 sys = (unsigned char *) dir + system_use_pos;
68 if (
69 sys[0] == 'S' &&
70 sys[1] == 'P' &&
71 sys[2] == 7 &&
72 sys[3] == 1 &&
73 sys[4] == 0xbe &&
74 sys[5] == 0xef)
76 *p_skip = sys[6];
77 return 1;
79 else
80 return 0;
83 /* Searches for the system use field with name p_name in the directory record
84 * p_dir and fills the buffer p_buf (with length p_buf_len) with the information
85 * contained in the system use field.
87 * p_index is the ordinal number of the system use field (if more than one
88 * system use field with the same name is recorded.) 0=first occurrence,
89 * 1=second occurrence, and so on.
91 * 1 is returned if the system use field has been found; otherwise 0
92 * is returned.
95 int Get_System_Use_Field
97 VOLUME *p_volume, directory_record *p_dir,
98 char *p_name,
99 char *p_buf,
100 int p_buf_len,
101 int p_index
104 int system_use_pos;
105 int slen, len;
106 ULONG length = p_dir->length;
107 unsigned char *buf = (unsigned char *) p_dir;
109 system_use_pos = 33 + p_dir->file_id_length;
110 if (system_use_pos & 1)
111 system_use_pos++;
112 system_use_pos += VOL(p_volume,skip);
114 /* the system use field must be at least 4 bytes long */
115 while (system_use_pos + 3 < length)
117 slen = buf[system_use_pos+2];
118 if (
119 buf[system_use_pos] == p_name[0] &&
120 buf[system_use_pos+1] == p_name[1]
123 if (p_index)
124 p_index--;
125 else
127 len = (slen < p_buf_len) ? slen : p_buf_len;
128 CopyMem(buf + system_use_pos, p_buf, len);
129 return 1;
132 /* look for continuation area: */
133 if (
134 buf[system_use_pos] == 'C' &&
135 buf[system_use_pos+1] == 'E'
138 ULONG newloc, offset;
139 CopyMem(buf + system_use_pos + 8, &newloc, 4);
140 CopyMem(buf + system_use_pos + 16, &offset, 4);
141 CopyMem(buf + system_use_pos + 24, &length, 4);
142 if (!Read_Chunk(p_volume->cd, newloc))
143 return 0;
144 buf = p_volume->cd->buffer;
145 system_use_pos = offset;
146 continue;
149 /* look for system use field terminator: */
150 if (
151 buf[system_use_pos] == 'S' &&
152 buf[system_use_pos+1] == 'T'
154 return 0;
156 system_use_pos += slen;
158 return 0;
161 /* Determines the Rock Ridge file name of the CDROM object p_obj.
162 * The file name will be stored in the buffer p_buf (with length p_buf_len).
163 * The file name will NOT be null-terminated. The number of characters in
164 * the file name is returned. If there is no Rock Ridge file name for
165 * p_obj, then -1 is returned.
168 int Get_RR_File_Name
169 (VOLUME *p_volume, directory_record *p_dir, char *p_buf, int p_buf_len)
171 struct nm_system_use_field {
172 char id[2];
173 unsigned char length;
174 unsigned char version;
175 unsigned char flags;
176 char name[210];
177 } nm;
178 int len, slen;
179 int index = 0;
180 int total = 0;
182 for (;;)
184 if (
185 !Get_System_Use_Field
186 (p_volume,p_dir,"NM",(char *)&nm,sizeof(nm),index)
188 return -1;
190 slen = nm.length-5;
191 len = (p_buf_len < slen) ? p_buf_len : slen;
192 if (len)
193 CopyMem(nm.name, p_buf, len);
195 total += len;
196 if (!(nm.flags & 1))
197 return total;
199 p_buf += len;
200 p_buf_len -= len;
201 index++;
205 /* Determines the Rock Ridge Amiga protection bits and file comment of the CDROM object p_obj.
206 * Protection bits will be stored in the p_prot.
207 * The file comment will be stored in the buffer p_buf (with length p_buf_len).
208 * The file comment will NOT be null-terminated. The number of characters in
209 * the file name is returned. If there is no Rock Ridge file comment for
210 * p_obj, then -1 is returned.
213 int Get_RR_File_Comment(VOLUME *p_volume, directory_record *p_dir, uint32_t *p_prot, char *p_buf, int p_buf_len)
216 #define AS_PROTECTION 0x01
217 #define AS_COMMENT 0x02
218 #define AS_COMMENT_CONTINUE 0x04
220 struct as_system_use_field
222 char id[2];
223 unsigned char length;
224 unsigned char version;
225 unsigned char flags;
226 char data[210];
227 } as;
228 char *ptr;
229 int len, slen;
230 int index = 0;
231 int total = 0;
232 uint32_t pbuf;
234 for (;;)
236 if (!Get_System_Use_Field(p_volume,p_dir,"AS",(char *)&as,sizeof(as),index))
237 return -1;
239 ptr = as.data;
240 if (as.flags & AS_PROTECTION) {
241 CopyMem(ptr, &pbuf, 4);
242 ptr += 4;
243 *p_prot = AROS_BE2LONG(pbuf) & ~(FIBF_WRITE | FIBF_DELETE);
245 if (!(as.flags & AS_COMMENT))
246 return -1;
247 slen = *ptr++ - 1;
248 len = (p_buf_len < slen) ? p_buf_len : slen;
249 if (len)
250 CopyMem(ptr, p_buf, len);
252 total += len;
253 if (!(as.flags & AS_COMMENT_CONTINUE))
254 return total;
256 p_buf += len;
257 p_buf_len -= len;
258 index++;
262 /* Returns 1 if the PX system use field indicates a symbolic link.
263 * amiga_mode is a pointer to storage area for AmigaOS protection bits.
266 int Is_A_Symbolic_Link(VOLUME *p_volume, directory_record *p_dir, uint32_t *amiga_mode)
268 struct px_system_use_field {
269 char id[2];
270 unsigned char length;
271 unsigned char version;
272 ULONG mode_i;
273 ULONG mode_m;
274 ULONG links_i;
275 ULONG links_m;
276 ULONG user_id_i;
277 ULONG user_id_m;
278 ULONG group_id_i;
279 ULONG group_id_m;
280 } px;
282 #if AROS_BIG_ENDIAN
283 #define mode mode_m
284 #else
285 #define mode mode_i
286 #endif
288 if (!Get_System_Use_Field(p_volume,p_dir,"PX",(char *)&px,sizeof(px),0))
289 return 0;
290 *amiga_mode = 0;
291 if (!(px.mode & S_IXUSR))
292 *amiga_mode |= FIBF_EXECUTE;
293 if (!(px.mode & S_IRUSR))
294 *amiga_mode |= FIBF_READ;
295 if (px.mode & S_IXGRP)
296 *amiga_mode |= FIBF_GRP_EXECUTE;
297 if (px.mode & S_IRGRP)
298 *amiga_mode |= FIBF_GRP_READ;
299 if (px.mode & S_IXOTH)
300 *amiga_mode |= FIBF_OTR_EXECUTE;
301 if (px.mode & S_IROTH)
302 *amiga_mode |= FIBF_OTR_READ;
304 0120000 is the POSIX code for symbolic links:
306 return (px.mode & 0770000) == 0120000;
309 /* Read content of SL system use field.
310 * A full path name (starting with ":" or "sys:") will always be returned.
313 t_bool Get_Link_Name(CDROM_OBJ *p_obj, char *p_buf, int p_buf_len) {
314 unsigned char buf[256];
315 char out[530];
316 int index = 0;
317 int len;
318 int offs;
319 char c;
321 out[0] = 0;
322 for (;;)
324 if (
325 !Get_System_Use_Field
326 (p_obj->volume,OBJ(p_obj,dir),"SL",(char *)buf,sizeof(buf),index)
329 return (index == 0) ? 0 : 1;
332 offs = 5;
333 for (;;)
336 if (StrLen (out) > 256)
337 return 0;
339 if (index == 0 && offs == 5)
341 /* handle the first component record: */
343 if (buf[5] & 4) /* parent directory */
345 CDROM_OBJ *parent1 = Find_Parent(p_obj);
346 CDROM_OBJ *parent2;
347 char fullpath[256];
348 if (!parent1)
349 return 0;
350 parent2 = Find_Parent(parent1);
351 if (!parent2)
352 return 0;
353 if (!Full_Path_Name(parent2, fullpath, sizeof (fullpath)))
354 return 0;
355 Close_Object(parent1);
356 Close_Object(parent2);
357 StrCat (out, fullpath);
358 if (out[1] != 0)
359 StrCat (out, "/");
361 else if (buf[5] & 8) /* root */
362 StrCat (out, "sys:");
363 else if (buf[5] & 16) /* volume root */
364 StrCat (out, ":");
365 else
367 /* current directory */
368 CDROM_OBJ *parent = Find_Parent(p_obj);
369 char fullpath[256];
370 if (!parent)
371 return 0;
372 if (!Full_Path_Name(parent, fullpath, sizeof (fullpath)))
373 return 0;
374 Close_Object(parent);
375 StrCat (out, fullpath);
376 if (out[1] != 0)
377 StrCat (out, "/");
381 if (out[0] && (c = out[StrLen(out)-1]) != ':' && c != '/')
382 StrCat (out, "/");
384 if (buf[offs] & 32) /* host name */
385 StrCat (out, "AMIGA");
387 len = StrLen (out);
388 CopyMem(buf + offs, out + len, buf[offs+1]);
389 out[len + buf[offs+1]] = 0;
391 offs += 2 + buf[offs+1];
392 if (offs >= buf[2])
393 break;
395 if (!(buf[4] & 1)) /* continue flag */
396 break;
397 index++;
399 CopyMem(out, p_buf, p_buf_len-1);
400 p_buf[p_buf_len-1] = 0;
401 return 1;
404 /* Check whether a system use field is present: */
406 int Has_System_Use_Field
407 (VOLUME *p_volume, directory_record *p_dir, char *p_name)
409 return Get_System_Use_Field(p_volume, p_dir, p_name, NULL, 0, 0);
412 /* Return content of "CL" system use field, or -1, if no such system use field
413 * is present.
416 LONG RR_Child_Link(VOLUME *p_volume, directory_record *p_dir) {
417 struct cl {
418 char name[2];
419 char length[1];
420 char version[1];
421 LONG pos_i;
422 LONG pos_m;
423 } buf;
425 if (!Get_System_Use_Field(p_volume, p_dir,"CL",(char *)&buf,sizeof(buf),0))
426 return -1;
427 else
428 #if AROS_BIG_ENDIAN
429 return buf.pos_m;
430 #else
431 return buf.pos_i;
432 #endif
435 /* Return content of "PL" system use field, or -1, if no such system use field
436 * is present.
439 LONG RR_Parent_Link(VOLUME *p_volume, directory_record *p_dir) {
440 struct pl {
441 char name[2];
442 char length[1];
443 char version[1];
444 LONG pos_i;
445 LONG pos_m;
446 } buf;
448 if (!Get_System_Use_Field(p_volume,p_dir,"PL",(char *)&buf,sizeof(buf),0))
449 return -1;
450 else
451 #if AROS_BIG_ENDIAN
452 return buf.pos_m;
453 #else
454 return buf.pos_i;
455 #endif