PageRenderTime 26ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/samba-3.5.6/source3/modules/vfs_netatalk.c

https://github.com/theuni/XBMC-deps
C | 448 lines | 317 code | 92 blank | 39 comment | 77 complexity | 664b6b602641b26c77b6876e1f3fb9ff MD5 | raw file
  1. /*
  2. * AppleTalk VFS module for Samba-3.x
  3. *
  4. * Copyright (C) Alexei Kotovich, 2002
  5. * Copyright (C) Stefan (metze) Metzmacher, 2003
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "includes.h"
  21. #undef DBGC_CLASS
  22. #define DBGC_CLASS DBGC_VFS
  23. #define APPLEDOUBLE ".AppleDouble"
  24. #define ADOUBLEMODE 0777
  25. /* atalk functions */
  26. static int atalk_build_paths(TALLOC_CTX *ctx, const char *path,
  27. const char *fname,
  28. char **adbl_path, char **orig_path,
  29. SMB_STRUCT_STAT *adbl_info,
  30. SMB_STRUCT_STAT *orig_info,
  31. bool fake_dir_create_times);
  32. static int atalk_unlink_file(const char *path);
  33. static int atalk_get_path_ptr(char *path)
  34. {
  35. int i = 0;
  36. int ptr = 0;
  37. for (i = 0; path[i]; i ++) {
  38. if (path[i] == '/')
  39. ptr = i;
  40. /* get out some 'spam';) from win32's file name */
  41. else if (path[i] == ':') {
  42. path[i] = '\0';
  43. break;
  44. }
  45. }
  46. return ptr;
  47. }
  48. static int atalk_build_paths(TALLOC_CTX *ctx, const char *path,
  49. const char *fname,
  50. char **adbl_path, char **orig_path,
  51. SMB_STRUCT_STAT *adbl_info,
  52. SMB_STRUCT_STAT *orig_info,
  53. bool fake_dir_create_times)
  54. {
  55. int ptr0 = 0;
  56. int ptr1 = 0;
  57. char *dname = 0;
  58. char *name = 0;
  59. if (!ctx || !path || !fname || !adbl_path || !orig_path ||
  60. !adbl_info || !orig_info)
  61. return -1;
  62. #if 0
  63. DEBUG(3, ("ATALK: PATH: %s[%s]\n", path, fname));
  64. #endif
  65. if (strstr(path, APPLEDOUBLE) || strstr(fname, APPLEDOUBLE)) {
  66. DEBUG(3, ("ATALK: path %s[%s] already contains %s\n", path, fname, APPLEDOUBLE));
  67. return -1;
  68. }
  69. if (fname[0] == '.') ptr0 ++;
  70. if (fname[1] == '/') ptr0 ++;
  71. *orig_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
  72. /* get pointer to last '/' */
  73. ptr1 = atalk_get_path_ptr(*orig_path);
  74. sys_lstat(*orig_path, orig_info, fake_dir_create_times);
  75. if (S_ISDIR(orig_info->st_ex_mode)) {
  76. *adbl_path = talloc_asprintf(ctx, "%s/%s/%s/",
  77. path, &fname[ptr0], APPLEDOUBLE);
  78. } else {
  79. dname = talloc_strdup(ctx, *orig_path);
  80. dname[ptr1] = '\0';
  81. name = *orig_path;
  82. *adbl_path = talloc_asprintf(ctx, "%s/%s/%s",
  83. dname, APPLEDOUBLE, &name[ptr1 + 1]);
  84. }
  85. #if 0
  86. DEBUG(3, ("ATALK: DEBUG:\n%s\n%s\n", *orig_path, *adbl_path));
  87. #endif
  88. sys_lstat(*adbl_path, adbl_info, fake_dir_create_times);
  89. return 0;
  90. }
  91. static int atalk_unlink_file(const char *path)
  92. {
  93. int ret = 0;
  94. become_root();
  95. ret = unlink(path);
  96. unbecome_root();
  97. return ret;
  98. }
  99. static void atalk_add_to_list(name_compare_entry **list)
  100. {
  101. int i, count = 0;
  102. name_compare_entry *new_list = 0;
  103. name_compare_entry *cur_list = 0;
  104. cur_list = *list;
  105. if (cur_list) {
  106. for (i = 0, count = 0; cur_list[i].name; i ++, count ++) {
  107. if (strstr(cur_list[i].name, APPLEDOUBLE))
  108. return;
  109. }
  110. }
  111. if (!(new_list = SMB_CALLOC_ARRAY(name_compare_entry, count + 2)))
  112. return;
  113. for (i = 0; i < count; i ++) {
  114. new_list[i].name = SMB_STRDUP(cur_list[i].name);
  115. new_list[i].is_wild = cur_list[i].is_wild;
  116. }
  117. new_list[i].name = SMB_STRDUP(APPLEDOUBLE);
  118. new_list[i].is_wild = False;
  119. free_namearray(*list);
  120. *list = new_list;
  121. new_list = 0;
  122. cur_list = 0;
  123. }
  124. static void atalk_rrmdir(TALLOC_CTX *ctx, char *path)
  125. {
  126. char *dpath;
  127. SMB_STRUCT_DIRENT *dent = 0;
  128. SMB_STRUCT_DIR *dir;
  129. if (!path) return;
  130. dir = sys_opendir(path);
  131. if (!dir) return;
  132. while (NULL != (dent = sys_readdir(dir))) {
  133. if (strcmp(dent->d_name, ".") == 0 ||
  134. strcmp(dent->d_name, "..") == 0)
  135. continue;
  136. if (!(dpath = talloc_asprintf(ctx, "%s/%s",
  137. path, dent->d_name)))
  138. continue;
  139. atalk_unlink_file(dpath);
  140. }
  141. sys_closedir(dir);
  142. }
  143. /* Disk operations */
  144. /* Directory operations */
  145. static SMB_STRUCT_DIR *atalk_opendir(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
  146. {
  147. SMB_STRUCT_DIR *ret = 0;
  148. ret = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
  149. /*
  150. * when we try to perform delete operation upon file which has fork
  151. * in ./.AppleDouble and this directory wasn't hidden by Samba,
  152. * MS Windows explorer causes the error: "Cannot find the specified file"
  153. * There is some workaround to avoid this situation, i.e. if
  154. * connection has not .AppleDouble entry in either veto or hide
  155. * list then it would be nice to add one.
  156. */
  157. atalk_add_to_list(&handle->conn->hide_list);
  158. atalk_add_to_list(&handle->conn->veto_list);
  159. return ret;
  160. }
  161. static int atalk_rmdir(struct vfs_handle_struct *handle, const char *path)
  162. {
  163. bool add = False;
  164. TALLOC_CTX *ctx = 0;
  165. char *dpath;
  166. if (!handle->conn->origpath || !path) goto exit_rmdir;
  167. /* due to there is no way to change bDeleteVetoFiles variable
  168. * from this module, gotta use talloc stuff..
  169. */
  170. strstr(path, APPLEDOUBLE) ? (add = False) : (add = True);
  171. if (!(ctx = talloc_init("remove_directory")))
  172. goto exit_rmdir;
  173. if (!(dpath = talloc_asprintf(ctx, "%s/%s%s",
  174. handle->conn->origpath, path, add ? "/"APPLEDOUBLE : "")))
  175. goto exit_rmdir;
  176. atalk_rrmdir(ctx, dpath);
  177. exit_rmdir:
  178. talloc_destroy(ctx);
  179. return SMB_VFS_NEXT_RMDIR(handle, path);
  180. }
  181. /* File operations */
  182. static int atalk_rename(struct vfs_handle_struct *handle,
  183. const struct smb_filename *smb_fname_src,
  184. const struct smb_filename *smb_fname_dst)
  185. {
  186. int ret = 0;
  187. char *oldname = NULL;
  188. char *adbl_path = NULL;
  189. char *orig_path = NULL;
  190. SMB_STRUCT_STAT adbl_info;
  191. SMB_STRUCT_STAT orig_info;
  192. NTSTATUS status;
  193. ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
  194. status = get_full_smb_filename(talloc_tos(), smb_fname_src, &oldname);
  195. if (!NT_STATUS_IS_OK(status)) {
  196. return ret;
  197. }
  198. if (atalk_build_paths(talloc_tos(), handle->conn->origpath, oldname,
  199. &adbl_path, &orig_path, &adbl_info,
  200. &orig_info, false) != 0)
  201. goto exit_rename;
  202. if (S_ISDIR(orig_info.st_ex_mode) || S_ISREG(orig_info.st_ex_mode)) {
  203. DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
  204. goto exit_rename;
  205. }
  206. atalk_unlink_file(adbl_path);
  207. exit_rename:
  208. TALLOC_FREE(oldname);
  209. TALLOC_FREE(adbl_path);
  210. TALLOC_FREE(orig_path);
  211. return ret;
  212. }
  213. static int atalk_unlink(struct vfs_handle_struct *handle,
  214. const struct smb_filename *smb_fname)
  215. {
  216. int ret = 0, i;
  217. char *path = NULL;
  218. char *adbl_path = NULL;
  219. char *orig_path = NULL;
  220. SMB_STRUCT_STAT adbl_info;
  221. SMB_STRUCT_STAT orig_info;
  222. NTSTATUS status;
  223. ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
  224. status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
  225. if (!NT_STATUS_IS_OK(status)) {
  226. return ret;
  227. }
  228. /* no .AppleDouble sync if veto or hide list is empty,
  229. * otherwise "Cannot find the specified file" error will be caused
  230. */
  231. if (!handle->conn->veto_list) return ret;
  232. if (!handle->conn->hide_list) return ret;
  233. for (i = 0; handle->conn->veto_list[i].name; i ++) {
  234. if (strstr(handle->conn->veto_list[i].name, APPLEDOUBLE))
  235. break;
  236. }
  237. if (!handle->conn->veto_list[i].name) {
  238. for (i = 0; handle->conn->hide_list[i].name; i ++) {
  239. if (strstr(handle->conn->hide_list[i].name, APPLEDOUBLE))
  240. break;
  241. else {
  242. DEBUG(3, ("ATALK: %s is not hidden, skipped..\n",
  243. APPLEDOUBLE));
  244. goto exit_unlink;
  245. }
  246. }
  247. }
  248. if (atalk_build_paths(talloc_tos(), handle->conn->origpath, path,
  249. &adbl_path, &orig_path,
  250. &adbl_info, &orig_info, false) != 0)
  251. goto exit_unlink;
  252. if (S_ISDIR(orig_info.st_ex_mode) || S_ISREG(orig_info.st_ex_mode)) {
  253. DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
  254. goto exit_unlink;
  255. }
  256. atalk_unlink_file(adbl_path);
  257. exit_unlink:
  258. TALLOC_FREE(path);
  259. TALLOC_FREE(adbl_path);
  260. TALLOC_FREE(orig_path);
  261. return ret;
  262. }
  263. static int atalk_chmod(struct vfs_handle_struct *handle, const char *path, mode_t mode)
  264. {
  265. int ret = 0;
  266. char *adbl_path = 0;
  267. char *orig_path = 0;
  268. SMB_STRUCT_STAT adbl_info;
  269. SMB_STRUCT_STAT orig_info;
  270. TALLOC_CTX *ctx;
  271. ret = SMB_VFS_NEXT_CHMOD(handle, path, mode);
  272. if (!path) return ret;
  273. if (!(ctx = talloc_init("chmod_file")))
  274. return ret;
  275. if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path,
  276. &orig_path, &adbl_info, &orig_info,
  277. false) != 0)
  278. goto exit_chmod;
  279. if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) {
  280. DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
  281. goto exit_chmod;
  282. }
  283. chmod(adbl_path, ADOUBLEMODE);
  284. exit_chmod:
  285. talloc_destroy(ctx);
  286. return ret;
  287. }
  288. static int atalk_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
  289. {
  290. int ret = 0;
  291. char *adbl_path = 0;
  292. char *orig_path = 0;
  293. SMB_STRUCT_STAT adbl_info;
  294. SMB_STRUCT_STAT orig_info;
  295. TALLOC_CTX *ctx;
  296. ret = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
  297. if (!path) return ret;
  298. if (!(ctx = talloc_init("chown_file")))
  299. return ret;
  300. if (atalk_build_paths(ctx, handle->conn->origpath, path,
  301. &adbl_path, &orig_path,
  302. &adbl_info, &orig_info, false) != 0)
  303. goto exit_chown;
  304. if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) {
  305. DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
  306. goto exit_chown;
  307. }
  308. if (chown(adbl_path, uid, gid) == -1) {
  309. DEBUG(3, ("ATALK: chown error %s\n", strerror(errno)));
  310. }
  311. exit_chown:
  312. talloc_destroy(ctx);
  313. return ret;
  314. }
  315. static int atalk_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
  316. {
  317. int ret = 0;
  318. char *adbl_path = 0;
  319. char *orig_path = 0;
  320. SMB_STRUCT_STAT adbl_info;
  321. SMB_STRUCT_STAT orig_info;
  322. TALLOC_CTX *ctx;
  323. ret = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
  324. if (!path) return ret;
  325. if (!(ctx = talloc_init("lchown_file")))
  326. return ret;
  327. if (atalk_build_paths(ctx, handle->conn->origpath, path,
  328. &adbl_path, &orig_path,
  329. &adbl_info, &orig_info, false) != 0)
  330. goto exit_lchown;
  331. if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) {
  332. DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
  333. goto exit_lchown;
  334. }
  335. if (lchown(adbl_path, uid, gid) == -1) {
  336. DEBUG(3, ("ATALK: lchown error %s\n", strerror(errno)));
  337. }
  338. exit_lchown:
  339. talloc_destroy(ctx);
  340. return ret;
  341. }
  342. static struct vfs_fn_pointers vfs_netatalk_fns = {
  343. .opendir = atalk_opendir,
  344. .rmdir = atalk_rmdir,
  345. .rename = atalk_rename,
  346. .unlink = atalk_unlink,
  347. .chmod = atalk_chmod,
  348. .chown = atalk_chown,
  349. .lchown = atalk_lchown,
  350. };
  351. NTSTATUS vfs_netatalk_init(void);
  352. NTSTATUS vfs_netatalk_init(void)
  353. {
  354. return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "netatalk",
  355. &vfs_netatalk_fns);
  356. }