cosmetix
[k8jam.git] / src / fileunix.c
blobe38c222bbffd895425b37ba1724003945190353b
1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
7 /*
8 * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
10 * External routines:
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)
35 #include <unistd.h>
37 #include "jam.h"
38 #include "filesys.h"
39 #include "pathsys.h"
41 #ifdef USE_FILEUNIX
43 #if defined(OS_MACOSX)
44 /* need unistd for rhapsody's proper lseek */
45 # include <sys/dir.h>
46 # include <unistd.h>
47 # define STRUCT_DIRENT struct direct
48 #else
49 # include <dirent.h>
50 # define STRUCT_DIRENT struct dirent
51 #endif
53 #include <ar.h>
56 // <0: error; 0: regular; 1: directory
57 int file_type (const char *diskname) {
58 struct stat stbuf;
59 if (stat(diskname, &stbuf) != 0) return -1;
60 if (S_ISDIR(stbuf.st_mode)) return 1;
61 if (S_ISREG(stbuf.st_mode)) return 0;
62 return -1;
67 * file_dirscan() - scan a directory for files
69 void file_dirscan (const char *dir, scanback func, void *closure) {
70 PATHNAME f;
71 DIR *d;
72 STRUCT_DIRENT *dirent;
73 static char filename[MAXJPATH];
74 /* first enter directory itself */
75 memset((char *)&f, '\0', sizeof(f));
76 f.f_dir.ptr = dir;
77 f.f_dir.len = strlen(dir);
78 dir = (*dir ? dir : ".");
79 /* special case / : enter it */
80 if (f.f_dir.len == 1 && f.f_dir.ptr[0] == '/') (*func)(closure, dir, 0 /* not stat()'ed */, (time_t)0);
81 /* Now enter contents of directory */
82 if (!(d = opendir(dir))) return;
83 if (DEBUG_BINDSCAN) printf("scan directory %s\n", dir);
84 while ((dirent = readdir(d))) {
85 f.f_base.ptr = dirent->d_name;
86 f.f_base.len = strlen(f.f_base.ptr);
87 path_build(filename, &f);
88 (*func)(closure, filename, 0 /* not stat()'ed */, (time_t)0);
90 closedir(d);
95 * file_time() - get timestamp of file, if not done by file_dirscan()
97 int file_time (const char *filename, time_t *time) {
98 struct stat statbuf;
99 if (stat(filename, &statbuf) < 0) return -1;
100 *time = statbuf.st_mtime;
101 return 0;
105 static long scan_long (const char *str, size_t ssize) {
106 long res = 0;
107 while (ssize > 0 && str[0] && (str[0] < '0' || str[0] > '9')) { ++str; --ssize; }
108 if (ssize > 0 && str[0]) {
109 while (ssize > 0 && str[0] >= '0' && str[0] <= '9') {
110 res = res*10+str[0]-'0';
111 ++str;
112 --ssize;
115 return res;
120 * file_archscan() - scan an archive for files
122 #define SARFMAG 2
123 #define SARHDR sizeof(struct ar_hdr)
125 void file_archscan (const char *archive, scanback func, void *closure) {
126 #ifndef NO_AR
127 struct ar_hdr ar_hdr;
128 static char buf[MAXJPATH];
129 long offset;
130 char *string_table = 0;
131 int fd;
132 if ((fd = open(archive, O_RDONLY, 0)) < 0) return;
133 if (read(fd, buf, SARMAG) != SARMAG || strncmp(ARMAG, buf, SARMAG)) {
134 close(fd);
135 return;
137 offset = 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)) {
140 long lar_date;
141 long lar_size;
142 char lar_name[256];
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 */
148 sscanf(ar_hdr.ar_date, "%ld", &lar_date);
149 sscanf(ar_hdr.ar_size, "%ld", &lar_size);
151 lar_date = scan_long(ar_hdr.ar_date, sizeof(ar_hdr.ar_date));
152 lar_size = scan_long(ar_hdr.ar_size, sizeof(ar_hdr.ar_size));
153 /* handle solaris string table
154 * the entry under the name // is the table, and entries with the name /nnnn refer to the table */
155 if (ar_hdr.ar_name[0] != '/') {
156 /* traditional archive entry names: ends at the first space, /, or null */
157 char *src = ar_hdr.ar_name;
158 const char *e = src+sizeof(ar_hdr.ar_name);
160 while (src < e && *src && *src != ' ' && *src != '/') *dst++ = *src++;
161 } else if (ar_hdr.ar_name[1] == '/') {
162 /* this is the "string table" entry of the symbol table,
163 * which holds strings of filenames that are longer than
164 * 15 characters (ie. don't fit into a ar_name) */
165 string_table = (char *)malloc(lar_size);
166 lseek(fd, offset+SARHDR, 0);
167 if (read(fd, string_table, lar_size) != lar_size) printf("error reading string table\n");
168 } else if (string_table && ar_hdr.ar_name[1] != ' ') {
169 /* long filenames are recognized by "/nnnn" where nnnn is
170 * the offset of the string in the string table represented
171 * in ASCII decimals */
172 char *src = string_table+atoi(ar_hdr.ar_name+1);
173 while (*src != '/') *dst++ = *src++;
175 /* terminate lar_name */
176 *dst = 0;
177 /* modern (BSD4.4) long names: if the name is "#1/nnnn", then the actual name is the nnnn bytes after the header */
178 if (!strcmp(lar_name, "#1")) {
179 int len = atoi(ar_hdr.ar_name+3);
180 if (read(fd, lar_name, len) != len) printf("error reading archive entry\n");
181 lar_name[len] = 0;
183 /* build name and pass it on */
184 if (lar_name[0]) {
185 if (DEBUG_BINDSCAN) printf("archive name %s found\n", lar_name);
186 snprintf(buf, sizeof(buf), "%s(%s)", archive, lar_name);
187 (*func)(closure, buf, 1 /* time valid */, (time_t)lar_date);
189 /* Position at next member */
190 offset += SARHDR+((lar_size+1)&(~1));
191 lseek(fd, offset, 0);
193 if (string_table) free(string_table);
194 close(fd);
195 #endif /* NO_AR */
199 #endif /* USE_FILEUNIX */