00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "includes.h"
00023
00024 #undef DBGC_CLASS
00025 #define DBGC_CLASS DBGC_VFS
00026
00027 #define APPLEDOUBLE ".AppleDouble"
00028 #define ADOUBLEMODE 0777
00029
00030
00031
00032 static int atalk_build_paths(TALLOC_CTX *ctx, const char *path,
00033 const char *fname, char **adbl_path, char **orig_path,
00034 SMB_STRUCT_STAT *adbl_info, SMB_STRUCT_STAT *orig_info);
00035
00036 static int atalk_unlink_file(const char *path);
00037
00038 static int atalk_get_path_ptr(char *path)
00039 {
00040 int i = 0;
00041 int ptr = 0;
00042
00043 for (i = 0; path[i]; i ++) {
00044 if (path[i] == '/')
00045 ptr = i;
00046
00047 else if (path[i] == ':') {
00048 path[i] = '\0';
00049 break;
00050 }
00051 }
00052
00053 return ptr;
00054 }
00055
00056 static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, const char *fname,
00057 char **adbl_path, char **orig_path,
00058 SMB_STRUCT_STAT *adbl_info, SMB_STRUCT_STAT *orig_info)
00059 {
00060 int ptr0 = 0;
00061 int ptr1 = 0;
00062 char *dname = 0;
00063 char *name = 0;
00064
00065 if (!ctx || !path || !fname || !adbl_path || !orig_path ||
00066 !adbl_info || !orig_info)
00067 return -1;
00068 #if 0
00069 DEBUG(3, ("ATALK: PATH: %s[%s]\n", path, fname));
00070 #endif
00071 if (strstr(path, APPLEDOUBLE) || strstr(fname, APPLEDOUBLE)) {
00072 DEBUG(3, ("ATALK: path %s[%s] already contains %s\n", path, fname, APPLEDOUBLE));
00073 return -1;
00074 }
00075
00076 if (fname[0] == '.') ptr0 ++;
00077 if (fname[1] == '/') ptr0 ++;
00078
00079 *orig_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
00080
00081
00082 ptr1 = atalk_get_path_ptr(*orig_path);
00083
00084 sys_lstat(*orig_path, orig_info);
00085
00086 if (S_ISDIR(orig_info->st_mode)) {
00087 *adbl_path = talloc_asprintf(ctx, "%s/%s/%s/",
00088 path, &fname[ptr0], APPLEDOUBLE);
00089 } else {
00090 dname = talloc_strdup(ctx, *orig_path);
00091 dname[ptr1] = '\0';
00092 name = *orig_path;
00093 *adbl_path = talloc_asprintf(ctx, "%s/%s/%s",
00094 dname, APPLEDOUBLE, &name[ptr1 + 1]);
00095 }
00096 #if 0
00097 DEBUG(3, ("ATALK: DEBUG:\n%s\n%s\n", *orig_path, *adbl_path));
00098 #endif
00099 sys_lstat(*adbl_path, adbl_info);
00100 return 0;
00101 }
00102
00103 static int atalk_unlink_file(const char *path)
00104 {
00105 int ret = 0;
00106
00107 become_root();
00108 ret = unlink(path);
00109 unbecome_root();
00110
00111 return ret;
00112 }
00113
00114 static void atalk_add_to_list(name_compare_entry **list)
00115 {
00116 int i, count = 0;
00117 name_compare_entry *new_list = 0;
00118 name_compare_entry *cur_list = 0;
00119
00120 cur_list = *list;
00121
00122 if (cur_list) {
00123 for (i = 0, count = 0; cur_list[i].name; i ++, count ++) {
00124 if (strstr(cur_list[i].name, APPLEDOUBLE))
00125 return;
00126 }
00127 }
00128
00129 if (!(new_list = SMB_CALLOC_ARRAY(name_compare_entry, (count == 0 ? 1 : count + 1))))
00130 return;
00131
00132 for (i = 0; i < count; i ++) {
00133 new_list[i].name = SMB_STRDUP(cur_list[i].name);
00134 new_list[i].is_wild = cur_list[i].is_wild;
00135 }
00136
00137 new_list[i].name = SMB_STRDUP(APPLEDOUBLE);
00138 new_list[i].is_wild = False;
00139
00140 free_namearray(*list);
00141
00142 *list = new_list;
00143 new_list = 0;
00144 cur_list = 0;
00145 }
00146
00147 static void atalk_rrmdir(TALLOC_CTX *ctx, char *path)
00148 {
00149 char *dpath;
00150 SMB_STRUCT_DIRENT *dent = 0;
00151 SMB_STRUCT_DIR *dir;
00152
00153 if (!path) return;
00154
00155 dir = sys_opendir(path);
00156 if (!dir) return;
00157
00158 while (NULL != (dent = sys_readdir(dir))) {
00159 if (strcmp(dent->d_name, ".") == 0 ||
00160 strcmp(dent->d_name, "..") == 0)
00161 continue;
00162 if (!(dpath = talloc_asprintf(ctx, "%s/%s",
00163 path, dent->d_name)))
00164 continue;
00165 atalk_unlink_file(dpath);
00166 }
00167
00168 sys_closedir(dir);
00169 }
00170
00171
00172
00173
00174
00175 static SMB_STRUCT_DIR *atalk_opendir(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
00176 {
00177 SMB_STRUCT_DIR *ret = 0;
00178
00179 ret = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 atalk_add_to_list(&handle->conn->hide_list);
00191 atalk_add_to_list(&handle->conn->veto_list);
00192
00193 return ret;
00194 }
00195
00196 static int atalk_rmdir(struct vfs_handle_struct *handle, const char *path)
00197 {
00198 BOOL add = False;
00199 TALLOC_CTX *ctx = 0;
00200 char *dpath;
00201
00202 if (!handle->conn->origpath || !path) goto exit_rmdir;
00203
00204
00205
00206
00207
00208 strstr(path, APPLEDOUBLE) ? (add = False) : (add = True);
00209
00210 if (!(ctx = talloc_init("remove_directory")))
00211 goto exit_rmdir;
00212
00213 if (!(dpath = talloc_asprintf(ctx, "%s/%s%s",
00214 handle->conn->origpath, path, add ? "/"APPLEDOUBLE : "")))
00215 goto exit_rmdir;
00216
00217 atalk_rrmdir(ctx, dpath);
00218
00219 exit_rmdir:
00220 talloc_destroy(ctx);
00221 return SMB_VFS_NEXT_RMDIR(handle, path);
00222 }
00223
00224
00225
00226 static int atalk_rename(struct vfs_handle_struct *handle, const char *oldname, const char *newname)
00227 {
00228 int ret = 0;
00229 char *adbl_path = 0;
00230 char *orig_path = 0;
00231 SMB_STRUCT_STAT adbl_info;
00232 SMB_STRUCT_STAT orig_info;
00233 TALLOC_CTX *ctx;
00234
00235 ret = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
00236
00237 if (!oldname) return ret;
00238
00239 if (!(ctx = talloc_init("rename_file")))
00240 return ret;
00241
00242 if (atalk_build_paths(ctx, handle->conn->origpath, oldname, &adbl_path, &orig_path,
00243 &adbl_info, &orig_info) != 0)
00244 goto exit_rename;
00245
00246 if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) {
00247 DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
00248 goto exit_rename;
00249 }
00250
00251 atalk_unlink_file(adbl_path);
00252
00253 exit_rename:
00254 talloc_destroy(ctx);
00255 return ret;
00256 }
00257
00258 static int atalk_unlink(struct vfs_handle_struct *handle, const char *path)
00259 {
00260 int ret = 0, i;
00261 char *adbl_path = 0;
00262 char *orig_path = 0;
00263 SMB_STRUCT_STAT adbl_info;
00264 SMB_STRUCT_STAT orig_info;
00265 TALLOC_CTX *ctx;
00266
00267 ret = SMB_VFS_NEXT_UNLINK(handle, path);
00268
00269 if (!path) return ret;
00270
00271
00272
00273
00274
00275 if (!handle->conn->veto_list) return ret;
00276 if (!handle->conn->hide_list) return ret;
00277
00278 for (i = 0; handle->conn->veto_list[i].name; i ++) {
00279 if (strstr(handle->conn->veto_list[i].name, APPLEDOUBLE))
00280 break;
00281 }
00282
00283 if (!handle->conn->veto_list[i].name) {
00284 for (i = 0; handle->conn->hide_list[i].name; i ++) {
00285 if (strstr(handle->conn->hide_list[i].name, APPLEDOUBLE))
00286 break;
00287 else {
00288 DEBUG(3, ("ATALK: %s is not hidden, skipped..\n",
00289 APPLEDOUBLE));
00290 return ret;
00291 }
00292 }
00293 }
00294
00295 if (!(ctx = talloc_init("unlink_file")))
00296 return ret;
00297
00298 if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path,
00299 &adbl_info, &orig_info) != 0)
00300 goto exit_unlink;
00301
00302 if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) {
00303 DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
00304 goto exit_unlink;
00305 }
00306
00307 atalk_unlink_file(adbl_path);
00308
00309 exit_unlink:
00310 talloc_destroy(ctx);
00311 return ret;
00312 }
00313
00314 static int atalk_chmod(struct vfs_handle_struct *handle, const char *path, mode_t mode)
00315 {
00316 int ret = 0;
00317 char *adbl_path = 0;
00318 char *orig_path = 0;
00319 SMB_STRUCT_STAT adbl_info;
00320 SMB_STRUCT_STAT orig_info;
00321 TALLOC_CTX *ctx;
00322
00323 ret = SMB_VFS_NEXT_CHMOD(handle, path, mode);
00324
00325 if (!path) return ret;
00326
00327 if (!(ctx = talloc_init("chmod_file")))
00328 return ret;
00329
00330 if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path,
00331 &adbl_info, &orig_info) != 0)
00332 goto exit_chmod;
00333
00334 if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) {
00335 DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
00336 goto exit_chmod;
00337 }
00338
00339 chmod(adbl_path, ADOUBLEMODE);
00340
00341 exit_chmod:
00342 talloc_destroy(ctx);
00343 return ret;
00344 }
00345
00346 static int atalk_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
00347 {
00348 int ret = 0;
00349 char *adbl_path = 0;
00350 char *orig_path = 0;
00351 SMB_STRUCT_STAT adbl_info;
00352 SMB_STRUCT_STAT orig_info;
00353 TALLOC_CTX *ctx;
00354
00355 ret = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
00356
00357 if (!path) return ret;
00358
00359 if (!(ctx = talloc_init("chown_file")))
00360 return ret;
00361
00362 if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, &orig_path,
00363 &adbl_info, &orig_info) != 0)
00364 goto exit_chown;
00365
00366 if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) {
00367 DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
00368 goto exit_chown;
00369 }
00370
00371 chown(adbl_path, uid, gid);
00372
00373 exit_chown:
00374 talloc_destroy(ctx);
00375 return ret;
00376 }
00377
00378 static vfs_op_tuple atalk_ops[] = {
00379
00380
00381
00382 {SMB_VFS_OP(atalk_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
00383 {SMB_VFS_OP(atalk_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
00384
00385
00386
00387 {SMB_VFS_OP(atalk_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
00388 {SMB_VFS_OP(atalk_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
00389 {SMB_VFS_OP(atalk_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
00390 {SMB_VFS_OP(atalk_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
00391
00392
00393
00394 {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
00395 };
00396
00397 NTSTATUS vfs_netatalk_init(void);
00398 NTSTATUS vfs_netatalk_init(void)
00399 {
00400 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "netatalk", atalk_ops);
00401 }