1/*  Copyright 1998-2002,2009 Alain Knaff.
2 *  This file is part of mtools.
3 *
4 *  Mtools is free software: you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation, either version 3 of the License, or
7 *  (at your option) any later version.
8 *
9 *  Mtools 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.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "sysincludes.h"
19#include "msdos.h"
20#include "stream.h"
21#include "mtools.h"
22#include "fsP.h"
23#include "file.h"
24#include "htable.h"
25#include "mainloop.h"
26#include <dirent.h>
27
28typedef struct Dir_t {
29	Class_t *Class;
30	int refs;
31	Stream_t *Next;
32	Stream_t *Buffer;
33
34	struct MT_STAT statbuf;
35	char *pathname;
36	DIR *dir;
37#ifdef HAVE_FCHDIR
38	int fd;
39#endif
40} Dir_t;
41
42/*#define FCHDIR_MODE*/
43
44static int get_dir_data(Stream_t *Stream, time_t *date, mt_size_t *size,
45			int *type, int *address)
46{
47	DeclareThis(Dir_t);
48
49	if(date)
50		*date = This->statbuf.st_mtime;
51	if(size)
52		*size = (mt_size_t) This->statbuf.st_size;
53	if(type)
54		*type = 1;
55	if(address)
56		*address = 0;
57	return 0;
58}
59
60static int dir_free(Stream_t *Stream)
61{
62	DeclareThis(Dir_t);
63
64	Free(This->pathname);
65	closedir(This->dir);
66	return 0;
67}
68
69static Class_t DirClass = {
70	0, /* read */
71	0, /* write */
72	0, /* flush */
73	dir_free, /* free */
74	0, /* get_geom */
75	get_dir_data ,
76	0 /* pre-allocate */
77};
78
79#ifdef HAVE_FCHDIR
80#define FCHDIR_MODE
81#endif
82
83int unix_dir_loop(Stream_t *Stream, MainParam_t *mp);
84int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg,
85	      int follow_dir_link);
86
87int unix_dir_loop(Stream_t *Stream, MainParam_t *mp)
88{
89	DeclareThis(Dir_t);
90	struct dirent *entry;
91	char *newName;
92	int ret=0;
93
94#ifdef FCHDIR_MODE
95	int fd;
96
97	fd = open(".", O_RDONLY);
98	chdir(This->pathname);
99#endif
100	while((entry=readdir(This->dir)) != NULL) {
101		if(got_signal)
102			break;
103		if(isSpecial(entry->d_name))
104			continue;
105#ifndef FCHDIR_MODE
106		newName = malloc(strlen(This->pathname) + 1 +
107				 strlen(entry->d_name) + 1);
108		if(!newName) {
109			ret = ERROR_ONE;
110			break;
111		}
112		strcpy(newName, This->pathname);
113		strcat(newName, "/");
114		strcat(newName, entry->d_name);
115#else
116		newName = entry->d_name;
117#endif
118		ret |= unix_loop(Stream, mp, newName, 0);
119#ifndef FCHDIR_MODE
120		free(newName);
121#endif
122	}
123#ifdef FCHDIR_MODE
124	fchdir(fd);
125	close(fd);
126#endif
127	return ret;
128}
129
130Stream_t *OpenDir(Stream_t *Stream, const char *filename)
131{
132	Dir_t *This;
133
134	This = New(Dir_t);
135
136	This->Class = &DirClass;
137	This->Next = 0;
138	This->refs = 1;
139	This->Buffer = 0;
140	This->pathname = malloc(strlen(filename)+1);
141	if(This->pathname == NULL) {
142		Free(This);
143		return NULL;
144	}
145	strcpy(This->pathname, filename);
146
147	if(MT_STAT(filename, &This->statbuf) < 0) {
148		Free(This->pathname);
149		Free(This);
150		return NULL;
151	}
152
153	This->dir = opendir(filename);
154	if(!This->dir) {
155		Free(This->pathname);
156		Free(This);
157		return NULL;
158	}
159
160	return (Stream_t *) This;
161}
162