2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 * This file is part of Jam - see jam.c for Copyright information.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
22 * file_dirscan() - scan a directory for files
23 * file_time() - get timestamp of file, if not done by file_dirscan()
24 * file_archscan() - scan an archive for files
26 * File_dirscan() and file_archscan() call back a caller provided function
27 * for each file found. A flag to this callback function lets file_dirscan()
28 * and file_archscan() indicate that a timestamp is being provided with the
29 * file. If file_dirscan() or file_archscan() do not provide the file's
30 * timestamp, interested parties may later call file_time().
40 #if defined(OS_MACOSX)
41 /* need unistd for rhapsody's proper lseek */
44 # define STRUCT_DIRENT struct direct
47 # define STRUCT_DIRENT struct dirent
53 // <0: error; 0: regular; 1: directory
54 int file_type (const char *diskname
) {
56 if (stat(diskname
, &stbuf
) != 0) return -1;
57 if (S_ISDIR(stbuf
.st_mode
)) return 1;
58 if (S_ISREG(stbuf
.st_mode
)) return 0;
64 * file_dirscan() - scan a directory for files
66 void file_dirscan (const char *dir
, scanback func
, void *closure
) {
69 STRUCT_DIRENT
*dirent
;
70 static char filename
[MAXJPATH
];
71 /* first enter directory itself */
72 memset((char *)&f
, '\0', sizeof(f
));
74 f
.f_dir
.len
= strlen(dir
);
75 dir
= (*dir
? dir
: ".");
76 /* special case / : enter it */
77 if (f
.f_dir
.len
== 1 && f
.f_dir
.ptr
[0] == '/') (*func
)(closure
, dir
, 0 /* not stat()'ed */, (time_t)0);
78 /* Now enter contents of directory */
79 if (!(d
= opendir(dir
))) return;
80 if (DEBUG_BINDSCAN
) printf("scan directory %s\n", dir
);
81 while ((dirent
= readdir(d
))) {
82 f
.f_base
.ptr
= dirent
->d_name
;
83 f
.f_base
.len
= strlen(f
.f_base
.ptr
);
84 path_build(filename
, &f
);
85 (*func
)(closure
, filename
, 0 /* not stat()'ed */, (time_t)0);
92 * file_time() - get timestamp of file, if not done by file_dirscan()
94 int file_time (const char *filename
, time_t *time
) {
96 if (stat(filename
, &statbuf
) < 0) return -1;
97 *time
= statbuf
.st_mtime
;
102 static long scan_long (const char *str
, size_t ssize
) {
104 while (ssize
> 0 && str
[0] && (str
[0] < '0' || str
[0] > '9')) { ++str
; --ssize
; }
105 if (ssize
> 0 && str
[0]) {
106 while (ssize
> 0 && str
[0] >= '0' && str
[0] <= '9') {
107 res
= res
*10+str
[0]-'0';
117 * file_archscan() - scan an archive for files
120 #define SARHDR sizeof(struct ar_hdr)
122 void file_archscan (const char *archive
, scanback func
, void *closure
) {
124 struct ar_hdr ar_hdr
;
125 static char buf
[MAXJPATH
];
127 char *string_table
= 0;
129 if ((fd
= open(archive
, O_RDONLY
, 0)) < 0) return;
130 if (read(fd
, buf
, SARMAG
) != SARMAG
|| strncmp(ARMAG
, buf
, SARMAG
)) {
135 if (DEBUG_BINDSCAN
) printf("scan archive %s\n", archive
);
137 while (read(fd
, &ar_hdr
, SARHDR
) == SARHDR
&& !memcmp(ar_hdr
._ar_name
.ar_fmag
, ARFMAG
, SARFMAG
)) {
139 while (read(fd
, &ar_hdr
, SARHDR
) == SARHDR
&& !memcmp(ar_hdr
.ar_fmag
, ARFMAG
, SARFMAG
)) {
144 char *dst
= lar_name
;
145 /* solaris sscanf() does strlen first, so terminate somewhere */
147 ar_hdr
._ar_name
.ar_fmag
[0] = 0;
149 ar_hdr
.ar_fmag
[0] = 0;
151 /* get date & size */
153 sscanf(ar_hdr.ar_date, "%ld", &lar_date);
154 sscanf(ar_hdr.ar_size, "%ld", &lar_size);
156 lar_date
= scan_long(ar_hdr
.ar_date
, sizeof(ar_hdr
.ar_date
));
157 lar_size
= scan_long(ar_hdr
.ar_size
, sizeof(ar_hdr
.ar_size
));
158 /* handle solaris string table
159 * the entry under the name // is the table, and entries with the name /nnnn refer to the table */
161 if (ar_hdr
._ar_name
.ar_name
[0] != '/') {
163 if (ar_hdr
.ar_name
[0] != '/') {
165 /* traditional archive entry names: ends at the first space, /, or null */
167 char *src
= ar_hdr
._ar_name
.ar_name
;
168 const char *e
= src
+sizeof(ar_hdr
._ar_name
.ar_name
);
170 char *src
= ar_hdr
.ar_name
;
171 const char *e
= src
+sizeof(ar_hdr
.ar_name
);
174 while (src
< e
&& *src
&& *src
!= ' ' && *src
!= '/') *dst
++ = *src
++;
176 } else if (ar_hdr
._ar_name
.ar_name
[1] == '/') {
178 } else if (ar_hdr
.ar_name
[1] == '/') {
180 /* this is the "string table" entry of the symbol table,
181 * which holds strings of filenames that are longer than
182 * 15 characters (ie. don't fit into a ar_name) */
183 string_table
= (char *)malloc(lar_size
);
184 lseek(fd
, offset
+SARHDR
, 0);
185 if (read(fd
, string_table
, lar_size
) != lar_size
) printf("error reading string table\n");
187 } else if (string_table
&& ar_hdr
._ar_name
.ar_name
[1] != ' ') {
189 } else if (string_table
&& ar_hdr
.ar_name
[1] != ' ') {
191 /* long filenames are recognized by "/nnnn" where nnnn is
192 * the offset of the string in the string table represented
193 * in ASCII decimals */
195 char *src
= string_table
+atoi(ar_hdr
._ar_name
.ar_name
+1);
197 char *src
= string_table
+atoi(ar_hdr
.ar_name
+1);
199 while (*src
!= '/') *dst
++ = *src
++;
201 /* terminate lar_name */
203 /* modern (BSD4.4) long names: if the name is "#1/nnnn", then the actual name is the nnnn bytes after the header */
204 if (!strcmp(lar_name
, "#1")) {
206 int len
= atoi(ar_hdr
._ar_name
.ar_name
+3);
208 int len
= atoi(ar_hdr
.ar_name
+3);
210 if (read(fd
, lar_name
, len
) != len
) printf("error reading archive entry\n");
213 /* build name and pass it on */
215 if (DEBUG_BINDSCAN
) printf("archive name %s found\n", lar_name
);
216 snprintf(buf
, sizeof(buf
), "%s(%s)", archive
, lar_name
);
217 (*func
)(closure
, buf
, 1 /* time valid */, (time_t)lar_date
);
219 /* Position at next member */
220 offset
+= SARHDR
+((lar_size
+1)&(~1));
221 lseek(fd
, offset
, 0);
223 if (string_table
) free(string_table
);
229 #endif /* USE_FILEUNIX */