2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
8 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
12 * file_dirscan() - scan a directory for files
13 * file_time() - get timestamp of file, if not done by file_dirscan()
14 * file_archscan() - scan an archive for files
16 * File_dirscan() and file_archscan() call back a caller provided function
17 * for each file found. A flag to this callback function lets file_dirscan()
18 * and file_archscan() indicate that a timestamp is being provided with the
19 * file. If file_dirscan() or file_archscan() do not provide the file's
20 * timestamp, interested parties may later call file_time().
22 * 04/08/94 (seiwald) - Coherent/386 support added.
23 * 12/19/94 (mikem) - solaris string table insanity support
24 * 02/14/95 (seiwald) - parse and build /xxx properly
25 * 05/03/96 (seiwald) - split into pathunix.c
26 * 11/21/96 (peterk) - BEOS does not have Unix-style archives
27 * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
28 * 04/03/01 (seiwald) - AIX uses SARMAG
29 * 07/16/02 (seiwald) - Support BSD style long filename in archives.
30 * 11/04/02 (seiwald) - const-ing for string literals
31 * 12/27/02 (seiwald) - support for AIX big archives
32 * 12/30/02 (seiwald) - terminate ar_hdr for solaris sscanf()
33 * 12/30/02 (seiwald) - skip solaris' empty archive member names (/, //xxx)
43 #if defined(OS_SEQUENT) || defined(OS_DGUX) || defined(OS_SCO) || defined(OS_ISC)
47 #if defined(OS_MACOSX)
48 /* need unistd for rhapsody's proper lseek */
51 # define STRUCT_DIRENT struct direct
54 # define STRUCT_DIRENT struct dirent
60 // <0: error; 0: regular; 1: directory
61 int getFileType (const char *diskname
) {
64 if (access(diskname
, R_OK
) != 0) return -1;
65 if (stat(diskname
, &stbuf
) != 0) return -1;
66 if (S_ISDIR(stbuf
.st_mode
)) return 1;
67 if (S_ISREG(stbuf
.st_mode
)) return 0;
73 * file_dirscan() - scan a directory for files
75 void file_dirscan (const char *dir
, scanback func
, void *closure
) {
78 STRUCT_DIRENT
*dirent
;
79 char filename
[MAXJPATH
];
81 /* first enter directory itself */
82 memset((char *)&f
, '\0', sizeof(f
));
84 f
.f_dir
.len
= strlen(dir
);
86 /* special case / : enter it */
87 if (f
.f_dir
.len
== 1 && f
.f_dir
.ptr
[0] == '/') (*func
)(closure
, dir
, 0 /* not stat()'ed */, (time_t)0);
88 /* Now enter contents of directory */
89 if (!(d
= opendir(dir
))) return;
90 if (DEBUG_BINDSCAN
) printf("scan directory %s\n", dir
);
91 while ((dirent
= readdir(d
))) {
93 /* broken structure definition on sinix. */
94 f
.f_base
.ptr
= dirent
->d_name
-2;
96 f
.f_base
.ptr
= dirent
->d_name
;
98 f
.f_base
.len
= strlen(f
.f_base
.ptr
);
99 path_build(&f
, filename
, 0);
100 (*func
)(closure
, filename
, 0 /* not stat()'ed */, (time_t)0);
107 * file_time() - get timestamp of file, if not done by file_dirscan()
109 int file_time (const char *filename
, time_t *time
) {
112 if (stat(filename
, &statbuf
) < 0) return -1;
113 *time
= statbuf
.st_mtime
;
119 * file_archscan() - scan an archive for files
122 #define SARHDR sizeof(struct ar_hdr)
124 void file_archscan (const char *archive
, scanback func
, void *closure
) {
126 struct ar_hdr ar_hdr
;
129 char *string_table
= 0;
132 if ((fd
= open(archive
, O_RDONLY
, 0)) < 0) return;
133 if (read(fd
, buf
, SARMAG
) != SARMAG
|| strncmp(ARMAG
, buf
, SARMAG
)) {
138 if (DEBUG_BINDSCAN
) printf("scan archive %s\n", archive
);
139 while (read(fd
, &ar_hdr
, SARHDR
) == SARHDR
&& !memcmp(ar_hdr
.ar_fmag
, ARFMAG
, SARFMAG
)) {
143 char *dst
= lar_name
;
144 /* solaris sscanf() does strlen first, so terminate somewhere */
145 ar_hdr
.ar_fmag
[0] = 0;
146 /* get date & size */
147 sscanf(ar_hdr
.ar_date
, "%ld", &lar_date
);
148 sscanf(ar_hdr
.ar_size
, "%ld", &lar_size
);
149 /* handle solaris string table
150 * the entry under the name // is the table, and entries with the name /nnnn refer to the table */
151 if (ar_hdr
.ar_name
[0] != '/') {
152 /* traditional archive entry names: ends at the first space, /, or null */
153 char *src
= ar_hdr
.ar_name
;
154 const char *e
= src
+sizeof(ar_hdr
.ar_name
);
156 while (src
< e
&& *src
&& *src
!= ' ' && *src
!= '/') *dst
++ = *src
++;
157 } else if (ar_hdr
.ar_name
[1] == '/') {
158 /* this is the "string table" entry of the symbol table,
159 * which holds strings of filenames that are longer than
160 * 15 characters (ie. don't fit into a ar_name) */
161 string_table
= (char *)malloc(lar_size
);
162 lseek(fd
, offset
+SARHDR
, 0);
163 if (read(fd
, string_table
, lar_size
) != lar_size
) printf("error reading string table\n");
164 } else if (string_table
&& ar_hdr
.ar_name
[1] != ' ') {
165 /* long filenames are recognized by "/nnnn" where nnnn is
166 * the offset of the string in the string table represented
167 * in ASCII decimals */
168 char *src
= string_table
+atoi(ar_hdr
.ar_name
+1);
169 while (*src
!= '/') *dst
++ = *src
++;
171 /* terminate lar_name */
173 /* modern (BSD4.4) long names: if the name is "#1/nnnn", then the actual name is the nnnn bytes after the header */
174 if (!strcmp(lar_name
, "#1")) {
175 int len
= atoi(ar_hdr
.ar_name
+3);
176 if (read(fd
, lar_name
, len
) != len
) printf("error reading archive entry\n");
179 /* build name and pass it on */
181 if (DEBUG_BINDSCAN
) printf("archive name %s found\n", lar_name
);
182 sprintf(buf
, "%s(%s)", archive
, lar_name
);
183 (*func
)(closure
, buf
, 1 /* time valid */, (time_t)lar_date
);
185 /* Position at next member */
186 offset
+= SARHDR
+((lar_size
+1)&(~1));
187 lseek(fd
, offset
, 0);
189 if (string_table
) free(string_table
);
195 #endif /* USE_FILEUNIX */